From ce50fcb105ab2e1f3b76583b21a1bd1b4d41d982 Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Fri, 21 Mar 2025 16:35:05 -0300 Subject: [PATCH] fix(StakeManager): Allow extending the lock after increasing stake to allow account reaching absolute max MP fix(MultiplierPointMath): Fix helper function to correctly estimate avaliable lock time chore(spec): remove additional field which does not exist anymore --- .gas-report | 84 +++++++-------- .gas-snapshot | 148 +++++++++++++-------------- certora/specs/RewardsStreamerMP.spec | 8 +- certora/specs/shared.spec | 2 +- src/RewardsStreamerMP.sol | 21 ---- src/interfaces/IStakeManager.sol | 2 - src/math/MultiplierPointMath.sol | 2 +- test/RewardsStreamerMP.t.sol | 87 +++++----------- 8 files changed, 146 insertions(+), 208 deletions(-) diff --git a/.gas-report b/.gas-report index 1097e6c..b6e24dc 100644 --- a/.gas-report +++ b/.gas-report @@ -10,7 +10,7 @@ |-------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------| | Function Name | Min | Avg | Median | Max | # Calls | |-------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------| -| fallback | 746 | 132103 | 190895 | 190943 | 517 | +| fallback | 746 | 132239 | 190895 | 190943 | 515 | ╰-------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╯ ╭-----------------------------------------------------+-----------------+---------+---------+---------+---------╮ @@ -24,7 +24,7 @@ |-----------------------------------------------------+-----------------+---------+---------+---------+---------| | Function Name | Min | Avg | Median | Max | # Calls | |-----------------------------------------------------+-----------------+---------+---------+---------+---------| -| run | 4015668 | 4015668 | 4015668 | 4015668 | 119 | +| run | 4015668 | 4015668 | 4015668 | 4015668 | 117 | ╰-----------------------------------------------------+-----------------+---------+---------+---------+---------╯ ╭-----------------------------------------------------------+-----------------+---------+---------+---------+---------╮ @@ -46,13 +46,13 @@ +=======================================================================================================================================+ | Deployment Cost | Deployment Size | | | | | |-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------| -| 8496724 | 40509 | | | | | +| 8427605 | 40187 | | | | | |-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------| | | | | | | | |-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------| | Function Name | Min | Avg | Median | Max | # Calls | |-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------| -| run | 7410704 | 7410704 | 7410704 | 7410704 | 94 | +| run | 7346139 | 7346139 | 7346139 | 7346139 | 92 | ╰-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╯ ╭---------------------------------------------------------+-----------------+-----+--------+-----+---------╮ @@ -66,7 +66,7 @@ |---------------------------------------------------------+-----------------+-----+--------+-----+---------| | Function Name | Min | Avg | Median | Max | # Calls | |---------------------------------------------------------+-----------------+-----+--------+-----+---------| -| activeNetworkConfig | 597 | 597 | 597 | 597 | 347 | +| activeNetworkConfig | 597 | 597 | 597 | 597 | 341 | ╰---------------------------------------------------------+-----------------+-----+--------+-----+---------╯ ╭-------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╮ @@ -74,13 +74,13 @@ +=========================================================================================================================================+ | Deployment Cost | Deployment Size | | | | | |-------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------| -| 5947188 | 28600 | | | | | +| 5878083 | 28278 | | | | | |-------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------| | | | | | | | |-------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------| | Function Name | Min | Avg | Median | Max | # Calls | |-------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------| -| runWithAdminAndProxy | 3373562 | 3373562 | 3373562 | 3373562 | 3 | +| runWithAdminAndProxy | 3309002 | 3309002 | 3309002 | 3309002 | 3 | ╰-------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╯ ╭------------------------------+-----------------+--------+--------+--------+---------╮ @@ -96,7 +96,7 @@ |------------------------------+-----------------+--------+--------+--------+---------| | acceptOwnership | 12042 | 12042 | 12042 | 12042 | 1 | |------------------------------+-----------------+--------+--------+--------+---------| -| addRewardDistributor | 2589 | 65629 | 70586 | 70586 | 155 | +| addRewardDistributor | 2589 | 65564 | 70586 | 70586 | 153 | |------------------------------+-----------------+--------+--------+--------+---------| | allowance | 482 | 482 | 482 | 482 | 3 | |------------------------------+-----------------+--------+--------+--------+---------| @@ -106,7 +106,7 @@ |------------------------------+-----------------+--------+--------+--------+---------| | getRewardDistributors | 1162 | 3406 | 3406 | 5650 | 6 | |------------------------------+-----------------+--------+--------+--------+---------| -| initialize | 95872 | 95872 | 95872 | 95872 | 119 | +| initialize | 95872 | 95872 | 95872 | 95872 | 117 | |------------------------------+-----------------+--------+--------+--------+---------| | mint | 2654 | 56378 | 72352 | 72352 | 18 | |------------------------------+-----------------+--------+--------+--------+---------| @@ -164,7 +164,7 @@ +=============================================================================================================+ | Deployment Cost | Deployment Size | | | | | |------------------------------------------------------+-----------------+--------+--------+--------+---------| -| 3584189 | 16606 | | | | | +| 3515097 | 16284 | | | | | |------------------------------------------------------+-----------------+--------+--------+--------+---------| | | | | | | | |------------------------------------------------------+-----------------+--------+--------+--------+---------| @@ -188,17 +188,17 @@ |------------------------------------------------------+-----------------+--------+--------+--------+---------| | getStakedBalance | 2643 | 2643 | 2643 | 2643 | 1 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| -| getVault | 2139 | 8528 | 2139 | 20139 | 4158 | +| getVault | 1970 | 7310 | 1970 | 17970 | 4182 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| -| initialize | 92752 | 92752 | 92752 | 92752 | 94 | +| initialize | 92752 | 92752 | 92752 | 92752 | 92 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| | lastRewardTime | 385 | 1385 | 1385 | 2385 | 2 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| -| leave | 97634 | 97634 | 97634 | 97634 | 1 | +| leave | 95188 | 95188 | 95188 | 95188 | 1 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| -| lock | 7106 | 42186 | 64216 | 113416 | 1034 | +| lock | 7106 | 45325 | 48853 | 90909 | 1034 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| -| migrateToVault | 13548 | 74440 | 15755 | 194018 | 3 | +| migrateToVault | 13548 | 72959 | 15755 | 189576 | 3 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| | mpBalanceOf | 917 | 2361 | 2316 | 7063 | 12 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| @@ -208,47 +208,47 @@ |------------------------------------------------------+-----------------+--------+--------+--------+---------| | proxiableUUID | 342 | 342 | 342 | 342 | 3 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| -| registerVault | 2539 | 74404 | 74970 | 74970 | 370 | +| registerVault | 2539 | 74392 | 74970 | 74970 | 362 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| | rewardEndTime | 385 | 1385 | 1385 | 2385 | 2 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| | rewardStartTime | 408 | 1408 | 1408 | 2408 | 2 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| -| rewardsBalanceOf | 2340 | 3544 | 3953 | 6340 | 268 | +| rewardsBalanceOf | 2340 | 3538 | 3953 | 6340 | 268 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| | rewardsBalanceOfAccount | 10220 | 10220 | 10220 | 10220 | 1 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| | setReward | 2486 | 105543 | 107054 | 107054 | 265 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| -| setRewardsSupplier | 26831 | 26831 | 26831 | 26831 | 89 | +| setRewardsSupplier | 26831 | 26831 | 26831 | 26831 | 87 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| -| setTrustedCodehash | 24194 | 24194 | 24194 | 24194 | 94 | +| setTrustedCodehash | 24194 | 24194 | 24194 | 24194 | 92 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| -| stake | 2703 | 151871 | 85074 | 271159 | 2666 | +| stake | 2703 | 142975 | 62559 | 248644 | 2668 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| | totalMP | 805 | 1257 | 1257 | 1710 | 6 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| -| totalMPAccrued | 385 | 1067 | 385 | 2385 | 4164 | +| totalMPAccrued | 385 | 1055 | 385 | 2385 | 4162 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| -| totalMPStaked | 429 | 1111 | 429 | 2429 | 4167 | +| totalMPStaked | 429 | 1099 | 429 | 2429 | 4165 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| -| totalMaxMP | 407 | 1089 | 407 | 2407 | 4164 | +| totalMaxMP | 407 | 1077 | 407 | 2407 | 4162 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| | totalRewardsAccrued | 385 | 385 | 385 | 385 | 3 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| -| totalRewardsSupply | 976 | 1602 | 1770 | 6715 | 290 | +| totalRewardsSupply | 976 | 1599 | 1770 | 6715 | 290 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| | totalShares | 662 | 662 | 662 | 662 | 6 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| -| totalStaked | 386 | 1067 | 386 | 2386 | 4171 | +| totalStaked | 386 | 1055 | 386 | 2386 | 4169 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| -| unstake | 41762 | 44651 | 41788 | 83357 | 269 | +| unstake | 41762 | 44586 | 41788 | 81026 | 269 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| | updateAccount | 369042 | 369042 | 369042 | 369042 | 1 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| | updateGlobalState | 15820 | 25876 | 29230 | 29230 | 8 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| -| updateVault | 34763 | 37203 | 34763 | 115885 | 1026 | +| updateVault | 34763 | 37437 | 34763 | 115885 | 1024 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| | upgradeTo | 10235 | 10851 | 10235 | 12701 | 4 | |------------------------------------------------------+-----------------+--------+--------+--------+---------| @@ -272,25 +272,25 @@ |----------------------------------------+-----------------+--------+--------+--------+---------| | emergencyExit | 15001 | 31441 | 31439 | 48539 | 263 | |----------------------------------------+-----------------+--------+--------+--------+---------| -| initialize | 97660 | 97660 | 97660 | 97660 | 370 | +| initialize | 97660 | 97660 | 97660 | 97660 | 362 | |----------------------------------------+-----------------+--------+--------+--------+---------| -| leave | 12161 | 127067 | 70915 | 354278 | 4 | +| leave | 12161 | 126456 | 69692 | 354278 | 4 | |----------------------------------------+-----------------+--------+--------+--------+---------| -| lock | 12091 | 57608 | 79682 | 128879 | 1035 | +| lock | 12091 | 60744 | 64319 | 106372 | 1035 | |----------------------------------------+-----------------+--------+--------+--------+---------| -| migrateToVault | 29036 | 101122 | 31243 | 243088 | 3 | +| migrateToVault | 29036 | 99641 | 31243 | 238646 | 3 | |----------------------------------------+-----------------+--------+--------+--------+---------| -| owner | 379 | 410 | 379 | 2379 | 378 | +| owner | 379 | 411 | 379 | 2379 | 370 | |----------------------------------------+-----------------+--------+--------+--------+---------| -| register | 12674 | 78052 | 78600 | 78600 | 370 | +| register | 12674 | 78039 | 78600 | 78600 | 362 | |----------------------------------------+-----------------+--------+--------+--------+---------| -| stake | 12071 | 185788 | 100567 | 326727 | 2667 | +| stake | 12071 | 177339 | 78052 | 304212 | 2669 | |----------------------------------------+-----------------+--------+--------+--------+---------| -| stakeManager | 369 | 369 | 369 | 369 | 369 | +| stakeManager | 369 | 369 | 369 | 369 | 361 | |----------------------------------------+-----------------+--------+--------+--------+---------| | trustStakeManager | 7580 | 7580 | 7580 | 7580 | 1 | |----------------------------------------+-----------------+--------+--------+--------+---------| -| unstake | 12048 | 61012 | 57231 | 114379 | 270 | +| unstake | 12048 | 60890 | 57231 | 112048 | 270 | |----------------------------------------+-----------------+--------+--------+--------+---------| | withdraw | 20754 | 20754 | 20754 | 20754 | 1 | ╰----------------------------------------+-----------------+--------+--------+--------+---------╯ @@ -306,9 +306,9 @@ |----------------------------------------------------+-----------------+------+--------+--------+---------| | Function Name | Min | Avg | Median | Max | # Calls | |----------------------------------------------------+-----------------+------+--------+--------+---------| -| fallback | 708 | 6812 | 2629 | 395419 | 23151 | +| fallback | 708 | 6583 | 2454 | 395419 | 23163 | |----------------------------------------------------+-----------------+------+--------+--------+---------| -| implementation | 346 | 2345 | 2346 | 2346 | 4350 | +| implementation | 346 | 2345 | 2346 | 2346 | 4344 | ╰----------------------------------------------------+-----------------+------+--------+--------+---------╯ ╭--------------------------------------------+-----------------+--------+--------+--------+---------╮ @@ -322,7 +322,7 @@ |--------------------------------------------+-----------------+--------+--------+--------+---------| | Function Name | Min | Avg | Median | Max | # Calls | |--------------------------------------------+-----------------+--------+--------+--------+---------| -| createVault | 230924 | 247653 | 248024 | 248024 | 369 | +| createVault | 230924 | 247645 | 248024 | 248024 | 361 | ╰--------------------------------------------+-----------------+--------+--------+--------+---------╯ ╭------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╮ @@ -410,11 +410,11 @@ |---------------------------------------------+-----------------+-------+--------+-------+---------| | Function Name | Min | Avg | Median | Max | # Calls | |---------------------------------------------+-----------------+-------+--------+-------+---------| -| approve | 29075 | 31523 | 29183 | 46259 | 2672 | +| approve | 29075 | 31481 | 29183 | 46259 | 2664 | |---------------------------------------------+-----------------+-------+--------+-------+---------| -| balanceOf | 561 | 1348 | 561 | 2561 | 4958 | +| balanceOf | 561 | 1339 | 561 | 2561 | 4956 | |---------------------------------------------+-----------------+-------+--------+-------+---------| -| mint | 33964 | 37163 | 34072 | 68248 | 2681 | +| mint | 33964 | 37111 | 34072 | 68248 | 2673 | ╰---------------------------------------------+-----------------+-------+--------+-------+---------╯ ╭-----------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╮ diff --git a/.gas-snapshot b/.gas-snapshot index 64c293e..a59655b 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,21 +1,21 @@ EmergencyExitTest:test_CannotEnableEmergencyModeTwice() (gas: 93510) -EmergencyExitTest:test_CannotLeaveBeforeEmergencyMode() (gas: 357967) -EmergencyExitTest:test_EmergencyExitBasic() (gas: 452843) -EmergencyExitTest:test_EmergencyExitMultipleUsers() (gas: 781167) -EmergencyExitTest:test_EmergencyExitToAlternateAddress() (gas: 458394) -EmergencyExitTest:test_EmergencyExitWithLock() (gas: 475778) -EmergencyExitTest:test_EmergencyExitWithRewards() (gas: 441142) +EmergencyExitTest:test_CannotLeaveBeforeEmergencyMode() (gas: 357956) +EmergencyExitTest:test_EmergencyExitBasic() (gas: 450623) +EmergencyExitTest:test_EmergencyExitMultipleUsers() (gas: 776726) +EmergencyExitTest:test_EmergencyExitToAlternateAddress() (gas: 456174) +EmergencyExitTest:test_EmergencyExitWithLock() (gas: 453263) +EmergencyExitTest:test_EmergencyExitWithRewards() (gas: 441131) EmergencyExitTest:test_OnlyOwnerCanEnableEmergencyMode() (gas: 39154) -FuzzTests:testFuzz_AccrueMP(uint128,uint64,uint64) (runs: 1003, μ: 408527, ~: 383746) -FuzzTests:testFuzz_AccrueMP_Relock(uint128,uint64,uint64,uint64) (runs: 1003, μ: 510823, ~: 487453) -FuzzTests:testFuzz_EmergencyExit(uint256,uint256) (runs: 1002, μ: 530631, ~: 512563) -FuzzTests:testFuzz_Lock(uint256,uint64) (runs: 1004, μ: 777485, ~: 801080) -FuzzTests:testFuzz_Relock(uint256,uint64,uint64) (runs: 1004, μ: 415384, ~: 399686) -FuzzTests:testFuzz_Rewards(uint256,uint256,uint256,uint16,uint16) (runs: 1000, μ: 639388, ~: 641300) -FuzzTests:testFuzz_Stake(uint256,uint64) (runs: 1004, μ: 314995, ~: 293349) -FuzzTests:testFuzz_Unstake(uint128,uint64,uint16,uint128) (runs: 1003, μ: 515012, ~: 492212) -FuzzTests:testFuzz_UpdateVault(uint128,uint64,uint64) (runs: 1003, μ: 408550, ~: 383769) -IntegrationTest:testStakeFoo() (gas: 1453985) +FuzzTests:testFuzz_AccrueMP(uint128,uint64,uint64) (runs: 1024, μ: 394287, ~: 358834) +FuzzTests:testFuzz_AccrueMP_Relock(uint128,uint64,uint64,uint64) (runs: 1024, μ: 494753, ~: 462295) +FuzzTests:testFuzz_EmergencyExit(uint256,uint256) (runs: 1007, μ: 519035, ~: 510343) +FuzzTests:testFuzz_Lock(uint256,uint64) (runs: 1024, μ: 777031, ~: 776145) +FuzzTests:testFuzz_Relock(uint256,uint64,uint64) (runs: 1024, μ: 400366, ~: 374940) +FuzzTests:testFuzz_Rewards(uint256,uint256,uint256,uint16,uint16) (runs: 1001, μ: 617477, ~: 618785) +FuzzTests:testFuzz_Stake(uint256,uint64) (runs: 1024, μ: 302125, ~: 268696) +FuzzTests:testFuzz_Unstake(uint128,uint64,uint16,uint128) (runs: 1024, μ: 500493, ~: 467093) +FuzzTests:testFuzz_UpdateVault(uint128,uint64,uint64) (runs: 1024, μ: 394310, ~: 358857) +IntegrationTest:testStakeFoo() (gas: 1439862) KarmaMintAllowanceTest:testAddKarmaDistributorOnlyOwner() (gas: 364802) KarmaMintAllowanceTest:testBalanceOf() (gas: 441486) KarmaMintAllowanceTest:testBalanceOfWithNoSystemTotalKarma() (gas: 49545) @@ -56,85 +56,83 @@ KarmaTest:testRemoveKarmaDistributorOnlyOwner() (gas: 88820) KarmaTest:testRemoveUnknownKarmaDistributor() (gas: 41398) KarmaTest:testTotalSupply() (gas: 349329) KarmaTest:testTransfersNotAllowed() (gas: 40241) -LeaveTest:test_LeaveShouldProperlyUpdateAccounting() (gas: 9813528) -LeaveTest:test_RevertWhenStakeManagerIsTrusted() (gas: 355148) -LeaveTest:test_TrustNewStakeManager() (gas: 9862860) -LockTest:test_LockFailsWithInvalidPeriod(uint256) (runs: 1004, μ: 393465, ~: 369257) -LockTest:test_LockFailsWithNoStake() (gas: 114275) -LockTest:test_LockFailsWithZero() (gas: 365276) -LockTest:test_LockMultipleTimesExceedMaxLock() (gas: 649138) -LockTest:test_LockWithPriorLock() (gas: 629170) -LockTest:test_LockWithoutPriorLock() (gas: 498962) -LockTest:test_RevertWhenVaultToLockIsEmpty() (gas: 114275) -MaliciousUpgradeTest:test_UpgradeStackOverflowStakeManager() (gas: 2014867) +LeaveTest:test_LeaveShouldProperlyUpdateAccounting() (gas: 9678086) +LeaveTest:test_RevertWhenStakeManagerIsTrusted() (gas: 355137) +LeaveTest:test_TrustNewStakeManager() (gas: 9729089) +LockTest:test_LockFailsWithInvalidPeriod(uint256) (runs: 1025, μ: 408592, ~: 408617) +LockTest:test_LockFailsWithNoStake() (gas: 91768) +LockTest:test_LockFailsWithZero() (gas: 365265) +LockTest:test_LockMultipleTimesExceedMaxLock() (gas: 664894) +LockTest:test_LockWithPriorLock() (gas: 598618) +LockTest:test_LockWithoutPriorLock() (gas: 474027) +LockTest:test_RevertWhenVaultToLockIsEmpty() (gas: 91768) +MaliciousUpgradeTest:test_UpgradeStackOverflowStakeManager() (gas: 2014856) MathTest:test_CalcAbsoluteMaxTotalMP() (gas: 5240) MathTest:test_CalcAccrueMP() (gas: 8599) MathTest:test_CalcBonusMP() (gas: 19200) MathTest:test_CalcInitialMP() (gas: 5836) MathTest:test_CalcMaxAccruedMP() (gas: 4886) MathTest:test_CalcMaxTotalMP() (gas: 19984) -MultipleVaultsStakeTest:test_StakeMultipleVaults() (gas: 867829) +MultipleVaultsStakeTest:test_StakeMultipleVaults() (gas: 867796) NFTMetadataGeneratorSVGTest:testGenerateMetadata() (gas: 92580) NFTMetadataGeneratorSVGTest:testSetImageStrings() (gas: 60081) NFTMetadataGeneratorSVGTest:testSetImageStringsRevert() (gas: 35891) NFTMetadataGeneratorURLTest:testGenerateMetadata() (gas: 108341) NFTMetadataGeneratorURLTest:testSetBaseURL() (gas: 50631) NFTMetadataGeneratorURLTest:testSetBaseURLRevert() (gas: 36066) -RewardsStreamerMP_RewardsTest:testRewardsBalanceOf() (gas: 1330208) +RewardsStreamerMP_RewardsTest:testRewardsBalanceOf() (gas: 1330186) RewardsStreamerMP_RewardsTest:testSetRewards() (gas: 224570) RewardsStreamerMP_RewardsTest:testSetRewards_RevertsBadAmount() (gas: 61280) RewardsStreamerMP_RewardsTest:testSetRewards_RevertsBadDuration() (gas: 101038) RewardsStreamerMP_RewardsTest:testSetRewards_RevertsNotAuthorized() (gas: 39300) -RewardsStreamerMP_RewardsTest:testTotalRewardsSupply() (gas: 762564) -StakeTest:test_RevertWhenStakeMultipleTimesExceedsMaxLockUpTime() (gas: 790648) -StakeTest:test_RevertWhenStakeMultipleTimesWithGapsExceedsMaxLockUpTime() (gas: 842833) -StakeTest:test_StakeMultipleAccounts() (gas: 607093) -StakeTest:test_StakeMultipleAccountsAndRewards() (gas: 615587) -StakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 1020283) -StakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 635454) -StakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 680092) -StakeTest:test_StakeMultipleTimesWithLockIncreaseAtSameBlock() (gas: 631217) -StakeTest:test_StakeMultipleTimesWithLockZeroAfterMaxLock() (gas: 749888) -StakeTest:test_StakeOneAccount() (gas: 341742) -StakeTest:test_StakeOneAccountAndRewards() (gas: 350276) -StakeTest:test_StakeOneAccountMPIncreasesMaxMPDoesNotChange() (gas: 654186) -StakeTest:test_StakeOneAccountReachingMPLimit() (gas: 538684) -StakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 380035) -StakeTest:test_StakeOneAccountWithMinLockUp() (gas: 380631) -StakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 380676) -StakeVaultMigrationTest:testMigrateToVault() (gas: 933616) -StakeVaultMigrationTest:test_RevertWhenMigrationVaultNotEmpty() (gas: 651195) +RewardsStreamerMP_RewardsTest:testTotalRewardsSupply() (gas: 762553) +StakeTest:test_StakeMultipleAccounts() (gas: 602653) +StakeTest:test_StakeMultipleAccountsAndRewards() (gas: 611147) +StakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 1014977) +StakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 612928) +StakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 635062) +StakeTest:test_StakeMultipleTimesDoesNotExceedsMaxMP() (gas: 1589437) +StakeTest:test_StakeMultipleTimesWithLockIncreaseAtSameBlock() (gas: 605951) +StakeTest:test_StakeMultipleTimesWithLockZeroAfterMaxLock() (gas: 1182972) +StakeTest:test_StakeOneAccount() (gas: 339523) +StakeTest:test_StakeOneAccountAndRewards() (gas: 348056) +StakeTest:test_StakeOneAccountMPIncreasesMaxMPDoesNotChange() (gas: 651757) +StakeTest:test_StakeOneAccountReachingMPLimit() (gas: 536255) +StakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 357498) +StakeTest:test_StakeOneAccountWithMinLockUp() (gas: 358116) +StakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 358161) +StakeVaultMigrationTest:testMigrateToVault() (gas: 926324) +StakeVaultMigrationTest:test_RevertWhenMigrationVaultNotEmpty() (gas: 651184) StakeVaultMigrationTest:test_RevertWhenNotOwnerOfMigrationVault() (gas: 68065) StakeVaultTest:testOwner() (gas: 15262) StakingTokenTest:testOwner() (gas: 15262) StakingTokenTest:testStakeToken() (gas: 13144) TrustedCodehashAccessTest:test_RevertWhenProxyCloneCodehashNotTrusted() (gas: 2023488) -UnstakeTest:test_RevertWhenStakeMultipleTimesExceedsMaxLockUpTime() (gas: 790648) -UnstakeTest:test_RevertWhenStakeMultipleTimesWithGapsExceedsMaxLockUpTime() (gas: 842877) -UnstakeTest:test_StakeMultipleAccounts() (gas: 607050) -UnstakeTest:test_StakeMultipleAccountsAndRewards() (gas: 615609) -UnstakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 1020327) -UnstakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 635498) -UnstakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 680136) -UnstakeTest:test_StakeMultipleTimesWithLockIncreaseAtSameBlock() (gas: 631217) -UnstakeTest:test_StakeMultipleTimesWithLockZeroAfterMaxLock() (gas: 749888) -UnstakeTest:test_StakeOneAccount() (gas: 341742) -UnstakeTest:test_StakeOneAccountAndRewards() (gas: 350253) -UnstakeTest:test_StakeOneAccountMPIncreasesMaxMPDoesNotChange() (gas: 654230) -UnstakeTest:test_StakeOneAccountReachingMPLimit() (gas: 538728) -UnstakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 380035) -UnstakeTest:test_StakeOneAccountWithMinLockUp() (gas: 380631) -UnstakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 380742) -UnstakeTest:test_UnstakeBonusMPAndAccuredMP() (gas: 630320) -UnstakeTest:test_UnstakeMultipleAccounts() (gas: 854539) -UnstakeTest:test_UnstakeMultipleAccountsAndRewards() (gas: 971298) -UnstakeTest:test_UnstakeOneAccount() (gas: 582511) -UnstakeTest:test_UnstakeOneAccountAndAccruedMP() (gas: 580840) -UnstakeTest:test_UnstakeOneAccountAndRewards() (gas: 501182) -UnstakeTest:test_UnstakeOneAccountWithLockUpAndAccruedMP() (gas: 617297) -UpdateVaultTest:test_UpdateAccount() (gas: 2503372) -UpgradeTest:test_RevertWhenNotOwner() (gas: 3660673) -UpgradeTest:test_UpgradeStakeManager() (gas: 9698983) +UnstakeTest:test_StakeMultipleAccounts() (gas: 602632) +UnstakeTest:test_StakeMultipleAccountsAndRewards() (gas: 611102) +UnstakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 1015021) +UnstakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 612994) +UnstakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 635061) +UnstakeTest:test_StakeMultipleTimesDoesNotExceedsMaxMP() (gas: 1589493) +UnstakeTest:test_StakeMultipleTimesWithLockIncreaseAtSameBlock() (gas: 605973) +UnstakeTest:test_StakeMultipleTimesWithLockZeroAfterMaxLock() (gas: 1182983) +UnstakeTest:test_StakeOneAccount() (gas: 339523) +UnstakeTest:test_StakeOneAccountAndRewards() (gas: 348055) +UnstakeTest:test_StakeOneAccountMPIncreasesMaxMPDoesNotChange() (gas: 651756) +UnstakeTest:test_StakeOneAccountReachingMPLimit() (gas: 536235) +UnstakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 357520) +UnstakeTest:test_StakeOneAccountWithMinLockUp() (gas: 358116) +UnstakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 358161) +UnstakeTest:test_UnstakeBonusMPAndAccuredMP() (gas: 607059) +UnstakeTest:test_UnstakeMultipleAccounts() (gas: 847228) +UnstakeTest:test_UnstakeMultipleAccountsAndRewards() (gas: 962376) +UnstakeTest:test_UnstakeOneAccount() (gas: 578496) +UnstakeTest:test_UnstakeOneAccountAndAccruedMP() (gas: 578523) +UnstakeTest:test_UnstakeOneAccountAndRewards() (gas: 498634) +UnstakeTest:test_UnstakeOneAccountWithLockUpAndAccruedMP() (gas: 594663) +UpdateVaultTest:test_UpdateAccount() (gas: 2503328) +UpgradeTest:test_RevertWhenNotOwner() (gas: 3591501) +UpgradeTest:test_UpgradeStakeManager() (gas: 9565211) VaultRegistrationTest:test_VaultRegistration() (gas: 63050) WithdrawTest:testOwner() (gas: 15296) -WithdrawTest:test_CannotWithdrawStakedFunds() (gas: 370795) \ No newline at end of file +WithdrawTest:test_CannotWithdrawStakedFunds() (gas: 370784) \ No newline at end of file diff --git a/certora/specs/RewardsStreamerMP.spec b/certora/specs/RewardsStreamerMP.spec index 518930d..a35e2cd 100644 --- a/certora/specs/RewardsStreamerMP.spec +++ b/certora/specs/RewardsStreamerMP.spec @@ -7,7 +7,7 @@ methods { function ERC20A.allowance(address, address) external returns(uint256) envfree; function ERC20A.totalSupply() external returns(uint256) envfree; function totalStaked() external returns (uint256) envfree; - function vaultData(address) external returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256) envfree; + function vaultData(address) external returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256) envfree; function lastMPUpdatedTime() external returns (uint256) envfree; function updateGlobalState() external; function updateVault(address vaultAddress) external; @@ -31,19 +31,19 @@ hook Sstore vaultData[KEY address vault].stakedBalance uint256 newValue (uint256 function getVaultMaxMP(address vault) returns uint256 { uint256 maxMP; - _, _, _, maxMP, _, _, _, _, _ = streamer.vaultData(vault); + _, _, _, maxMP, _, _, _, _ = streamer.vaultData(vault); return maxMP; } function getVaultMPAccrued(address vault) returns uint256 { uint256 vaultMPAccrued; - _, _, vaultMPAccrued, _, _, _, _, _, _ = streamer.vaultData(vault); + _, _, vaultMPAccrued, _, _, _, _, _ = streamer.vaultData(vault); return vaultMPAccrued; } function getVaultLockUntil(address vault) returns uint256 { uint256 lockUntil; - _, _, _, _, _, lockUntil, _, _, _ = streamer.vaultData(vault); + _, _, _, _, _, lockUntil, _, _ = streamer.vaultData(vault); return lockUntil; } diff --git a/certora/specs/shared.spec b/certora/specs/shared.spec index aa6bde2..a5d2bd8 100644 --- a/certora/specs/shared.spec +++ b/certora/specs/shared.spec @@ -2,7 +2,7 @@ using RewardsStreamerMP as streamer; function getVaultStakedBalance(address vault) returns uint256 { uint256 stakedBalance; - stakedBalance, _, _, _, _, _, _, _, _ = streamer.vaultData(vault); + stakedBalance, _, _, _, _, _, _, _ = streamer.vaultData(vault); return stakedBalance; } diff --git a/src/RewardsStreamerMP.sol b/src/RewardsStreamerMP.sol index 6593acc..d1253b5 100644 --- a/src/RewardsStreamerMP.sol +++ b/src/RewardsStreamerMP.sol @@ -35,7 +35,6 @@ contract RewardsStreamerMP is uint256 lockUntil; uint256 mpStaked; uint256 rewardsAccrued; - uint256 totalLockTime; } /*////////////////////////////////////////////////////////////////////////// @@ -188,13 +187,6 @@ contract RewardsStreamerMP is VaultData storage vault = vaultData[msg.sender]; - if (lockPeriod > 0) { - if (vault.totalLockTime + lockPeriod > MAX_LOCKUP_PERIOD) { - revert StakingManager__InvalidLockPeriod(); - } - vault.totalLockTime += lockPeriod; - } - (uint256 _deltaMpTotal, uint256 _deltaMPMax, uint256 _newLockEnd) = _calculateStake(vault.stakedBalance, vault.maxMP, vault.lockUntil, block.timestamp, amount, lockPeriod); @@ -232,11 +224,6 @@ contract RewardsStreamerMP is revert StakingManager__DurationCannotBeZero(); } - if (vault.totalLockTime + lockPeriod > MAX_LOCKUP_PERIOD) { - revert StakingManager__InvalidLockPeriod(); - } - vault.totalLockTime += lockPeriod; - _updateGlobalState(); _updateVault(msg.sender, false); (uint256 deltaMp, uint256 newLockEnd) = @@ -290,7 +277,6 @@ contract RewardsStreamerMP is vault.rewardIndex = 0; vault.lockUntil = 0; vault.lastMPUpdateTime = 0; - vault.totalLockTime = 0; } emit AccountLeft(msg.sender); @@ -400,7 +386,6 @@ contract RewardsStreamerMP is newVault.lastMPUpdateTime = oldVault.lastMPUpdateTime; newVault.lockUntil = oldVault.lockUntil; newVault.rewardsAccrued = oldVault.rewardsAccrued; - newVault.totalLockTime = oldVault.totalLockTime; delete vaultData[msg.sender]; @@ -482,12 +467,6 @@ contract RewardsStreamerMP is // if the user can unstake it means the lock period has ended // and we can reset lockUntil vault.lockUntil = 0; - - // if the user withdraws all their staked balance - // we reset the totalLockTime - if (vault.stakedBalance == 0) { - vault.totalLockTime = 0; - } } function _totalShares() internal view returns (uint256) { diff --git a/src/interfaces/IStakeManager.sol b/src/interfaces/IStakeManager.sol index aa84b72..81ee947 100644 --- a/src/interfaces/IStakeManager.sol +++ b/src/interfaces/IStakeManager.sol @@ -21,8 +21,6 @@ interface IStakeManager is ITrustedCodehashAccess, IStakeConstants { error StakingManager__InvalidVault(); /// @notice Emitted when the amount to stake is zero. error StakingManager__AmountCannotBeZero(); - /// @notice Emitted when the lock period is not zero. - error StakingManager__InvalidLockPeriod(); /// @notice Emitted when emergency mode is enabled. error StakingManager__EmergencyModeEnabled(); /// @notice Emitted trying to migrate to non empty vault diff --git a/src/math/MultiplierPointMath.sol b/src/math/MultiplierPointMath.sol index 15cdc7c..fcf8c84 100644 --- a/src/math/MultiplierPointMath.sol +++ b/src/math/MultiplierPointMath.sol @@ -122,7 +122,7 @@ abstract contract MultiplierPointMath is IStakeConstants { * @return lockTime Amount of lock time allowed to be increased */ function _lockTimeAvailable(uint256 _balance, uint256 _mpMax) internal pure returns (uint256 lockTime) { - return Math.mulDiv((_balance * MP_MPY_ABSOLUTE) - _mpMax, YEAR, _balance * 100); + return Math.mulDiv(_maxAbsoluteTotalMP(_balance) - _mpMax, YEAR, _balance); } /** diff --git a/test/RewardsStreamerMP.t.sol b/test/RewardsStreamerMP.t.sol index e1779ac..a658f6e 100644 --- a/test/RewardsStreamerMP.t.sol +++ b/test/RewardsStreamerMP.t.sol @@ -988,7 +988,7 @@ contract StakeTest is RewardsStreamerMPTest { } function test_StakeMultipleTimesWithLockZeroAfterMaxLock() public { - uint256 stakeAmount = 10e18; + uint256 stakeAmount = 10e6; uint256 initialTime = vm.getBlockTimestamp(); // stake and lock 4 years @@ -1002,9 +1002,11 @@ contract StakeTest is RewardsStreamerMPTest { vm.warp(initialTime + 4 * YEAR); _stake(alice, stakeAmount, 0); - // staking with lock > 0 should revert as max lock time was reached - vm.expectRevert(IStakeManager.StakingManager__InvalidLockPeriod.selector); - _stake(alice, stakeAmount, MIN_LOCKUP_PERIOD); + _stake(alice, stakeAmount, 0); + // locking up to new limit should render same maxMP as staking initially the whole + _lock(alice, _lockTimeAvailable(stakeAmount * 4, streamer.getVault(vaults[alice]).maxMP)); + _stake(bob, stakeAmount * 4, MAX_LOCKUP_PERIOD); + assertEq(streamer.getVault(vaults[bob]).maxMP, streamer.getVault(vaults[alice]).maxMP); } function test_StakeMultipleTimesWithLockIncreaseAtSameBlock() public { @@ -1059,61 +1061,21 @@ contract StakeTest is RewardsStreamerMPTest { ); // any lock up beyond the max lock up period should revert - vm.expectRevert(IStakeManager.StakingManager__InvalidLockPeriod.selector); + vm.expectRevert(StakeMath.StakeMath__InvalidLockingPeriod.selector); _stake(alice, 1, MIN_LOCKUP_PERIOD); } - function test_RevertWhenStakeMultipleTimesExceedsMaxLockUpTime() public { + function test_StakeMultipleTimesDoesNotExceedsMaxMP() public { // stake and lock 1 year - uint256 stakeAmount = 10e18; - _stake(alice, stakeAmount, YEAR); - - vm.warp(vm.getBlockTimestamp() + YEAR); - - // stake and lock another year - _stake(alice, stakeAmount, YEAR); - - vm.warp(vm.getBlockTimestamp() + YEAR); - - // stake and lock another 2 * year - _stake(alice, stakeAmount, 2 * YEAR); - - vm.warp(vm.getBlockTimestamp() + (2 * YEAR)); - - // we have now a total lock up of 4 years, - // so the next stake/or lock attempt should revert - vm.expectRevert(IStakeManager.StakingManager__InvalidLockPeriod.selector); - _stake(alice, stakeAmount, MIN_LOCKUP_PERIOD); - } - - function test_RevertWhenStakeMultipleTimesWithGapsExceedsMaxLockUpTime() public { - uint256 stakeAmount = 10e18; - - // stake and lock 1 year - _stake(alice, stakeAmount, YEAR); - vm.warp(vm.getBlockTimestamp() + YEAR); - - // wait for 1 year - vm.warp(vm.getBlockTimestamp() + YEAR); - - // stake and lock another year - _stake(alice, stakeAmount, YEAR); - vm.warp(vm.getBlockTimestamp() + YEAR); - - // wait for 2 years - vm.warp(vm.getBlockTimestamp() + 2 * YEAR); - - // stake and lock another 2 * year - _stake(alice, stakeAmount, 2 * YEAR); - vm.warp(vm.getBlockTimestamp() + (2 * YEAR)); - - // we have now staked for 7 years but locked up for 4 years, - // so the next stake/or lock attempt should revert - vm.expectRevert(IStakeManager.StakingManager__InvalidLockPeriod.selector); - _stake(alice, stakeAmount, MIN_LOCKUP_PERIOD); - - vm.expectRevert(IStakeManager.StakingManager__InvalidLockPeriod.selector); - _lock(alice, MIN_LOCKUP_PERIOD); + uint256 stakeAmount = 10e16; + uint256 i = 0; + do { + i++; + _stake(alice, stakeAmount, YEAR); + vm.warp(vm.getBlockTimestamp() + YEAR); + } while (_lockTimeAvailable(stakeAmount * i, streamer.getVault(vaults[alice]).maxMP) > MIN_LOCKUP_PERIOD); + _stake(bob, stakeAmount * i, _estimateLockTime(streamer.getVault(vaults[alice]).maxMP, stakeAmount * i)); + assertEq(streamer.getVault(vaults[bob]).maxMP, streamer.getVault(vaults[alice]).maxMP); } function test_StakeMultipleAccounts() public { @@ -2043,7 +2005,7 @@ contract LockTest is RewardsStreamerMPTest { ); // lock for another year should fail as 4 years is the maximum of total lock time - vm.expectRevert(IStakeManager.StakingManager__InvalidLockPeriod.selector); + vm.expectRevert(StakeMath.StakeMath__AbsoluteMaxMPOverflow.selector); _lock(alice, YEAR); } @@ -3149,16 +3111,18 @@ contract FuzzTests is RewardsStreamerMPTest { expectedRevert = IStakeManager.StakingManager__DurationCannotBeZero.selector; return; } - if (lockUpPeriod > MAX_LOCKUP_PERIOD) { - expectedRevert = IStakeManager.StakingManager__InvalidLockPeriod.selector; - return; - } + CheckVaultParams storage expectedAccountParams = expectedAccountState[account]; if (expectedAccountParams.vaultBalance == 0) { expectedRevert = StakeMath.StakeMath__InsufficientBalance.selector; return; } + if (lockUpPeriod > MAX_LOCKUP_PERIOD) { + expectedRevert = StakeMath.StakeMath__InvalidLockingPeriod.selector; + return; + } + uint256 calcLockEnd = Math.max( expectedVaultLockState[expectedAccountParams.account].lockEnd, vm.getBlockTimestamp() ) + lockUpPeriod; @@ -3169,8 +3133,7 @@ contract FuzzTests is RewardsStreamerMPTest { } if (expectedVaultLockState[expectedAccountParams.account].totalLockUp + lockUpPeriod > MAX_LOCKUP_PERIOD) { // total lock time surpassed the maximum allowed - //expectedRevert = StakeMath.StakeMath__AbsoluteMaxMPOverflow.selector; - expectedRevert = IStakeManager.StakingManager__InvalidLockPeriod.selector; + expectedRevert = StakeMath.StakeMath__AbsoluteMaxMPOverflow.selector; } else { expectedRevert = NO_REVERT; uint256 additionalBonusMP = _bonusMP(expectedAccountParams.vaultBalance, lockUpPeriod);