Skip to content

Commit f8dfb76

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

File tree

1 file changed

+188
-1
lines changed

1 file changed

+188
-1
lines changed

lockup/src/lib.rs

Lines changed: 188 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1663,8 +1663,9 @@ 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
1668+
// Visualisation: https://github.com/near/core-contracts/pull/191#issuecomment-996846656
16681669
// This test checks that termination of vesting
16691670
// fixes the amount of tokens that finally should become liquid (*),
16701671
// but does not change the schedule of unlocking the tokens.
@@ -1973,6 +1974,192 @@ mod tests {
19731974
);
19741975
}
19751976

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

0 commit comments

Comments
 (0)