Skip to content

Commit 5dd63e2

Browse files
committed
test(lockup): add test vesting after lockup
1 parent ad2028e commit 5dd63e2

File tree

1 file changed

+191
-1
lines changed

1 file changed

+191
-1
lines changed

lockup/src/lib.rs

Lines changed: 191 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1663,7 +1663,7 @@ mod tests {
16631663
}
16641664

16651665
#[test]
1666-
fn test_unlocking_schedule_with_termination() {
1666+
fn test_unlocking_schedule_with_termination_and_vesting_started_before_phase2() {
16671667
// https://wiki.near.org/getting-started/near-token/lockups#termination-of-vesting
16681668
// This test checks that termination of vesting
16691669
// fixes the amount of tokens that finally should become liquid (*),
@@ -1973,6 +1973,196 @@ mod tests {
19731973
);
19741974
}
19751975

1976+
#[test]
1977+
fn test_unlocking_schedule_with_termination_and_vesting_started_after_phase2() {
1978+
// https://wiki.near.org/getting-started/near-token/lockups#termination-of-vesting
1979+
// This test checks that termination of vesting
1980+
// fixes the amount of tokens that finally should become liquid (*),
1981+
// but does not change the schedule of unlocking the tokens.
1982+
// The contract should act as there was no termination at all,
1983+
// until we do not reach the amount (*).
1984+
// After we reach this amount, the unlocking process should stop.
1985+
1986+
// Taking bigger lockup amount because we compare the balances further
1987+
// and there is a comparison delta.
1988+
// We want to be sure that this delta does not grow on bigger numbers
1989+
let lockup_amount = to_yocto(LOCKUP_NEAR * 1000);
1990+
let mut context = basic_context();
1991+
context.account_balance = lockup_amount;
1992+
testing_env!(context.clone());
1993+
1994+
let vesting_cliff_offset = YEAR + 300;
1995+
let vesting_schedule = new_vesting_schedule(vesting_cliff_offset);
1996+
let mut contract = new_contract(
1997+
true,
1998+
Some(vesting_schedule.clone()),
1999+
Some(to_nanos(YEAR * 4).into()),
2000+
true,
2001+
);
2002+
2003+
// Vesting starts at day 800: 300 days after transfers enabled
2004+
let ts_vesting_started = to_ts(GENESIS_TIME_IN_DAYS - YEAR + vesting_cliff_offset);
2005+
assert_eq!(vesting_schedule.start_timestamp.0, ts_vesting_started);
2006+
2007+
// We don't use lockup_timestamp,
2008+
// it means that lockup starts from the transfers enabled moment
2009+
assert_eq!(contract.lockup_information.lockup_timestamp, None);
2010+
2011+
// Transfers are enabled at day 500, lockup also starts here
2012+
if let TransfersInformation::TransfersEnabled {
2013+
transfers_timestamp,
2014+
} = &contract.lockup_information.transfers_information
2015+
{
2016+
assert_eq!(transfers_timestamp.0, to_ts(GENESIS_TIME_IN_DAYS));
2017+
} else {
2018+
assert!(false, "Transfers should be enabled");
2019+
}
2020+
2021+
// Vesting cliff ends at day 1165
2022+
assert_eq!(
2023+
vesting_schedule.cliff_timestamp.0,
2024+
to_ts(GENESIS_TIME_IN_DAYS + vesting_cliff_offset)
2025+
);
2026+
2027+
// Lockup cliff ends at day 865
2028+
assert_eq!(contract.lockup_information.lockup_duration, to_nanos(YEAR));
2029+
2030+
// Everything is locked and unvested in the beginning
2031+
assert_eq!(
2032+
contract.get_vesting_information(),
2033+
VestingInformation::VestingHash(
2034+
VestingScheduleWithSalt {
2035+
vesting_schedule: vesting_schedule.clone(),
2036+
salt: SALT.to_vec().into(),
2037+
}
2038+
.hash()
2039+
.into()
2040+
)
2041+
);
2042+
assert_eq!(contract.get_owners_balance().0, 0);
2043+
assert_eq!(contract.get_liquid_owners_balance().0, 0);
2044+
assert_eq!(contract.get_locked_amount().0, lockup_amount);
2045+
assert_eq!(
2046+
contract.get_unvested_amount(vesting_schedule.clone()).0,
2047+
lockup_amount
2048+
);
2049+
assert_eq!(
2050+
contract
2051+
.get_locked_vested_amount(vesting_schedule.clone())
2052+
.0,
2053+
0
2054+
);
2055+
2056+
// *** day 1164: day before vesting cliff is passed ***
2057+
let ts_1_day_before_vesting_cliff = to_ts(GENESIS_TIME_IN_DAYS + vesting_cliff_offset - 1);
2058+
assert_eq!(
2059+
ts_1_day_before_vesting_cliff,
2060+
vesting_schedule.cliff_timestamp.0 - to_nanos(1)
2061+
);
2062+
context.block_timestamp = ts_1_day_before_vesting_cliff;
2063+
testing_env!(context.clone());
2064+
2065+
// Tokens are fully unvested
2066+
assert_eq!(
2067+
contract.get_unvested_amount(vesting_schedule.clone()).0,
2068+
lockup_amount
2069+
);
2070+
// But some of tokens have already unlocked
2071+
assert_almost_eq_with_max_delta(
2072+
to_yocto(545205),
2073+
contract.get_locked_amount().0,
2074+
to_yocto(1),
2075+
);
2076+
2077+
// *** day 1165: day of vesting cliff ***
2078+
let ts_day_of_vesting_cliff = to_ts(GENESIS_TIME_IN_DAYS + vesting_cliff_offset);
2079+
assert_eq!(ts_day_of_vesting_cliff, vesting_schedule.cliff_timestamp.0);
2080+
context.block_timestamp = ts_day_of_vesting_cliff;
2081+
testing_env!(context.clone());
2082+
2083+
// 25% is vested
2084+
let vesting_nanos_passed = (ts_day_of_vesting_cliff - ts_vesting_started) as u128;
2085+
let vesting_nanos_total =
2086+
(vesting_schedule.end_timestamp.0 - vesting_schedule.start_timestamp.0) as u128;
2087+
2088+
let expected_unvested_amount_at_cliff_day =
2089+
lockup_amount - lockup_amount / vesting_nanos_total * vesting_nanos_passed;
2090+
let unvested_amount_at_cliff_day = contract.get_unvested_amount(vesting_schedule.clone()).0;
2091+
assert_almost_eq_with_max_delta(
2092+
expected_unvested_amount_at_cliff_day,
2093+
unvested_amount_at_cliff_day,
2094+
to_yocto(1),
2095+
);
2096+
assert_eq!(to_yocto(750000), unvested_amount_at_cliff_day);
2097+
2098+
// *** day 1230: day of termination ***
2099+
let ts_termination_day = to_ts(GENESIS_TIME_IN_DAYS + YEAR * 2);
2100+
context.block_timestamp = ts_termination_day;
2101+
testing_env!(context.clone());
2102+
2103+
assert_eq!(
2104+
contract.get_vesting_information(),
2105+
VestingInformation::VestingHash(
2106+
VestingScheduleWithSalt {
2107+
vesting_schedule: vesting_schedule.clone(),
2108+
salt: SALT.to_vec().into(),
2109+
}
2110+
.hash()
2111+
.into()
2112+
)
2113+
);
2114+
2115+
// Some tokens are vested
2116+
let vesting_nanos_passed = (ts_termination_day - ts_vesting_started) as u128;
2117+
let expected_unvested_amount_at_termination_day =
2118+
lockup_amount - lockup_amount / vesting_nanos_total * vesting_nanos_passed;
2119+
let unvested_amount_at_termination_day =
2120+
contract.get_unvested_amount(vesting_schedule.clone()).0;
2121+
assert_almost_eq_with_max_delta(
2122+
expected_unvested_amount_at_termination_day,
2123+
unvested_amount_at_termination_day,
2124+
to_yocto(1),
2125+
);
2126+
assert_almost_eq_with_max_delta(
2127+
to_yocto(705479),
2128+
unvested_amount_at_termination_day,
2129+
to_yocto(1),
2130+
);
2131+
2132+
// Terminate the vesting
2133+
context.predecessor_account_id = account_foundation();
2134+
context.signer_account_pk = public_key(3).into();
2135+
context.is_view = false;
2136+
testing_env!(context.clone());
2137+
contract.terminate_vesting(Some(VestingScheduleWithSalt {
2138+
vesting_schedule: vesting_schedule.clone(),
2139+
salt: SALT.to_vec().into(),
2140+
}));
2141+
2142+
context.is_view = true;
2143+
testing_env!(context.clone());
2144+
assert_eq!(
2145+
contract.get_vesting_information(),
2146+
VestingInformation::Terminating(TerminationInformation {
2147+
unvested_amount: unvested_amount_at_termination_day.into(),
2148+
status: TerminationStatus::ReadyToWithdraw,
2149+
})
2150+
);
2151+
2152+
// *** day 1231: 1 day after termination ***
2153+
let ts_1_day_after_termination = to_ts(GENESIS_TIME_IN_DAYS + YEAR * 2 + 1);
2154+
context.block_timestamp = ts_1_day_after_termination;
2155+
testing_env!(context.clone());
2156+
2157+
// Nothing new is vested since termination
2158+
let unvested_amount_1_day_after_termination =
2159+
contract.get_unvested_amount(vesting_schedule.clone()).0;
2160+
assert_eq!(
2161+
unvested_amount_1_day_after_termination,
2162+
unvested_amount_at_termination_day
2163+
);
2164+
}
2165+
19762166
#[test]
19772167
fn test_termination_with_staking() {
19782168
let lockup_amount = to_yocto(1000);

0 commit comments

Comments
 (0)