Fix economics calculation and tests

pull/2623/head
vzotova 2021-03-10 16:41:47 +03:00 committed by Kieran Prasch
parent ed032de9e8
commit fc2ff03e35
4 changed files with 29 additions and 22 deletions

View File

@ -348,7 +348,7 @@ class StandardTokenEconomics(BaseEconomics):
with localcontext() as ctx:
ctx.prec = self._precision
one_year_in_periods = ONE_YEAR_IN_HOURS // hours_per_period
one_year_in_periods = Decimal(ONE_YEAR_IN_HOURS / hours_per_period)
initial_supply = Decimal(initial_supply)
@ -392,7 +392,7 @@ class StandardTokenEconomics(BaseEconomics):
issuance_decay_coefficient=issuance_decay_coefficient,
lock_duration_coefficient_1=lock_duration_coefficient_1,
lock_duration_coefficient_2=lock_duration_coefficient_2,
maximum_rewarded_periods=maximum_rewarded_periods,
maximum_rewarded_periods=int(maximum_rewarded_periods),
hours_per_period=hours_per_period,
**kwargs)
@ -425,8 +425,8 @@ class StandardTokenEconomics(BaseEconomics):
if t <= phase_switch_in_periods:
S_t = S_0 + t * I_s_per_period
else:
one_year_in_periods = ONE_YEAR_IN_HOURS // self.hours_per_period
S_p1 = self.first_phase_supply
one_year_in_periods = Decimal(ONE_YEAR_IN_HOURS / self.hours_per_period)
S_p1 = self.first_phase_max_issuance * phase_switch_in_periods
T_half = self.token_halving # in years
T_half_in_periods = T_half * one_year_in_periods
t = t - phase_switch_in_periods

View File

@ -23,7 +23,7 @@ from nucypher.crypto.powers import TransactingPower
# Experimental max error
MAX_ERROR_FIRST_PHASE = 1e-20
MAX_ERROR_SECOND_PHASE = 3e-5
MAX_ERROR_SECOND_PHASE = 5e-3
MAX_PERIODS_SECOND_PHASE = 100

View File

