mirror of https://github.com/nucypher/nucypher.git
Merge pull request #2693 from derekpierre/reward-ratio
Add CLI disclaimer about known issue with the "stake increase" and "stake merge" operations and recommend workaround - instead create sub-stake then merge after commitment performed in period after sub-stake creationpull/2731/head
commit
1f215b8d36
|
@ -0,0 +1,2 @@
|
|||
Add disclaimers to ``nucypher stake increase`` and ``nucypher stake merge`` CLI operations to provide warning about
|
||||
potential reduced rewards for the first period after stake increase due to a known bug, and the workaround.
|
|
@ -94,6 +94,8 @@ from nucypher.cli.literature import (
|
|||
FETCHING_INACTIVE_STAKES,
|
||||
MIGRATION_ALREADY_PERFORMED,
|
||||
CONFIRM_MANUAL_MIGRATION,
|
||||
CONFIRM_INCREASING_STAKE_DISCLAIMER,
|
||||
CONFIRM_MERGE_DISCLAIMER
|
||||
)
|
||||
from nucypher.cli.options import (
|
||||
group_options,
|
||||
|
@ -634,6 +636,7 @@ def increase(general_config: GroupGeneralConfig,
|
|||
#
|
||||
|
||||
if not force:
|
||||
click.confirm(CONFIRM_INCREASING_STAKE_DISCLAIMER, abort=True)
|
||||
lock_periods = current_stake.periods_remaining - 1
|
||||
current_period = STAKEHOLDER.staker.staking_agent.get_current_period()
|
||||
unlock_period = current_stake.final_locked_period + 1
|
||||
|
@ -1031,8 +1034,18 @@ def merge(general_config: GroupGeneralConfig,
|
|||
s.final_locked_period == stake_1.final_locked_period)
|
||||
|
||||
if not force:
|
||||
click.confirm(CONFIRM_MERGE.format(stake_index_1=stake_1.index, stake_index_2=stake_2.index), abort=True)
|
||||
if stake_1.first_locked_period != stake_2.first_locked_period:
|
||||
# this condition means that a temporary sub-stake will need to be created as part of the merge
|
||||
|
||||
# Need to ensure that a commitment has occurred in the period after the sub-stake was created
|
||||
# before merging to avoid issue observed in #2691
|
||||
last_commitment = STAKEHOLDER.staker.last_committed_period
|
||||
if last_commitment < (stake_1.first_locked_period + 1) \
|
||||
or last_commitment < (stake_2.first_locked_period + 1):
|
||||
# show disclaimer - potential for issue seen in #2691
|
||||
click.confirm(CONFIRM_MERGE_DISCLAIMER, abort=True)
|
||||
|
||||
click.confirm(CONFIRM_MERGE.format(stake_index_1=stake_1.index, stake_index_2=stake_2.index), abort=True)
|
||||
|
||||
# Non-interactive: Consistency check to prevent the above agreement from going stale.
|
||||
last_second_current_period = STAKEHOLDER.staker.staking_agent.get_current_period()
|
||||
|
|
|
@ -90,6 +90,23 @@ CONFIRM_BROADCAST_CREATE_STAKE = "Publish staged stake to the blockchain?"
|
|||
|
||||
CONFIRM_INCREASING_STAKE = "Confirm increase stake (index: {stake_index}) by {value}?"
|
||||
|
||||
CONFIRM_INCREASING_STAKE_DISCLAIMER = """
|
||||
NOTE: Due to a known issue with the StakingEscrow contract, using the increase operation may lead to reduced staking
|
||||
rewards for the first period after the increase (GitHub Issue: https://github.com/nucypher/nucypher/issues/2691).
|
||||
|
||||
The workaround to increase stake size without reduced staking rewards is the following:
|
||||
1. Create a new sub-stake with the same duration as the current sub-stake
|
||||
2. Wait until there has been a Worker node commitment made in the period after the sub-stake was created
|
||||
3. Once there has been a commitment made in the period after the sub-stake was created, merge the sub-stakes at any time afterwards
|
||||
|
||||
For example,
|
||||
- If you created a sub-stake in period 10
|
||||
- Wait until there has been a commitment made in the period after the sub-stake was created (i.e. in period 11)
|
||||
- Then merge the sub-stake in period 11 after the commitment, or during any period afterwards
|
||||
|
||||
Are you sure you want to use the increase operation instead of the workaround?
|
||||
"""
|
||||
|
||||
INSUFFICIENT_BALANCE_TO_INCREASE = "There are no tokens to increase stake"
|
||||
|
||||
INSUFFICIENT_BALANCE_TO_CREATE = "Insufficient NU for stake creation."
|
||||
|
@ -285,6 +302,19 @@ SUCCESSFUL_STAKE_PROLONG = 'Successfully Prolonged Stake'
|
|||
|
||||
CONFIRM_MERGE = "Publish merging of {stake_index_1} and {stake_index_2} stakes?"
|
||||
|
||||
CONFIRM_MERGE_DISCLAIMER = """
|
||||
NOTE: Due to a known issue with the StakingEscrow contract, using the merge operation may lead to reduced staking
|
||||
rewards for the first period after the merge (GitHub Issue: https://github.com/nucypher/nucypher/issues/2691).
|
||||
|
||||
Before merging a sub-stake, ensure that there has been a Worker node commitment that occurred in the period after the
|
||||
sub-stake was created. For example,
|
||||
- If you created a sub-stake in period 10
|
||||
- Wait until there has been a Worker node commitment made in the period after the sub-stake was created (i.e. in period 11)
|
||||
- Merge the sub-stake in period 11 after the commitment, or any time afterwards
|
||||
|
||||
Are you sure you want to merge now instead of waiting?
|
||||
"""
|
||||
|
||||
SUCCESSFUL_STAKES_MERGE = 'Successfully Merged Stakes'
|
||||
|
||||
CONFIRM_REMOVE_SUBSTAKE = "Publish removal of {stake_index} stake?"
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
"""
|
||||
This file is part of nucypher.
|
||||
|
||||
nucypher is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
nucypher is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from collections import Callable
|
||||
|
||||
from nucypher.blockchain.eth.agents import StakingEscrowAgent, NucypherTokenAgent, PolicyManagerAgent, ContractAgency
|
||||
from nucypher.blockchain.eth.signers.software import Web3Signer
|
||||
from nucypher.blockchain.eth.token import NU
|
||||
from nucypher.crypto.powers import TransactingPower
|
||||
|
||||
# Experimental max error
|
||||
from tests.contracts.integration.utils import commit_to_next_period, prepare_staker, MAX_NUNIT_ERROR
|
||||
|
||||
|
||||
def check_rewards_ratios_after_increase(testerchain,
|
||||
agency,
|
||||
token_economics,
|
||||
test_registry,
|
||||
increase_callable: Callable,
|
||||
skip_problematic_assertions_after_increase=False): # set to True to allow values to be printed and failing assertions skipped
|
||||
num_test_periods = 20
|
||||
min_periods_before_increase = 10
|
||||
|
||||
testerchain.time_travel(hours=1)
|
||||
staking_agent = ContractAgency.get_agent(StakingEscrowAgent, registry=test_registry)
|
||||
token_agent = ContractAgency.get_agent(NucypherTokenAgent, registry=test_registry)
|
||||
_policy_agent = ContractAgency.get_agent(PolicyManagerAgent, registry=test_registry)
|
||||
|
||||
origin = testerchain.etherbase_account
|
||||
ursula1 = testerchain.ursula_account(0) # staker that will stake minimum
|
||||
ursula2 = testerchain.ursula_account(1) # staker that will also stake minimum
|
||||
ursula3 = testerchain.ursula_account(2) # staker that will stake 2x minimum
|
||||
ursula3_staking_ratio = 2 # 2x min stake
|
||||
ursula4 = testerchain.ursula_account(3) # staker that will stake minimum but then increase stake to 2x minimum
|
||||
|
||||
origin_tpower = TransactingPower(signer=Web3Signer(client=testerchain.client), account=origin)
|
||||
ursula1_tpower = TransactingPower(signer=Web3Signer(client=testerchain.client), account=ursula1)
|
||||
ursula2_tpower = TransactingPower(signer=Web3Signer(client=testerchain.client), account=ursula2)
|
||||
ursula3_tpower = TransactingPower(signer=Web3Signer(client=testerchain.client), account=ursula3)
|
||||
ursula4_tpower = TransactingPower(signer=Web3Signer(client=testerchain.client), account=ursula4)
|
||||
ursulas_tpowers = [ursula1_tpower, ursula2_tpower, ursula3_tpower, ursula4_tpower]
|
||||
|
||||
configs = [(ursula1, ursula1_tpower, token_economics.minimum_allowed_locked), # simple staker staking minimum
|
||||
(ursula2, ursula2_tpower, token_economics.minimum_allowed_locked), # other staker staking minimum
|
||||
(ursula3, ursula3_tpower, token_economics.minimum_allowed_locked * ursula3_staking_ratio), # staker staking 2x minimum
|
||||
(ursula4, ursula4_tpower, token_economics.minimum_allowed_locked) # staker starting with minimum but will increase stake
|
||||
]
|
||||
for config in configs:
|
||||
prepare_staker(origin_tpower, staking_agent, token_agent, token_economics, config[0], config[1], config[2])
|
||||
|
||||
commit_to_next_period(staking_agent, ursulas_tpowers)
|
||||
testerchain.time_travel(periods=1)
|
||||
commit_to_next_period(staking_agent, ursulas_tpowers)
|
||||
|
||||
# no staking rewards as yet
|
||||
assert staking_agent.calculate_staking_reward(staker_address=ursula1) == 0
|
||||
assert staking_agent.calculate_staking_reward(staker_address=ursula2) == 0
|
||||
assert staking_agent.calculate_staking_reward(staker_address=ursula3) == 0
|
||||
assert staking_agent.calculate_staking_reward(staker_address=ursula4) == 0
|
||||
|
||||
# Get rewards
|
||||
ursula1_prior_period_cumulative_rewards = None
|
||||
ursula2_prior_period_cumulative_rewards = None
|
||||
ursula3_prior_period_cumulative_rewards = None
|
||||
ursula4_prior_period_cumulative_rewards = None
|
||||
|
||||
ursula4_period_of_increase = -1
|
||||
|
||||
ursula1_total_rewards_at_increase = None
|
||||
ursula2_total_rewards_at_increase = None
|
||||
ursula3_total_rewards_at_increase = None
|
||||
ursula4_total_rewards_at_increase = None
|
||||
|
||||
for i in range(1, num_test_periods+1):
|
||||
testerchain.time_travel(periods=1)
|
||||
commit_to_next_period(staking_agent, ursulas_tpowers)
|
||||
|
||||
ursula1_rewards = staking_agent.calculate_staking_reward(staker_address=ursula1)
|
||||
ursula2_rewards = staking_agent.calculate_staking_reward(staker_address=ursula2)
|
||||
ursula3_rewards = staking_agent.calculate_staking_reward(staker_address=ursula3)
|
||||
ursula4_rewards = staking_agent.calculate_staking_reward(staker_address=ursula4)
|
||||
|
||||
if ursula4_period_of_increase == -1:
|
||||
# still in phase before ursula4 increases their stake
|
||||
|
||||
# compare cumulative rewards
|
||||
assert ursula1_rewards == ursula2_rewards, f"rewards minted during {i} for {i-1}" # staking the same
|
||||
assert ursula4_rewards == ursula1_rewards, f"rewards minted during {i} for {i-1}" # pre-increase
|
||||
assert abs(ursula3_rewards - ursula1_rewards - ursula2_rewards) < MAX_NUNIT_ERROR, \
|
||||
f"rewards minted during {i} for {i-1}" # 2x
|
||||
else:
|
||||
# increase of stake performed by ursula4
|
||||
|
||||
# per period reward check
|
||||
ursula1_reward_for_period = (NU.from_nunits(ursula1_rewards)
|
||||
- ursula1_prior_period_cumulative_rewards)
|
||||
ursula2_reward_for_period = (NU.from_nunits(ursula2_rewards)
|
||||
- ursula2_prior_period_cumulative_rewards)
|
||||
ursula3_reward_for_period = (NU.from_nunits(ursula3_rewards)
|
||||
- ursula3_prior_period_cumulative_rewards)
|
||||
ursula4_reward_for_period = (NU.from_nunits(ursula4_rewards)
|
||||
- ursula4_prior_period_cumulative_rewards)
|
||||
|
||||
print(f">>> ursula1 reward calculated during period {i} for {i - 1}: {ursula1_reward_for_period}")
|
||||
print(f">>> ursula2 reward calculated during period {i} for {i - 1}: {ursula2_reward_for_period}")
|
||||
print(f">>> ursula3 reward calculated during period {i} for {i - 1}: {ursula3_reward_for_period}")
|
||||
print(f">>> ursula4 reward calculated during period {i} for {i - 1}: {ursula4_reward_for_period}")
|
||||
|
||||
if i == (ursula4_period_of_increase + 1):
|
||||
# this is the first period after increase
|
||||
assert skip_problematic_assertions_after_increase \
|
||||
or (ursula1_reward_for_period == ursula2_reward_for_period) # staking the same
|
||||
|
||||
# minted rewards for prior period (when stake was still same size) in which case reward for period should still be equal
|
||||
assert skip_problematic_assertions_after_increase \
|
||||
or (ursula4_reward_for_period == ursula1_reward_for_period)
|
||||
assert abs(ursula3_reward_for_period.to_tokens()
|
||||
- ursula1_reward_for_period.to_tokens()
|
||||
- ursula2_reward_for_period.to_tokens()) < MAX_NUNIT_ERROR
|
||||
|
||||
ursula1_total_rewards_at_increase = NU.from_nunits(ursula1_rewards)
|
||||
ursula2_total_rewards_at_increase = NU.from_nunits(ursula2_rewards)
|
||||
ursula3_total_rewards_at_increase = NU.from_nunits(ursula3_rewards)
|
||||
ursula4_total_rewards_at_increase = NU.from_nunits(ursula4_rewards)
|
||||
print(f">>> ursula1 total rewards when increase occurred {ursula1_total_rewards_at_increase}")
|
||||
print(f">>> ursula2 total rewards when increase occurred {ursula2_total_rewards_at_increase}")
|
||||
print(f">>> ursula3 total rewards when increase occurred {ursula3_total_rewards_at_increase}")
|
||||
print(f">>> ursula4 total rewards when increase occurred {ursula4_total_rewards_at_increase}")
|
||||
else:
|
||||
# ursula 1 and ursula 2 sill receive same rewards after increase
|
||||
assert (ursula2_reward_for_period == ursula1_reward_for_period), f"rewards minted during {i} for {i-1}"
|
||||
|
||||
# ursula3 and ursula4 now staking the same amount after increase so receive same rewards
|
||||
assert (ursula3_reward_for_period == ursula4_reward_for_period), f"rewards minted during {i} for {i-1}"
|
||||
|
||||
# ursula4, ursula3 now staking 2x ursula1, ursula2
|
||||
assert abs(ursula4_reward_for_period.to_tokens()
|
||||
- ursula1_reward_for_period.to_tokens()
|
||||
- ursula2_reward_for_period.to_tokens()) < MAX_NUNIT_ERROR, \
|
||||
f"per period reward during period {i} for period {i-1}; increase performed in {ursula4_period_of_increase}"
|
||||
|
||||
# now we check total rewards since increase performed by ursula2
|
||||
ursula1_total_rewards_since_increase = (NU.from_nunits(ursula1_rewards)
|
||||
- ursula1_total_rewards_at_increase)
|
||||
|
||||
ursula2_total_rewards_since_increase = (NU.from_nunits(ursula2_rewards)
|
||||
- ursula2_total_rewards_at_increase)
|
||||
|
||||
ursula3_total_rewards_since_increase = (NU.from_nunits(ursula3_rewards)
|
||||
- ursula3_total_rewards_at_increase)
|
||||
|
||||
ursula4_total_rewards_since_increase = (NU.from_nunits(ursula4_rewards)
|
||||
- ursula4_total_rewards_at_increase)
|
||||
|
||||
print(f">>> ursula1 rewards since increase: {ursula1_total_rewards_since_increase}")
|
||||
print(f">>> ursula2 rewards since increase: {ursula2_total_rewards_since_increase}")
|
||||
print(f">>> ursula3 rewards since increase: {ursula3_total_rewards_since_increase}")
|
||||
print(f">>> ursula4 rewards since increase: {ursula4_total_rewards_since_increase}")
|
||||
|
||||
# total rewards received since increase occurred
|
||||
# ursula1 and ursula2 receive the same
|
||||
assert ursula1_total_rewards_since_increase == ursula2_total_rewards_since_increase
|
||||
|
||||
# ursula3 should receive same as ursula4 since increase since staking same amount since increase
|
||||
assert ursula4_total_rewards_since_increase == ursula3_total_rewards_since_increase
|
||||
|
||||
# ursula4 should receive 2x ursula1 and ursula2 rewards
|
||||
assert abs(ursula4_total_rewards_since_increase.to_tokens()
|
||||
- ursula1_total_rewards_since_increase.to_tokens()
|
||||
- ursula2_total_rewards_since_increase.to_tokens()) < MAX_NUNIT_ERROR
|
||||
|
||||
# update cumulative rewards values
|
||||
ursula1_prior_period_cumulative_rewards = NU.from_nunits(ursula1_rewards)
|
||||
ursula2_prior_period_cumulative_rewards = NU.from_nunits(ursula2_rewards)
|
||||
ursula3_prior_period_cumulative_rewards = NU.from_nunits(ursula3_rewards)
|
||||
ursula4_prior_period_cumulative_rewards = NU.from_nunits(ursula4_rewards)
|
||||
|
||||
# Perform ursula4 increase of stake at a random period (switch//10) in phase 1
|
||||
if (i >= min_periods_before_increase) \
|
||||
and ursula4_rewards >= token_economics.minimum_allowed_locked \
|
||||
and ursula4_period_of_increase == -1:
|
||||
# minimum periods elapsed before attempting increase
|
||||
# AND enough rewards received to stake min stake amount
|
||||
# AND not already previously increased
|
||||
|
||||
lock_periods = 100 * token_economics.maximum_rewarded_periods # winddown is off
|
||||
amount = token_economics.minimum_allowed_locked
|
||||
increase_callable(i, staking_agent, lock_periods, amount, ursula4_tpower)
|
||||
ursula4_period_of_increase = i
|
||||
ursula4_prior_period_cumulative_rewards -= NU.from_nunits(
|
||||
token_economics.minimum_allowed_locked) # adjust for amount taken out of unlocked rewards
|
||||
|
||||
assert ursula4_period_of_increase != -1, "increase of stake actually occurred"
|
|
@ -15,55 +15,55 @@ You should have received a copy of the GNU Affero General Public License
|
|||
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
|
||||
import pytest
|
||||
|
||||
from nucypher.blockchain.eth.agents import StakingEscrowAgent, NucypherTokenAgent, PolicyManagerAgent, ContractAgency
|
||||
from nucypher.blockchain.eth.signers.software import Web3Signer
|
||||
from nucypher.crypto.powers import TransactingPower
|
||||
|
||||
# Experimental max error
|
||||
from tests.contracts.integration.utils import prepare_staker, commit_to_next_period
|
||||
|
||||
MAX_ERROR_FIRST_PHASE = 1e-20
|
||||
MAX_ERROR_SECOND_PHASE = 5e-3
|
||||
MAX_PERIODS_SECOND_PHASE = 100
|
||||
|
||||
|
||||
@pytest.mark.nightly
|
||||
def test_reward(testerchain, agency, token_economics):
|
||||
def test_reward(testerchain, agency, token_economics, test_registry):
|
||||
testerchain.time_travel(hours=1)
|
||||
token_agent, staking_agent, _policy_agent = agency
|
||||
staking_agent = ContractAgency.get_agent(StakingEscrowAgent, registry=test_registry)
|
||||
token_agent = ContractAgency.get_agent(NucypherTokenAgent, registry=test_registry)
|
||||
_policy_agent = ContractAgency.get_agent(PolicyManagerAgent, registry=test_registry)
|
||||
origin = testerchain.etherbase_account
|
||||
ursula = testerchain.ursula_account(0)
|
||||
ursula1 = testerchain.ursula_account(0)
|
||||
ursula2 = testerchain.ursula_account(1)
|
||||
origin_tpower = TransactingPower(signer=Web3Signer(client=testerchain.client), account=origin)
|
||||
ursula_tpower = TransactingPower(signer=Web3Signer(client=testerchain.client), account=ursula)
|
||||
ursula1_tpower = TransactingPower(signer=Web3Signer(client=testerchain.client), account=ursula1)
|
||||
ursula2_tpower = TransactingPower(signer=Web3Signer(client=testerchain.client), account=ursula2)
|
||||
|
||||
# Prepare one staker
|
||||
_txhash = token_agent.transfer(amount=token_economics.minimum_allowed_locked,
|
||||
target_address=ursula,
|
||||
transacting_power=origin_tpower)
|
||||
_txhash = token_agent.approve_transfer(amount=token_economics.minimum_allowed_locked,
|
||||
spender_address=staking_agent.contract_address,
|
||||
transacting_power=ursula_tpower)
|
||||
_txhash = staking_agent.deposit_tokens(amount=token_economics.minimum_allowed_locked,
|
||||
lock_periods=100 * token_economics.maximum_rewarded_periods,
|
||||
transacting_power=ursula_tpower,
|
||||
staker_address=ursula)
|
||||
prepare_staker(origin_tpower, staking_agent, token_agent, token_economics, ursula1, ursula1_tpower, token_economics.minimum_allowed_locked)
|
||||
prepare_staker(origin_tpower, staking_agent, token_agent, token_economics, ursula2, ursula2_tpower,
|
||||
token_economics.minimum_allowed_locked * 3) # 3x min
|
||||
|
||||
_txhash = staking_agent.bond_worker(staker_address=ursula, worker_address=ursula)
|
||||
_txhash = staking_agent.set_restaking(staker_address=ursula, value=False)
|
||||
|
||||
_txhash = staking_agent.commit_to_next_period(worker_address=ursula)
|
||||
ursulas_tpowers = [ursula1_tpower, ursula2_tpower]
|
||||
commit_to_next_period(staking_agent, ursulas_tpowers)
|
||||
testerchain.time_travel(periods=1)
|
||||
_txhash = staking_agent.commit_to_next_period(worker_address=ursula)
|
||||
assert staking_agent.calculate_staking_reward(staker_address=ursula) == 0
|
||||
commit_to_next_period(staking_agent, ursulas_tpowers)
|
||||
|
||||
assert staking_agent.calculate_staking_reward(staker_address=ursula1) == 0
|
||||
assert staking_agent.calculate_staking_reward(staker_address=ursula2) == 0
|
||||
|
||||
# Get a reward
|
||||
switch = token_economics.first_phase_final_period()
|
||||
for i in range(1, switch + MAX_PERIODS_SECOND_PHASE):
|
||||
testerchain.time_travel(periods=1)
|
||||
_txhash = staking_agent.commit_to_next_period(transacting_power=ursula_tpower)
|
||||
contract_reward = staking_agent.calculate_staking_reward(staker_address=ursula)
|
||||
commit_to_next_period(staking_agent, ursulas_tpowers)
|
||||
|
||||
ursula1_rewards = staking_agent.calculate_staking_reward(staker_address=ursula1)
|
||||
ursula2_rewards = staking_agent.calculate_staking_reward(staker_address=ursula2)
|
||||
calculations_reward = token_economics.cumulative_rewards_at_period(i)
|
||||
error = abs((contract_reward - calculations_reward) / calculations_reward)
|
||||
error = abs((ursula1_rewards + ursula2_rewards - calculations_reward) / calculations_reward)
|
||||
if i <= switch:
|
||||
assert error < MAX_ERROR_FIRST_PHASE
|
||||
else:
|
||||
|
|
|
@ -0,0 +1,224 @@
|
|||
"""
|
||||
This file is part of nucypher.
|
||||
|
||||
nucypher is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
nucypher is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from nucypher.blockchain.eth.agents import StakingEscrowAgent, NucypherTokenAgent, PolicyManagerAgent, ContractAgency
|
||||
from nucypher.blockchain.eth.signers.software import Web3Signer
|
||||
from nucypher.blockchain.eth.token import NU
|
||||
from nucypher.crypto.powers import TransactingPower
|
||||
|
||||
# Experimental max error
|
||||
from tests.contracts.integration.utils import prepare_staker, commit_to_next_period, MAX_NUNIT_ERROR
|
||||
|
||||
|
||||
def test_stake_increase_add_merge_after_commitment_in_period_after_add(testerchain,
|
||||
agency,
|
||||
token_economics,
|
||||
test_registry,
|
||||
skip_problematic_assertions_after_increase=False): # set to True to allow values to be printed and failing assertions skipped
|
||||
num_test_periods = 20
|
||||
min_periods_before_merge = 10
|
||||
|
||||
testerchain.time_travel(hours=1)
|
||||
staking_agent = ContractAgency.get_agent(StakingEscrowAgent, registry=test_registry)
|
||||
token_agent = ContractAgency.get_agent(NucypherTokenAgent, registry=test_registry)
|
||||
_policy_agent = ContractAgency.get_agent(PolicyManagerAgent, registry=test_registry)
|
||||
|
||||
origin = testerchain.etherbase_account
|
||||
ursula1 = testerchain.ursula_account(0) # staker that will stake minimum
|
||||
ursula2 = testerchain.ursula_account(1) # staker that will also stake minimum
|
||||
ursula3 = testerchain.ursula_account(2) # staker that will stake 2x minimum
|
||||
ursula3_staking_ratio = 2 # 2x min stake
|
||||
ursula4 = testerchain.ursula_account(3) # staker that will stake minimum but then add new stake and merge to 2x minimum
|
||||
|
||||
origin_tpower = TransactingPower(signer=Web3Signer(client=testerchain.client), account=origin)
|
||||
ursula1_tpower = TransactingPower(signer=Web3Signer(client=testerchain.client), account=ursula1)
|
||||
ursula2_tpower = TransactingPower(signer=Web3Signer(client=testerchain.client), account=ursula2)
|
||||
ursula3_tpower = TransactingPower(signer=Web3Signer(client=testerchain.client), account=ursula3)
|
||||
ursula4_tpower = TransactingPower(signer=Web3Signer(client=testerchain.client), account=ursula4)
|
||||
ursulas_tpowers = [ursula1_tpower, ursula2_tpower, ursula3_tpower, ursula4_tpower]
|
||||
|
||||
configs = [(ursula1, ursula1_tpower, token_economics.minimum_allowed_locked), # simple staker staking minimum
|
||||
(ursula2, ursula2_tpower, token_economics.minimum_allowed_locked), # other staker staking minimum
|
||||
(ursula3, ursula3_tpower, token_economics.minimum_allowed_locked * ursula3_staking_ratio), # staker staking 2x minimum
|
||||
(ursula4, ursula4_tpower, token_economics.minimum_allowed_locked) # staker starting with minimum but will increase stake
|
||||
]
|
||||
for config in configs:
|
||||
prepare_staker(origin_tpower, staking_agent, token_agent, token_economics, config[0], config[1], config[2])
|
||||
|
||||
commit_to_next_period(staking_agent, ursulas_tpowers)
|
||||
testerchain.time_travel(periods=1)
|
||||
commit_to_next_period(staking_agent, ursulas_tpowers)
|
||||
|
||||
# no staking rewards as yet
|
||||
assert staking_agent.calculate_staking_reward(staker_address=ursula1) == 0
|
||||
assert staking_agent.calculate_staking_reward(staker_address=ursula2) == 0
|
||||
assert staking_agent.calculate_staking_reward(staker_address=ursula3) == 0
|
||||
assert staking_agent.calculate_staking_reward(staker_address=ursula4) == 0
|
||||
|
||||
# Get rewards
|
||||
ursula1_prior_period_cumulative_rewards = None
|
||||
ursula2_prior_period_cumulative_rewards = None
|
||||
ursula3_prior_period_cumulative_rewards = None
|
||||
ursula4_prior_period_cumulative_rewards = None
|
||||
|
||||
ursula4_period_of_additional_substake = -1
|
||||
ursula4_period_of_merge = -1
|
||||
|
||||
ursula1_total_rewards_at_increase = None
|
||||
ursula2_total_rewards_at_increase = None
|
||||
ursula3_total_rewards_at_increase = None
|
||||
ursula4_total_rewards_at_increase = None
|
||||
|
||||
for i in range(1, num_test_periods+1):
|
||||
testerchain.time_travel(periods=1)
|
||||
commit_to_next_period(staking_agent, ursulas_tpowers)
|
||||
|
||||
ursula1_rewards = staking_agent.calculate_staking_reward(staker_address=ursula1)
|
||||
ursula2_rewards = staking_agent.calculate_staking_reward(staker_address=ursula2)
|
||||
ursula3_rewards = staking_agent.calculate_staking_reward(staker_address=ursula3)
|
||||
ursula4_rewards = staking_agent.calculate_staking_reward(staker_address=ursula4)
|
||||
|
||||
if ursula4_period_of_additional_substake == -1:
|
||||
# still in phase before ursula4 increases their stake
|
||||
|
||||
# compare cumulative rewards
|
||||
assert ursula1_rewards == ursula2_rewards, f"rewards minted during {i} for {i-1}" # staking the same
|
||||
assert ursula4_rewards == ursula1_rewards, f"rewards minted during {i} for {i-1}" # pre-increase
|
||||
assert abs(ursula3_rewards - ursula1_rewards - ursula2_rewards) < MAX_NUNIT_ERROR, \
|
||||
f"rewards minted during {i} for {i-1}" # 2x
|
||||
else:
|
||||
# sub-stake added by ursula4
|
||||
|
||||
# per period reward check
|
||||
ursula1_reward_for_period = (NU.from_nunits(ursula1_rewards)
|
||||
- ursula1_prior_period_cumulative_rewards)
|
||||
ursula2_reward_for_period = (NU.from_nunits(ursula2_rewards)
|
||||
- ursula2_prior_period_cumulative_rewards)
|
||||
ursula3_reward_for_period = (NU.from_nunits(ursula3_rewards)
|
||||
- ursula3_prior_period_cumulative_rewards)
|
||||
ursula4_reward_for_period = (NU.from_nunits(ursula4_rewards)
|
||||
- ursula4_prior_period_cumulative_rewards)
|
||||
|
||||
print(f">>> ursula1 reward calculated during period {i} for {i - 1}: {ursula1_reward_for_period}")
|
||||
print(f">>> ursula2 reward calculated during period {i} for {i - 1}: {ursula2_reward_for_period}")
|
||||
print(f">>> ursula3 reward calculated during period {i} for {i - 1}: {ursula3_reward_for_period}")
|
||||
print(f">>> ursula4 reward calculated during period {i} for {i - 1}: {ursula4_reward_for_period}")
|
||||
|
||||
if i == (ursula4_period_of_additional_substake + 1):
|
||||
# this is the first period after increase
|
||||
assert skip_problematic_assertions_after_increase \
|
||||
or (ursula1_reward_for_period == ursula2_reward_for_period) # staking the same
|
||||
|
||||
# minted rewards for prior period (when stake was still same size) in which case reward for period should still be equal
|
||||
assert skip_problematic_assertions_after_increase \
|
||||
or (ursula4_reward_for_period == ursula1_reward_for_period)
|
||||
assert abs(ursula3_reward_for_period.to_tokens()
|
||||
- ursula1_reward_for_period.to_tokens()
|
||||
- ursula2_reward_for_period.to_tokens()) < MAX_NUNIT_ERROR
|
||||
|
||||
ursula1_total_rewards_at_increase = NU.from_nunits(ursula1_rewards)
|
||||
ursula2_total_rewards_at_increase = NU.from_nunits(ursula2_rewards)
|
||||
ursula3_total_rewards_at_increase = NU.from_nunits(ursula3_rewards)
|
||||
ursula4_total_rewards_at_increase = NU.from_nunits(ursula4_rewards)
|
||||
print(f">>> ursula1 total rewards when increase occurred {ursula1_total_rewards_at_increase}")
|
||||
print(f">>> ursula2 total rewards when increase occurred {ursula2_total_rewards_at_increase}")
|
||||
print(f">>> ursula3 total rewards when increase occurred {ursula3_total_rewards_at_increase}")
|
||||
print(f">>> ursula4 total rewards when increase occurred {ursula4_total_rewards_at_increase}")
|
||||
else:
|
||||
# ursula 1 and ursula 2 sill receive same rewards after increase
|
||||
assert (ursula2_reward_for_period == ursula1_reward_for_period), f"rewards minted during {i} for {i-1}"
|
||||
|
||||
# ursula3 and ursula4 now staking the same amount after additional sub-stake so receive same rewards
|
||||
assert abs(ursula3_reward_for_period.to_tokens()
|
||||
- ursula4_reward_for_period.to_tokens()) < MAX_NUNIT_ERROR, f"rewards minted during {i} for {i-1}"
|
||||
|
||||
# ursula4, ursula3 now staking 2x ursula1, ursula2
|
||||
assert abs(ursula4_reward_for_period.to_tokens()
|
||||
- ursula1_reward_for_period.to_tokens()
|
||||
- ursula2_reward_for_period.to_tokens()) < MAX_NUNIT_ERROR, \
|
||||
f"per period reward during period {i} for period {i-1}; increase performed in {ursula4_period_of_additional_substake}"
|
||||
|
||||
# now we check total rewards since increase performed by ursula2
|
||||
ursula1_total_rewards_since_increase = (NU.from_nunits(ursula1_rewards)
|
||||
- ursula1_total_rewards_at_increase)
|
||||
|
||||
ursula2_total_rewards_since_increase = (NU.from_nunits(ursula2_rewards)
|
||||
- ursula2_total_rewards_at_increase)
|
||||
|
||||
ursula3_total_rewards_since_increase = (NU.from_nunits(ursula3_rewards)
|
||||
- ursula3_total_rewards_at_increase)
|
||||
|
||||
ursula4_total_rewards_since_increase = (NU.from_nunits(ursula4_rewards)
|
||||
- ursula4_total_rewards_at_increase)
|
||||
|
||||
print(f">>> ursula1 rewards since increase: {ursula1_total_rewards_since_increase}")
|
||||
print(f">>> ursula2 rewards since increase: {ursula2_total_rewards_since_increase}")
|
||||
print(f">>> ursula3 rewards since increase: {ursula3_total_rewards_since_increase}")
|
||||
print(f">>> ursula4 rewards since increase: {ursula4_total_rewards_since_increase}")
|
||||
|
||||
# total rewards received since increase occurred
|
||||
# ursula1 and ursula2 receive the same
|
||||
assert ursula1_total_rewards_since_increase == ursula2_total_rewards_since_increase
|
||||
|
||||
# ursula3 should receive same as ursula4 since increase since staking same amount since increase
|
||||
assert abs(ursula4_total_rewards_since_increase.to_tokens()
|
||||
- ursula3_total_rewards_since_increase.to_tokens()) < MAX_NUNIT_ERROR
|
||||
|
||||
# ursula4 should receive 2x ursula1 and ursula2 rewards
|
||||
assert abs(ursula4_total_rewards_since_increase.to_tokens()
|
||||
- ursula1_total_rewards_since_increase.to_tokens()
|
||||
- ursula2_total_rewards_since_increase.to_tokens()) < MAX_NUNIT_ERROR
|
||||
|
||||
# update cumulative rewards values
|
||||
ursula1_prior_period_cumulative_rewards = NU.from_nunits(ursula1_rewards)
|
||||
ursula2_prior_period_cumulative_rewards = NU.from_nunits(ursula2_rewards)
|
||||
ursula3_prior_period_cumulative_rewards = NU.from_nunits(ursula3_rewards)
|
||||
ursula4_prior_period_cumulative_rewards = NU.from_nunits(ursula4_rewards)
|
||||
|
||||
# Add ursula4 sub-stake at a random period (switch//10) in phase 1
|
||||
if (i >= min_periods_before_merge) \
|
||||
and ursula4_rewards >= token_economics.minimum_allowed_locked \
|
||||
and ursula4_period_of_additional_substake == -1:
|
||||
# minimum periods elapsed before attempting increase
|
||||
# AND enough rewards received to stake min stake amount
|
||||
# AND sub-stake not already previously created
|
||||
|
||||
# add new sub-stake but don't merge as yet
|
||||
lock_periods = 100 * token_economics.maximum_rewarded_periods # winddown is off
|
||||
staking_agent.lock_and_create(transacting_power=ursula4_tpower,
|
||||
amount=token_economics.minimum_allowed_locked,
|
||||
lock_periods=lock_periods)
|
||||
print(f">>> Added new sub-stake to ursula4 in period {i}")
|
||||
ursula4_period_of_additional_substake = i
|
||||
ursula4_prior_period_cumulative_rewards -= NU.from_nunits(token_economics.minimum_allowed_locked) # adjust for amount taken out of unlocked rewards
|
||||
elif ursula4_period_of_additional_substake != -1 and i == (ursula4_period_of_additional_substake + 1): # wait 1 period before merging
|
||||
# merge ursula4 sub-stakes
|
||||
substake_0 = staking_agent.get_substake_info(staker_address=ursula4_tpower.account, stake_index=0)
|
||||
substake_1 = staking_agent.get_substake_info(staker_address=ursula4_tpower.account, stake_index=1)
|
||||
assert substake_0.last_period == substake_1.last_period
|
||||
last_committed_period = staking_agent.get_last_committed_period(staker_address=ursula4_tpower.account)
|
||||
assert last_committed_period >= substake_0.first_period + 1 # original sub-stake
|
||||
# new sub-stake (ensure commitment occurred in period after sub-stake was created
|
||||
assert last_committed_period == substake_1.first_period + 1
|
||||
_ = staking_agent.merge_stakes(transacting_power=ursula4_tpower,
|
||||
stake_index_1=0,
|
||||
stake_index_2=1)
|
||||
print(f">>> Merged sub-stake (0, 1) for ursula4 in period {i}")
|
||||
ursula4_period_of_merge = i
|
||||
|
||||
assert ursula4_period_of_additional_substake != -1, "addition of sub-stake actually occurred"
|
||||
assert ursula4_period_of_merge != -1 and ursula4_period_of_merge == (ursula4_period_of_additional_substake + 1), "merge of sub-stake actually occurred"
|
|
@ -0,0 +1,42 @@
|
|||
"""
|
||||
This file is part of nucypher.
|
||||
|
||||
nucypher is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
nucypher is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
import pytest
|
||||
|
||||
from tests.contracts.integration.increase import check_rewards_ratios_after_increase
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="This test depicts the known issue related to increasing stake and is expected to fail "
|
||||
"- see Issue #2691.")
|
||||
def test_rewards_ratios_after_increase_via_merge(testerchain, agency, token_economics, test_registry):
|
||||
check_rewards_ratios_after_increase(testerchain, agency, token_economics, test_registry,
|
||||
increase_callable=_increase_stake_via_merge,
|
||||
skip_problematic_assertions_after_increase=False)
|
||||
|
||||
|
||||
def _increase_stake_via_merge(i, staking_agent, lock_periods, amount, ursula4_tpower):
|
||||
# increase ursula4 stake by min staking amount via merge so that stake ratio of ursula1 or ursula2: ursula 4 is 1:2
|
||||
_ = staking_agent.lock_and_create(transacting_power=ursula4_tpower,
|
||||
amount=amount,
|
||||
lock_periods=lock_periods)
|
||||
substake_0 = staking_agent.get_substake_info(staker_address=ursula4_tpower.account, stake_index=0)
|
||||
substake_1 = staking_agent.get_substake_info(staker_address=ursula4_tpower.account, stake_index=1)
|
||||
assert substake_0.last_period == substake_1.last_period
|
||||
|
||||
_ = staking_agent.merge_stakes(transacting_power=ursula4_tpower,
|
||||
stake_index_1=0,
|
||||
stake_index_2=1)
|
||||
print(f">>> Increase ursula4 NU via merge in period {i}")
|
|
@ -0,0 +1,35 @@
|
|||
"""
|
||||
This file is part of nucypher.
|
||||
|
||||
nucypher is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
nucypher is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
import pytest
|
||||
|
||||
from tests.contracts.integration.increase import check_rewards_ratios_after_increase
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="This test depicts the known issue related to increasing stake and is expected to fail "
|
||||
"- see Issue #2691.")
|
||||
def test_rewards_ratios_after_increase(testerchain, agency, token_economics, test_registry):
|
||||
check_rewards_ratios_after_increase(testerchain, agency, token_economics, test_registry,
|
||||
increase_callable=_increase_stake,
|
||||
skip_problematic_assertions_after_increase=False)
|
||||
|
||||
|
||||
def _increase_stake(i, staking_agent, lock_periods, amount, ursula4_tpower):
|
||||
# increase ursula4 stake by min staking amount so that stake ratio of ursula1 or ursula2: ursula 4 is 1:2
|
||||
staking_agent.lock_and_increase(transacting_power=ursula4_tpower,
|
||||
amount=amount,
|
||||
stake_index=0)
|
||||
print(f">>> Increase ursula4 NU in period {i}")
|
|
@ -0,0 +1,42 @@
|
|||
"""
|
||||
This file is part of nucypher.
|
||||
|
||||
nucypher is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
nucypher is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
MAX_NUNIT_ERROR = 10 * 1e-18 # 2 decimal places
|
||||
|
||||
|
||||
def commit_to_next_period(staking_agent, ursulas_tpowers):
|
||||
for ursula_tpower in ursulas_tpowers:
|
||||
staking_agent.commit_to_next_period(transacting_power=ursula_tpower)
|
||||
|
||||
|
||||
def prepare_staker(origin_tpower, staking_agent, token_agent, token_economics, ursula, ursula_tpower, amount, lock_periods=None):
|
||||
if not lock_periods:
|
||||
lock_periods = 100 * token_economics.maximum_rewarded_periods
|
||||
|
||||
# Prepare one staker
|
||||
_txhash = token_agent.transfer(amount=amount,
|
||||
target_address=ursula,
|
||||
transacting_power=origin_tpower)
|
||||
_txhash = token_agent.approve_transfer(amount=amount,
|
||||
spender_address=staking_agent.contract_address,
|
||||
transacting_power=ursula_tpower)
|
||||
_txhash = staking_agent.deposit_tokens(amount=amount,
|
||||
lock_periods=lock_periods,
|
||||
transacting_power=ursula_tpower,
|
||||
staker_address=ursula)
|
||||
_txhash = staking_agent.bond_worker(transacting_power=ursula_tpower, worker_address=ursula)
|
||||
_txhash = staking_agent.set_restaking(transacting_power=ursula_tpower, value=False)
|
|
@ -73,7 +73,9 @@ from nucypher.cli.literature import (
|
|||
TOKEN_REWARD_CURRENT,
|
||||
TOKEN_REWARD_NOT_FOUND,
|
||||
TOKEN_REWARD_PAST,
|
||||
TOKEN_REWARD_PAST_HEADER
|
||||
TOKEN_REWARD_PAST_HEADER,
|
||||
CONFIRM_INCREASING_STAKE_DISCLAIMER,
|
||||
CONFIRM_MERGE_DISCLAIMER
|
||||
)
|
||||
from nucypher.cli.painting.staking import REWARDS_TABLE_COLUMNS, TOKEN_DECIMAL_PLACE
|
||||
from nucypher.config.constants import TEMPORARY_DOMAIN
|
||||
|
@ -668,7 +670,8 @@ def test_increase_interactive(click_runner,
|
|||
user_input = '\n'.join((str(selected_index),
|
||||
str(sub_stake_index),
|
||||
str(additional_value.to_tokens()),
|
||||
YES,
|
||||
YES, # confirm disclaimer
|
||||
YES, # confirm increase
|
||||
INSECURE_DEVELOPMENT_PASSWORD))
|
||||
|
||||
result = click_runner.invoke(stake, command, input=user_input, catch_exceptions=False)
|
||||
|
@ -697,6 +700,7 @@ def test_increase_interactive(click_runner,
|
|||
upper_limit = NU.from_nunits(balance)
|
||||
assert CONFIRM_STAKE_USE_UNLOCKED not in result.output # default is use staker address
|
||||
assert PROMPT_STAKE_INCREASE_VALUE.format(upper_limit=upper_limit) in result.output
|
||||
assert CONFIRM_INCREASING_STAKE_DISCLAIMER in result.output
|
||||
assert CONFIRM_INCREASING_STAKE.format(stake_index=sub_stake_index, value=additional_value) in result.output
|
||||
assert SUCCESSFUL_STAKE_INCREASE in result.output
|
||||
|
||||
|
@ -752,6 +756,7 @@ def test_increase_non_interactive(click_runner,
|
|||
|
||||
upper_limit = NU.from_nunits(token_economics.maximum_allowed_locked - locked_tokens)
|
||||
assert PROMPT_STAKE_INCREASE_VALUE.format(upper_limit=upper_limit) not in result.output
|
||||
assert CONFIRM_INCREASING_STAKE_DISCLAIMER not in result.output
|
||||
assert CONFIRM_INCREASING_STAKE.format(stake_index=sub_stake_index, value=additional_value) not in result.output
|
||||
assert SUCCESSFUL_STAKE_INCREASE in result.output
|
||||
assert CONFIRM_STAKE_USE_UNLOCKED not in result.output # default is use staker address
|
||||
|
@ -799,7 +804,8 @@ def test_increase_lock_interactive(click_runner,
|
|||
str(sub_stake_index),
|
||||
YES,
|
||||
str(additional_value.to_tokens()),
|
||||
YES,
|
||||
YES, # confirm disclaimer
|
||||
YES, # confirm increase
|
||||
INSECURE_DEVELOPMENT_PASSWORD))
|
||||
|
||||
result = click_runner.invoke(stake, command, input=user_input, catch_exceptions=False)
|
||||
|
@ -826,6 +832,7 @@ def test_increase_lock_interactive(click_runner,
|
|||
|
||||
upper_limit = NU.from_nunits(token_economics.maximum_allowed_locked - locked_tokens)
|
||||
assert PROMPT_STAKE_INCREASE_VALUE.format(upper_limit=upper_limit) in result.output
|
||||
assert CONFIRM_INCREASING_STAKE_DISCLAIMER in result.output
|
||||
assert CONFIRM_INCREASING_STAKE.format(stake_index=sub_stake_index, value=additional_value) in result.output
|
||||
assert SUCCESSFUL_STAKE_INCREASE in result.output
|
||||
assert CONFIRM_STAKE_USE_UNLOCKED in result.output # value not provided but --from-unlocked specified so prompted
|
||||
|
@ -876,6 +883,7 @@ def test_increase_lock_non_interactive(click_runner,
|
|||
upper_limit = NU.from_nunits(unlocked_tokens)
|
||||
assert CONFIRM_STAKE_USE_UNLOCKED not in result.output # value provided so not prompted
|
||||
assert PROMPT_STAKE_INCREASE_VALUE.format(upper_limit=upper_limit) not in result.output
|
||||
assert CONFIRM_INCREASING_STAKE_DISCLAIMER not in result.output
|
||||
assert CONFIRM_INCREASING_STAKE.format(stake_index=sub_stake_index, value=additional_value) not in result.output
|
||||
assert SUCCESSFUL_STAKE_INCREASE in result.output
|
||||
|
||||
|
@ -1217,7 +1225,8 @@ def test_merge_interactive(click_runner,
|
|||
user_input = '\n'.join((str(selected_index),
|
||||
str(sub_stake_index_1),
|
||||
str(sub_stake_index_2),
|
||||
YES,
|
||||
YES, # confirm disclaimer
|
||||
YES, # confirm merge
|
||||
INSECURE_DEVELOPMENT_PASSWORD))
|
||||
|
||||
result = click_runner.invoke(stake, command, input=user_input, catch_exceptions=False)
|
||||
|
@ -1225,6 +1234,7 @@ def test_merge_interactive(click_runner,
|
|||
|
||||
final_period = surrogate_stakes[selected_index][sub_stake_index_1].last_period
|
||||
assert ONLY_DISPLAYING_MERGEABLE_STAKES_NOTE.format(final_period=final_period) in result.output
|
||||
assert CONFIRM_MERGE_DISCLAIMER in result.output # different start periods and no worker commitment
|
||||
assert CONFIRM_MERGE.format(stake_index_1=sub_stake_index_1, stake_index_2=sub_stake_index_2) in result.output
|
||||
assert SUCCESSFUL_STAKES_MERGE in result.output
|
||||
|
||||
|
@ -1257,7 +1267,8 @@ def test_merge_partially_interactive(click_runner,
|
|||
'--network', TEMPORARY_DOMAIN,
|
||||
'--staking-address', surrogate_stakers[selected_index])
|
||||
user_input = '\n'.join((str(sub_stake_index_2),
|
||||
YES,
|
||||
YES, # confirm disclaimer
|
||||
YES, # confirm merge
|
||||
INSECURE_DEVELOPMENT_PASSWORD))
|
||||
|
||||
command = base_command + ('--index-1', sub_stake_index_1)
|
||||
|
@ -1266,6 +1277,7 @@ def test_merge_partially_interactive(click_runner,
|
|||
|
||||
final_period = surrogate_stakes[selected_index][sub_stake_index_1].last_period
|
||||
assert ONLY_DISPLAYING_MERGEABLE_STAKES_NOTE.format(final_period=final_period) in result.output
|
||||
assert CONFIRM_MERGE_DISCLAIMER in result.output # different start periods and no worker commitment
|
||||
assert CONFIRM_MERGE.format(stake_index_1=sub_stake_index_1, stake_index_2=sub_stake_index_2) in result.output
|
||||
assert SUCCESSFUL_STAKES_MERGE in result.output
|
||||
|
||||
|
|
Loading…
Reference in New Issue