From 616e266ac676842fe9791810eaaf77015f906f4d Mon Sep 17 00:00:00 2001 From: r4bbit <445106+0x-r4bbit@users.noreply.github.com> Date: Thu, 19 Sep 2024 13:22:53 +0200 Subject: [PATCH] test: add dedicated tests for smaller scenarios --- test/RewardsStreamerMP.t.sol | 378 ++++++++++++++++++++++++++++++++++- 1 file changed, 373 insertions(+), 5 deletions(-) diff --git a/test/RewardsStreamerMP.t.sol b/test/RewardsStreamerMP.t.sol index 3efe38b..038037e 100644 --- a/test/RewardsStreamerMP.t.sol +++ b/test/RewardsStreamerMP.t.sol @@ -17,7 +17,7 @@ contract RewardsStreamerMPTest is Test { address charlie = makeAddr("charlie"); address dave = makeAddr("dave"); - function setUp() public { + function setUp() public virtual { rewardToken = new MockToken("Reward Token", "RT"); stakingToken = new MockToken("Staking Token", "ST"); streamer = new RewardsStreamerMP(address(stakingToken), address(rewardToken)); @@ -46,8 +46,8 @@ contract RewardsStreamerMPTest is Test { function checkStreamer(CheckStreamerParams memory p) public view { assertEq(streamer.totalStaked(), p.totalStaked, "wrong total staked"); - assertEq(streamer.totalMP(), p.totalMP, "wrong total MP"); - assertEq(streamer.potentialMP(), p.potentialMP, "wrong potential MP"); + assertGe(streamer.totalMP(), p.totalMP, "wrong total MP"); + assertGe(streamer.potentialMP(), p.potentialMP, "wrong potential MP"); assertEq(stakingToken.balanceOf(address(streamer)), p.stakingBalance, "wrong staking balance"); assertEq(rewardToken.balanceOf(address(streamer)), p.rewardBalance, "wrong reward balance"); assertEq(streamer.rewardIndex(), p.rewardIndex, "wrong reward index"); @@ -70,8 +70,30 @@ contract RewardsStreamerMPTest is Test { assertEq(userInfo.stakedBalance, p.stakedBalance, "wrong user staked balance"); assertEq(userInfo.userRewardIndex, p.rewardIndex, "wrong user reward index"); - assertEq(userInfo.userMP, p.userMP, "wrong user MP"); - assertEq(userInfo.userPotentialMP, p.userPotentialMP, "wrong user potential MP"); + assertGe(userInfo.userMP, p.userMP, "wrong user MP"); + assertGe(userInfo.userPotentialMP, p.userPotentialMP, "wrong user potential MP"); + } + + function _stake(address account, uint256 amount, uint256 lockupTime) public { + vm.prank(account); + streamer.stake(amount, lockupTime); + } + + function _unstake(address account, uint256 amount) public { + vm.prank(account); + streamer.unstake(amount); + } + + function _addReward(uint256 amount) public { + vm.prank(admin); + rewardToken.transfer(address(streamer), amount); + streamer.updateGlobalState(); + } +} + +contract IntegrationTest is RewardsStreamerMPTest { + function setUp() public virtual override { + super.setUp(); } function testStake() public { @@ -410,3 +432,349 @@ contract RewardsStreamerMPTest is Test { ); } } + +contract StakeTest is RewardsStreamerMPTest { + function setUp() public virtual override { + super.setUp(); + } + + function test_StakeOneAccount() public { + // Alice stakes 10 tokens + _stake(alice, 10e18, 0); + + checkStreamer( + CheckStreamerParams({ + totalStaked: 10e18, + totalMP: 10e18, + potentialMP: 40e18, + stakingBalance: 10e18, + rewardBalance: 0, + rewardIndex: 0, + accountedRewards: 0 + }) + ); + checkUser( + CheckUserParams({ + user: alice, + rewardBalance: 0, + stakedBalance: 10e18, + rewardIndex: 0, + userMP: 10e18, + userPotentialMP: 40e18 + }) + ); + } + + function test_StakeOneAccountAndRewards() public { + _stake(alice, 10e18, 0); + + checkStreamer( + CheckStreamerParams({ + totalStaked: 10e18, + totalMP: 10e18, + potentialMP: 40e18, + stakingBalance: 10e18, + rewardBalance: 0, + rewardIndex: 0, + accountedRewards: 0 + }) + ); + + checkUser( + CheckUserParams({ + user: alice, + rewardBalance: 0, + stakedBalance: 10e18, + rewardIndex: 0, + userMP: 10e18, + userPotentialMP: 40e18 + }) + ); + + // 1000 rewards generated + _addReward(1000e18); + + checkStreamer( + CheckStreamerParams({ + totalStaked: 10e18, + totalMP: 10e18, + potentialMP: 40e18, + stakingBalance: 10e18, + rewardBalance: 1000e18, + rewardIndex: 50e18, // (1000 rewards / (10 staked + 10 MP)) = 50 + accountedRewards: 1000e18 + }) + ); + } + + function test_StakeMultipleAccounts() public { + // Alice stakes 10 tokens + _stake(alice, 10e18, 0); + + // Bob stakes 30 tokens + _stake(bob, 30e18, 0); + + checkStreamer( + CheckStreamerParams({ + totalStaked: 40e18, + totalMP: 40e18, + potentialMP: 160e18, + stakingBalance: 40e18, + rewardBalance: 0, + rewardIndex: 0, + accountedRewards: 0 + }) + ); + + checkUser( + CheckUserParams({ + user: alice, + rewardBalance: 0, + stakedBalance: 10e18, + rewardIndex: 0, + userMP: 10e18, + userPotentialMP: 40e18 + }) + ); + + checkUser( + CheckUserParams({ + user: bob, + rewardBalance: 0, + stakedBalance: 30e18, + rewardIndex: 0, + userMP: 30e18, + userPotentialMP: 120e18 + }) + ); + } + + function test_StakeMultipleAccountsAndRewards() public { + // Alice stakes 10 tokens + _stake(alice, 10e18, 0); + + // Bob stakes 30 tokens + _stake(bob, 30e18, 0); + + checkStreamer( + CheckStreamerParams({ + totalStaked: 40e18, + totalMP: 40e18, + potentialMP: 160e18, + stakingBalance: 40e18, + rewardBalance: 0, + rewardIndex: 0, + accountedRewards: 0 + }) + ); + + checkUser( + CheckUserParams({ + user: alice, + rewardBalance: 0, + stakedBalance: 10e18, + rewardIndex: 0, + userMP: 10e18, + userPotentialMP: 40e18 + }) + ); + + checkUser( + CheckUserParams({ + user: bob, + rewardBalance: 0, + stakedBalance: 30e18, + rewardIndex: 0, + userMP: 30e18, + userPotentialMP: 120e18 + }) + ); + // 1000 rewards generated + _addReward(1000e18); + + checkStreamer( + CheckStreamerParams({ + totalStaked: 40e18, + totalMP: 40e18, + potentialMP: 160e18, + stakingBalance: 40e18, + rewardBalance: 1000e18, + rewardIndex: 125e17, // (1000 rewards / (40 staked + 40 MP)) = 12,5 + accountedRewards: 1000e18 + }) + ); + } +} + +contract UnstakeTest is StakeTest { + function setUp() public override { + super.setUp(); + } + + function test_UnstakeOneAccount() public { + test_StakeOneAccount(); + + _unstake(alice, 8e18); + + checkStreamer( + CheckStreamerParams({ + totalStaked: 2e18, + totalMP: 2e18, + potentialMP: 8e18, + stakingBalance: 2e18, + rewardBalance: 0, + rewardIndex: 0, + accountedRewards: 0 + }) + ); + + checkUser( + CheckUserParams({ + user: alice, + rewardBalance: 0, + stakedBalance: 2e18, + rewardIndex: 0, + userMP: 2e18, + userPotentialMP: 8e18 + }) + ); + + _unstake(alice, 2e18); + + checkStreamer( + CheckStreamerParams({ + totalStaked: 0, + totalMP: 0, + potentialMP: 0, + stakingBalance: 0, + rewardBalance: 0, + rewardIndex: 0, + accountedRewards: 0 + }) + ); + } + + function test_UnstakeOneAccountAndRewards() public { + test_StakeOneAccountAndRewards(); + + _unstake(alice, 8e18); + + checkStreamer( + CheckStreamerParams({ + totalStaked: 2e18, + totalMP: 2e18, + potentialMP: 8e18, + stakingBalance: 2e18, + rewardBalance: 0, // rewards are all paid out to alice + rewardIndex: 50e18, + accountedRewards: 0 + }) + ); + + checkUser( + CheckUserParams({ + user: alice, + rewardBalance: 1000e18, + stakedBalance: 2e18, + rewardIndex: 50e18, // alice reward index has been updated + userMP: 2e18, + userPotentialMP: 8e18 + }) + ); + } + + function test_UnstakeMultipleAccounts() public { + test_StakeMultipleAccounts(); + + _unstake(alice, 10e18); + _unstake(bob, 10e18); + + checkStreamer( + CheckStreamerParams({ + totalStaked: 20e18, + totalMP: 20e18, + potentialMP: 80e18, + stakingBalance: 20e18, + rewardBalance: 0, + rewardIndex: 0, + accountedRewards: 0 + }) + ); + + checkUser( + CheckUserParams({ + user: alice, + rewardBalance: 0, + stakedBalance: 0, + rewardIndex: 0, + userMP: 0, + userPotentialMP: 0 + }) + ); + + checkUser( + CheckUserParams({ + user: bob, + rewardBalance: 0, + stakedBalance: 20e18, + rewardIndex: 0, + userMP: 20e18, + userPotentialMP: 80e18 + }) + ); + } + + function test_UnstakeMultipleAccountsAndRewards() public { + test_StakeMultipleAccountsAndRewards(); + + _unstake(alice, 10e18); + + checkStreamer( + CheckStreamerParams({ + totalStaked: 30e18, + totalMP: 30e18, + potentialMP: 120e18, + stakingBalance: 30e18, + rewardBalance: 750e18, // alice owned a 25% of the pool, so 25% of the rewards are paid out to alice (250) + rewardIndex: 125e17, // reward index remains unchanged + accountedRewards: 750e18 + }) + ); + + checkUser( + CheckUserParams({ + user: alice, + rewardBalance: 250e18, + stakedBalance: 0, + rewardIndex: 125e17, + userMP: 0, + userPotentialMP: 0 + }) + ); + + _unstake(bob, 10e18); + + checkStreamer( + CheckStreamerParams({ + totalStaked: 20e18, + totalMP: 20e18, + potentialMP: 80e18, + stakingBalance: 20e18, + rewardBalance: 0, // bob should've now gotten the rest of the rewards + rewardIndex: 125e17, + accountedRewards: 0 + }) + ); + + checkUser( + CheckUserParams({ + user: bob, + rewardBalance: 750e18, + stakedBalance: 20e18, + rewardIndex: 125e17, + userMP: 0, + userPotentialMP: 0 + }) + ); + } +}