@ -41,6 +41,7 @@ def test_exact_economics():
#
# Expected Output
#
one_year_in_periods = 365 / 7
# Supply
expected_total_supply = 3885390081748248632541961138
@ -55,12 +56,13 @@ def test_exact_economics():
# Staking 2 phase
decay_half_life = 2
multiplier = 0.5
expected_lock_duration_coefficient_1 = 365
expected_lock_duration_coefficient_1 = one_year_in_periods
expected_lock_duration_coefficient_2 = 2 * expected_lock_duration_coefficient_1
expected_phase2_coefficient = 1053
expected_phase2_coefficient = 150
expected_minting_coefficient = expected_phase2_coefficient * expected_lock_duration_coefficient_2
assert expected_lock_duration_coefficient_1 * decay_half_life == round(expected_minting_coefficient * log(2) * multiplier / 365)
assert int(expected_lock_duration_coefficient_1 * decay_half_life) == \
round(expected_minting_coefficient * log(2) * multiplier / one_year_in_periods)
#
# Sanity
@ -83,8 +85,8 @@ def test_exact_economics():
# Sanity check expected testing outputs
assert Decimal(expected_total_supply) / expected_initial_supply == expected_supply_ratio
assert expected_reward_supply == expected_total_supply - expected_initial_supply
assert reward_saturation * 365 * multiplier == expected_lock_duration_coefficient_1 * (1 - multiplier)
assert int(365 ** 2 * reward_saturation * decay_half_life / log(2) / (1-multiplier) / expected_lock_duration_coefficient_2) == \
assert reward_saturation * one_year_in_periods * multiplier == expected_lock_duration_coefficient_1 * (1 - multiplier)
assert int(one_year_in_periods ** 2 * reward_saturation * decay_half_life / log(2) / (1-multiplier) / expected_lock_duration_coefficient_2) == \
expected_phase2_coefficient
@ -97,7 +99,7 @@ def test_exact_economics():
52 * 2, # Denominator of the locking duration coefficient (k2)
52, # Max periods that will be additionally rewarded (awarded_periods)
2829579800000000000000000000, # Total supply for the first phase
7036845384615384615384615, # Max possible reward for one period for all stakers in the first phase
7017566356164383151812537, # Max possible reward for one period for all stakers in the first phase
4, # Min amount of periods during which tokens can be locked
15000000000000000000000, # min locked NuNits
30000000000000000000000000, # max locked NuNits
@ -111,16 +113,18 @@ def test_exact_economics():
with localcontext() as ctx:
ctx.prec = StandardTokenEconomics._precision
one_year_in_periods = Decimal(one_year_in_periods)
# Check that total_supply calculated correctly
assert Decimal(e.erc20_total_supply) / e.initial_supply == expected_supply_ratio
assert e.erc20_total_supply == expected_total_supply
# Check reward rates for the second phase
initial_rate = (e.erc20_total_supply - int(e.first_phase_total_supply)) * (e.lock_duration_coefficient_1 + 52) / \
initial_rate = (e.erc20_total_supply - int(e.first_phase_total_supply)) * (e.lock_duration_coefficient_1 + one_year_in_periods) / \
(e.issuance_decay_coefficient * e.lock_duration_coefficient_2)
assert int(initial_rate) == int(e.first_phase_max_issuance)
assert int(LOG2 / (e.token_halving * 52) * (e.erc20_total_supply - int(e.first_phase_total_supply))) == int(initial_rate)
assert int(LOG2 / (e.token_halving * one_year_in_periods) * (e.erc20_total_supply - int(e.first_phase_total_supply))) == \
int(initial_rate)
initial_rate_small = (e.erc20_total_supply - int(e.first_phase_total_supply)) * e.lock_duration_coefficient_1 / \
(e.issuance_decay_coefficient * e.lock_duration_coefficient_2)
@ -141,26 +145,29 @@ def test_exact_economics():
# Check phase 1 doesn't overshoot
switch_period = 5 * 52
assert e.first_phase_final_period() == switch_period
assert e.token_supply_at_period(period=switch_period) == expected_phase1_supply + expected_initial_supply
assert e.token_supply_at_period(period=switch_period) <= expected_phase1_supply + expected_initial_supply
assert e.token_supply_at_period(period=switch_period + 1) > expected_phase1_supply + expected_initial_supply
assert e.token_supply_at_period(period=switch_period) < e.token_supply_at_period(period=switch_period + 1)
assert e.rewards_during_period(period=1) == round(e.first_phase_max_issuance)
assert e.rewards_during_period(period=switch_period) == round(e.first_phase_max_issuance)
assert e.rewards_during_period(period=switch_period + 1) < int(e.first_phase_max_issuance)
# Last NuNit is minted after 188 years (or 68500 periods).
# Last NuNit is minted after 188 years (or 9800 periods).
# That's the year 2208, if token is launched in 2020.
# 23rd century schizoid man!
assert expected_total_supply == e.token_supply_at_period(period=68500//7)
assert abs(expected_total_supply - e.token_supply_at_period(period=9800)) < e.first_phase_max_issuance
assert e.erc20_total_supply == expected_total_supply
# After 1 year:
assert 1_365_915_960_000000000000000000 == e.token_supply_at_period(period=52)
assert 365_915_960_000000000000000000 == e.cumulative_rewards_at_period(period=52)
expected_reward_one_year = 52 * 7017566356164383151812537
assert abs((expected_initial_supply + expected_reward_one_year) - e.token_supply_at_period(period=52)) <= 100
assert abs(expected_reward_one_year - e.cumulative_rewards_at_period(period=52)) <= 100
assert e.erc20_initial_supply + e.cumulative_rewards_at_period(52) == e.token_supply_at_period(period=52)
# Checking that the supply function is monotonic in phase 1
todays_supply = e.token_supply_at_period(period=0)
for t in range(68500//7):
for t in range(9800):
tomorrows_supply = e.token_supply_at_period(period=t + 1)
assert tomorrows_supply >= todays_supply
todays_supply = tomorrows_supply

View File

@ -250,13 +250,13 @@ def test_stake_validation(mock_testerchain, token_economics, mock_staking_agent)
validate_prolong(stake=stake, additional_periods=1)
stake = make_sub_stake(first_locked_period=current_period - 2,
final_locked_period=current_period + 10,
final_locked_period=current_period + 2,
value=nu)
with pytest.raises(Stake.StakingError):
validate_prolong(stake=stake, additional_periods=1)
with pytest.raises(Stake.StakingError):
validate_prolong(stake=stake, additional_periods=token_economics.minimum_locked_periods - 11)
validate_prolong(stake=stake, additional_periods=token_economics.minimum_locked_periods - 10)
validate_prolong(stake=stake, additional_periods=token_economics.minimum_locked_periods - 3)
validate_prolong(stake=stake, additional_periods=token_economics.minimum_locked_periods - 2)
# Validate increase method
stake = make_sub_stake(first_locked_period=current_period - 2,