From e8ad4b0a04d1fbe65451c919e9604b3cf6656a77 Mon Sep 17 00:00:00 2001 From: has5aan Date: Mon, 3 Jun 2024 15:50:04 +0200 Subject: [PATCH 01/18] Refactors scenarios --- test/L2/L2Reward.t.sol | 841 ++++++++++++----------------------------- 1 file changed, 245 insertions(+), 596 deletions(-) diff --git a/test/L2/L2Reward.t.sol b/test/L2/L2Reward.t.sol index 6b489965..0a72329d 100644 --- a/test/L2/L2Reward.t.sol +++ b/test/L2/L2Reward.t.sol @@ -35,6 +35,11 @@ contract L2RewardTest is Test { uint16 delay; } + struct Scenario { + address[] stakers; + uint256[] lockIDs; + } + struct Position { uint256 amount; uint256 duration; @@ -210,6 +215,82 @@ contract L2RewardTest is Test { vm.stopPrank(); } + function onDay(uint256 day) private { + vm.warp((deploymentDate + day) * 86400); + } + + function stakerCreatesPosition( + uint256 stakerIndex, + uint256 amount, + uint256 duration, + Scenario memory scenario + ) + private + { + vm.startPrank(scenario.stakers[stakerIndex]); + l2LiskToken.approve(address(l2Reward), amount); + scenario.lockIDs[stakerIndex] = l2Reward.createPosition(amount, duration); + vm.stopPrank(); + } + + function stakerPausesPosition(uint256 stakerIndex, Scenario memory scenario) private { + uint256[] memory positionsToBeModified = new uint256[](1); + positionsToBeModified[0] = scenario.lockIDs[stakerIndex]; + vm.prank(scenario.stakers[stakerIndex]); + l2Reward.pauseUnlocking(positionsToBeModified); + } + + function stakerInitiatesFastUnlock(uint256 stakerIndex, Scenario memory scenario) private { + uint256[] memory positionsToBeModified = new uint256[](1); + positionsToBeModified[0] = scenario.lockIDs[stakerIndex]; + vm.prank(scenario.stakers[stakerIndex]); + l2Reward.initiateFastUnlock(positionsToBeModified); + } + + function stakerReumesPosition(uint256 stakerIndex, Scenario memory scenario) private { + uint256[] memory positionsToBeModified = new uint256[](1); + positionsToBeModified[0] = scenario.lockIDs[stakerIndex]; + vm.prank(scenario.stakers[stakerIndex]); + l2Reward.resumeUnlockingCountdown(positionsToBeModified); + } + + function stakerUnlocksPosition(uint256 stakerIndex, Scenario memory scenario) private { + uint256[] memory positionsToBeModified = new uint256[](1); + positionsToBeModified[0] = scenario.lockIDs[stakerIndex]; + vm.prank(scenario.stakers[stakerIndex]); + l2Reward.deletePositions(positionsToBeModified); + } + + function stakerExtendsPositionBy( + uint256 stakerIndex, + uint256 durationExtension, + Scenario memory scenario + ) + private + { + L2Reward.ExtendedDuration[] memory durationExtensions = new L2Reward.ExtendedDuration[](1); + durationExtensions[0].lockID = scenario.lockIDs[stakerIndex]; + durationExtensions[0].durationExtension = durationExtension; + vm.prank(scenario.stakers[stakerIndex]); + l2Reward.extendDuration(durationExtensions); + } + + function stakerIncreasesAmountOfThePositionBy( + uint256 stakerIndex, + uint256 amountIncrease, + Scenario memory scenario + ) + private + { + L2Reward.IncreasedAmount[] memory increasingAmounts = new L2Reward.IncreasedAmount[](1); + increasingAmounts[0].lockID = scenario.lockIDs[stakerIndex]; + increasingAmounts[0].amountIncrease = amountIncrease; + vm.startPrank(scenario.stakers[stakerIndex]); + l2LiskToken.approve(address(l2Reward), amountIncrease); + l2Reward.increaseLockingAmount(increasingAmounts); + vm.stopPrank(); + } + function createScenario1() private returns (uint256[] memory, address[] memory) { address[] memory stakers = given_anArrayOfStakersOfLength(7); uint256[] memory lockIDs = new uint256[](7); @@ -217,8 +298,6 @@ contract L2RewardTest is Test { uint256 funds = convertLiskToSmallestDenomination(5000); uint256 balance = convertLiskToSmallestDenomination(500); - uint256[] memory positionsToBeModified = new uint256[](1); - // owner gets balance given_accountHasBalance(address(this), funds); // fund the reward contract, 10 Lisk per day for 500 @@ -228,109 +307,39 @@ contract L2RewardTest is Test { for (uint8 i = 0; i < stakers.length; i++) { given_accountHasBalance(stakers[i], balance); } + Scenario memory scenario = Scenario({ stakers: stakers, lockIDs: lockIDs }); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - vm.warp(19740 days + 1 days); - - // stake 1: (100 LSK, 30 days) - // extended on day 50 by 30 days - lockIDs[0] = when_stakerCreatesPosition( - stakers[0], Position({ amount: convertLiskToSmallestDenomination(100), duration: 30 }) - ); - - // stake 2: (100 LSK, 80 days) - // paused on day 30, resumes on day 80 - lockIDs[1] = when_stakerCreatesPosition( - stakers[1], Position({ amount: convertLiskToSmallestDenomination(100), duration: 80 }) - ); - - vm.warp(19740 days + 10 days); - // stake 3: (100 LSK, 100 days) - lockIDs[2] = when_stakerCreatesPosition( - stakers[2], Position({ amount: convertLiskToSmallestDenomination(100), duration: 100 }) - ); - - vm.warp(19740 days + 30 days); - // pauses stake 1 on day 30 - positionsToBeModified[0] = lockIDs[1]; - vm.prank(stakers[1]); - l2Reward.pauseUnlocking(positionsToBeModified); - + onDay(1); + stakerCreatesPosition(0, LSK(100), 30, scenario); + stakerCreatesPosition(1, LSK(100), 80, scenario); + onDay(10); + stakerCreatesPosition(2, LSK(100), 100, scenario); + onDay(30); + stakerPausesPosition(1, scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - vm.warp(19740 days + 35 days); - // stake 4: (50 LSK, 14 days) - // staked on day 35, expires on day 49 - lockIDs[3] = when_stakerCreatesPosition( - stakers[3], Position({ amount: convertLiskToSmallestDenomination(50), duration: 14 }) - ); - + onDay(35); + stakerCreatesPosition(3, LSK(50), 14, scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - vm.warp(19740 days + 49 days); - // stake 4 is unlocked - positionsToBeModified[0] = lockIDs[3]; - vm.prank(stakers[3]); - l2Reward.deletePositions(positionsToBeModified); - + onDay(49); + stakerUnlocksPosition(3, scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - // stake 5: (80 LSK, 80 days) - // Staked on Day 49, paused on Day 89 - lockIDs[4] = when_stakerCreatesPosition( - stakers[4], Position({ amount: convertLiskToSmallestDenomination(80), duration: 80 }) - ); - + stakerCreatesPosition(4, LSK(80), 80, scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - vm.warp(19740 days + 50 days); - // extend stake 1 by 30 days - L2Reward.ExtendedDuration[] memory durationExtensions = new L2Reward.ExtendedDuration[](1); - durationExtensions[0].lockID = lockIDs[0]; - durationExtensions[0].durationExtension = 30; - vm.prank(stakers[0]); - l2Reward.extendDuration(durationExtensions); - - vm.warp(19740 days + 70 days); - // stake 6: (100 LSK, 150 days) - // Increases amount at day 100 by 50 - lockIDs[5] = when_stakerCreatesPosition( - stakers[5], Position({ amount: convertLiskToSmallestDenomination(100), duration: 150 }) - ); - + onDay(50); + stakerExtendsPositionBy(0, 30, scenario); + onDay(70); + stakerCreatesPosition(5, LSK(100), 150, scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - vm.warp(19740 days + 80 days); - // resumes stake 2 on day 80 - positionsToBeModified[0] = lockIDs[1]; - vm.prank(stakers[1]); - l2Reward.resumeUnlockingCountdown(positionsToBeModified); - - vm.warp(19740 days + 89 days); - // Pauses stake 5 on day 89 - positionsToBeModified[0] = lockIDs[4]; - vm.prank(stakers[4]); - l2Reward.pauseUnlocking(positionsToBeModified); - - vm.warp(19740 days + 95 days); - // stake 7: (200 LSK, 200 days) - lockIDs[6] = when_stakerCreatesPosition( - stakers[6], Position({ amount: convertLiskToSmallestDenomination(200), duration: 200 }) - ); - + onDay(80); + stakerReumesPosition(1, scenario); + onDay(89); + stakerPausesPosition(4, scenario); + onDay(95); + stakerCreatesPosition(6, LSK(200), 200, scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - vm.warp(19740 days + 100 days); - // Increases amount for stake 6 - L2Reward.IncreasedAmount[] memory increasingAmounts = new L2Reward.IncreasedAmount[](1); - increasingAmounts[0].lockID = lockIDs[5]; - increasingAmounts[0].amountIncrease = convertLiskToSmallestDenomination(50); - vm.startPrank(stakers[5]); - l2LiskToken.approve(address(l2Reward), increasingAmounts[0].amountIncrease); - l2Reward.increaseLockingAmount(increasingAmounts); - vm.stopPrank(); - + onDay(100); + stakerIncreasesAmountOfThePositionBy(6, LSK(50), scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); return (lockIDs, stakers); @@ -339,7 +348,6 @@ contract L2RewardTest is Test { function createScenario2() private returns (uint256[] memory, address[] memory) { address[] memory stakers = given_anArrayOfStakersOfLength(7); uint256[] memory lockIDs = new uint256[](7); - uint256 funds = convertLiskToSmallestDenomination(5000); uint256 balance = convertLiskToSmallestDenomination(500); @@ -355,129 +363,42 @@ contract L2RewardTest is Test { given_accountHasBalance(stakers[i], balance); } - vm.warp(19740 days + 1 days); - - checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - // stake 1: (100 LSK, 730 days max duration) - // Will never get modified - lockIDs[0] = when_stakerCreatesPosition( - stakers[0], Position({ amount: convertLiskToSmallestDenomination(100), duration: 730 }) - ); - - // stake 2: (100 LSK, 730 days - max duration) - // paused after 2 days, then no modifications - lockIDs[1] = when_stakerCreatesPosition( - stakers[1], Position({ amount: convertLiskToSmallestDenomination(100), duration: 730 }) - ); - - vm.warp(19740 days + 2 days); - // Pause lockIDs[1] - positionsToBeModified[0] = lockIDs[1]; - vm.prank(stakers[1]); - l2Reward.pauseUnlocking(positionsToBeModified); - - vm.warp(19740 days + 5 days); - // stake 3: (200 LSK, 30 days), let expire and do nothing - lockIDs[2] = when_stakerCreatesPosition( - stakers[2], Position({ amount: convertLiskToSmallestDenomination(200), duration: 30 }) - ); - - checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - vm.warp(19740 days + 10 days); - // stake 4: (50 LSK, 100 days) - // pause immediately. At day 20 increase amount, at day 90 extend duration - lockIDs[3] = when_stakerCreatesPosition( - stakers[3], Position({ amount: convertLiskToSmallestDenomination(50), duration: 100 }) - ); - positionsToBeModified[0] = lockIDs[3]; - vm.prank(stakers[3]); - l2Reward.pauseUnlocking(positionsToBeModified); - - vm.warp(19740 days + 20 days); - // increase amount for stake 4 by 30 LSK - L2Reward.IncreasedAmount[] memory increasingAmounts = new L2Reward.IncreasedAmount[](1); - increasingAmounts[0].lockID = lockIDs[3]; - increasingAmounts[0].amountIncrease = convertLiskToSmallestDenomination(30); - vm.startPrank(stakers[3]); - l2LiskToken.approve(address(l2Reward), increasingAmounts[0].amountIncrease); - l2Reward.increaseLockingAmount(increasingAmounts); - vm.stopPrank(); - - // stake 5: (100 LSK, 200 days). - // At day 30 will be paused, day 40 fast unlock - lockIDs[4] = when_stakerCreatesPosition( - stakers[4], Position({ amount: convertLiskToSmallestDenomination(100), duration: 200 }) - ); - - vm.warp(19740 days + 25 days); - // stake 6: (150 LSK, 100 days) - // day 50 will be paused, day 80 resumed, day 93 increase amount to 180 - lockIDs[5] = when_stakerCreatesPosition( - stakers[5], Position({ amount: convertLiskToSmallestDenomination(150), duration: 100 }) - ); - - checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - vm.warp(19740 days + 30 days); - // pause unlocking of stake 5 - positionsToBeModified[0] = lockIDs[4]; - vm.prank(stakers[4]); - l2Reward.pauseUnlocking(positionsToBeModified); - - vm.warp(19740 days + 40 days); - // initiate fast unlock for stake 5 - positionsToBeModified[0] = lockIDs[4]; - vm.prank(stakers[4]); - l2Reward.initiateFastUnlock(positionsToBeModified); - - vm.warp(19740 days + 50 days); - // pause stake 6 - positionsToBeModified[0] = lockIDs[5]; - vm.prank(stakers[5]); - l2Reward.pauseUnlocking(positionsToBeModified); - - vm.warp(19740 days + 55 days); - // stake 7 (30LSK, 14 days - min duration) - // Expires in day 69. Then in day 85 extended by 25 days - lockIDs[6] = when_stakerCreatesPosition( - stakers[6], Position({ amount: convertLiskToSmallestDenomination(30), duration: 14 }) - ); - - checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - vm.warp(19740 days + 80 days); - // resume countdown for stake 6 - positionsToBeModified[0] = lockIDs[5]; - vm.prank(stakers[5]); - l2Reward.resumeUnlockingCountdown(positionsToBeModified); - - vm.warp(19740 days + 85 days); - // extend stake 7 by 25 days - L2Reward.ExtendedDuration[] memory durationExtensions = new L2Reward.ExtendedDuration[](1); - durationExtensions[0].lockID = lockIDs[6]; - durationExtensions[0].durationExtension = 25; - vm.prank(stakers[6]); - l2Reward.extendDuration(durationExtensions); - - vm.warp(19740 days + 90 days); - // extend duration for stake 4 by 65 - durationExtensions = new L2Reward.ExtendedDuration[](1); - durationExtensions[0].lockID = lockIDs[3]; - durationExtensions[0].durationExtension = 65; - vm.prank(stakers[3]); - l2Reward.extendDuration(durationExtensions); - - vm.warp(19740 days + 93 days); - // increase amount for stake 6 - increasingAmounts[0].lockID = lockIDs[5]; - increasingAmounts[0].amountIncrease = convertLiskToSmallestDenomination(30); - vm.startPrank(stakers[5]); - l2LiskToken.approve(address(l2Reward), increasingAmounts[0].amountIncrease); - l2Reward.increaseLockingAmount(increasingAmounts); - vm.stopPrank(); - + Scenario memory scenario = Scenario({ stakers: stakers, lockIDs: lockIDs }); + onDay(1); + checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + stakerCreatesPosition(0, LSK(100), 730, scenario); + stakerCreatesPosition(1, LSK(100), 730, scenario); + onDay(2); + stakerPausesPosition(1, scenario); + onDay(5); + stakerCreatesPosition(2, LSK(200), 30, scenario); + checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + onDay(10); + stakerCreatesPosition(3, LSK(50), 100, scenario); + stakerPausesPosition(3, scenario); + onDay(20); + stakerIncreasesAmountOfThePositionBy(3, LSK(30), scenario); + stakerCreatesPosition(4, LSK(100), 200, scenario); + onDay(25); + stakerCreatesPosition(5, LSK(150), 100, scenario); + checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + onDay(30); + stakerPausesPosition(4, scenario); + onDay(40); + stakerInitiatesFastUnlock(4, scenario); + onDay(50); + stakerPausesPosition(5, scenario); + onDay(55); + stakerCreatesPosition(6, LSK(30), 14, scenario); + checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + onDay(80); + stakerReumesPosition(5, scenario); + onDay(85); + stakerExtendsPositionBy(6, 25, scenario); + onDay(90); + stakerExtendsPositionBy(3, 65, scenario); + onDay(93); + stakerIncreasesAmountOfThePositionBy(5, LSK(30), scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); return (lockIDs, stakers); @@ -506,381 +427,105 @@ contract L2RewardTest is Test { given_accountHasBalance(stakers[i], balance); } - vm.warp(19740 days + 1 days); - - // stake 1: (100 LSK, 730 days max duration) - // created on day 1 - // amount increased on day 30 by 90 LSK - // paused on day 70 - // resumed on day 100 and extended on day 110 by 30 days - lockIDs[0] = when_stakerCreatesPosition( - stakers[0], Position({ amount: convertLiskToSmallestDenomination(100), duration: 730 }) - ); - - // stake 2: (30 LSK, 50 days) - // created on day 1 - lockIDs[1] = when_stakerCreatesPosition( - stakers[1], Position({ amount: convertLiskToSmallestDenomination(30), duration: 50 }) - ); - - checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - // stake 3: (400 LSK, 730 days) - // created on day 1 - lockIDs[2] = when_stakerCreatesPosition( - stakers[2], Position({ amount: convertLiskToSmallestDenomination(400), duration: 730 }) - ); - - vm.warp(19740 days + 15 days); - // stake 4: (5 LSK, 300 days) - // created on day 15 - // amount increased on day 30 by 1 LSK - lockIDs[3] = when_stakerCreatesPosition( - stakers[3], Position({ amount: convertLiskToSmallestDenomination(5), duration: 300 }) - ); - - vm.warp(19740 days + 20 days); - // stake 5: (500 LSK, 50 days) - // Will: fast unlock (day 30), extendDuration by 21 days (day 31), increase amount by 30 LSK and pause Duration - // (day 40), - // resume (108) - lockIDs[4] = when_stakerCreatesPosition( - stakers[4], Position({ amount: convertLiskToSmallestDenomination(500), duration: 50 }) - ); - - checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - // stake 6: (1250LSK, 80 days) - // will: Initiate fast unlock (day 35), pause next day (36), extend to 20 days(day 75), resume unlocking (day - // 100) - lockIDs[5] = when_stakerCreatesPosition( - stakers[5], Position({ amount: convertLiskToSmallestDenomination(1250), duration: 80 }) - ); - - vm.warp(19740 days + 30 days); - // stake 1: amount increase on day 30 by 90 LSK - increasingAmounts[0].lockID = lockIDs[0]; - increasingAmounts[0].amountIncrease = convertLiskToSmallestDenomination(90); - vm.startPrank(stakers[0]); - l2LiskToken.approve(address(l2Reward), increasingAmounts[0].amountIncrease); - l2Reward.increaseLockingAmount(increasingAmounts); - vm.stopPrank(); - - // stake 4: amount increase on day 30 by 1 LSK - increasingAmounts[0].lockID = lockIDs[3]; - increasingAmounts[0].amountIncrease = convertLiskToSmallestDenomination(1); - vm.startPrank(stakers[3]); - l2LiskToken.approve(address(l2Reward), increasingAmounts[0].amountIncrease); - l2Reward.increaseLockingAmount(increasingAmounts); - vm.stopPrank(); - - // stake 5: Initiate fast unlock - positionsToBeModified[0] = lockIDs[4]; - vm.prank(stakers[4]); - l2Reward.initiateFastUnlock(positionsToBeModified); - - vm.warp(19740 days + 31 days); - durationExtensions[0].lockID = lockIDs[4]; - durationExtensions[0].durationExtension = 21; - vm.prank(stakers[4]); - l2Reward.extendDuration(durationExtensions); - - vm.warp(19740 days + 35 days); - // stake 6: Initiate fast unlock - positionsToBeModified[0] = lockIDs[5]; - vm.prank(stakers[5]); - l2Reward.initiateFastUnlock(positionsToBeModified); - - vm.warp(19740 days + 36 days); - // stake 6 pauses locking duration - vm.prank(stakers[5]); - l2Reward.pauseUnlocking(positionsToBeModified); - - // stake 7: (125LSK, 80 days) - // will: Initiate fast unlock (day 60), extend locking duration to 8 (day 61), pauseLocking duration (day 61), - // extend duration by 4 days (day 65) and increase amount by 50 LSK (day 65), resume unlocking day 107 - lockIDs[6] = when_stakerCreatesPosition( - stakers[6], Position({ amount: convertLiskToSmallestDenomination(125), duration: 80 }) - ); - - checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - vm.warp(19740 days + 40 days); - // increase amount and pause duration for stake 5 - increasingAmounts[0].lockID = lockIDs[4]; - increasingAmounts[0].amountIncrease = convertLiskToSmallestDenomination(30); - positionsToBeModified[0] = lockIDs[4]; - vm.startPrank(stakers[4]); - l2LiskToken.approve(address(l2Reward), increasingAmounts[0].amountIncrease); - l2Reward.increaseLockingAmount(increasingAmounts); - l2Reward.pauseUnlocking(positionsToBeModified); - vm.stopPrank(); - - vm.warp(19740 days + 45 days); - // stake 8: (2000LSK, 70 days) - // will: Initiate fast unlock (day 68), extend locking duration to 150 (day 69), initiateFastUnlock again day - // 107 - lockIDs[7] = when_stakerCreatesPosition( - stakers[7], Position({ amount: convertLiskToSmallestDenomination(2000), duration: 70 }) - ); - - // stake 9: (220LSK, 600 days) - // will: pause (day 50), increaseAmount to 300 (day 55), initiateFastUnlock (day 58), pause remaining duration - // day 59 - lockIDs[8] = when_stakerCreatesPosition( - stakers[8], Position({ amount: convertLiskToSmallestDenomination(220), duration: 600 }) - ); - - //stake 10: (300LSK, 534 days) - // will pause duration (day 51), extendDuration to 650 (by 116 days) (day 52), do nothing else until the end - lockIDs[9] = when_stakerCreatesPosition( - stakers[9], Position({ amount: convertLiskToSmallestDenomination(300), duration: 534 }) - ); - - checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - //stake 11: (80LSK, 53 days) - // will extend locking duration by 10 days (day 66), pause (day 68), extend duration by 10 days (day 101), - // resume (day 106) - lockIDs[10] = when_stakerCreatesPosition( - stakers[10], Position({ amount: convertLiskToSmallestDenomination(80), duration: 53 }) - ); - - //stake 12: (110LSK, 23 days) - // let expire and then extend duration at day 76 by 50 days - lockIDs[11] = when_stakerCreatesPosition( - stakers[11], Position({ amount: convertLiskToSmallestDenomination(110), duration: 23 }) - ); - - checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - //stake 13: (1000LSK, 68 days) - // will extend duration by 100 days at day 100. Then (day 102) increase amount by 500LSK. Day 104 pause - // duration, day 107 increase amount by 500LSK, day 110 resume unlocking - lockIDs[12] = when_stakerCreatesPosition( - stakers[12], Position({ amount: convertLiskToSmallestDenomination(1000), duration: 68 }) - ); - - vm.warp(19740 days + 50 days); - // stake 9 is paused - positionsToBeModified[0] = lockIDs[8]; - vm.prank(stakers[8]); - l2Reward.pauseUnlocking(positionsToBeModified); - - vm.warp(19740 days + 51 days); - // stake 10 paused - positionsToBeModified[0] = lockIDs[9]; - vm.prank(stakers[9]); - l2Reward.pauseUnlocking(positionsToBeModified); - - vm.warp(19740 days + 52 days); - // stake 10 extended by 116 days - durationExtensions[0].lockID = lockIDs[9]; - durationExtensions[0].durationExtension = 116; - vm.prank(stakers[9]); - l2Reward.extendDuration(durationExtensions); - - vm.warp(19740 days + 55 days); - // stake 9 increases amount by 300 LSK - increasingAmounts[0].lockID = lockIDs[8]; - increasingAmounts[0].amountIncrease = convertLiskToSmallestDenomination(300); - vm.startPrank(stakers[8]); - l2LiskToken.approve(address(l2Reward), increasingAmounts[0].amountIncrease); - l2Reward.increaseLockingAmount(increasingAmounts); - vm.stopPrank(); - - vm.warp(19740 days + 58 days); - // stake 9 initiates fast unlock - positionsToBeModified[0] = lockIDs[8]; - vm.prank(stakers[8]); - l2Reward.initiateFastUnlock(positionsToBeModified); - - vm.warp(19740 days + 59 days); - // stake 9 is paused - positionsToBeModified[0] = lockIDs[8]; - vm.prank(stakers[8]); - l2Reward.pauseUnlocking(positionsToBeModified); - - checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - vm.warp(19740 days + 60 days); - // stake 7: Initiate fast unlock - positionsToBeModified[0] = lockIDs[6]; - vm.prank(stakers[6]); - l2Reward.initiateFastUnlock(positionsToBeModified); - - vm.warp(19740 days + 61 days); - // stake 7 extends locking duration by 8 days and pauses unlocking - durationExtensions[0].lockID = lockIDs[6]; - durationExtensions[0].durationExtension = 8; - vm.prank(stakers[6]); - l2Reward.extendDuration(durationExtensions); - positionsToBeModified[0] = lockIDs[6]; - vm.prank(stakers[6]); - l2Reward.pauseUnlocking(positionsToBeModified); - - vm.warp(19740 days + 65 days); - // stake 7 extends duration - durationExtensions[0].lockID = lockIDs[6]; - durationExtensions[0].durationExtension = 4; - vm.prank(stakers[6]); - l2Reward.extendDuration(durationExtensions); - - checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - // stake 7 increases amount - increasingAmounts = new L2Reward.IncreasedAmount[](1); - increasingAmounts[0].lockID = lockIDs[6]; - increasingAmounts[0].amountIncrease = convertLiskToSmallestDenomination(50); - vm.startPrank(stakers[6]); - l2LiskToken.approve(address(l2Reward), increasingAmounts[0].amountIncrease); - l2Reward.increaseLockingAmount(increasingAmounts); - vm.stopPrank(); - - vm.warp(19740 days + 66 days); - // stake 11 extended by 10 days - durationExtensions[0].lockID = lockIDs[10]; - durationExtensions[0].durationExtension = 10; - vm.prank(stakers[10]); - l2Reward.extendDuration(durationExtensions); - - checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - vm.warp(19740 days + 68 days); - // stake 8 initiates fast unlock - positionsToBeModified[0] = lockIDs[7]; - vm.prank(stakers[7]); - l2Reward.initiateFastUnlock(positionsToBeModified); - - // stake 11 pauses - positionsToBeModified[0] = lockIDs[10]; - vm.prank(stakers[10]); - l2Reward.pauseUnlocking(positionsToBeModified); - - vm.warp(19740 days + 69 days); - // stake 8 extends duration by 150 days - durationExtensions[0].lockID = lockIDs[7]; - durationExtensions[0].durationExtension = 150; - vm.prank(stakers[7]); - l2Reward.extendDuration(durationExtensions); - - vm.warp(19740 days + 70 days); - // stake 1: paused on day 70 - positionsToBeModified[0] = lockIDs[0]; - vm.prank(stakers[0]); - l2Reward.pauseUnlocking(positionsToBeModified); - - checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - vm.warp(19740 days + 75 days); - // stake 6: extended on day 75 by 20 days - durationExtensions[0].lockID = lockIDs[5]; - durationExtensions[0].durationExtension = 20; - vm.prank(stakers[5]); - l2Reward.extendDuration(durationExtensions); - - vm.warp(19740 days + 76 days); - // extends stake 12 by 50 days - durationExtensions[0].lockID = lockIDs[11]; - durationExtensions[0].durationExtension = 50; - vm.prank(stakers[11]); - l2Reward.extendDuration(durationExtensions); - - vm.warp(19740 days + 100 days); - // stake 1: resumed on day 100 - positionsToBeModified[0] = lockIDs[0]; - vm.prank(stakers[0]); - l2Reward.resumeUnlockingCountdown(positionsToBeModified); - - // stake 6: resume unlocking - positionsToBeModified[0] = lockIDs[5]; - vm.prank(stakers[5]); - l2Reward.resumeUnlockingCountdown(positionsToBeModified); - - // stake 14: (500 LSK, 14 days) - // created on day 100 - // paused right away - lockIDs[13] = when_stakerCreatesPosition( - stakers[13], Position({ amount: convertLiskToSmallestDenomination(500), duration: 14 }) - ); - - checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - positionsToBeModified[0] = lockIDs[13]; - vm.prank(stakers[13]); - l2Reward.pauseUnlocking(positionsToBeModified); - - // stake 13 extends duration by 100 days - durationExtensions[0].lockID = lockIDs[12]; - durationExtensions[0].durationExtension = 100; - vm.prank(stakers[12]); - l2Reward.extendDuration(durationExtensions); - - vm.warp(19740 days + 101 days); - // stake 11 extended by 10 days - durationExtensions[0].lockID = lockIDs[10]; - durationExtensions[0].durationExtension = 10; - vm.prank(stakers[10]); - l2Reward.extendDuration(durationExtensions); - - vm.warp(19740 days + 102 days); - // stake 13 increases amount by 500 LSK - increasingAmounts[0].lockID = lockIDs[12]; - increasingAmounts[0].amountIncrease = 500; - vm.startPrank(stakers[12]); - l2LiskToken.approve(address(l2Reward), increasingAmounts[0].amountIncrease); - l2Reward.increaseLockingAmount(increasingAmounts); - vm.stopPrank(); - - checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - vm.warp(19740 days + 104 days); - // stake 13 pauses - positionsToBeModified[0] = lockIDs[12]; - vm.prank(stakers[12]); - l2Reward.pauseUnlocking(positionsToBeModified); - - checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - vm.warp(19740 days + 107 days); - // resumes stake 7 on day 107 - positionsToBeModified[0] = lockIDs[6]; - vm.prank(stakers[6]); - l2Reward.resumeUnlockingCountdown(positionsToBeModified); - - // stake 8 initiates fast unlock on day 107 - positionsToBeModified[0] = lockIDs[7]; - vm.prank(stakers[7]); - l2Reward.initiateFastUnlock(positionsToBeModified); - - checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - // stake 13 increases amount by 500 LSK - increasingAmounts[0].lockID = lockIDs[12]; - increasingAmounts[0].amountIncrease = 500; - vm.startPrank(stakers[12]); - l2LiskToken.approve(address(l2Reward), increasingAmounts[0].amountIncrease); - l2Reward.increaseLockingAmount(increasingAmounts); - vm.stopPrank(); - - vm.warp(19740 days + 108 days); - // resume unlocking for stake 5 - positionsToBeModified[0] = lockIDs[4]; - vm.prank(stakers[4]); - l2Reward.resumeUnlockingCountdown(positionsToBeModified); - - vm.warp(19740 days + 110 days); - // stake 1: extended on day 110 by 30 days - durationExtensions[0].lockID = lockIDs[0]; - durationExtensions[0].durationExtension = 30; - vm.prank(stakers[0]); - l2Reward.extendDuration(durationExtensions); - - // stake 13 resumes - positionsToBeModified[0] = lockIDs[12]; - vm.prank(stakers[12]); - l2Reward.resumeUnlockingCountdown(positionsToBeModified); - + Scenario memory scenario = Scenario({ stakers: stakers, lockIDs: lockIDs }); + + onDay(1); + stakerCreatesPosition(0, LSK(100), 730, scenario); + stakerCreatesPosition(1, LSK(30), 50, scenario); + checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + stakerCreatesPosition(2, LSK(400), 730, scenario); + onDay(15); + stakerCreatesPosition(3, LSK(5), 300, scenario); + onDay(20); + stakerCreatesPosition(4, LSK(500), 50, scenario); + checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + stakerCreatesPosition(5, LSK(1250), 80, scenario); + onDay(30); + stakerIncreasesAmountOfThePositionBy(0, LSK(90), scenario); + stakerIncreasesAmountOfThePositionBy(3, LSK(1), scenario); + stakerInitiatesFastUnlock(4, scenario); + onDay(31); + stakerExtendsPositionBy(4, 21, scenario); + onDay(35); + stakerInitiatesFastUnlock(5, scenario); + onDay(36); + stakerPausesPosition(5, scenario); + stakerCreatesPosition(6, LSK(125), 80, scenario); + checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + onDay(40); + stakerIncreasesAmountOfThePositionBy(4, LSK(30), scenario); + stakerPausesPosition(4, scenario); + onDay(45); + stakerCreatesPosition(7, LSK(2000), 70, scenario); + stakerCreatesPosition(8, LSK(220), 600, scenario); + stakerCreatesPosition(9, LSK(300), 534, scenario); + checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + stakerCreatesPosition(10, LSK(80), 53, scenario); + stakerCreatesPosition(11, LSK(110), 23, scenario); + checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + stakerCreatesPosition(12, LSK(1000), 68, scenario); + onDay(50); + stakerPausesPosition(8, scenario); + onDay(51); + stakerPausesPosition(9, scenario); + onDay(52); + stakerExtendsPositionBy(9, 116, scenario); + onDay(55); + stakerIncreasesAmountOfThePositionBy(8, LSK(300), scenario); + onDay(58); + stakerInitiatesFastUnlock(8, scenario); + onDay(59); + stakerPausesPosition(8, scenario); + checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + onDay(60); + stakerInitiatesFastUnlock(6, scenario); + onDay(61); + stakerExtendsPositionBy(6, 8, scenario); + stakerPausesPosition(6, scenario); + onDay(65); + stakerExtendsPositionBy(6, 4, scenario); + checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + stakerIncreasesAmountOfThePositionBy(6, LSK(50), scenario); + onDay(66); + stakerExtendsPositionBy(10, 10, scenario); + checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + onDay(68); + stakerInitiatesFastUnlock(7, scenario); + stakerPausesPosition(10, scenario); + onDay(69); + stakerExtendsPositionBy(7, 150, scenario); + onDay(70); + stakerPausesPosition(0, scenario); + checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + onDay(75); + stakerExtendsPositionBy(5, 20, scenario); + onDay(76); + stakerExtendsPositionBy(11, 50, scenario); + onDay(100); + stakerReumesPosition(0, scenario); + stakerReumesPosition(5, scenario); + stakerCreatesPosition(13, LSK(500), 14, scenario); + checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + stakerPausesPosition(13, scenario); + stakerExtendsPositionBy(12, 100, scenario); + onDay(101); + stakerExtendsPositionBy(10, 10, scenario); + onDay(102); + stakerIncreasesAmountOfThePositionBy(12, LSK(500), scenario); + checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + onDay(104); + stakerPausesPosition(12, scenario); + checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + onDay(107); + stakerReumesPosition(6, scenario); + stakerInitiatesFastUnlock(7, scenario); + checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + stakerIncreasesAmountOfThePositionBy(12, 500, scenario); + onDay(108); + stakerReumesPosition(4, scenario); + onDay(110); + stakerExtendsPositionBy(0, 30, scenario); + stakerReumesPosition(12, scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); return (lockIDs, stakers); @@ -3275,4 +2920,8 @@ contract L2RewardTest is Test { function convertLiskToSmallestDenomination(uint256 lisk) internal pure returns (uint256) { return lisk * 10 ** 18; } + + function LSK(uint256 lisk) internal pure returns (uint256) { + return lisk * 10 ** 18; + } } From b0ecb59759e9d59ae5323ef355bfa50c00afb80b Mon Sep 17 00:00:00 2001 From: has5aan Date: Mon, 3 Jun 2024 20:46:58 +0200 Subject: [PATCH 02/18] refactor: test_scenario1_dailyRewards --- test/L2/L2Reward.t.sol | 272 ++++++++++++++++------------------------- 1 file changed, 104 insertions(+), 168 deletions(-) diff --git a/test/L2/L2Reward.t.sol b/test/L2/L2Reward.t.sol index 0a72329d..058cafce 100644 --- a/test/L2/L2Reward.t.sol +++ b/test/L2/L2Reward.t.sol @@ -38,6 +38,10 @@ contract L2RewardTest is Test { struct Scenario { address[] stakers; uint256[] lockIDs; + uint8 claimCount; + uint256[] oldBalances; + uint256[] balances; + uint256 lastClaimedAmount; } struct Position { @@ -259,6 +263,7 @@ contract L2RewardTest is Test { positionsToBeModified[0] = scenario.lockIDs[stakerIndex]; vm.prank(scenario.stakers[stakerIndex]); l2Reward.deletePositions(positionsToBeModified); + delete scenario.lockIDs[stakerIndex]; } function stakerExtendsPositionBy( @@ -291,10 +296,37 @@ contract L2RewardTest is Test { vm.stopPrank(); } - function createScenario1() private returns (uint256[] memory, address[] memory) { + function allStakersClaim(Scenario memory scenario) private { + uint256[] memory positionsToBeModified = new uint256[](1); + scenario.lastClaimedAmount = 0; + for (uint8 i = 0; i < scenario.stakers.length; i++) { + if (scenario.lockIDs[i] == 0) { + continue; + } + + // scenario.oldBalances[i] = scenario.balances[i]; + + positionsToBeModified[0] = scenario.lockIDs[i]; + vm.prank(scenario.stakers[i]); + l2Reward.claimRewards(positionsToBeModified); + + scenario.balances[i] = l2LiskToken.balanceOf(scenario.stakers[i]); + + scenario.lastClaimedAmount += scenario.balances[i] - scenario.oldBalances[i]; + } + } + + function cacheBalances(Scenario memory scenario) private { + for (uint8 i = 0; i < scenario.stakers.length; i++) { + scenario.oldBalances[i] = l2LiskToken.balanceOf(scenario.stakers[i]); + } + } + + function createScenario1() private returns (uint256[] memory, address[] memory, Scenario memory) { address[] memory stakers = given_anArrayOfStakersOfLength(7); uint256[] memory lockIDs = new uint256[](7); - + uint256[] memory balances = new uint256[](7); + uint256[] memory oldBalances = new uint256[](7); uint256 funds = convertLiskToSmallestDenomination(5000); uint256 balance = convertLiskToSmallestDenomination(500); @@ -307,7 +339,14 @@ contract L2RewardTest is Test { for (uint8 i = 0; i < stakers.length; i++) { given_accountHasBalance(stakers[i], balance); } - Scenario memory scenario = Scenario({ stakers: stakers, lockIDs: lockIDs }); + Scenario memory scenario = Scenario({ + stakers: stakers, + lockIDs: lockIDs, + balances: balances, + oldBalances: oldBalances, + claimCount: 0, + lastClaimedAmount: 0 + }); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); onDay(1); @@ -342,7 +381,7 @@ contract L2RewardTest is Test { stakerIncreasesAmountOfThePositionBy(6, LSK(50), scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - return (lockIDs, stakers); + return (lockIDs, stakers, scenario); } function createScenario2() private returns (uint256[] memory, address[] memory) { @@ -350,7 +389,8 @@ contract L2RewardTest is Test { uint256[] memory lockIDs = new uint256[](7); uint256 funds = convertLiskToSmallestDenomination(5000); uint256 balance = convertLiskToSmallestDenomination(500); - + uint256[] memory balances = new uint256[](7); + uint256[] memory oldBalances = new uint256[](7); uint256[] memory positionsToBeModified = new uint256[](1); // owner gets balance @@ -363,7 +403,14 @@ contract L2RewardTest is Test { given_accountHasBalance(stakers[i], balance); } - Scenario memory scenario = Scenario({ stakers: stakers, lockIDs: lockIDs }); + Scenario memory scenario = Scenario({ + stakers: stakers, + lockIDs: lockIDs, + balances: balances, + oldBalances: oldBalances, + claimCount: 0, + lastClaimedAmount: 0 + }); onDay(1); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); stakerCreatesPosition(0, LSK(100), 730, scenario); @@ -407,7 +454,8 @@ contract L2RewardTest is Test { function createScenario3() private returns (uint256[] memory, address[] memory) { address[] memory stakers = given_anArrayOfStakersOfLength(14); uint256[] memory lockIDs = new uint256[](14); - + uint256[] memory balances = new uint256[](7); + uint256[] memory oldBalances = new uint256[](7); uint256 funds = convertLiskToSmallestDenomination(5000); uint256 balance = convertLiskToSmallestDenomination(5000); @@ -427,7 +475,14 @@ contract L2RewardTest is Test { given_accountHasBalance(stakers[i], balance); } - Scenario memory scenario = Scenario({ stakers: stakers, lockIDs: lockIDs }); + Scenario memory scenario = Scenario({ + stakers: stakers, + lockIDs: lockIDs, + balances: balances, + oldBalances: oldBalances, + claimCount: 0, + lastClaimedAmount: 0 + }); onDay(1); stakerCreatesPosition(0, LSK(100), 730, scenario); @@ -569,6 +624,16 @@ contract L2RewardTest is Test { return expiryDate; } + function lastClaimedRewardEqualsDailyRewardBetweenDays(uint256 reward, uint256 startDay, uint256 endDay) private { + uint256 sumOfDailyRewards; + for (uint256 i = deploymentDate + startDay; i <= deploymentDate + endDay; i++) { + sumOfDailyRewards += l2Reward.dailyRewards(i); + } + + assertTrue(sumOfDailyRewards > reward); + assertEq(sumOfDailyRewards / 10 ** 4, reward / 10 ** 4); + } + function test_scenario1_dailyRewards() public { // Scenario: rewards alloted for a certain day(s) is less than or equal to dailyRewards available for those // days. @@ -587,172 +652,42 @@ contract L2RewardTest is Test { address[] memory stakers; uint256[] memory positionsToBeModified = new uint256[](1); uint256[] memory balances = new uint256[](7); - uint256 totalRewards; - - (lockIDs, stakers) = createScenario1(); - - vm.warp(19740 days + 105 days); - - for (uint8 i = 0; i < lockIDs.length; i++) { - // lockIDs[3] has been deleted - if (i == 3) { - continue; - } - positionsToBeModified[0] = lockIDs[i]; - when_rewardsAreClaimedByStaker(stakers[i], positionsToBeModified); - } - - // get balances before claiming rewards again - for (uint8 i = 0; i < stakers.length; i++) { - balances[i] = l2LiskToken.balanceOf(stakers[i]); - } - - vm.warp(19740 days + 106 days); - // all positions claim rewards on day 106 only position at index 1, 3, 4, 5, and 6 are valid - for (uint8 i = 0; i < stakers.length; i++) { - // lockIDs[3] has been deleted - if (i == 3) { - continue; - } - positionsToBeModified[0] = lockIDs[i]; - when_rewardsAreClaimedByStaker(stakers[i], positionsToBeModified); - } - - for (uint8 i = 0; i < stakers.length; i++) { - totalRewards += l2LiskToken.balanceOf(stakers[i]) - balances[i]; - } - - // total rewards calimed on day 106 are less than or equal to dailyRewards on day 105 - assertTrue(totalRewards <= l2Reward.dailyRewards(19740 + 105)); - assertEq(totalRewards / 10, l2Reward.dailyRewards(19740 + 105) / 10); - - vm.warp(19740 days + 115 days); - - // get balances before claiming rewards again - for (uint8 i = 0; i < stakers.length; i++) { - balances[i] = l2LiskToken.balanceOf(stakers[i]); - } - - // all positions claim rewards on day 115 only position at index 1, 3, 4, 5, and 6 are valid - for (uint8 i = 0; i < stakers.length; i++) { - // lockIDs[3] has been deleted - if (i == 3) { - continue; - } - positionsToBeModified[0] = lockIDs[i]; - when_rewardsAreClaimedByStaker(stakers[i], positionsToBeModified); - } - - totalRewards = 0; - for (uint8 i = 0; i < stakers.length; i++) { - totalRewards += l2LiskToken.balanceOf(stakers[i]) - balances[i]; - } - uint256 sumOfDailyRewards; - for (uint256 i = deploymentDate + 106; i < deploymentDate + 115; i++) { - sumOfDailyRewards += l2Reward.dailyRewards(i); - } - - assertTrue(sumOfDailyRewards > totalRewards); - assertEq(sumOfDailyRewards / 10 ** 3, totalRewards / 10 ** 3); - - // balances before claiming on day 150 - for (uint8 i = 0; i < stakers.length; i++) { - balances[i] = l2LiskToken.balanceOf(stakers[i]); - } - - // all positions claim rewards on day 150 - vm.warp(19740 days + 150 days); - for (uint8 i = 0; i < stakers.length; i++) { - // lockIDs[3] has been deleted - if (i == 3) { - continue; - } - - positionsToBeModified[0] = lockIDs[i]; - when_rewardsAreClaimedByStaker(stakers[i], positionsToBeModified); - } - - // all positions claim rewards on day 230 - vm.warp(19740 days + 230 days); - for (uint8 i = 0; i < stakers.length; i++) { - // lockIDs[3] has been deleted - if (i == 3) { - continue; - } - - positionsToBeModified[0] = lockIDs[i]; - when_rewardsAreClaimedByStaker(stakers[i], positionsToBeModified); - } - - totalRewards = 0; - for (uint8 i = 0; i < stakers.length; i++) { - totalRewards += l2LiskToken.balanceOf(stakers[i]) - balances[i]; - } - - sumOfDailyRewards = 0; - for (uint256 i = 19740 + 115; i < 19740 + 230; i++) { - sumOfDailyRewards += l2Reward.dailyRewards(i); - } - - // console2.logUint(totalRewards); - // console2.logUint(sumOfDailyRewards); - assertTrue(sumOfDailyRewards > totalRewards); - assertEq(totalRewards / 10 ** 3, sumOfDailyRewards / 10 ** 3); + uint256 totalRewards; + Scenario memory scenario; + + (lockIDs, stakers, scenario) = createScenario1(); + + onDay(105); + allStakersClaim(scenario); + cacheBalances(scenario); + onDay(106); + allStakersClaim(scenario); + lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 105, 105); + onDay(115); + cacheBalances(scenario); + allStakersClaim(scenario); + lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 106, 114); + cacheBalances(scenario); + onDay(150); + allStakersClaim(scenario); + onDay(230); + allStakersClaim(scenario); + lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 115, 229); // stake 4 gets resumed, expiry date should be 270 - positionsToBeModified[0] = lockIDs[4]; - vm.prank(stakers[4]); - l2Reward.resumeUnlockingCountdown(positionsToBeModified); - assertEq(l2LockingPosition.getLockingPosition(lockIDs[4]).expDate, 19740 + 270); - + stakerReumesPosition(4, scenario); + assertEq(l2LockingPosition.getLockingPosition(scenario.lockIDs[4]).expDate, deploymentDate + 270); // stake 7 initiates fast unlock on day 240 - vm.warp(19740 days + 240 days); - positionsToBeModified[0] = lockIDs[6]; - vm.prank(stakers[6]); - l2Reward.initiateFastUnlock(positionsToBeModified); - + onDay(240); + stakerInitiatesFastUnlock(6, scenario); // stake 5 claims rewards on day 240 positionsToBeModified[0] = lockIDs[4]; when_rewardsAreClaimedByStaker(stakers[4], positionsToBeModified); - - // balances before claiming on day 275 - for (uint8 i = 0; i < stakers.length; i++) { - balances[i] = l2LiskToken.balanceOf(stakers[i]); - } - - // all stakes claim rewards on day 275 - vm.warp(19740 days + 275 days); - for (uint8 i = 0; i < stakers.length; i++) { - // lockIDs[3] has been deleted - if (i == 3) { - continue; - } - - positionsToBeModified[0] = lockIDs[i]; - when_rewardsAreClaimedByStaker(stakers[i], positionsToBeModified); - } - - totalRewards = 0; - for (uint8 i = 0; i < stakers.length; i++) { - totalRewards += l2LiskToken.balanceOf(stakers[i]) - balances[i]; - } - - sumOfDailyRewards = 0; - for (uint256 i = 19740 + 240; i < 19740 + 270; i++) { - sumOfDailyRewards += l2Reward.dailyRewards(i); - } - - assertTrue(sumOfDailyRewards > totalRewards); - assertEq(sumOfDailyRewards / 10 ** 3, totalRewards / 10 ** 3); - - // staker 2 doesn't get balance as lockIDs[2] is expired - assertEq(l2LiskToken.balanceOf(stakers[2]), balances[2]); - - // staker 5 and 7 gets balance as lockIDs[4] and lockIDs[6] are active - assertTrue(l2LiskToken.balanceOf(stakers[4]) > balances[4]); - assertTrue(l2LiskToken.balanceOf(stakers[6]) > balances[6]); - + cacheBalances(scenario); + onDay(275); + allStakersClaim(scenario); + lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 240, 269); for (uint256 i = 19740 + 270; i < 19740 + 275; i++) { assertEq(l2Reward.totalWeights(i), 0); } @@ -775,6 +710,7 @@ contract L2RewardTest is Test { address[] memory stakers; uint256[] memory positionsToBeModified = new uint256[](1); uint256[] memory balances = new uint256[](7); + Scenario memory scenario; uint256 totalRewards; (lockIDs, stakers) = createScenario2(); @@ -915,7 +851,7 @@ contract L2RewardTest is Test { uint256[] memory lockIDs; address[] memory stakers; - (lockIDs, stakers) = createScenario1(); + (lockIDs, stakers,) = createScenario1(); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); } From 41a5b2c7c1984bd75f9d4f49a5fa0fa345546c26 Mon Sep 17 00:00:00 2001 From: has5aan Date: Mon, 3 Jun 2024 20:58:15 +0200 Subject: [PATCH 03/18] refactor: merge all tests for scenario1 into test_scenario1 refactor: merge all tests for scenario1 into test_scenario1 refactor: merge all tests for scenario1 into test_scenario1 --- test/L2/L2Reward.t.sol | 111 ++++++++++++++--------------------------- 1 file changed, 38 insertions(+), 73 deletions(-) diff --git a/test/L2/L2Reward.t.sol b/test/L2/L2Reward.t.sol index 058cafce..5f4e39b1 100644 --- a/test/L2/L2Reward.t.sol +++ b/test/L2/L2Reward.t.sol @@ -296,6 +296,13 @@ contract L2RewardTest is Test { vm.stopPrank(); } + function stakerClaimRewards(uint256 stakerIndex, Scenario memory scenario) private { + uint256[] memory positionsToBeModified = new uint256[](1); + positionsToBeModified[0] = scenario.lockIDs[stakerIndex]; + vm.prank(scenario.stakers[stakerIndex]); + l2Reward.claimRewards(positionsToBeModified); + } + function allStakersClaim(Scenario memory scenario) private { uint256[] memory positionsToBeModified = new uint256[](1); scenario.lastClaimedAmount = 0; @@ -304,8 +311,6 @@ contract L2RewardTest is Test { continue; } - // scenario.oldBalances[i] = scenario.balances[i]; - positionsToBeModified[0] = scenario.lockIDs[i]; vm.prank(scenario.stakers[i]); l2Reward.claimRewards(positionsToBeModified); @@ -322,13 +327,14 @@ contract L2RewardTest is Test { } } - function createScenario1() private returns (uint256[] memory, address[] memory, Scenario memory) { + function test_scenario1() public { address[] memory stakers = given_anArrayOfStakersOfLength(7); uint256[] memory lockIDs = new uint256[](7); uint256[] memory balances = new uint256[](7); uint256[] memory oldBalances = new uint256[](7); uint256 funds = convertLiskToSmallestDenomination(5000); uint256 balance = convertLiskToSmallestDenomination(500); + uint256[] memory positionsToBeModified = new uint256[](1); // owner gets balance given_accountHasBalance(address(this), funds); @@ -380,8 +386,35 @@ contract L2RewardTest is Test { onDay(100); stakerIncreasesAmountOfThePositionBy(6, LSK(50), scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - return (lockIDs, stakers, scenario); + onDay(105); + allStakersClaim(scenario); + cacheBalances(scenario); + onDay(106); + allStakersClaim(scenario); + lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 105, 105); + onDay(115); + cacheBalances(scenario); + allStakersClaim(scenario); + lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 106, 114); + cacheBalances(scenario); + onDay(150); + allStakersClaim(scenario); + onDay(230); + allStakersClaim(scenario); + lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 115, 229); + // stake 4 gets resumed, expiry date should be 270 + stakerReumesPosition(4, scenario); + assertEq(l2LockingPosition.getLockingPosition(scenario.lockIDs[4]).expDate, deploymentDate + 270); + onDay(240); + stakerInitiatesFastUnlock(6, scenario); + stakerClaimRewards(4, scenario); + cacheBalances(scenario); + onDay(275); + allStakersClaim(scenario); + lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 240, 269); + for (uint256 i = 19740 + 270; i < 19740 + 275; i++) { + assertEq(l2Reward.totalWeights(i), 0); + } } function createScenario2() private returns (uint256[] memory, address[] memory) { @@ -634,65 +667,6 @@ contract L2RewardTest is Test { assertEq(sumOfDailyRewards / 10 ** 4, reward / 10 ** 4); } - function test_scenario1_dailyRewards() public { - // Scenario: rewards alloted for a certain day(s) is less than or equal to dailyRewards available for those - // days. - // Description: - // claim rewards agains all positions on day 105 - // Act: - // move to day 106, claim rewards against all positions again - // Assert: - // total rewards claimed on day 106 is equal to daily rewards available for day 105. - // Act: - // move to day 115, claim rewards against all positions again - // Assert: - // total rewards claimed on day 115 is equal to sum of daily rewards between day 106 and 114. - - uint256[] memory lockIDs; - address[] memory stakers; - uint256[] memory positionsToBeModified = new uint256[](1); - uint256[] memory balances = new uint256[](7); - uint256 sumOfDailyRewards; - - uint256 totalRewards; - Scenario memory scenario; - - (lockIDs, stakers, scenario) = createScenario1(); - - onDay(105); - allStakersClaim(scenario); - cacheBalances(scenario); - onDay(106); - allStakersClaim(scenario); - lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 105, 105); - onDay(115); - cacheBalances(scenario); - allStakersClaim(scenario); - lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 106, 114); - cacheBalances(scenario); - onDay(150); - allStakersClaim(scenario); - onDay(230); - allStakersClaim(scenario); - lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 115, 229); - // stake 4 gets resumed, expiry date should be 270 - stakerReumesPosition(4, scenario); - assertEq(l2LockingPosition.getLockingPosition(scenario.lockIDs[4]).expDate, deploymentDate + 270); - // stake 7 initiates fast unlock on day 240 - onDay(240); - stakerInitiatesFastUnlock(6, scenario); - // stake 5 claims rewards on day 240 - positionsToBeModified[0] = lockIDs[4]; - when_rewardsAreClaimedByStaker(stakers[4], positionsToBeModified); - cacheBalances(scenario); - onDay(275); - allStakersClaim(scenario); - lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 240, 269); - for (uint256 i = 19740 + 270; i < 19740 + 275; i++) { - assertEq(l2Reward.totalWeights(i), 0); - } - } - function test_scenario2_dailyRewards() public { // Scenario: rewards alloted for a certain day(s) is less than or equal to dailyRewards available for those // days. @@ -847,15 +821,6 @@ contract L2RewardTest is Test { assertEq(sumOfDailyRewards / 10 ** 3, totalRewards / 10 ** 3); } - function test_scenario1_pendingUnlockAmount() public { - uint256[] memory lockIDs; - address[] memory stakers; - - (lockIDs, stakers,) = createScenario1(); - - checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - } - function test_scenario2_pendingUnlockAmount() public { uint256[] memory lockIDs; address[] memory stakers; From 3c4c2b55709c6ecab9cc7474c72f6b780b4021c6 Mon Sep 17 00:00:00 2001 From: has5aan Date: Tue, 4 Jun 2024 00:25:39 +0200 Subject: [PATCH 04/18] Adds checkRewardsContractBalance --- test/L2/L2Reward.t.sol | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/test/L2/L2Reward.t.sol b/test/L2/L2Reward.t.sol index 5f4e39b1..bad078bc 100644 --- a/test/L2/L2Reward.t.sol +++ b/test/L2/L2Reward.t.sol @@ -38,7 +38,6 @@ contract L2RewardTest is Test { struct Scenario { address[] stakers; uint256[] lockIDs; - uint8 claimCount; uint256[] oldBalances; uint256[] balances; uint256 lastClaimedAmount; @@ -327,6 +326,16 @@ contract L2RewardTest is Test { } } + function checkRewardsContractBalance(uint256 funds) public { + uint256 sumOfDailyRewards; + for (uint256 i = deploymentDate; i < l2Reward.todayDay(); i++) { + sumOfDailyRewards += l2Reward.dailyRewards(i); + } + + assertTrue(l2LiskToken.balanceOf(address(l2Reward)) > funds - sumOfDailyRewards); + assertEq(l2LiskToken.balanceOf(address(l2Reward)) / 10 ** 4, (funds - sumOfDailyRewards) / 10 ** 4); + } + function test_scenario1() public { address[] memory stakers = given_anArrayOfStakersOfLength(7); uint256[] memory lockIDs = new uint256[](7); @@ -350,7 +359,6 @@ contract L2RewardTest is Test { lockIDs: lockIDs, balances: balances, oldBalances: oldBalances, - claimCount: 0, lastClaimedAmount: 0 }); @@ -388,19 +396,24 @@ contract L2RewardTest is Test { checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); onDay(105); allStakersClaim(scenario); + checkRewardsContractBalance(funds); cacheBalances(scenario); onDay(106); allStakersClaim(scenario); + checkRewardsContractBalance(funds); lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 105, 105); onDay(115); cacheBalances(scenario); allStakersClaim(scenario); + checkRewardsContractBalance(funds); lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 106, 114); cacheBalances(scenario); onDay(150); allStakersClaim(scenario); + checkRewardsContractBalance(funds); onDay(230); allStakersClaim(scenario); + checkRewardsContractBalance(funds); lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 115, 229); // stake 4 gets resumed, expiry date should be 270 stakerReumesPosition(4, scenario); @@ -441,7 +454,6 @@ contract L2RewardTest is Test { lockIDs: lockIDs, balances: balances, oldBalances: oldBalances, - claimCount: 0, lastClaimedAmount: 0 }); onDay(1); @@ -513,7 +525,6 @@ contract L2RewardTest is Test { lockIDs: lockIDs, balances: balances, oldBalances: oldBalances, - claimCount: 0, lastClaimedAmount: 0 }); From de21139ecfef1286b975cf81ac59c9df39475321 Mon Sep 17 00:00:00 2001 From: has5aan Date: Tue, 4 Jun 2024 00:41:51 +0200 Subject: [PATCH 05/18] refactor: removes redundant pending unlock amount test methods for scenario2 and scenario3 --- test/L2/L2Reward.t.sol | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/test/L2/L2Reward.t.sol b/test/L2/L2Reward.t.sol index bad078bc..6d159108 100644 --- a/test/L2/L2Reward.t.sol +++ b/test/L2/L2Reward.t.sol @@ -832,24 +832,6 @@ contract L2RewardTest is Test { assertEq(sumOfDailyRewards / 10 ** 3, totalRewards / 10 ** 3); } - function test_scenario2_pendingUnlockAmount() public { - uint256[] memory lockIDs; - address[] memory stakers; - - (lockIDs, stakers) = createScenario2(); - - checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - } - - function test_scenario3_pendingUnlockAmount() public { - uint256[] memory lockIDs; - address[] memory stakers; - - (lockIDs, stakers) = createScenario3(); - - checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - } - function test_createPosition_l2RewardContractShouldBeApprovedToTransferFromStakerAccount() public { address staker = address(0x1); uint256 duration = 20; From 10c95f9deb69648316643fa27076388933350274 Mon Sep 17 00:00:00 2001 From: has5aan Date: Tue, 4 Jun 2024 00:51:42 +0200 Subject: [PATCH 06/18] refactor: moves the logic from scenario2_dailyRewards to scenario2 --- test/L2/L2Reward.t.sol | 90 ++++++------------------------------------ 1 file changed, 11 insertions(+), 79 deletions(-) diff --git a/test/L2/L2Reward.t.sol b/test/L2/L2Reward.t.sol index 6d159108..cb6219e1 100644 --- a/test/L2/L2Reward.t.sol +++ b/test/L2/L2Reward.t.sol @@ -430,7 +430,7 @@ contract L2RewardTest is Test { } } - function createScenario2() private returns (uint256[] memory, address[] memory) { + function test_scenario2() private { address[] memory stakers = given_anArrayOfStakersOfLength(7); uint256[] memory lockIDs = new uint256[](7); uint256 funds = convertLiskToSmallestDenomination(5000); @@ -492,8 +492,16 @@ contract L2RewardTest is Test { onDay(93); stakerIncreasesAmountOfThePositionBy(5, LSK(30), scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - return (lockIDs, stakers); + onDay(105); + allStakersClaim(scenario); + cacheBalances(scenario); + onDay(106); + allStakersClaim(scenario); + lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 105, 105); + onDay(115); + cacheBalances(scenario); + allStakersClaim(scenario); + lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 106, 114); } function createScenario3() private returns (uint256[] memory, address[] memory) { @@ -678,82 +686,6 @@ contract L2RewardTest is Test { assertEq(sumOfDailyRewards / 10 ** 4, reward / 10 ** 4); } - function test_scenario2_dailyRewards() public { - // Scenario: rewards alloted for a certain day(s) is less than or equal to dailyRewards available for those - // days. - // Description: - // claim rewards against all positions on day 105 - // Act: - // move to day 106, claim rewards against all positions again - // Assert: - // total rewards claimed on day 106 is equal to daily rewards available for day 105. - // Act: - // move to day 115, claim rewards against all positions again - // Assert: - // total rewards claimed on day 115 is equal to sum of daily rewards between day 106 and 114. - uint256[] memory lockIDs; - address[] memory stakers; - uint256[] memory positionsToBeModified = new uint256[](1); - uint256[] memory balances = new uint256[](7); - Scenario memory scenario; - uint256 totalRewards; - - (lockIDs, stakers) = createScenario2(); - - vm.warp(19740 days + 105 days); - - for (uint8 i = 0; i < lockIDs.length; i++) { - positionsToBeModified[0] = lockIDs[i]; - when_rewardsAreClaimedByStaker(stakers[i], positionsToBeModified); - } - - // get balances before claiming rewards again - for (uint8 i = 0; i < stakers.length; i++) { - balances[i] = l2LiskToken.balanceOf(stakers[i]); - } - - vm.warp(19740 days + 106 days); - // all positions claim rewards on day 106 - for (uint8 i = 0; i < stakers.length; i++) { - positionsToBeModified[0] = lockIDs[i]; - when_rewardsAreClaimedByStaker(stakers[i], positionsToBeModified); - } - - for (uint8 i = 0; i < stakers.length; i++) { - totalRewards += l2LiskToken.balanceOf(stakers[i]) - balances[i]; - } - - // total rewards claimed on day 106 are less than or equal to dailyRewards on day 105. - assertTrue(totalRewards <= l2Reward.dailyRewards(19740 + 105)); - assertEq(totalRewards / 10, l2Reward.dailyRewards(19740 + 105) / 10); - - vm.warp(19740 days + 115 days); - - // get balances before claiming rewards again - for (uint8 i = 0; i < stakers.length; i++) { - balances[i] = l2LiskToken.balanceOf(stakers[i]); - } - - // all positions claim rewards on day 115 - for (uint8 i = 0; i < stakers.length; i++) { - positionsToBeModified[0] = lockIDs[i]; - when_rewardsAreClaimedByStaker(stakers[i], positionsToBeModified); - } - - totalRewards = 0; - for (uint8 i = 0; i < stakers.length; i++) { - totalRewards += l2LiskToken.balanceOf(stakers[i]) - balances[i]; - } - - uint256 sumOfDailyRewards; - for (uint256 i = deploymentDate + 106; i < deploymentDate + 115; i++) { - sumOfDailyRewards += l2Reward.dailyRewards(i); - } - - assertTrue(sumOfDailyRewards > totalRewards); - assertEq(sumOfDailyRewards / 10 ** 2, totalRewards / 10 ** 2); - } - function test_scenario3_dailyRewards() public { // Scenario: rewards alloted for a certain day(s) is less than or equal to dailyRewards available for those // days. From 75f1d02efd3837874a23b24af8741417532986ef Mon Sep 17 00:00:00 2001 From: has5aan Date: Tue, 4 Jun 2024 01:00:59 +0200 Subject: [PATCH 07/18] refactor: moves the logic from scenario3_dailyRewards to scenario3 --- test/L2/L2Reward.t.sol | 98 ++++++------------------------------------ 1 file changed, 14 insertions(+), 84 deletions(-) diff --git a/test/L2/L2Reward.t.sol b/test/L2/L2Reward.t.sol index cb6219e1..e38fa44b 100644 --- a/test/L2/L2Reward.t.sol +++ b/test/L2/L2Reward.t.sol @@ -430,7 +430,7 @@ contract L2RewardTest is Test { } } - function test_scenario2() private { + function test_scenario2() public { address[] memory stakers = given_anArrayOfStakersOfLength(7); uint256[] memory lockIDs = new uint256[](7); uint256 funds = convertLiskToSmallestDenomination(5000); @@ -504,11 +504,11 @@ contract L2RewardTest is Test { lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 106, 114); } - function createScenario3() private returns (uint256[] memory, address[] memory) { + function test_scenario3() public { address[] memory stakers = given_anArrayOfStakersOfLength(14); uint256[] memory lockIDs = new uint256[](14); - uint256[] memory balances = new uint256[](7); - uint256[] memory oldBalances = new uint256[](7); + uint256[] memory balances = new uint256[](14); + uint256[] memory oldBalances = new uint256[](14); uint256 funds = convertLiskToSmallestDenomination(5000); uint256 balance = convertLiskToSmallestDenomination(5000); @@ -634,8 +634,16 @@ contract L2RewardTest is Test { stakerExtendsPositionBy(0, 30, scenario); stakerReumesPosition(12, scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); - - return (lockIDs, stakers); + onDay(200); + allStakersClaim(scenario); + cacheBalances(scenario); + onDay(201); + allStakersClaim(scenario); + lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 200, 200); + cacheBalances(scenario); + onDay(250); + allStakersClaim(scenario); + lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 201, 249); } function checkConsistencyPendingUnlockDailyUnlocked( @@ -686,84 +694,6 @@ contract L2RewardTest is Test { assertEq(sumOfDailyRewards / 10 ** 4, reward / 10 ** 4); } - function test_scenario3_dailyRewards() public { - // Scenario: rewards alloted for a certain day(s) is less than or equal to dailyRewards available for those - // days. - // Description: - // claim rewards against all positions on day 200 - // Act: - // move to day 201, claim rewards against all positions again - // Assert: - // total rewards claimed on day 201 is equal to daily rewards available for day 200 - // Act: - // move to day 250, claim rewards against all positions again - // Assert: - // total rewards claimed on day 250 is equal to sum of daily rewards between 201 and 249 - - uint256[] memory lockIDs; - address[] memory stakers; - uint256[] memory positionsToBeModified = new uint256[](1); - uint256[] memory balances = new uint256[](14); - uint256 totalRewards; - - (lockIDs, stakers) = createScenario3(); - - vm.warp(19740 days + 200 days); - - // claim rewards against all positions on day 200 - for (uint8 i = 0; i < lockIDs.length; i++) { - positionsToBeModified[0] = lockIDs[i]; - when_rewardsAreClaimedByStaker(stakers[i], positionsToBeModified); - } - - // get balances before claiming rewards again - for (uint8 i = 0; i < stakers.length; i++) { - balances[i] = l2LiskToken.balanceOf(stakers[i]); - } - - vm.warp(19740 days + 201 days); - // all positions claim rewards on day 201 - for (uint8 i = 0; i < lockIDs.length; i++) { - positionsToBeModified[0] = lockIDs[i]; - when_rewardsAreClaimedByStaker(stakers[i], positionsToBeModified); - } - - totalRewards = 0; - for (uint8 i = 0; i < stakers.length; i++) { - totalRewards += l2LiskToken.balanceOf(stakers[i]) - balances[i]; - } - - // total rewards claimed on day 201 are less than or equal to dailyRewards on day 200 - assertTrue(totalRewards <= l2Reward.dailyRewards(19740 + 200)); - assertEq(totalRewards / 10 ** 3, l2Reward.dailyRewards(19740 + 200) / 10 ** 3); - - vm.warp(19740 days + 250 days); - - // get balances before claiming rewards again - for (uint8 i = 0; i < stakers.length; i++) { - balances[i] = l2LiskToken.balanceOf(stakers[i]); - } - - // all positions claim rewards on day 250 - for (uint8 i = 0; i < stakers.length; i++) { - positionsToBeModified[0] = lockIDs[i]; - when_rewardsAreClaimedByStaker(stakers[i], positionsToBeModified); - } - - totalRewards = 0; - for (uint8 i = 0; i < stakers.length; i++) { - totalRewards += l2LiskToken.balanceOf(stakers[i]) - balances[i]; - } - - uint256 sumOfDailyRewards; - for (uint256 i = 19740 + 201; i < 19740 + 250; i++) { - sumOfDailyRewards += l2Reward.dailyRewards(i); - } - - assertTrue(sumOfDailyRewards >= totalRewards); - assertEq(sumOfDailyRewards / 10 ** 3, totalRewards / 10 ** 3); - } - function test_createPosition_l2RewardContractShouldBeApprovedToTransferFromStakerAccount() public { address staker = address(0x1); uint256 duration = 20; From 65d61db564e7e02c5ca62d715537d49deb49da5b Mon Sep 17 00:00:00 2001 From: has5aan Date: Tue, 4 Jun 2024 13:22:19 +0200 Subject: [PATCH 08/18] add scenario4 to test surplus and reward contract balance --- src/L2/L2Reward.sol | 5 +++ test/L2/L2Reward.t.sol | 87 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 82 insertions(+), 10 deletions(-) diff --git a/src/L2/L2Reward.sol b/src/L2/L2Reward.sol index e6e7c2f5..4e6f571b 100644 --- a/src/L2/L2Reward.sol +++ b/src/L2/L2Reward.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.23; +import { console2 } from "forge-std/Test.sol"; import { Initializable } from "@openzeppelin-upgradeable/contracts/proxy/utils/Initializable.sol"; import { Ownable2StepUpgradeable } from "@openzeppelin-upgradeable/contracts/access/Ownable2StepUpgradeable.sol"; import { UUPSUpgradeable } from "@openzeppelin-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol"; @@ -141,14 +142,18 @@ contract L2Reward is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, IS if (today <= d) return; uint256 cappedRewards; + // console2.logUint(totalAmountLocked); for (; d < today; d++) { totalWeights[d] = totalWeight; + // console2.logUint(totalAmountLocked); + cappedRewards = totalAmountLocked / 365; // capping in rewards if (dailyRewards[d] > cappedRewards) { + // console2.log(d); rewardsSurplus += dailyRewards[d] - cappedRewards; dailyRewards[d] = cappedRewards; } diff --git a/test/L2/L2Reward.t.sol b/test/L2/L2Reward.t.sol index e38fa44b..b8fd013c 100644 --- a/test/L2/L2Reward.t.sol +++ b/test/L2/L2Reward.t.sol @@ -41,6 +41,7 @@ contract L2RewardTest is Test { uint256[] oldBalances; uint256[] balances; uint256 lastClaimedAmount; + uint256 rewardsSurplus; } struct Position { @@ -320,7 +321,7 @@ contract L2RewardTest is Test { } } - function cacheBalances(Scenario memory scenario) private { + function cacheBalances(Scenario memory scenario) private view { for (uint8 i = 0; i < scenario.stakers.length; i++) { scenario.oldBalances[i] = l2LiskToken.balanceOf(scenario.stakers[i]); } @@ -336,6 +337,26 @@ contract L2RewardTest is Test { assertEq(l2LiskToken.balanceOf(address(l2Reward)) / 10 ** 4, (funds - sumOfDailyRewards) / 10 ** 4); } + function verifyRewardsSurplusForLockedAmountBetweenDays( + uint256 dailyRewards, + uint256 totalAmountLocked, + uint256 startDay, + uint256 endDay, + Scenario memory scenario + ) + public + { + uint256 rewardsCap = totalAmountLocked / 365; + uint256 expectedSurplus; + + for (uint256 d = deploymentDate + startDay; d <= deploymentDate + endDay; d++) { + expectedSurplus += dailyRewards - rewardsCap; + } + + scenario.rewardsSurplus += expectedSurplus; + assertEq(scenario.rewardsSurplus, l2Reward.rewardsSurplus()); + } + function test_scenario1() public { address[] memory stakers = given_anArrayOfStakersOfLength(7); uint256[] memory lockIDs = new uint256[](7); @@ -343,7 +364,6 @@ contract L2RewardTest is Test { uint256[] memory oldBalances = new uint256[](7); uint256 funds = convertLiskToSmallestDenomination(5000); uint256 balance = convertLiskToSmallestDenomination(500); - uint256[] memory positionsToBeModified = new uint256[](1); // owner gets balance given_accountHasBalance(address(this), funds); @@ -359,7 +379,8 @@ contract L2RewardTest is Test { lockIDs: lockIDs, balances: balances, oldBalances: oldBalances, - lastClaimedAmount: 0 + lastClaimedAmount: 0, + rewardsSurplus: 0 }); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); @@ -437,7 +458,6 @@ contract L2RewardTest is Test { uint256 balance = convertLiskToSmallestDenomination(500); uint256[] memory balances = new uint256[](7); uint256[] memory oldBalances = new uint256[](7); - uint256[] memory positionsToBeModified = new uint256[](1); // owner gets balance given_accountHasBalance(address(this), funds); @@ -454,7 +474,8 @@ contract L2RewardTest is Test { lockIDs: lockIDs, balances: balances, oldBalances: oldBalances, - lastClaimedAmount: 0 + lastClaimedAmount: 0, + rewardsSurplus: 0 }); onDay(1); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); @@ -512,10 +533,6 @@ contract L2RewardTest is Test { uint256 funds = convertLiskToSmallestDenomination(5000); uint256 balance = convertLiskToSmallestDenomination(5000); - uint256[] memory positionsToBeModified = new uint256[](1); - L2Reward.ExtendedDuration[] memory durationExtensions = new L2Reward.ExtendedDuration[](1); - L2Reward.IncreasedAmount[] memory increasingAmounts = new L2Reward.IncreasedAmount[](1); - // owner gets balance given_accountHasBalance(address(this), funds); // fund the reward contract, 10 Lisk per day for 500 days @@ -533,7 +550,8 @@ contract L2RewardTest is Test { lockIDs: lockIDs, balances: balances, oldBalances: oldBalances, - lastClaimedAmount: 0 + lastClaimedAmount: 0, + rewardsSurplus: 0 }); onDay(1); @@ -646,6 +664,55 @@ contract L2RewardTest is Test { lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 201, 249); } + function test_scenario4() public { + address[] memory stakers = given_anArrayOfStakersOfLength(5); + uint256[] memory lockIDs = new uint256[](5); + uint256[] memory balances = new uint256[](5); + uint256[] memory oldBalances = new uint256[](5); + uint256 funds = LSK(5000); + uint256 balance = LSK(500); + + // owner gets balance + given_accountHasBalance(address(this), funds); + // fund the reward contact, 1 LSK per day for 500 days + uint256 dailyRewards = given_ownerHasFundedStaking(Funds({ amount: funds, duration: 500, delay: 1 })); + + // all the stakers gets balance + for (uint8 i = 0; i < stakers.length; i++) { + given_accountHasBalance(stakers[i], balance); + } + + Scenario memory scenario = Scenario({ + stakers: stakers, + lockIDs: lockIDs, + balances: balances, + oldBalances: oldBalances, + lastClaimedAmount: 0, + rewardsSurplus: 0 + }); + + onDay(1); + stakerCreatesPosition(0, LSK(150), 150, scenario); + stakerCreatesPosition(1, LSK(250), 250, scenario); + onDay(10); + stakerCreatesPosition(2, LSK(250), 150, scenario); + verifyRewardsSurplusForLockedAmountBetweenDays(dailyRewards, LSK(400), 1, 9, scenario); + onDay(30); + stakerCreatesPosition(3, LSK(50), 100, scenario); + verifyRewardsSurplusForLockedAmountBetweenDays(dailyRewards, LSK(650), 10, 29, scenario); + onDay(35); + stakerCreatesPosition(4, LSK(10), 120, scenario); + verifyRewardsSurplusForLockedAmountBetweenDays(dailyRewards, LSK(700), 30, 34, scenario); + onDay(40); + allStakersClaim(scenario); + verifyRewardsSurplusForLockedAmountBetweenDays(dailyRewards, LSK(710), 35, 39, scenario); + checkRewardsContractBalance(funds); + onDay(50); + allStakersClaim(scenario); + checkRewardsContractBalance(funds); + verifyRewardsSurplusForLockedAmountBetweenDays(dailyRewards, LSK(710), 40, 49, scenario); + } + function checkConsistencyPendingUnlockDailyUnlocked( uint256[] memory lockIDs, uint256 expiryDateOfLongestStake From 87b3c100ccb1af6dd787627536c5c06aac96323f Mon Sep 17 00:00:00 2001 From: has5aan Date: Tue, 4 Jun 2024 13:26:44 +0200 Subject: [PATCH 09/18] Reverts L2Reward --- src/L2/L2Reward.sol | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/L2/L2Reward.sol b/src/L2/L2Reward.sol index 4e6f571b..e6e7c2f5 100644 --- a/src/L2/L2Reward.sol +++ b/src/L2/L2Reward.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.23; -import { console2 } from "forge-std/Test.sol"; import { Initializable } from "@openzeppelin-upgradeable/contracts/proxy/utils/Initializable.sol"; import { Ownable2StepUpgradeable } from "@openzeppelin-upgradeable/contracts/access/Ownable2StepUpgradeable.sol"; import { UUPSUpgradeable } from "@openzeppelin-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol"; @@ -142,18 +141,14 @@ contract L2Reward is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, IS if (today <= d) return; uint256 cappedRewards; - // console2.logUint(totalAmountLocked); for (; d < today; d++) { totalWeights[d] = totalWeight; - // console2.logUint(totalAmountLocked); - cappedRewards = totalAmountLocked / 365; // capping in rewards if (dailyRewards[d] > cappedRewards) { - // console2.log(d); rewardsSurplus += dailyRewards[d] - cappedRewards; dailyRewards[d] = cappedRewards; } From 4be62a5089e163af257d8ee07b034e1e3803f238 Mon Sep 17 00:00:00 2001 From: has5aan Date: Tue, 4 Jun 2024 19:23:49 +0200 Subject: [PATCH 10/18] Adds more complex assertions to scenario4 regarding surplus verification --- test/L2/L2Reward.t.sol | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/test/L2/L2Reward.t.sol b/test/L2/L2Reward.t.sol index b8fd013c..5a0c1b73 100644 --- a/test/L2/L2Reward.t.sol +++ b/test/L2/L2Reward.t.sol @@ -348,12 +348,17 @@ contract L2RewardTest is Test { { uint256 rewardsCap = totalAmountLocked / 365; uint256 expectedSurplus; + uint256 lastDay = deploymentDate + endDay; - for (uint256 d = deploymentDate + startDay; d <= deploymentDate + endDay; d++) { + for (uint256 d = deploymentDate + startDay; d <= lastDay; d++) { expectedSurplus += dailyRewards - rewardsCap; } + // console2.logUint(expectedSurplus); scenario.rewardsSurplus += expectedSurplus; + // console2.log(l2Reward.rewardsSurplus()); + // console2.log(scenario.rewardsSurplus); + assertEq(scenario.rewardsSurplus, l2Reward.rewardsSurplus()); } @@ -705,12 +710,23 @@ contract L2RewardTest is Test { verifyRewardsSurplusForLockedAmountBetweenDays(dailyRewards, LSK(700), 30, 34, scenario); onDay(40); allStakersClaim(scenario); - verifyRewardsSurplusForLockedAmountBetweenDays(dailyRewards, LSK(710), 35, 39, scenario); checkRewardsContractBalance(funds); onDay(50); allStakersClaim(scenario); checkRewardsContractBalance(funds); - verifyRewardsSurplusForLockedAmountBetweenDays(dailyRewards, LSK(710), 40, 49, scenario); + onDay(90); + allStakersClaim(scenario); + checkRewardsContractBalance(funds); + verifyRewardsSurplusForLockedAmountBetweenDays(dailyRewards, LSK(710), 35, 89, scenario); + onDay(130); + allStakersClaim(scenario); + checkRewardsContractBalance(funds); + verifyRewardsSurplusForLockedAmountBetweenDays(dailyRewards, LSK(710), 90, 129, scenario); + onDay(150); + allStakersClaim(scenario); + checkRewardsContractBalance(funds); + // stake 3's expDate is on 130th day so total amount locked reduces by LSK(50). + verifyRewardsSurplusForLockedAmountBetweenDays(dailyRewards, LSK(660), 130, 149, scenario); } function checkConsistencyPendingUnlockDailyUnlocked( From 690f8f52085f46a29143c2d79105bcdfb24b7329 Mon Sep 17 00:00:00 2001 From: has5aan Date: Mon, 17 Jun 2024 12:26:39 +0200 Subject: [PATCH 11/18] adds checkConsistencyTotalWeight --- test/L2/L2Reward.t.sol | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/test/L2/L2Reward.t.sol b/test/L2/L2Reward.t.sol index 5a0c1b73..cbc6c7c5 100644 --- a/test/L2/L2Reward.t.sol +++ b/test/L2/L2Reward.t.sol @@ -354,10 +354,7 @@ contract L2RewardTest is Test { expectedSurplus += dailyRewards - rewardsCap; } - // console2.logUint(expectedSurplus); scenario.rewardsSurplus += expectedSurplus; - // console2.log(l2Reward.rewardsSurplus()); - // console2.log(scenario.rewardsSurplus); assertEq(scenario.rewardsSurplus, l2Reward.rewardsSurplus()); } @@ -391,9 +388,11 @@ contract L2RewardTest is Test { checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); onDay(1); stakerCreatesPosition(0, LSK(100), 30, scenario); + checkConsistencyTotalWeight(getLargestExpiryDate(lockIDs)); stakerCreatesPosition(1, LSK(100), 80, scenario); onDay(10); stakerCreatesPosition(2, LSK(100), 100, scenario); + checkConsistencyTotalWeight(getLargestExpiryDate(lockIDs)); onDay(30); stakerPausesPosition(1, scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); @@ -408,6 +407,7 @@ contract L2RewardTest is Test { onDay(50); stakerExtendsPositionBy(0, 30, scenario); onDay(70); + checkConsistencyTotalWeight(getLargestExpiryDate(lockIDs)); stakerCreatesPosition(5, LSK(100), 150, scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); onDay(80); @@ -424,6 +424,7 @@ contract L2RewardTest is Test { allStakersClaim(scenario); checkRewardsContractBalance(funds); cacheBalances(scenario); + checkConsistencyTotalWeight(getLargestExpiryDate(lockIDs)); onDay(106); allStakersClaim(scenario); checkRewardsContractBalance(funds); @@ -437,6 +438,7 @@ contract L2RewardTest is Test { onDay(150); allStakersClaim(scenario); checkRewardsContractBalance(funds); + checkConsistencyTotalWeight(getLargestExpiryDate(lockIDs)); onDay(230); allStakersClaim(scenario); checkRewardsContractBalance(funds); @@ -451,6 +453,7 @@ contract L2RewardTest is Test { onDay(275); allStakersClaim(scenario); lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 240, 269); + checkConsistencyTotalWeight(getLargestExpiryDate(lockIDs)); for (uint256 i = 19740 + 270; i < 19740 + 275; i++) { assertEq(l2Reward.totalWeights(i), 0); } @@ -729,6 +732,19 @@ contract L2RewardTest is Test { verifyRewardsSurplusForLockedAmountBetweenDays(dailyRewards, LSK(660), 130, 149, scenario); } + function checkConsistencyTotalWeight(uint256 expiryDateOfLongestStake) private { + if (l2Reward.todayDay() < expiryDateOfLongestStake) { + assertTrue(l2Reward.totalWeight() > 0); + } else { + assertEq(l2Reward.totalWeight(), 0); + } + + uint256 sumOfDailyWeights = 0; + for (uint256 i = deploymentDate; i < l2Reward.todayDay(); i++) { + sumOfDailyWeights += l2Reward.totalWeights(i); + } + } + function checkConsistencyPendingUnlockDailyUnlocked( uint256[] memory lockIDs, uint256 expiryDateOfLongestStake From 3b1630e8a98b97414d2fc8dba9acd1f2e8f78831 Mon Sep 17 00:00:00 2001 From: has5aan Date: Thu, 20 Jun 2024 15:33:21 +0200 Subject: [PATCH 12/18] adds zero value check for amount and duration when adding rewards --- src/L2/L2Reward.sol | 8 +++++++- test/L2/L2Reward.t.sol | 26 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/L2/L2Reward.sol b/src/L2/L2Reward.sol index e6e7c2f5..cd0eb809 100644 --- a/src/L2/L2Reward.sol +++ b/src/L2/L2Reward.sol @@ -518,7 +518,9 @@ contract L2Reward is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, IS /// @param duration Duration in days for which the daily rewards is to be added. /// @param delay Determines the start day from today till duration for whom rewards should be added. function _addRewards(uint256 amount, uint16 duration, uint16 delay) internal virtual { - require(delay > 0, "Funding should start from next day or later"); + require(amount > 0, "L2Reward: Funded amount should be greater than zero"); + require(duration > 0, "L2Reward: Funding duration should be greater than zero"); + require(delay > 0, "L2Reward: Funding should start from next day or later"); uint256 dailyReward = amount / duration; uint256 today = todayDay(); @@ -533,6 +535,8 @@ contract L2Reward is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, IS /// @param duration Duration in days for which the daily rewards is to be added. /// @param delay Determines the start day from today till duration from which rewards should be added. function addUnusedRewards(uint256 amount, uint16 duration, uint16 delay) public virtual onlyOwner { + require(amount > 0, "L2Reward: Funded amount should be greater than zero"); + require(duration > 0, "L2Reward: Funding duration should be greater than zero"); require(delay > 0, "L2Reward: Rewards can only be added from next day or later"); require(amount <= rewardsSurplus, "L2Reward: Reward amount should not exceed available surplus funds"); @@ -548,6 +552,8 @@ contract L2Reward is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, IS /// @param duration Duration in days for which the daily rewards is to be added. /// @param delay Determines the start day from today till duration for which rewards should be added. function fundStakingRewards(uint256 amount, uint16 duration, uint16 delay) public virtual onlyOwner { + require(amount > 0, "L2Reward: Funded amount should be greater than zero"); + require(duration > 0, "L2Reward: Funding duration should be greater than zero"); require(delay > 0, "L2Reward: Funding should start from next day or later"); IL2LiskToken(l2TokenContract).transferFrom(msg.sender, address(this), amount); diff --git a/test/L2/L2Reward.t.sol b/test/L2/L2Reward.t.sol index cbc6c7c5..63e2de5e 100644 --- a/test/L2/L2Reward.t.sol +++ b/test/L2/L2Reward.t.sol @@ -891,6 +891,20 @@ contract L2RewardTest is Test { l2Reward.fundStakingRewards(convertLiskToSmallestDenomination(3550), 255, 1); } + function test_fundStakingRewards_amountShouldBeGreaterThanZeroWhenFundingStakingRewards() public { + vm.expectRevert("L2Reward: Funded amount should be greater than zero"); + + vm.prank(address(this)); + l2Reward.fundStakingRewards(0, 100, 1); + } + + function test_fundStakingRewards_durationShouldBeGreaterThanZeroWhenFundingStakingRewards() public { + vm.expectRevert("L2Reward: Funding duration should be greater than zero"); + + vm.prank(address(this)); + l2Reward.fundStakingRewards(100, 0, 1); + } + function test_fundStakingRewards_delayShouldBeGreaterThanZeroWhenFundingStakingRewards() public { vm.expectRevert("L2Reward: Funding should start from next day or later"); @@ -2626,6 +2640,18 @@ contract L2RewardTest is Test { l2Reward.addUnusedRewards(100, 100, 1); } + function test_addUnusedRewards_amountShouldBeGreaterThanZeroWhenAddingRewards() public { + vm.expectRevert("L2Reward: Funded amount should be greater than zero"); + + l2Reward.addUnusedRewards(0, 100, 1); + } + + function test_addUnusedRewards_durationShouldBeGreaterThanZeroWhenAddingRewards() public { + vm.expectRevert("L2Reward: Funding duration should be greater than zero"); + + l2Reward.addUnusedRewards(100, 0, 1); + } + function test_addUnusedRewards_delayShouldBeGreaterThanZeroWhenAddingRewards() public { vm.expectRevert("L2Reward: Rewards can only be added from next day or later"); From e8d23cf25d191710e448f2f15a1b18934e872433 Mon Sep 17 00:00:00 2001 From: has5aan Date: Fri, 21 Jun 2024 17:31:34 +0200 Subject: [PATCH 13/18] added stakerClaimOnDayAndCheckConsistencyTotalWeight and removed checkConsistencyTotalWeight --- test/L2/L2Reward.t.sol | 56 +++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/test/L2/L2Reward.t.sol b/test/L2/L2Reward.t.sol index 63e2de5e..ed574a9e 100644 --- a/test/L2/L2Reward.t.sol +++ b/test/L2/L2Reward.t.sol @@ -42,6 +42,7 @@ contract L2RewardTest is Test { uint256[] balances; uint256 lastClaimedAmount; uint256 rewardsSurplus; + uint256 totalWeight; } struct Position { @@ -327,6 +328,10 @@ contract L2RewardTest is Test { } } + function cacheTotalWeight(Scenario memory scenario) private view { + scenario.totalWeight = l2Reward.totalWeight(); + } + function checkRewardsContractBalance(uint256 funds) public { uint256 sumOfDailyRewards; for (uint256 i = deploymentDate; i < l2Reward.todayDay(); i++) { @@ -382,17 +387,18 @@ contract L2RewardTest is Test { balances: balances, oldBalances: oldBalances, lastClaimedAmount: 0, - rewardsSurplus: 0 + rewardsSurplus: 0, + totalWeight: 0 }); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); onDay(1); stakerCreatesPosition(0, LSK(100), 30, scenario); - checkConsistencyTotalWeight(getLargestExpiryDate(lockIDs)); + stakerClaimOnDayAndCheckConsistencyTotalWeight(0, 2, getLargestExpiryDate(lockIDs), scenario); stakerCreatesPosition(1, LSK(100), 80, scenario); onDay(10); stakerCreatesPosition(2, LSK(100), 100, scenario); - checkConsistencyTotalWeight(getLargestExpiryDate(lockIDs)); + stakerClaimOnDayAndCheckConsistencyTotalWeight(2, 11, getLargestExpiryDate(lockIDs), scenario); onDay(30); stakerPausesPosition(1, scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); @@ -406,8 +412,8 @@ contract L2RewardTest is Test { checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); onDay(50); stakerExtendsPositionBy(0, 30, scenario); + stakerClaimOnDayAndCheckConsistencyTotalWeight(0, 51, getLargestExpiryDate(lockIDs), scenario); onDay(70); - checkConsistencyTotalWeight(getLargestExpiryDate(lockIDs)); stakerCreatesPosition(5, LSK(100), 150, scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); onDay(80); @@ -424,7 +430,7 @@ contract L2RewardTest is Test { allStakersClaim(scenario); checkRewardsContractBalance(funds); cacheBalances(scenario); - checkConsistencyTotalWeight(getLargestExpiryDate(lockIDs)); + stakerClaimOnDayAndCheckConsistencyTotalWeight(0, 106, getLargestExpiryDate(lockIDs), scenario); onDay(106); allStakersClaim(scenario); checkRewardsContractBalance(funds); @@ -438,7 +444,7 @@ contract L2RewardTest is Test { onDay(150); allStakersClaim(scenario); checkRewardsContractBalance(funds); - checkConsistencyTotalWeight(getLargestExpiryDate(lockIDs)); + // checkConsistencyTotalWeight(getLargestExpiryDate(lockIDs)); onDay(230); allStakersClaim(scenario); checkRewardsContractBalance(funds); @@ -453,7 +459,7 @@ contract L2RewardTest is Test { onDay(275); allStakersClaim(scenario); lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 240, 269); - checkConsistencyTotalWeight(getLargestExpiryDate(lockIDs)); + // checkConsistencyTotalWeight(getLargestExpiryDate(lockIDs)); for (uint256 i = 19740 + 270; i < 19740 + 275; i++) { assertEq(l2Reward.totalWeights(i), 0); } @@ -483,7 +489,8 @@ contract L2RewardTest is Test { balances: balances, oldBalances: oldBalances, lastClaimedAmount: 0, - rewardsSurplus: 0 + rewardsSurplus: 0, + totalWeight: 0 }); onDay(1); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); @@ -559,7 +566,8 @@ contract L2RewardTest is Test { balances: balances, oldBalances: oldBalances, lastClaimedAmount: 0, - rewardsSurplus: 0 + rewardsSurplus: 0, + totalWeight: 0 }); onDay(1); @@ -696,7 +704,8 @@ contract L2RewardTest is Test { balances: balances, oldBalances: oldBalances, lastClaimedAmount: 0, - rewardsSurplus: 0 + rewardsSurplus: 0, + totalWeight: 0 }); onDay(1); @@ -732,17 +741,36 @@ contract L2RewardTest is Test { verifyRewardsSurplusForLockedAmountBetweenDays(dailyRewards, LSK(660), 130, 149, scenario); } - function checkConsistencyTotalWeight(uint256 expiryDateOfLongestStake) private { + function checkConsistencyTotalWeight(Scenario memory scenario, uint256 expiryDateOfLongestStake) private { if (l2Reward.todayDay() < expiryDateOfLongestStake) { assertTrue(l2Reward.totalWeight() > 0); } else { assertEq(l2Reward.totalWeight(), 0); } - uint256 sumOfDailyWeights = 0; - for (uint256 i = deploymentDate; i < l2Reward.todayDay(); i++) { - sumOfDailyWeights += l2Reward.totalWeights(i); + assertEq(l2Reward.totalWeights(l2Reward.todayDay() - 1), scenario.totalWeight); + } + + function stakerClaimOnDayAndCheckConsistencyTotalWeight( + uint256 stakerIndex, + uint256 day, + uint256 expiryDateOfLongestStake, + Scenario memory scenario + ) + private + { + if (l2Reward.todayDay() < expiryDateOfLongestStake) { + assertTrue(l2Reward.totalWeight() > 0); + } else { + assertEq(l2Reward.totalWeight(), 0); } + + uint256 oldTotalWeight = l2Reward.totalWeight(); + + onDay(day); + stakerClaimRewards(stakerIndex, scenario); + + assertEq(l2Reward.totalWeights(l2Reward.todayDay() - 1), oldTotalWeight); } function checkConsistencyPendingUnlockDailyUnlocked( From ee756724a168f1e919c2da6ee61beb7a43c0cb82 Mon Sep 17 00:00:00 2001 From: has5aan Date: Mon, 24 Jun 2024 10:19:42 +0200 Subject: [PATCH 14/18] test consistency of total weight and daily weights --- test/L2/L2Reward.t.sol | 64 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/test/L2/L2Reward.t.sol b/test/L2/L2Reward.t.sol index ed574a9e..62179dcb 100644 --- a/test/L2/L2Reward.t.sol +++ b/test/L2/L2Reward.t.sol @@ -394,13 +394,15 @@ contract L2RewardTest is Test { checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); onDay(1); stakerCreatesPosition(0, LSK(100), 30, scenario); - stakerClaimOnDayAndCheckConsistencyTotalWeight(0, 2, getLargestExpiryDate(lockIDs), scenario); stakerCreatesPosition(1, LSK(100), 80, scenario); + cacheTotalWeight(scenario); onDay(10); stakerCreatesPosition(2, LSK(100), 100, scenario); - stakerClaimOnDayAndCheckConsistencyTotalWeight(2, 11, getLargestExpiryDate(lockIDs), scenario); + checkConsistencyTotalWeight(1, getLargestExpiryDate(lockIDs), scenario); + cacheTotalWeight(scenario); onDay(30); stakerPausesPosition(1, scenario); + checkConsistencyTotalWeight(10, getLargestExpiryDate(lockIDs), scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); onDay(35); stakerCreatesPosition(3, LSK(50), 14, scenario); @@ -412,9 +414,10 @@ contract L2RewardTest is Test { checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); onDay(50); stakerExtendsPositionBy(0, 30, scenario); - stakerClaimOnDayAndCheckConsistencyTotalWeight(0, 51, getLargestExpiryDate(lockIDs), scenario); + cacheTotalWeight(scenario); onDay(70); stakerCreatesPosition(5, LSK(100), 150, scenario); + checkConsistencyTotalWeight(50, getLargestExpiryDate(lockIDs), scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); onDay(80); stakerReumesPosition(1, scenario); @@ -423,14 +426,15 @@ contract L2RewardTest is Test { onDay(95); stakerCreatesPosition(6, LSK(200), 200, scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + cacheTotalWeight(scenario); onDay(100); stakerIncreasesAmountOfThePositionBy(6, LSK(50), scenario); + checkConsistencyTotalWeight(95, getLargestExpiryDate(lockIDs), scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); onDay(105); allStakersClaim(scenario); checkRewardsContractBalance(funds); cacheBalances(scenario); - stakerClaimOnDayAndCheckConsistencyTotalWeight(0, 106, getLargestExpiryDate(lockIDs), scenario); onDay(106); allStakersClaim(scenario); checkRewardsContractBalance(funds); @@ -444,22 +448,23 @@ contract L2RewardTest is Test { onDay(150); allStakersClaim(scenario); checkRewardsContractBalance(funds); - // checkConsistencyTotalWeight(getLargestExpiryDate(lockIDs)); + cacheTotalWeight(scenario); onDay(230); allStakersClaim(scenario); + checkConsistencyTotalWeight(150, getLargestExpiryDate(lockIDs), scenario); checkRewardsContractBalance(funds); lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 115, 229); - // stake 4 gets resumed, expiry date should be 270 stakerReumesPosition(4, scenario); assertEq(l2LockingPosition.getLockingPosition(scenario.lockIDs[4]).expDate, deploymentDate + 270); onDay(240); stakerInitiatesFastUnlock(6, scenario); stakerClaimRewards(4, scenario); cacheBalances(scenario); + cacheTotalWeight(scenario); onDay(275); allStakersClaim(scenario); + checkConsistencyTotalWeight(240, getLargestExpiryDate(lockIDs), scenario); lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 240, 269); - // checkConsistencyTotalWeight(getLargestExpiryDate(lockIDs)); for (uint256 i = 19740 + 270; i < 19740 + 275; i++) { assertEq(l2Reward.totalWeights(i), 0); } @@ -496,22 +501,30 @@ contract L2RewardTest is Test { checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); stakerCreatesPosition(0, LSK(100), 730, scenario); stakerCreatesPosition(1, LSK(100), 730, scenario); + cacheTotalWeight(scenario); onDay(2); stakerPausesPosition(1, scenario); + checkConsistencyTotalWeight(1, getLargestExpiryDate(lockIDs), scenario); + cacheTotalWeight(scenario); onDay(5); stakerCreatesPosition(2, LSK(200), 30, scenario); + checkConsistencyTotalWeight(2, getLargestExpiryDate(lockIDs), scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); onDay(10); stakerCreatesPosition(3, LSK(50), 100, scenario); stakerPausesPosition(3, scenario); + cacheTotalWeight(scenario); onDay(20); stakerIncreasesAmountOfThePositionBy(3, LSK(30), scenario); + checkConsistencyTotalWeight(10, getLargestExpiryDate(lockIDs), scenario); stakerCreatesPosition(4, LSK(100), 200, scenario); onDay(25); stakerCreatesPosition(5, LSK(150), 100, scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + cacheTotalWeight(scenario); onDay(30); stakerPausesPosition(4, scenario); + checkConsistencyTotalWeight(25, getLargestExpiryDate(lockIDs), scenario); onDay(40); stakerInitiatesFastUnlock(4, scenario); onDay(50); @@ -519,14 +532,18 @@ contract L2RewardTest is Test { onDay(55); stakerCreatesPosition(6, LSK(30), 14, scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + cacheTotalWeight(scenario); onDay(80); stakerReumesPosition(5, scenario); + checkConsistencyTotalWeight(55, getLargestExpiryDate(lockIDs), scenario); onDay(85); stakerExtendsPositionBy(6, 25, scenario); onDay(90); stakerExtendsPositionBy(3, 65, scenario); + cacheTotalWeight(scenario); onDay(93); stakerIncreasesAmountOfThePositionBy(5, LSK(30), scenario); + checkConsistencyTotalWeight(90, getLargestExpiryDate(lockIDs), scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); onDay(105); allStakersClaim(scenario); @@ -534,9 +551,11 @@ contract L2RewardTest is Test { onDay(106); allStakersClaim(scenario); lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 105, 105); + cacheTotalWeight(scenario); onDay(115); cacheBalances(scenario); allStakersClaim(scenario); + checkConsistencyTotalWeight(106, getLargestExpiryDate(lockIDs), scenario); lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 106, 114); } @@ -577,9 +596,11 @@ contract L2RewardTest is Test { stakerCreatesPosition(2, LSK(400), 730, scenario); onDay(15); stakerCreatesPosition(3, LSK(5), 300, scenario); + cacheTotalWeight(scenario); onDay(20); stakerCreatesPosition(4, LSK(500), 50, scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + checkConsistencyTotalWeight(15, getLargestExpiryDate(lockIDs), scenario); stakerCreatesPosition(5, LSK(1250), 80, scenario); onDay(30); stakerIncreasesAmountOfThePositionBy(0, LSK(90), scenario); @@ -589,6 +610,7 @@ contract L2RewardTest is Test { stakerExtendsPositionBy(4, 21, scenario); onDay(35); stakerInitiatesFastUnlock(5, scenario); + cacheTotalWeight(scenario); onDay(36); stakerPausesPosition(5, scenario); stakerCreatesPosition(6, LSK(125), 80, scenario); @@ -605,8 +627,10 @@ contract L2RewardTest is Test { stakerCreatesPosition(11, LSK(110), 23, scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); stakerCreatesPosition(12, LSK(1000), 68, scenario); + cacheTotalWeight(scenario); onDay(50); stakerPausesPosition(8, scenario); + checkConsistencyTotalWeight(45, getLargestExpiryDate(lockIDs), scenario); onDay(51); stakerPausesPosition(9, scenario); onDay(52); @@ -615,14 +639,18 @@ contract L2RewardTest is Test { stakerIncreasesAmountOfThePositionBy(8, LSK(300), scenario); onDay(58); stakerInitiatesFastUnlock(8, scenario); + cacheTotalWeight(scenario); onDay(59); stakerPausesPosition(8, scenario); + checkConsistencyTotalWeight(58, getLargestExpiryDate(lockIDs), scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); onDay(60); stakerInitiatesFastUnlock(6, scenario); + cacheTotalWeight(scenario); onDay(61); stakerExtendsPositionBy(6, 8, scenario); stakerPausesPosition(6, scenario); + checkConsistencyTotalWeight(60, getLargestExpiryDate(lockIDs), scenario); onDay(65); stakerExtendsPositionBy(6, 4, scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); @@ -630,13 +658,19 @@ contract L2RewardTest is Test { onDay(66); stakerExtendsPositionBy(10, 10, scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + cacheTotalWeight(scenario); onDay(68); stakerInitiatesFastUnlock(7, scenario); stakerPausesPosition(10, scenario); + checkConsistencyTotalWeight(66, getLargestExpiryDate(lockIDs), scenario); + cacheTotalWeight(scenario); onDay(69); stakerExtendsPositionBy(7, 150, scenario); + checkConsistencyTotalWeight(68, getLargestExpiryDate(lockIDs), scenario); + cacheTotalWeight(scenario); onDay(70); stakerPausesPosition(0, scenario); + checkConsistencyTotalWeight(69, getLargestExpiryDate(lockIDs), scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); onDay(75); stakerExtendsPositionBy(5, 20, scenario); @@ -654,8 +688,10 @@ contract L2RewardTest is Test { onDay(102); stakerIncreasesAmountOfThePositionBy(12, LSK(500), scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + cacheTotalWeight(scenario); onDay(104); stakerPausesPosition(12, scenario); + checkConsistencyTotalWeight(102, getLargestExpiryDate(lockIDs), scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); onDay(107); stakerReumesPosition(6, scenario); @@ -668,8 +704,10 @@ contract L2RewardTest is Test { stakerExtendsPositionBy(0, 30, scenario); stakerReumesPosition(12, scenario); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); + cacheTotalWeight(scenario); onDay(200); allStakersClaim(scenario); + // checkConsistencyTotalWeight(110, getLargestExpiryDate(lockIDs), scenario); cacheBalances(scenario); onDay(201); allStakersClaim(scenario); @@ -711,8 +749,10 @@ contract L2RewardTest is Test { onDay(1); stakerCreatesPosition(0, LSK(150), 150, scenario); stakerCreatesPosition(1, LSK(250), 250, scenario); + cacheTotalWeight(scenario); onDay(10); stakerCreatesPosition(2, LSK(250), 150, scenario); + checkConsistencyTotalWeight(1, getLargestExpiryDate(lockIDs), scenario); verifyRewardsSurplusForLockedAmountBetweenDays(dailyRewards, LSK(400), 1, 9, scenario); onDay(30); stakerCreatesPosition(3, LSK(50), 100, scenario); @@ -741,14 +781,20 @@ contract L2RewardTest is Test { verifyRewardsSurplusForLockedAmountBetweenDays(dailyRewards, LSK(660), 130, 149, scenario); } - function checkConsistencyTotalWeight(Scenario memory scenario, uint256 expiryDateOfLongestStake) private { + function checkConsistencyTotalWeight( + uint256 lastTrsDate, + uint256 expiryDateOfLongestStake, + Scenario memory scenario + ) + private + { if (l2Reward.todayDay() < expiryDateOfLongestStake) { assertTrue(l2Reward.totalWeight() > 0); } else { assertEq(l2Reward.totalWeight(), 0); } - assertEq(l2Reward.totalWeights(l2Reward.todayDay() - 1), scenario.totalWeight); + assertEq(l2Reward.totalWeights(deploymentDate + lastTrsDate), scenario.totalWeight); } function stakerClaimOnDayAndCheckConsistencyTotalWeight( From 95767f44af1dcfa5260e68eafe2952720bd4704a Mon Sep 17 00:00:00 2001 From: has5aan Date: Wed, 26 Jun 2024 12:09:42 +0200 Subject: [PATCH 15/18] updates scenario2 and scenario3 to check reward contract balance --- test/L2/L2Reward.t.sol | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/test/L2/L2Reward.t.sol b/test/L2/L2Reward.t.sol index 62179dcb..476f09ae 100644 --- a/test/L2/L2Reward.t.sol +++ b/test/L2/L2Reward.t.sol @@ -2,6 +2,7 @@ pragma solidity 0.8.23; import { Test, console2 } from "forge-std/Test.sol"; +import { Vm } from "forge-std/Vm.sol"; import { IL2LiskToken, IL2Staking, L2Reward } from "src/L2/L2Reward.sol"; import { ERC721Upgradeable } from "@openzeppelin-upgradeable/contracts/token/ERC721/ERC721Upgradeable.sol"; import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; @@ -43,6 +44,7 @@ contract L2RewardTest is Test { uint256 lastClaimedAmount; uint256 rewardsSurplus; uint256 totalWeight; + uint256 penalty; } struct Position { @@ -249,7 +251,14 @@ contract L2RewardTest is Test { uint256[] memory positionsToBeModified = new uint256[](1); positionsToBeModified[0] = scenario.lockIDs[stakerIndex]; vm.prank(scenario.stakers[stakerIndex]); + vm.recordLogs(); l2Reward.initiateFastUnlock(positionsToBeModified); + + Vm.Log[] memory entries = vm.getRecordedLogs(); + assertEq(entries[entries.length - 2].topics[0], keccak256("FastUnlockInitiated(uint256,uint256)")); + uint256 penalty = abi.decode(entries[entries.length - 2].data, (uint256)); + + scenario.penalty += penalty; } function stakerReumesPosition(uint256 stakerIndex, Scenario memory scenario) private { @@ -388,7 +397,8 @@ contract L2RewardTest is Test { oldBalances: oldBalances, lastClaimedAmount: 0, rewardsSurplus: 0, - totalWeight: 0 + totalWeight: 0, + penalty: 0 }); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); @@ -495,7 +505,8 @@ contract L2RewardTest is Test { oldBalances: oldBalances, lastClaimedAmount: 0, rewardsSurplus: 0, - totalWeight: 0 + totalWeight: 0, + penalty: 0 }); onDay(1); checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); @@ -547,14 +558,17 @@ contract L2RewardTest is Test { checkConsistencyPendingUnlockDailyUnlocked(lockIDs, getLargestExpiryDate(lockIDs)); onDay(105); allStakersClaim(scenario); + checkRewardsContractBalance(funds + scenario.penalty); cacheBalances(scenario); onDay(106); allStakersClaim(scenario); + checkRewardsContractBalance(funds + scenario.penalty); lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 105, 105); cacheTotalWeight(scenario); onDay(115); cacheBalances(scenario); allStakersClaim(scenario); + checkRewardsContractBalance(funds + scenario.penalty); checkConsistencyTotalWeight(106, getLargestExpiryDate(lockIDs), scenario); lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 106, 114); } @@ -586,7 +600,8 @@ contract L2RewardTest is Test { oldBalances: oldBalances, lastClaimedAmount: 0, rewardsSurplus: 0, - totalWeight: 0 + totalWeight: 0, + penalty: 0 }); onDay(1); @@ -707,14 +722,16 @@ contract L2RewardTest is Test { cacheTotalWeight(scenario); onDay(200); allStakersClaim(scenario); - // checkConsistencyTotalWeight(110, getLargestExpiryDate(lockIDs), scenario); + checkRewardsContractBalance(funds + scenario.penalty); cacheBalances(scenario); onDay(201); allStakersClaim(scenario); + checkRewardsContractBalance(funds + scenario.penalty); lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 200, 200); cacheBalances(scenario); onDay(250); allStakersClaim(scenario); + checkRewardsContractBalance(funds + scenario.penalty); lastClaimedRewardEqualsDailyRewardBetweenDays(scenario.lastClaimedAmount, 201, 249); } @@ -743,7 +760,8 @@ contract L2RewardTest is Test { oldBalances: oldBalances, lastClaimedAmount: 0, rewardsSurplus: 0, - totalWeight: 0 + totalWeight: 0, + penalty: 0 }); onDay(1); From cf210fbd03796ffaf5c1f4329866f7795f472d83 Mon Sep 17 00:00:00 2001 From: has5aan Date: Wed, 26 Jun 2024 12:26:19 +0200 Subject: [PATCH 16/18] refactors and adds docs --- test/L2/L2Reward.t.sol | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/L2/L2Reward.t.sol b/test/L2/L2Reward.t.sol index 476f09ae..a4ab7383 100644 --- a/test/L2/L2Reward.t.sol +++ b/test/L2/L2Reward.t.sol @@ -341,6 +341,8 @@ contract L2RewardTest is Test { scenario.totalWeight = l2Reward.totalWeight(); } + /// @notice Checks the balance of reward contract. + /// @dev only valid when all stakes are valid and all of them claims. function checkRewardsContractBalance(uint256 funds) public { uint256 sumOfDailyRewards; for (uint256 i = deploymentDate; i < l2Reward.todayDay(); i++) { @@ -800,7 +802,7 @@ contract L2RewardTest is Test { } function checkConsistencyTotalWeight( - uint256 lastTrsDate, + uint256 dayOfLastTrs, uint256 expiryDateOfLongestStake, Scenario memory scenario ) @@ -812,7 +814,7 @@ contract L2RewardTest is Test { assertEq(l2Reward.totalWeight(), 0); } - assertEq(l2Reward.totalWeights(deploymentDate + lastTrsDate), scenario.totalWeight); + assertEq(l2Reward.totalWeights(deploymentDate + dayOfLastTrs), scenario.totalWeight); } function stakerClaimOnDayAndCheckConsistencyTotalWeight( From 27ca2e6754216271290646bb2976360687e7f216 Mon Sep 17 00:00:00 2001 From: has5aan Date: Wed, 26 Jun 2024 23:37:07 +0200 Subject: [PATCH 17/18] resolves compiler warnings --- test/L2/L2Reward.t.sol | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/test/L2/L2Reward.t.sol b/test/L2/L2Reward.t.sol index a4ab7383..97384fcf 100644 --- a/test/L2/L2Reward.t.sol +++ b/test/L2/L2Reward.t.sol @@ -343,7 +343,7 @@ contract L2RewardTest is Test { /// @notice Checks the balance of reward contract. /// @dev only valid when all stakes are valid and all of them claims. - function checkRewardsContractBalance(uint256 funds) public { + function checkRewardsContractBalance(uint256 funds) private view { uint256 sumOfDailyRewards; for (uint256 i = deploymentDate; i < l2Reward.todayDay(); i++) { sumOfDailyRewards += l2Reward.dailyRewards(i); @@ -360,7 +360,8 @@ contract L2RewardTest is Test { uint256 endDay, Scenario memory scenario ) - public + private + view { uint256 rewardsCap = totalAmountLocked / 365; uint256 expectedSurplus; @@ -807,6 +808,7 @@ contract L2RewardTest is Test { Scenario memory scenario ) private + view { if (l2Reward.todayDay() < expiryDateOfLongestStake) { assertTrue(l2Reward.totalWeight() > 0); @@ -877,7 +879,14 @@ contract L2RewardTest is Test { return expiryDate; } - function lastClaimedRewardEqualsDailyRewardBetweenDays(uint256 reward, uint256 startDay, uint256 endDay) private { + function lastClaimedRewardEqualsDailyRewardBetweenDays( + uint256 reward, + uint256 startDay, + uint256 endDay + ) + private + view + { uint256 sumOfDailyRewards; for (uint256 i = deploymentDate + startDay; i <= deploymentDate + endDay; i++) { sumOfDailyRewards += l2Reward.dailyRewards(i); From 305caaf6b0ab6eccd9cf9c2c33b33bb34592a98b Mon Sep 17 00:00:00 2001 From: has5aan Date: Thu, 27 Jun 2024 13:21:39 +0200 Subject: [PATCH 18/18] adds documentation to assertion functions --- test/L2/L2Reward.t.sol | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/test/L2/L2Reward.t.sol b/test/L2/L2Reward.t.sol index 97384fcf..b8eb88af 100644 --- a/test/L2/L2Reward.t.sol +++ b/test/L2/L2Reward.t.sol @@ -342,7 +342,7 @@ contract L2RewardTest is Test { } /// @notice Checks the balance of reward contract. - /// @dev only valid when all stakes are valid and all of them claims. + /// @dev Only valid when all stakes are valid and all of them claims. function checkRewardsContractBalance(uint256 funds) private view { uint256 sumOfDailyRewards; for (uint256 i = deploymentDate; i < l2Reward.todayDay(); i++) { @@ -353,6 +353,9 @@ contract L2RewardTest is Test { assertEq(l2LiskToken.balanceOf(address(l2Reward)) / 10 ** 4, (funds - sumOfDailyRewards) / 10 ** 4); } + /// @notice Checks aggregation to rewards surplus for locked amounts. + /// @dev There must be no transaction causing the change to the locked amount or daily rewards in the intended + /// duration. function verifyRewardsSurplusForLockedAmountBetweenDays( uint256 dailyRewards, uint256 totalAmountLocked, @@ -819,28 +822,6 @@ contract L2RewardTest is Test { assertEq(l2Reward.totalWeights(deploymentDate + dayOfLastTrs), scenario.totalWeight); } - function stakerClaimOnDayAndCheckConsistencyTotalWeight( - uint256 stakerIndex, - uint256 day, - uint256 expiryDateOfLongestStake, - Scenario memory scenario - ) - private - { - if (l2Reward.todayDay() < expiryDateOfLongestStake) { - assertTrue(l2Reward.totalWeight() > 0); - } else { - assertEq(l2Reward.totalWeight(), 0); - } - - uint256 oldTotalWeight = l2Reward.totalWeight(); - - onDay(day); - stakerClaimRewards(stakerIndex, scenario); - - assertEq(l2Reward.totalWeights(l2Reward.todayDay() - 1), oldTotalWeight); - } - function checkConsistencyPendingUnlockDailyUnlocked( uint256[] memory lockIDs, uint256 expiryDateOfLongestStake