From ad2028ef1d12d18d0dc99dcab21a2720e2dce332 Mon Sep 17 00:00:00 2001 From: Olga Telezhnaya Date: Thu, 11 Nov 2021 19:55:37 +0300 Subject: [PATCH 1/4] test(lockup): add test of unlocking schedule with termination --- lockup/src/lib.rs | 311 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 311 insertions(+) diff --git a/lockup/src/lib.rs b/lockup/src/lib.rs index 079e9fed..fb950b4d 100644 --- a/lockup/src/lib.rs +++ b/lockup/src/lib.rs @@ -1662,6 +1662,317 @@ mod tests { ); } + #[test] + fn test_unlocking_schedule_with_termination() { + // https://wiki.near.org/getting-started/near-token/lockups#termination-of-vesting + // This test checks that termination of vesting + // fixes the amount of tokens that finally should become liquid (*), + // but does not change the schedule of unlocking the tokens. + // The contract should act as there was no termination at all, + // until we do not reach the amount (*). + // After we reach this amount, the unlocking process should stop. + + // Taking bigger lockup amount because we compare the balances further + // and there is a comparison delta. + // We want to be sure that this delta does not grow on bigger numbers + let lockup_amount = to_yocto(LOCKUP_NEAR * 1000); + let mut context = basic_context(); + context.account_balance = lockup_amount; + testing_env!(context.clone()); + + let vesting_cliff_offset = 100; + let vesting_schedule = new_vesting_schedule(vesting_cliff_offset); + let mut contract = new_contract( + true, + Some(vesting_schedule.clone()), + Some(to_nanos(YEAR * 4).into()), + true, + ); + + // Vesting starts at day 235 + let ts_vesting_started = to_ts(GENESIS_TIME_IN_DAYS - YEAR + vesting_cliff_offset); + assert_eq!(vesting_schedule.start_timestamp.0, ts_vesting_started); + + // We don't use lockup_timestamp, + // it means that lockup starts from the transfers enabled moment + assert_eq!(contract.lockup_information.lockup_timestamp, None); + + // Transfers are enabled at day 500, lockup also starts here + if let TransfersInformation::TransfersEnabled { + transfers_timestamp, + } = &contract.lockup_information.transfers_information + { + assert_eq!(transfers_timestamp.0, to_ts(GENESIS_TIME_IN_DAYS)); + } else { + assert!(false, "Transfers should be enabled"); + } + + // Vesting cliff ends at day 600 + assert_eq!( + vesting_schedule.cliff_timestamp.0, + to_ts(GENESIS_TIME_IN_DAYS + vesting_cliff_offset) + ); + + // Lockup cliff ends at day 865 + assert_eq!(contract.lockup_information.lockup_duration, to_nanos(YEAR)); + + // Everything is locked and unvested in the beginning + assert_eq!( + contract.get_vesting_information(), + VestingInformation::VestingHash( + VestingScheduleWithSalt { + vesting_schedule: vesting_schedule.clone(), + salt: SALT.to_vec().into(), + } + .hash() + .into() + ) + ); + assert_eq!(contract.get_owners_balance().0, 0); + assert_eq!(contract.get_liquid_owners_balance().0, 0); + assert_eq!(contract.get_locked_amount().0, lockup_amount); + assert_eq!( + contract.get_unvested_amount(vesting_schedule.clone()).0, + lockup_amount + ); + assert_eq!( + contract + .get_locked_vested_amount(vesting_schedule.clone()) + .0, + 0 + ); + + // *** day 599: day before vesting cliff is passed *** + let ts_1_day_before_vesting_cliff = to_ts(GENESIS_TIME_IN_DAYS + vesting_cliff_offset - 1); + assert_eq!( + ts_1_day_before_vesting_cliff, + vesting_schedule.cliff_timestamp.0 - to_nanos(1) + ); + context.block_timestamp = ts_1_day_before_vesting_cliff; + testing_env!(context.clone()); + + // Everything is still locked and unvested + assert_eq!(contract.get_owners_balance().0, 0); + assert_eq!(contract.get_liquid_owners_balance().0, 0); + assert_eq!(contract.get_locked_amount().0, lockup_amount); + assert_eq!( + contract.get_unvested_amount(vesting_schedule.clone()).0, + lockup_amount + ); + assert_eq!( + contract + .get_locked_vested_amount(vesting_schedule.clone()) + .0, + 0 + ); + + // *** day 600: day of vesting cliff *** + let ts_day_of_vesting_cliff = to_ts(GENESIS_TIME_IN_DAYS + vesting_cliff_offset); + assert_eq!(ts_day_of_vesting_cliff, vesting_schedule.cliff_timestamp.0); + context.block_timestamp = ts_day_of_vesting_cliff; + testing_env!(context.clone()); + + // 25% is vested + let vesting_nanos_passed = (ts_day_of_vesting_cliff - ts_vesting_started) as u128; + let vesting_nanos_total = + (vesting_schedule.end_timestamp.0 - vesting_schedule.start_timestamp.0) as u128; + + let expected_vested_amount_at_cliff_day = + lockup_amount / vesting_nanos_total * vesting_nanos_passed; + let vested_amount_at_cliff_day = contract + .get_locked_vested_amount(vesting_schedule.clone()) + .0; + assert_almost_eq_with_max_delta( + expected_vested_amount_at_cliff_day, + vested_amount_at_cliff_day, + to_yocto(1), + ); + assert_eq!(to_yocto(250000), vested_amount_at_cliff_day); + + let expected_unvested_amount_at_cliff_day = + lockup_amount - expected_vested_amount_at_cliff_day; + let unvested_amount_at_cliff_day = contract.get_unvested_amount(vesting_schedule.clone()).0; + assert_almost_eq_with_max_delta( + expected_unvested_amount_at_cliff_day, + unvested_amount_at_cliff_day, + to_yocto(1), + ); + assert_eq!(to_yocto(750000), unvested_amount_at_cliff_day); + + // But tokens are still locked due to lockup + assert_eq!(contract.get_owners_balance().0, 0); + assert_eq!(contract.get_liquid_owners_balance().0, 0); + assert_eq!(contract.get_locked_amount().0, lockup_amount); + + // *** day 800: day of termination *** + let ts_termination_day = to_ts(GENESIS_TIME_IN_DAYS + vesting_cliff_offset + 200); + context.block_timestamp = ts_termination_day; + testing_env!(context.clone()); + + assert_eq!( + contract.get_vesting_information(), + VestingInformation::VestingHash( + VestingScheduleWithSalt { + vesting_schedule: vesting_schedule.clone(), + salt: SALT.to_vec().into(), + } + .hash() + .into() + ) + ); + + // Some tokens are vested + let vesting_nanos_passed = (ts_termination_day - ts_vesting_started) as u128; + let expected_vested_amount_at_termination_day = + lockup_amount / vesting_nanos_total * vesting_nanos_passed; + let locked_vested_amount_at_termination_day = contract + .get_locked_vested_amount(vesting_schedule.clone()) + .0; + + assert_almost_eq_with_max_delta( + expected_vested_amount_at_termination_day, + locked_vested_amount_at_termination_day, + to_yocto(1), + ); + assert_almost_eq_with_max_delta( + to_yocto(386986), + locked_vested_amount_at_termination_day, + to_yocto(1), + ); + + let expected_unvested_amount_at_termination_day = + lockup_amount - expected_vested_amount_at_termination_day; + let unvested_amount_at_termination_day = + contract.get_unvested_amount(vesting_schedule.clone()).0; + assert_almost_eq_with_max_delta( + expected_unvested_amount_at_termination_day, + unvested_amount_at_termination_day, + to_yocto(1), + ); + assert_almost_eq_with_max_delta( + to_yocto(613014), + unvested_amount_at_termination_day, + to_yocto(1), + ); + + // But tokens are still locked due to lockup + assert_eq!(contract.get_owners_balance().0, 0); + assert_eq!(contract.get_liquid_owners_balance().0, 0); + assert_eq!(contract.get_locked_amount().0, lockup_amount); + + // Terminate the vesting + context.predecessor_account_id = account_foundation(); + context.signer_account_pk = public_key(3).into(); + context.is_view = false; + testing_env!(context.clone()); + contract.terminate_vesting(Some(VestingScheduleWithSalt { + vesting_schedule: vesting_schedule.clone(), + salt: SALT.to_vec().into(), + })); + + context.is_view = true; + testing_env!(context.clone()); + assert_eq!( + contract.get_vesting_information(), + VestingInformation::Terminating(TerminationInformation { + unvested_amount: unvested_amount_at_termination_day.into(), + status: TerminationStatus::ReadyToWithdraw, + }) + ); + + // *** day 801: 1 day after termination *** + let ts_1_day_after_termination = to_ts(GENESIS_TIME_IN_DAYS + vesting_cliff_offset + 201); + context.block_timestamp = ts_1_day_after_termination; + testing_env!(context.clone()); + + // All the tokens are still locked + assert_eq!(contract.get_owners_balance().0, 0); + assert_eq!(contract.get_liquid_owners_balance().0, 0); + assert_eq!(contract.get_locked_amount().0, lockup_amount); + + // Nothing new is vested since termination + let unvested_amount_1_day_after_termination = + contract.get_unvested_amount(vesting_schedule.clone()).0; + assert_eq!( + unvested_amount_1_day_after_termination, + unvested_amount_at_termination_day + ); + + // *** day 864: 1 day before lockup cliff is passed *** + let ts_day_before_lockup_cliff = to_ts(GENESIS_TIME_IN_DAYS + YEAR - 1); + context.block_timestamp = ts_day_before_lockup_cliff; + testing_env!(context.clone()); + + // All the tokens are still locked + assert_eq!(contract.get_owners_balance().0, 0); + assert_eq!(contract.get_liquid_owners_balance().0, 0); + assert_eq!(contract.get_locked_amount().0, lockup_amount); + + // Nothing new is vested since termination + let unvested_amount_day_before_lockup_cliff = + contract.get_unvested_amount(vesting_schedule.clone()).0; + assert_eq!( + unvested_amount_day_before_lockup_cliff, + unvested_amount_at_termination_day + ); + + // *** day 865: day of lockup cliff *** + let ts_day_of_lockup_cliff = to_ts(GENESIS_TIME_IN_DAYS + YEAR); + context.block_timestamp = ts_day_of_lockup_cliff; + testing_env!(context.clone()); + + let unlocked_amount_day_of_lockup_cliff = contract.get_liquid_owners_balance().0; + let expected_unlocked_amount_day_of_lockup_cliff = lockup_amount + / (contract.lockup_information.release_duration.unwrap() as u128) + * (to_nanos(YEAR) as u128); + assert_almost_eq_with_max_delta( + expected_unlocked_amount_day_of_lockup_cliff, + unlocked_amount_day_of_lockup_cliff, + to_yocto(1), + ); + assert_eq!(to_yocto(250000), unlocked_amount_day_of_lockup_cliff); + + // *** day 1064: 1 day before unlock stopped *** + let ts_1_day_before_unlock_stop = to_ts(GENESIS_TIME_IN_DAYS + YEAR + 199); + context.block_timestamp = ts_1_day_before_unlock_stop; + testing_env!(context.clone()); + + let locked_amount_1_day_before_unlock_stop = contract.get_locked_amount().0; + + // *** day 1065, unlock stopped *** + let ts_day_unlock_stopped = to_ts(GENESIS_TIME_IN_DAYS + YEAR + 200); + context.block_timestamp = ts_day_unlock_stopped; + testing_env!(context.clone()); + + let locked_amount_day_unlock_stopped = contract.get_locked_amount().0; + assert!( + locked_amount_day_unlock_stopped < locked_amount_1_day_before_unlock_stop, + "Locked amount should decrease" + ); + assert_eq!( + locked_amount_day_unlock_stopped, + unvested_amount_at_termination_day + ); + + // We unlock 684 tokens in one day, + // it means that our delta (1 token) is small enough to detect any issue + assert_almost_eq_with_max_delta( + to_yocto(684), + locked_amount_1_day_before_unlock_stop - locked_amount_day_unlock_stopped, + to_yocto(1), + ); + + // *** day 1066, 1 day after unlock stopped *** + let ts_1_day_after_unlock_stopped = to_ts(GENESIS_TIME_IN_DAYS + YEAR + 201); + context.block_timestamp = ts_1_day_after_unlock_stopped; + testing_env!(context.clone()); + + assert_eq!( + contract.get_locked_amount().0, + unvested_amount_at_termination_day + ); + } + #[test] fn test_termination_with_staking() { let lockup_amount = to_yocto(1000); From f8dfb769aea057e8737ca178cfb85cfd4539cfd4 Mon Sep 17 00:00:00 2001 From: Olga Telezhnaya Date: Fri, 17 Dec 2021 17:42:35 +0300 Subject: [PATCH 2/4] test(lockup): add test vesting after lockup --- lockup/src/lib.rs | 189 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 188 insertions(+), 1 deletion(-) diff --git a/lockup/src/lib.rs b/lockup/src/lib.rs index fb950b4d..1ec493e4 100644 --- a/lockup/src/lib.rs +++ b/lockup/src/lib.rs @@ -1663,8 +1663,9 @@ mod tests { } #[test] - fn test_unlocking_schedule_with_termination() { + fn test_unlocking_schedule_with_termination_and_vesting_started_before_phase2() { // https://wiki.near.org/getting-started/near-token/lockups#termination-of-vesting + // Visualisation: https://github.com/near/core-contracts/pull/191#issuecomment-996846656 // This test checks that termination of vesting // fixes the amount of tokens that finally should become liquid (*), // but does not change the schedule of unlocking the tokens. @@ -1973,6 +1974,192 @@ mod tests { ); } + #[test] + fn test_unlocking_schedule_with_termination_and_vesting_started_after_phase2() { + // https://wiki.near.org/getting-started/near-token/lockups#termination-of-vesting + // Visualisation: https://github.com/near/core-contracts/pull/191#issuecomment-996847344 + // This test checks positive scenario when vesting started after transfers enabled moment. + + // Taking bigger lockup amount because we compare the balances further + // and there is a comparison delta. + // We want to be sure that this delta does not grow on bigger numbers + let lockup_amount = to_yocto(LOCKUP_NEAR * 1000); + let mut context = basic_context(); + context.account_balance = lockup_amount; + testing_env!(context.clone()); + + let vesting_cliff_offset = YEAR + 300; + let vesting_schedule = new_vesting_schedule(vesting_cliff_offset); + let mut contract = new_contract( + true, + Some(vesting_schedule.clone()), + Some(to_nanos(YEAR * 4).into()), + true, + ); + + // Vesting starts at day 800: 300 days after transfers enabled + let ts_vesting_started = to_ts(GENESIS_TIME_IN_DAYS - YEAR + vesting_cliff_offset); + assert_eq!(vesting_schedule.start_timestamp.0, ts_vesting_started); + + // We don't use lockup_timestamp, + // it means that lockup starts from the transfers enabled moment + assert_eq!(contract.lockup_information.lockup_timestamp, None); + + // Transfers are enabled at day 500, lockup also starts here + if let TransfersInformation::TransfersEnabled { + transfers_timestamp, + } = &contract.lockup_information.transfers_information + { + assert_eq!(transfers_timestamp.0, to_ts(GENESIS_TIME_IN_DAYS)); + } else { + assert!(false, "Transfers should be enabled"); + } + + // Vesting cliff ends at day 1165 + assert_eq!( + vesting_schedule.cliff_timestamp.0, + to_ts(GENESIS_TIME_IN_DAYS + vesting_cliff_offset) + ); + + // Lockup cliff ends at day 865 + assert_eq!(contract.lockup_information.lockup_duration, to_nanos(YEAR)); + + // Everything is locked and unvested in the beginning + assert_eq!( + contract.get_vesting_information(), + VestingInformation::VestingHash( + VestingScheduleWithSalt { + vesting_schedule: vesting_schedule.clone(), + salt: SALT.to_vec().into(), + } + .hash() + .into() + ) + ); + assert_eq!(contract.get_owners_balance().0, 0); + assert_eq!(contract.get_liquid_owners_balance().0, 0); + assert_eq!(contract.get_locked_amount().0, lockup_amount); + assert_eq!( + contract.get_unvested_amount(vesting_schedule.clone()).0, + lockup_amount + ); + assert_eq!( + contract + .get_locked_vested_amount(vesting_schedule.clone()) + .0, + 0 + ); + + // *** day 1164: day before vesting cliff is passed *** + let ts_1_day_before_vesting_cliff = to_ts(GENESIS_TIME_IN_DAYS + vesting_cliff_offset - 1); + assert_eq!( + ts_1_day_before_vesting_cliff, + vesting_schedule.cliff_timestamp.0 - to_nanos(1) + ); + context.block_timestamp = ts_1_day_before_vesting_cliff; + testing_env!(context.clone()); + + // Tokens are fully unvested + assert_eq!( + contract.get_unvested_amount(vesting_schedule.clone()).0, + lockup_amount + ); + // But some of tokens have already unlocked + assert_almost_eq_with_max_delta( + to_yocto(545205), + contract.get_locked_amount().0, + to_yocto(1), + ); + + // *** day 1165: day of vesting cliff *** + let ts_day_of_vesting_cliff = to_ts(GENESIS_TIME_IN_DAYS + vesting_cliff_offset); + assert_eq!(ts_day_of_vesting_cliff, vesting_schedule.cliff_timestamp.0); + context.block_timestamp = ts_day_of_vesting_cliff; + testing_env!(context.clone()); + + // 25% is vested + let vesting_nanos_passed = (ts_day_of_vesting_cliff - ts_vesting_started) as u128; + let vesting_nanos_total = + (vesting_schedule.end_timestamp.0 - vesting_schedule.start_timestamp.0) as u128; + + let expected_unvested_amount_at_cliff_day = + lockup_amount - lockup_amount / vesting_nanos_total * vesting_nanos_passed; + let unvested_amount_at_cliff_day = contract.get_unvested_amount(vesting_schedule.clone()).0; + assert_almost_eq_with_max_delta( + expected_unvested_amount_at_cliff_day, + unvested_amount_at_cliff_day, + to_yocto(1), + ); + assert_eq!(to_yocto(750000), unvested_amount_at_cliff_day); + + // *** day 1230: day of termination *** + let ts_termination_day = to_ts(GENESIS_TIME_IN_DAYS + YEAR * 2); + context.block_timestamp = ts_termination_day; + testing_env!(context.clone()); + + assert_eq!( + contract.get_vesting_information(), + VestingInformation::VestingHash( + VestingScheduleWithSalt { + vesting_schedule: vesting_schedule.clone(), + salt: SALT.to_vec().into(), + } + .hash() + .into() + ) + ); + + // Some tokens are vested + let vesting_nanos_passed = (ts_termination_day - ts_vesting_started) as u128; + let expected_unvested_amount_at_termination_day = + lockup_amount - lockup_amount / vesting_nanos_total * vesting_nanos_passed; + let unvested_amount_at_termination_day = + contract.get_unvested_amount(vesting_schedule.clone()).0; + assert_almost_eq_with_max_delta( + expected_unvested_amount_at_termination_day, + unvested_amount_at_termination_day, + to_yocto(1), + ); + assert_almost_eq_with_max_delta( + to_yocto(705479), + unvested_amount_at_termination_day, + to_yocto(1), + ); + + // Terminate the vesting + context.predecessor_account_id = account_foundation(); + context.signer_account_pk = public_key(3).into(); + context.is_view = false; + testing_env!(context.clone()); + contract.terminate_vesting(Some(VestingScheduleWithSalt { + vesting_schedule: vesting_schedule.clone(), + salt: SALT.to_vec().into(), + })); + + context.is_view = true; + testing_env!(context.clone()); + assert_eq!( + contract.get_vesting_information(), + VestingInformation::Terminating(TerminationInformation { + unvested_amount: unvested_amount_at_termination_day.into(), + status: TerminationStatus::ReadyToWithdraw, + }) + ); + + // *** day 1231: 1 day after termination *** + let ts_1_day_after_termination = to_ts(GENESIS_TIME_IN_DAYS + YEAR * 2 + 1); + context.block_timestamp = ts_1_day_after_termination; + testing_env!(context.clone()); + + // Nothing new is vested since termination + let unvested_amount_1_day_after_termination = + contract.get_unvested_amount(vesting_schedule.clone()).0; + assert_eq!( + unvested_amount_1_day_after_termination, + unvested_amount_at_termination_day + ); + } + #[test] fn test_termination_with_staking() { let lockup_amount = to_yocto(1000); From 3d726901f5a28bb90ccdcf38d651abca180d1117 Mon Sep 17 00:00:00 2001 From: Olga Telezhnaya Date: Fri, 17 Dec 2021 19:59:12 +0300 Subject: [PATCH 3/4] test(lockup): get rid of rounding by using u256 --- lockup/src/lib.rs | 68 ++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/lockup/src/lib.rs b/lockup/src/lib.rs index 1ec493e4..bf981e6a 100644 --- a/lockup/src/lib.rs +++ b/lockup/src/lib.rs @@ -1778,25 +1778,25 @@ mod tests { let vesting_nanos_total = (vesting_schedule.end_timestamp.0 - vesting_schedule.start_timestamp.0) as u128; - let expected_vested_amount_at_cliff_day = - lockup_amount / vesting_nanos_total * vesting_nanos_passed; + let expected_vested_amount_at_cliff_day = (U256::from(lockup_amount) + * U256::from(vesting_nanos_passed) + / U256::from(vesting_nanos_total)) + .as_u128(); let vested_amount_at_cliff_day = contract .get_locked_vested_amount(vesting_schedule.clone()) .0; - assert_almost_eq_with_max_delta( + assert_eq!( expected_vested_amount_at_cliff_day, - vested_amount_at_cliff_day, - to_yocto(1), + vested_amount_at_cliff_day ); assert_eq!(to_yocto(250000), vested_amount_at_cliff_day); let expected_unvested_amount_at_cliff_day = lockup_amount - expected_vested_amount_at_cliff_day; let unvested_amount_at_cliff_day = contract.get_unvested_amount(vesting_schedule.clone()).0; - assert_almost_eq_with_max_delta( + assert_eq!( expected_unvested_amount_at_cliff_day, - unvested_amount_at_cliff_day, - to_yocto(1), + unvested_amount_at_cliff_day ); assert_eq!(to_yocto(750000), unvested_amount_at_cliff_day); @@ -1824,16 +1824,17 @@ mod tests { // Some tokens are vested let vesting_nanos_passed = (ts_termination_day - ts_vesting_started) as u128; - let expected_vested_amount_at_termination_day = - lockup_amount / vesting_nanos_total * vesting_nanos_passed; + let expected_vested_amount_at_termination_day = (U256::from(lockup_amount) + * U256::from(vesting_nanos_passed) + / U256::from(vesting_nanos_total)) + .as_u128(); let locked_vested_amount_at_termination_day = contract .get_locked_vested_amount(vesting_schedule.clone()) .0; - assert_almost_eq_with_max_delta( - expected_vested_amount_at_termination_day, - locked_vested_amount_at_termination_day, - to_yocto(1), + assert_eq!( + expected_vested_amount_at_termination_day + 1, + locked_vested_amount_at_termination_day ); assert_almost_eq_with_max_delta( to_yocto(386986), @@ -1845,10 +1846,9 @@ mod tests { lockup_amount - expected_vested_amount_at_termination_day; let unvested_amount_at_termination_day = contract.get_unvested_amount(vesting_schedule.clone()).0; - assert_almost_eq_with_max_delta( + assert_eq!( expected_unvested_amount_at_termination_day, - unvested_amount_at_termination_day, - to_yocto(1), + unvested_amount_at_termination_day + 1 ); assert_almost_eq_with_max_delta( to_yocto(613014), @@ -1923,13 +1923,13 @@ mod tests { testing_env!(context.clone()); let unlocked_amount_day_of_lockup_cliff = contract.get_liquid_owners_balance().0; - let expected_unlocked_amount_day_of_lockup_cliff = lockup_amount - / (contract.lockup_information.release_duration.unwrap() as u128) - * (to_nanos(YEAR) as u128); - assert_almost_eq_with_max_delta( + let expected_unlocked_amount_day_of_lockup_cliff = (U256::from(lockup_amount) + * U256::from(to_nanos(YEAR)) + / U256::from(contract.lockup_information.release_duration.unwrap())) + .as_u128(); + assert_eq!( expected_unlocked_amount_day_of_lockup_cliff, - unlocked_amount_day_of_lockup_cliff, - to_yocto(1), + unlocked_amount_day_of_lockup_cliff ); assert_eq!(to_yocto(250000), unlocked_amount_day_of_lockup_cliff); @@ -2082,13 +2082,14 @@ mod tests { let vesting_nanos_total = (vesting_schedule.end_timestamp.0 - vesting_schedule.start_timestamp.0) as u128; - let expected_unvested_amount_at_cliff_day = - lockup_amount - lockup_amount / vesting_nanos_total * vesting_nanos_passed; + let expected_unvested_amount_at_cliff_day = lockup_amount + - (U256::from(lockup_amount) * U256::from(vesting_nanos_passed) + / U256::from(vesting_nanos_total)) + .as_u128(); let unvested_amount_at_cliff_day = contract.get_unvested_amount(vesting_schedule.clone()).0; - assert_almost_eq_with_max_delta( + assert_eq!( expected_unvested_amount_at_cliff_day, - unvested_amount_at_cliff_day, - to_yocto(1), + unvested_amount_at_cliff_day ); assert_eq!(to_yocto(750000), unvested_amount_at_cliff_day); @@ -2111,14 +2112,15 @@ mod tests { // Some tokens are vested let vesting_nanos_passed = (ts_termination_day - ts_vesting_started) as u128; - let expected_unvested_amount_at_termination_day = - lockup_amount - lockup_amount / vesting_nanos_total * vesting_nanos_passed; + let expected_unvested_amount_at_termination_day = lockup_amount + - (U256::from(lockup_amount) * U256::from(vesting_nanos_passed) + / U256::from(vesting_nanos_total)) + .as_u128(); let unvested_amount_at_termination_day = contract.get_unvested_amount(vesting_schedule.clone()).0; - assert_almost_eq_with_max_delta( + assert_eq!( expected_unvested_amount_at_termination_day, - unvested_amount_at_termination_day, - to_yocto(1), + unvested_amount_at_termination_day + 1 ); assert_almost_eq_with_max_delta( to_yocto(705479), From 883edf6070bc1cfc39d6dd16da067dc07b6ec662 Mon Sep 17 00:00:00 2001 From: Olga Telezhnaya Date: Tue, 28 Dec 2021 11:56:13 +0300 Subject: [PATCH 4/4] test(lockup): check liquid == (initial - locked) --- lockup/src/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lockup/src/lib.rs b/lockup/src/lib.rs index bf981e6a..880d8a50 100644 --- a/lockup/src/lib.rs +++ b/lockup/src/lib.rs @@ -1972,6 +1972,11 @@ mod tests { contract.get_locked_amount().0, unvested_amount_at_termination_day ); + + assert_eq!( + contract.get_liquid_owners_balance().0, + lockup_amount - unvested_amount_at_termination_day + ); } #[test] @@ -2160,6 +2165,11 @@ mod tests { unvested_amount_1_day_after_termination, unvested_amount_at_termination_day ); + + assert_eq!( + contract.get_liquid_owners_balance().0, + lockup_amount - unvested_amount_at_termination_day + ); } #[test]