From 872824b90561c2540f3aadd1aeb11f95a95b0a13 Mon Sep 17 00:00:00 2001 From: albert Date: Fri, 3 Nov 2023 13:37:00 +0100 Subject: [PATCH] chore: add tests --- contracts/utils/TokenVestingStaking.sol | 6 +--- .../release/test_release_staking.py | 1 - .../revoke/test_revoke_staking.py | 31 +++++++++++++++++++ .../stakeStProvider/test_stProvider.py | 30 ++++++++++++++++++ 4 files changed, 62 insertions(+), 6 deletions(-) diff --git a/contracts/utils/TokenVestingStaking.sol b/contracts/utils/TokenVestingStaking.sol index 2fc15a18..b2495e63 100644 --- a/contracts/utils/TokenVestingStaking.sol +++ b/contracts/utils/TokenVestingStaking.sol @@ -160,9 +160,6 @@ contract TokenVestingStaking is ITokenVestingStaking, Shared { token.safeTransfer(beneficiary, unreleased); } - // TODO: Revoking during linear vesting (after staking period) will not respect the linear vesting, - // it will just revoke anything on the contract and anything that is currently staked. We - // either accept this or we don't allow revokation after stakingVestingEnd /** * @notice Allows the revoker to revoke the vesting and stop the beneficiary from releasing any * tokens if the vesting period has not been completed. Any staked tokens at the time of @@ -200,7 +197,6 @@ contract TokenVestingStaking is ITokenVestingStaking, Shared { */ function _releasableAmount(IERC20 token) private view returns (uint256) { return _vestedAmount(token) - released[token]; - // return block.timestamp < end ? 0 : token.balanceOf(address(this)); } /** @@ -219,7 +215,7 @@ contract TokenVestingStaking is ITokenVestingStaking, Shared { if (block.timestamp >= end || revoked) { return totalBalance; } else { - // Assumption cliff == 0 + // No cliff return (totalBalance * (block.timestamp - stakingVestingEnd)) / (end - stakingVestingEnd); } } diff --git a/tests/token_vesting/release/test_release_staking.py b/tests/token_vesting/release/test_release_staking.py index a93858cc..162de6fb 100644 --- a/tests/token_vesting/release/test_release_staking.py +++ b/tests/token_vesting/release/test_release_staking.py @@ -161,7 +161,6 @@ def test_release_staking_rewards_after_end( ) -# Test that the assert(!canStake) is not reached => cliff == end == start + QUARTER_YEAR + YEAR @given(st_sleepTime=strategy("uint256", min_value=QUARTER_YEAR, max_value=YEAR * 2)) def test_release_around_cliff( addrs, cf, tokenVestingStaking, addressHolder, st_sleepTime diff --git a/tests/token_vesting/revoke/test_revoke_staking.py b/tests/token_vesting/revoke/test_revoke_staking.py index d07355e0..69fe6cfb 100644 --- a/tests/token_vesting/revoke/test_revoke_staking.py +++ b/tests/token_vesting/revoke/test_revoke_staking.py @@ -178,3 +178,34 @@ def test_fund_revoked_staked(addrs, cf, tokenVestingStaking): with reverts(REV_MSG_TOKEN_REVOKED): tv.fundStateChainAccount(nodeID1, MAX_TEST_FUND, {"from": addrs.BENEFICIARY}) retrieve_revoked_and_check(tv, cf, addrs.REVOKER, MAX_TEST_FUND) + + +# Revoke with some tokens staked and linear vesting has started +def test_revoke_staked_linear(addrs, cf, tokenVestingStaking): + tv, stakingVestingEnd, end, total = tokenVestingStaking + amount_staked = (total * 2) // 3 + tv.fundStateChainAccount(JUNK_HEX, amount_staked, {"from": addrs.BENEFICIARY}) + # Half the vesting period + chain.sleep(stakingVestingEnd + (end - stakingVestingEnd) // 2 - getChainTime()) + amountInContract = total - amount_staked + assert cf.flip.balanceOf(tv) == amountInContract + + # Release approx half of the tokens in the contract + tx = tv.release(cf.flip, {"from": addrs.BENEFICIARY}) + releasedAmount = tx.events["TokensReleased"]["amount"] + assert amountInContract // 2 <= releasedAmount <= amountInContract * 1.01 // 2 + amountInContract = amountInContract - releasedAmount + assert cf.flip.balanceOf(tv) == amountInContract + + # Revoke remaining tokens in the contract + tx = tv.revoke(cf.flip, {"from": addrs.REVOKER}) + revokedAmount = tx.events["TokenVestingRevoked"]["refund"] + assert revokedAmount == amountInContract + + # Imitate unstake the amount + cf.flip.transfer(tv, amount_staked, {"from": addrs.DEPLOYER}) + + with reverts(REV_MSG_TOKEN_REVOKED): + tv.release(cf.flip, {"from": addrs.BENEFICIARY}) + + retrieve_revoked_and_check(tv, cf, addrs.REVOKER, amount_staked) diff --git a/tests/token_vesting/stakeStProvider/test_stProvider.py b/tests/token_vesting/stakeStProvider/test_stProvider.py index 1b28c218..51207e09 100644 --- a/tests/token_vesting/stakeStProvider/test_stProvider.py +++ b/tests/token_vesting/stakeStProvider/test_stProvider.py @@ -220,3 +220,33 @@ def test_stProviderClaimRewardsSlash(addrs, tokenVestingStaking, cf, mockStProvi with reverts(REV_MSG_INTEGER_OVERFLOW): tv.claimStProviderRewards(2**256 - 1, {"from": addrs.BENEFICIARY}) + + +def test_stProviderRewards_release(addrs, tokenVestingStaking, cf, mockStProvider): + tv, stakingVestingEnd, end, total = tokenVestingStaking + stFLIP, minter, _, _ = mockStProvider + reward_amount = total + + cf.flip.approve(minter, 2**256 - 1, {"from": addrs.DEPLOYER}) + minter.mint(addrs.DEPLOYER, reward_amount, {"from": addrs.DEPLOYER}) + + flipStaked = total // 3 + flipInContract = total - flipStaked + tv.stakeToStProvider(flipStaked, {"from": addrs.BENEFICIARY}) + stFlipInContract = flipStaked + + # Earn rewards + stFLIP.transfer(tv, reward_amount, {"from": addrs.DEPLOYER}) + stFlipInContract += reward_amount + + # Approximately into the middle of the vesting period + chain.sleep(stakingVestingEnd + (end - stakingVestingEnd) // 2 - getChainTime()) + + # The vested percentage of FLIP and stFLIP can be released. + tx = tv.release(cf.flip, {"from": addrs.BENEFICIARY}) + releasedAmount = tx.events["TokensReleased"]["amount"] + assert flipInContract // 2 <= releasedAmount <= flipInContract * 1.01 // 2 + + tx = tv.release(stFLIP, {"from": addrs.BENEFICIARY}) + releasedAmount = tx.events["TokensReleased"]["amount"] + assert stFlipInContract // 2 <= releasedAmount <= stFlipInContract * 1.01 // 2