nucypher/tests/contracts/integration/increase.py

207 lines
12 KiB
Python
Raw Normal View History

"""
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"