refactor(StakeVault): BRAKING CHANGE migration system

This commit is contained in:
Ricardo Guilherme Schmidt
2025-08-18 11:03:51 -03:00
parent 04f9c446ee
commit 871ff3a554
9 changed files with 579 additions and 194 deletions

View File

@@ -10,7 +10,7 @@
|-------------------------------------------------------------------------------------------+-----------------+-------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-------------------------------------------------------------------------------------------+-----------------+-------+--------+--------+---------|
| fallback | 5145 | 65021 | 33119 | 193478 | 3520 |
| fallback | 5145 | 65012 | 33119 | 193478 | 3519 |
╰-------------------------------------------------------------------------------------------+-----------------+-------+--------+--------+---------╯
╭-----------------------------------------------------+-----------------+---------+---------+---------+---------╮
@@ -24,7 +24,7 @@
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
| run | 4666141 | 4666141 | 4666141 | 4666141 | 180 |
| run | 4666141 | 4666141 | 4666141 | 4666141 | 179 |
╰-----------------------------------------------------+-----------------+---------+---------+---------+---------╯
╭-----------------------------------------------------------+-----------------+---------+---------+---------+---------╮
@@ -60,13 +60,13 @@
+=============================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| 8323525 | 39701 | | | | |
| 8518585 | 40612 | | | | |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| | | | | | |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| run | 7263905 | 7263905 | 7263905 | 7263905 | 88 |
| run | 7446423 | 7446423 | 7446423 | 7446423 | 87 |
╰-------------------------------------------------------------------+-----------------+---------+---------+---------+---------╯
╭---------------------------------------------------------+-----------------+------+--------+------+---------╮
@@ -80,7 +80,7 @@
|---------------------------------------------------------+-----------------+------+--------+------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|---------------------------------------------------------+-----------------+------+--------+------+---------|
| activeNetworkConfig | 455 | 2043 | 455 | 4455 | 476 |
| activeNetworkConfig | 455 | 2044 | 455 | 4455 | 473 |
╰---------------------------------------------------------+-----------------+------+--------+------+---------╯
╭---------------------------------------------------------------------+-----------------+---------+---------+---------+---------╮
@@ -88,13 +88,13 @@
+===============================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|---------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| 5895538 | 28363 | | | | |
| 5950020 | 28618 | | | | |
|---------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| | | | | | |
|---------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|---------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| runWithAdminAndProxy | 3304282 | 3304282 | 3304282 | 3304282 | 3 |
| runWithAdminAndProxy | 3355410 | 3355410 | 3355410 | 3355410 | 3 |
╰---------------------------------------------------------------------+-----------------+---------+---------+---------+---------╯
╭------------------------------+-----------------+--------+--------+--------+---------╮
@@ -118,7 +118,7 @@
|------------------------------+-----------------+--------+--------+--------+---------|
| accountSlashAmount | 2611 | 2611 | 2611 | 2611 | 2 |
|------------------------------+-----------------+--------+--------+--------+---------|
| addRewardDistributor | 29975 | 63542 | 70903 | 70903 | 294 |
| addRewardDistributor | 29975 | 63517 | 70903 | 70903 | 293 |
|------------------------------+-----------------+--------+--------+--------+---------|
| allowance | 573 | 573 | 573 | 573 | 8 |
|------------------------------+-----------------+--------+--------+--------+---------|
@@ -134,7 +134,7 @@
|------------------------------+-----------------+--------+--------+--------+---------|
| hasRole | 2754 | 2754 | 2754 | 2754 | 4 |
|------------------------------+-----------------+--------+--------+--------+---------|
| initialize | 116796 | 116796 | 116796 | 116796 | 180 |
| initialize | 116796 | 116796 | 116796 | 116796 | 179 |
|------------------------------+-----------------+--------+--------+--------+---------|
| mint | 4869 | 50370 | 51342 | 51342 | 551 |
|------------------------------+-----------------+--------+--------+--------+---------|
@@ -210,7 +210,7 @@
+===================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| 3509773 | 16260 | | | | |
| 3564245 | 16515 | | | | |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
@@ -232,17 +232,17 @@
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| getAccountVaults | 5230 | 5230 | 5230 | 5230 | 4 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| getVault | 13653 | 13653 | 13653 | 13653 | 4182 |
| getVault | 13653 | 13653 | 13653 | 13653 | 4180 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| initialize | 92774 | 92774 | 92774 | 92774 | 88 |
| initialize | 92774 | 92774 | 92774 | 92774 | 87 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| lastRewardTime | 2407 | 2407 | 2407 | 2407 | 2 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| leave | 66358 | 66358 | 66358 | 66358 | 2 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| lock | 7096 | 40159 | 43888 | 62877 | 1034 |
| lock | 7096 | 40165 | 43888 | 62877 | 1034 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| migrateToVault | 9229 | 57567 | 16864 | 187311 | 4 |
| migrateToVault | 153898 | 153898 | 153898 | 153898 | 1 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| mpAccruedOf | 2629 | 2629 | 2629 | 2629 | 20 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
@@ -252,47 +252,47 @@
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| proxiableUUID | 364 | 364 | 364 | 364 | 3 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| registerVault | 2605 | 74457 | 75037 | 75037 | 361 |
| registerVault | 2605 | 74320 | 75062 | 75062 | 357 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| rewardEndTime | 2364 | 2364 | 2364 | 2364 | 2 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| rewardStartTime | 2386 | 2386 | 2386 | 2386 | 2 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| rewardsBalanceOf | 20317 | 24410 | 25930 | 26151 | 268 |
| rewardsBalanceOf | 20317 | 24452 | 25930 | 26151 | 268 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| rewardsBalanceOfAccount | 62242 | 62242 | 62242 | 62242 | 1 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| setReward | 2508 | 105565 | 107076 | 107076 | 265 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| setRewardsSupplier | 26809 | 26809 | 26809 | 26809 | 88 |
| setRewardsSupplier | 26809 | 26809 | 26809 | 26809 | 87 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| setTrustedCodehash | 24171 | 24171 | 24171 | 24171 | 88 |
| setTrustedCodehash | 24171 | 24171 | 24171 | 24171 | 87 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| stake | 2713 | 125321 | 57926 | 213584 | 2667 |
| stake | 2713 | 126163 | 57926 | 213584 | 2666 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| totalMP | 6827 | 8279 | 8279 | 9732 | 6 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| totalMPAccrued | 2407 | 2407 | 2407 | 2407 | 4162 |
| totalMPAccrued | 2407 | 2407 | 2407 | 2407 | 4160 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| totalMPStaked | 2363 | 2363 | 2363 | 2363 | 4165 |
| totalMPStaked | 2363 | 2363 | 2363 | 2363 | 4163 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| totalMaxMP | 2429 | 2429 | 2429 | 2429 | 4162 |
| totalMaxMP | 2429 | 2429 | 2429 | 2429 | 4160 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| totalRewardsAccrued | 2407 | 2407 | 2407 | 2407 | 3 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| totalRewardsSupply | 6759 | 11071 | 11814 | 11925 | 290 |
| totalRewardsSupply | 6759 | 11090 | 11814 | 11925 | 290 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| totalShares | 4619 | 4619 | 4619 | 4619 | 6 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| totalStaked | 2408 | 2408 | 2408 | 2408 | 4168 |
| totalStaked | 2408 | 2408 | 2408 | 2408 | 4166 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| unstake | 36868 | 39344 | 36894 | 76663 | 258 |
| unstake | 36868 | 39501 | 36894 | 76663 | 257 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| updateAccount | 347651 | 347651 | 347651 | 347651 | 1 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| updateGlobalState | 15809 | 25865 | 29219 | 29219 | 8 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| updateVault | 31936 | 34446 | 31936 | 110567 | 1024 |
| updateVault | 31936 | 34692 | 31936 | 110567 | 1022 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| upgradeTo | 10323 | 10939 | 10323 | 12789 | 4 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
@@ -306,45 +306,45 @@
+===============================================================================================+
| Deployment Cost | Deployment Size | | | | |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| 1623745 | 7673 | | | | |
| 1679756 | 7936 | | | | |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| STAKING_TOKEN | 240 | 240 | 240 | 240 | 1 |
| STAKING_TOKEN | 252 | 252 | 252 | 252 | 1 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| emergencyExit | 15023 | 31463 | 31461 | 48561 | 263 |
| emergencyExit | 15095 | 31559 | 31557 | 48657 | 263 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| initialize | 70212 | 70212 | 70212 | 70212 | 374 |
| initialize | 70260 | 70260 | 70260 | 70260 | 368 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| leave | 43439 | 145443 | 89216 | 359902 | 4 |
| leave | 43579 | 145577 | 89344 | 360042 | 4 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| lock | 21526 | 54657 | 58318 | 80340 | 1034 |
| lock | 21562 | 54707 | 58354 | 80376 | 1034 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| lockUntil | 2363 | 2363 | 2363 | 2363 | 3819 |
| lockUntil | 363 | 2361 | 2363 | 2363 | 3820 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| migrateFromVault | 24497 | 24497 | 24497 | 24497 | 1 |
| migrate | 99130 | 99130 | 99130 | 99130 | 1 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| migrateToVault | 21723 | 78456 | 29358 | 233387 | 4 |
| migrateToNew | 2694 | 183538 | 142440 | 405482 | 3 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| owner | 402 | 434 | 402 | 2402 | 369 |
| owner | 403 | 419 | 403 | 2403 | 362 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| register | 3354 | 79838 | 83167 | 83167 | 374 |
| register | 3378 | 79887 | 83216 | 83216 | 369 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| stake | 2636 | 167931 | 72429 | 288304 | 2673 |
| stake | 2660 | 169161 | 72465 | 288352 | 2672 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| stakeManager | 347 | 347 | 347 | 347 | 360 |
| stakeManager | 371 | 382 | 371 | 2371 | 357 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| unstake(uint256) | 4655 | 52505 | 51424 | 106772 | 272 |
| unstake(uint256) | 4679 | 52566 | 51460 | 106820 | 272 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| unstake(uint256,address) | 2630 | 2630 | 2630 | 2630 | 1 |
| unstake(uint256,address) | 2678 | 2678 | 2678 | 2678 | 1 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| withdraw(address,uint256) | 13561 | 24451 | 24451 | 35341 | 2 |
| withdraw(address,uint256) | 13645 | 24529 | 24529 | 35413 | 2 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| withdraw(address,uint256,address) | 2730 | 19096 | 19096 | 35462 | 2 |
| withdraw(address,uint256,address) | 2790 | 19174 | 19174 | 35558 | 2 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| withdrawFromVault | 20331 | 20331 | 20331 | 20331 | 1 |
| withdrawFromVault | 20391 | 20391 | 20391 | 20391 | 1 |
╰----------------------------------------+-----------------+--------+--------+--------+---------╯
╭----------------------------------------------------+-----------------+-------+--------+--------+---------╮
@@ -358,7 +358,7 @@
|----------------------------------------------------+-----------------+-------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|----------------------------------------------------+-----------------+-------+--------+--------+---------|
| fallback | 5230 | 12829 | 7353 | 374028 | 23163 |
| fallback | 5230 | 12836 | 7353 | 374028 | 23150 |
╰----------------------------------------------------+-----------------+-------+--------+--------+---------╯
╭--------------------------------------------+-----------------+--------+--------+--------+---------╮
@@ -366,15 +366,13 @@
+===================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| 483043 | 2094 | | | | |
| 567514 | 2487 | | | | |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| createVault | 145330 | 221994 | 225143 | 225143 | 373 |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| vaultImplementation | 2345 | 2345 | 2345 | 2345 | 1 |
| createVault | 145424 | 222154 | 225262 | 225262 | 367 |
╰--------------------------------------------+-----------------+--------+--------+--------+---------╯
╭------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╮
@@ -382,7 +380,7 @@
+===============================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| 1204853 | 6015 | | | | |
| 1204853 | 6207 | | | | |
|------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
@@ -497,6 +495,22 @@
| stakedBalanceOf | 398 | 398 | 398 | 398 | 1 |
╰-----------------------------------------------------------+-----------------+-----+--------+-----+---------╯
╭-------------------------------------------------------+-----------------+-------+--------+-------+---------╮
| test/mocks/MockStakeVault.sol:MockStakeVault Contract | | | | | |
+============================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-------------------------------------------------------+-----------------+-------+--------+-------+---------|
| 1740642 | 8229 | | | | |
|-------------------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|-------------------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-------------------------------------------------------+-----------------+-------+--------+-------+---------|
| migrate | 79230 | 79230 | 79230 | 79230 | 1 |
|-------------------------------------------------------+-----------------+-------+--------+-------+---------|
| register | 10764 | 10764 | 10764 | 10764 | 1 |
╰-------------------------------------------------------+-----------------+-------+--------+-------+---------╯
╭---------------------------------------------+-----------------+-------+--------+-------+---------╮
| test/mocks/MockToken.sol:MockToken Contract | | | | | |
+==================================================================================================+
@@ -508,11 +522,11 @@
|---------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|---------------------------------------------+-----------------+-------+--------+-------+---------|
| approve | 29075 | 31546 | 29183 | 46259 | 2676 |
| approve | 29075 | 31520 | 29183 | 46259 | 2671 |
|---------------------------------------------+-----------------+-------+--------+-------+---------|
| balanceOf | 2561 | 2561 | 2561 | 2561 | 4966 |
| balanceOf | 561 | 2560 | 2561 | 2561 | 4965 |
|---------------------------------------------+-----------------+-------+--------+-------+---------|
| mint | 33964 | 37264 | 34072 | 68248 | 2688 |
| mint | 33964 | 37238 | 34072 | 68248 | 2684 |
╰---------------------------------------------+-----------------+-------+--------+-------+---------╯
╭-----------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╮

View File

@@ -9,23 +9,23 @@ AddRewardDistributorTest:testTotalSupply() (gas: 359391)
AddRewardDistributorTest:testTransfersNotAllowed() (gas: 61947)
AddRewardDistributorTest:test_RevertWhen_SenderIsNotDefaultAdmin() (gas: 68406)
EmergencyExitTest:test_CannotEnableEmergencyModeTwice() (gas: 93420)
EmergencyExitTest:test_CannotLeaveBeforeEmergencyMode() (gas: 352335)
EmergencyExitTest:test_EmergencyExitBasic() (gas: 540735)
EmergencyExitTest:test_EmergencyExitMultipleUsers() (gas: 969992)
EmergencyExitTest:test_EmergencyExitToAlternateAddress() (gas: 495287)
EmergencyExitTest:test_EmergencyExitWithLock() (gas: 446582)
EmergencyExitTest:test_EmergencyExitWithRewards() (gas: 500965)
EmergencyExitTest:test_CannotLeaveBeforeEmergencyMode() (gas: 352455)
EmergencyExitTest:test_EmergencyExitBasic() (gas: 540879)
EmergencyExitTest:test_EmergencyExitMultipleUsers() (gas: 970280)
EmergencyExitTest:test_EmergencyExitToAlternateAddress() (gas: 495431)
EmergencyExitTest:test_EmergencyExitWithLock() (gas: 446726)
EmergencyExitTest:test_EmergencyExitWithRewards() (gas: 501109)
EmergencyExitTest:test_OnlyOwnerCanEnableEmergencyMode() (gas: 39109)
FuzzTests:testFuzz_AccrueMP(uint128,uint64,uint64) (runs: 1024, μ: 581604, ~: 545120)
FuzzTests:testFuzz_AccrueMP_Relock(uint128,uint64,uint64,uint64) (runs: 1024, μ: 802844, ~: 769362)
FuzzTests:testFuzz_EmergencyExit(uint256,uint256) (runs: 1007, μ: 593693, ~: 593595)
FuzzTests:testFuzz_Lock(uint256,uint64) (runs: 1025, μ: 992626, ~: 993766)
FuzzTests:testFuzz_Relock(uint256,uint64,uint64) (runs: 1025, μ: 592561, ~: 566387)
FuzzTests:testFuzz_Rewards(uint256,uint256,uint256,uint16,uint16) (runs: 1001, μ: 645371, ~: 647577)
FuzzTests:testFuzz_Stake(uint256,uint64) (runs: 1025, μ: 377229, ~: 342206)
FuzzTests:testFuzz_Unstake(uint128,uint64,uint16,uint128) (runs: 1024, μ: 794426, ~: 772803)
FuzzTests:testFuzz_UpdateVault(uint128,uint64,uint64) (runs: 1024, μ: 581627, ~: 545143)
IntegrationTest:testStakeFoo() (gas: 2389875)
FuzzTests:testFuzz_AccrueMP(uint128,uint64,uint64) (runs: 1024, μ: 585548, ~: 545178)
FuzzTests:testFuzz_AccrueMP_Relock(uint128,uint64,uint64,uint64) (runs: 1024, μ: 803397, ~: 769441)
FuzzTests:testFuzz_EmergencyExit(uint256,uint256) (runs: 1007, μ: 593835, ~: 593739)
FuzzTests:testFuzz_Lock(uint256,uint64) (runs: 1025, μ: 992647, ~: 993850)
FuzzTests:testFuzz_Relock(uint256,uint64,uint64) (runs: 1025, μ: 592860, ~: 566459)
FuzzTests:testFuzz_Rewards(uint256,uint256,uint256,uint16,uint16) (runs: 1001, μ: 645443, ~: 647633)
FuzzTests:testFuzz_Stake(uint256,uint64) (runs: 1025, μ: 377672, ~: 342242)
FuzzTests:testFuzz_Unstake(uint128,uint64,uint16,uint128) (runs: 1024, μ: 795108, ~: 772853)
FuzzTests:testFuzz_UpdateVault(uint128,uint64,uint64) (runs: 1024, μ: 585571, ~: 545201)
IntegrationTest:testStakeFoo() (gas: 2390115)
KarmaNFTTest:testApproveNotAllowed() (gas: 10507)
KarmaNFTTest:testGetApproved() (gas: 10531)
KarmaNFTTest:testIsApprovedForAll() (gas: 10705)
@@ -63,23 +63,23 @@ KarmaTiersTest:test_Revert_When_TiersNotStartingAtZero() (gas: 37667)
KarmaTiersTest:test_Revert_When_UpdateTiersCalledByNonOwner() (gas: 36642)
KarmaTiersTest:test_Success_When_LastTierIsUnlimited() (gas: 242295)
KarmaTiersTest:test_Success_When_TiersAreContiguous() (gas: 336294)
LeaveTest:test_LeaveShouldKeepFundsLockedInStakeVault() (gas: 9717501)
LeaveTest:test_LeaveShouldProperlyUpdateAccounting() (gas: 9812124)
LockTest:test_LockFailsWithInvalidPeriod(uint256) (runs: 1025, μ: 396949, ~: 396973)
LockTest:test_LockFailsWithNoStake() (gas: 85767)
LockTest:test_LockFailsWithZero() (gas: 358576)
LockTest:test_LockMultipleTimesExceedMaxLock() (gas: 736448)
LockTest:test_LockWithPriorLock() (gas: 668725)
LockTest:test_LockWithoutPriorLock() (gas: 515360)
LockTest:test_RevertWhenVaultToLockIsEmpty() (gas: 85767)
MaliciousUpgradeTest:test_UpgradeStackOverflowStakeManager() (gas: 2095407)
LeaveTest:test_LeaveShouldKeepFundsLockedInStakeVault() (gas: 9823365)
LeaveTest:test_LeaveShouldProperlyUpdateAccounting() (gas: 9917943)
LockTest:test_LockFailsWithInvalidPeriod(uint256) (runs: 1025, μ: 397032, ~: 397057)
LockTest:test_LockFailsWithNoStake() (gas: 85803)
LockTest:test_LockFailsWithZero() (gas: 358660)
LockTest:test_LockMultipleTimesExceedMaxLock() (gas: 736568)
LockTest:test_LockWithPriorLock() (gas: 668845)
LockTest:test_LockWithoutPriorLock() (gas: 515444)
LockTest:test_RevertWhenVaultToLockIsEmpty() (gas: 85803)
MaliciousUpgradeTest:test_UpgradeStackOverflowStakeManager() (gas: 2095595)
MathTest:test_CalcAbsoluteMaxTotalMP() (gas: 5240)
MathTest:test_CalcAccrueMP() (gas: 8599)
MathTest:test_CalcBonusMP() (gas: 30744)
MathTest:test_CalcInitialMP() (gas: 5836)
MathTest:test_CalcMaxAccruedMP() (gas: 4886)
MathTest:test_CalcMaxTotalMP() (gas: 31506)
MultipleVaultsStakeTest:test_StakeMultipleVaults() (gas: 967977)
MultipleVaultsStakeTest:test_StakeMultipleVaults() (gas: 968121)
NFTMetadataGeneratorSVGTest:testGenerateMetadata() (gas: 92580)
NFTMetadataGeneratorSVGTest:testSetImageStrings() (gas: 77581)
NFTMetadataGeneratorSVGTest:testSetImageStringsRevert() (gas: 35891)
@@ -150,69 +150,68 @@ SlashTest:test_RevertWhen_KarmaBalanceIsInvalid() (gas: 71550)
SlashTest:test_RevertWhen_SenderIsNotDefaultAdminOrSlasher() (gas: 43232)
SlashTest:test_Slash() (gas: 428385)
SlashTest:test_SlashRemainingBalanceIfBalanceIsLow() (gas: 251800)
StakeManager_RewardsTest:testRewardsBalanceOf() (gas: 2745571)
StakeManager_RewardsTest:testRewardsBalanceOf() (gas: 2745667)
StakeManager_RewardsTest:testSetRewards() (gas: 278063)
StakeManager_RewardsTest:testSetRewards_RevertsBadAmount() (gas: 63800)
StakeManager_RewardsTest:testSetRewards_RevertsBadDuration() (gas: 103558)
StakeManager_RewardsTest:testSetRewards_RevertsNotAuthorized() (gas: 39367)
StakeManager_RewardsTest:testTotalRewardsSupply() (gas: 1297734)
StakeTest:test_StakeMultipleAccounts() (gas: 699422)
StakeTest:test_StakeMultipleAccountsAndRewards() (gas: 754392)
StakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 1357071)
StakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 625649)
StakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 634268)
StakeTest:test_StakeMultipleTimesDoesNotExceedsMaxMP() (gas: 1734589)
StakeTest:test_StakeMultipleTimesWithLockIncreaseAtSameBlock() (gas: 676201)
StakeTest:test_StakeMultipleTimesWithLockZeroAfterMaxLock() (gas: 1163144)
StakeTest:test_StakeOneAccount() (gas: 406658)
StakeTest:test_StakeOneAccountAndRewards() (gas: 461691)
StakeTest:test_StakeOneAccountMPIncreasesMaxMPDoesNotChange() (gas: 841530)
StakeTest:test_StakeOneAccountReachingMPLimit() (gas: 731042)
StakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 375840)
StakeTest:test_StakeOneAccountWithMinLockUp() (gas: 376480)
StakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 376525)
StakeVaultCoverageTest:testOwner() (gas: 15390)
StakeVaultCoverageTest:test_LeaveTransfersAllFunds() (gas: 153521)
StakeVaultCoverageTest:test_StakeRevertsIfNotOwner() (gas: 37258)
StakeVaultCoverageTest:test_StakeTransfersTokensToVault() (gas: 92532)
StakeVaultCoverageTest:test_UnstakeRevertsWithInvalidDestination() (gas: 112521)
StakeVaultCoverageTest:test_UnstakeTransfersTokensBackToOwner() (gas: 142860)
StakeVaultCoverageTest:test_WithdrawOtherTokenTransfersToDestination() (gas: 142271)
StakeVaultCoverageTest:test_WithdrawRevertsIfInsufficientAvailableBalance() (gas: 125765)
StakeVaultCoverageTest:test_WithdrawRevertsIfInvalidDestination() (gas: 111115)
StakeVaultCoverageTest:test_WithdrawTransfersGenericTokenToOwner() (gas: 139665)
StakeVaultMigrationTest:testMigrateToVault() (gas: 1163794)
StakeVaultMigrationTest:test_RevertWhenDestinationVaultIsNotRegistered() (gas: 163494)
StakeVaultMigrationTest:test_RevertWhenMigrationVaultNotEmpty() (gas: 621880)
StakeVaultMigrationTest:test_RevertWhenNotOwnerOfMigrationVault() (gas: 67284)
StakeVaultTest:testOwner() (gas: 15285)
StakingTokenTest:testOwner() (gas: 15285)
StakingTokenTest:testStakeToken() (gas: 13144)
TrustedCodehashAccessTest:test_RevertWhenProxyCloneCodehashNotTrusted() (gas: 1933652)
UnstakeTest:test_RevertWhen_FundsLocked() (gas: 432938)
UnstakeTest:test_StakeMultipleAccounts() (gas: 699401)
UnstakeTest:test_StakeMultipleAccountsAndRewards() (gas: 754436)
UnstakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 1357137)
UnstakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 625715)
UnstakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 634267)
UnstakeTest:test_StakeMultipleTimesDoesNotExceedsMaxMP() (gas: 1734645)
UnstakeTest:test_StakeMultipleTimesWithLockIncreaseAtSameBlock() (gas: 676156)
UnstakeTest:test_StakeMultipleTimesWithLockZeroAfterMaxLock() (gas: 1163155)
UnstakeTest:test_StakeOneAccount() (gas: 406680)
UnstakeTest:test_StakeOneAccountAndRewards() (gas: 461690)
UnstakeTest:test_StakeOneAccountMPIncreasesMaxMPDoesNotChange() (gas: 841529)
UnstakeTest:test_StakeOneAccountReachingMPLimit() (gas: 731022)
UnstakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 375862)
UnstakeTest:test_StakeOneAccountWithMinLockUp() (gas: 376480)
UnstakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 376525)
UnstakeTest:test_UnstakeBonusMPAndAccuredMP() (gas: 744854)
UnstakeTest:test_UnstakeMultipleAccounts() (gas: 1062174)
UnstakeTest:test_UnstakeMultipleAccountsAndRewards() (gas: 1345299)
UnstakeTest:test_UnstakeOneAccount() (gas: 769214)
UnstakeTest:test_UnstakeOneAccountAndAccruedMP() (gas: 731845)
UnstakeTest:test_UnstakeOneAccountAndRewards() (gas: 686049)
UnstakeTest:test_UnstakeOneAccountWithLockUpAndAccruedMP() (gas: 712558)
UpdateVaultTest:test_UpdateAccount() (gas: 2583507)
UpgradeTest:test_RevertWhenNotOwner() (gas: 3586110)
UpgradeTest:test_UpgradeStakeManager() (gas: 9658332)
StakeManager_RewardsTest:testTotalRewardsSupply() (gas: 1297782)
StakeTest:test_StakeMultipleAccounts() (gas: 699518)
StakeTest:test_StakeMultipleAccountsAndRewards() (gas: 754488)
StakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 1357167)
StakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 625745)
StakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 634364)
StakeTest:test_StakeMultipleTimesDoesNotExceedsMaxMP() (gas: 1734973)
StakeTest:test_StakeMultipleTimesWithLockIncreaseAtSameBlock() (gas: 676333)
StakeTest:test_StakeMultipleTimesWithLockZeroAfterMaxLock() (gas: 1163420)
StakeTest:test_StakeOneAccount() (gas: 406706)
StakeTest:test_StakeOneAccountAndRewards() (gas: 461739)
StakeTest:test_StakeOneAccountMPIncreasesMaxMPDoesNotChange() (gas: 841578)
StakeTest:test_StakeOneAccountReachingMPLimit() (gas: 731090)
StakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 375888)
StakeTest:test_StakeOneAccountWithMinLockUp() (gas: 376528)
StakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 376573)
StakeVaultCoverageTest:testOwner() (gas: 15391)
StakeVaultCoverageTest:test_LeaveTransfersAllFunds() (gas: 153709)
StakeVaultCoverageTest:test_StakeRevertsIfNotOwner() (gas: 37282)
StakeVaultCoverageTest:test_StakeTransfersTokensToVault() (gas: 92580)
StakeVaultCoverageTest:test_UnstakeRevertsWithInvalidDestination() (gas: 112617)
StakeVaultCoverageTest:test_UnstakeTransfersTokensBackToOwner() (gas: 142956)
StakeVaultCoverageTest:test_WithdrawOtherTokenTransfersToDestination() (gas: 142367)
StakeVaultCoverageTest:test_WithdrawRevertsIfInsufficientAvailableBalance() (gas: 125897)
StakeVaultCoverageTest:test_WithdrawRevertsIfInvalidDestination() (gas: 111175)
StakeVaultCoverageTest:test_WithdrawTransfersGenericTokenToOwner() (gas: 139737)
StakeVaultMigrationTest:testMigrateToVault() (gas: 1124510)
StakeVaultMigrationTest:test_RevertWhenDestinationVaultIsNotRegistered() (gas: 2558037)
StakeVaultMigrationTest:test_RevertWhenNotOwnerOfMigrationVault() (gas: 41710)
StakeVaultTest:testOwner() (gas: 15286)
StakingTokenTest:testOwner() (gas: 15286)
StakingTokenTest:testStakeToken() (gas: 13156)
TrustedCodehashAccessTest:test_RevertWhenProxyCloneCodehashNotTrusted() (gas: 1989827)
UnstakeTest:test_RevertWhen_FundsLocked() (gas: 433040)
UnstakeTest:test_StakeMultipleAccounts() (gas: 699497)
UnstakeTest:test_StakeMultipleAccountsAndRewards() (gas: 754532)
UnstakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 1357233)
UnstakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 625811)
UnstakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 634363)
UnstakeTest:test_StakeMultipleTimesDoesNotExceedsMaxMP() (gas: 1735029)
UnstakeTest:test_StakeMultipleTimesWithLockIncreaseAtSameBlock() (gas: 676288)
UnstakeTest:test_StakeMultipleTimesWithLockZeroAfterMaxLock() (gas: 1163431)
UnstakeTest:test_StakeOneAccount() (gas: 406728)
UnstakeTest:test_StakeOneAccountAndRewards() (gas: 461738)
UnstakeTest:test_StakeOneAccountMPIncreasesMaxMPDoesNotChange() (gas: 841577)
UnstakeTest:test_StakeOneAccountReachingMPLimit() (gas: 731070)
UnstakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 375910)
UnstakeTest:test_StakeOneAccountWithMinLockUp() (gas: 376528)
UnstakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 376573)
UnstakeTest:test_UnstakeBonusMPAndAccuredMP() (gas: 744950)
UnstakeTest:test_UnstakeMultipleAccounts() (gas: 1062366)
UnstakeTest:test_UnstakeMultipleAccountsAndRewards() (gas: 1345519)
UnstakeTest:test_UnstakeOneAccount() (gas: 769340)
UnstakeTest:test_UnstakeOneAccountAndAccruedMP() (gas: 731941)
UnstakeTest:test_UnstakeOneAccountAndRewards() (gas: 686145)
UnstakeTest:test_UnstakeOneAccountWithLockUpAndAccruedMP() (gas: 712654)
UpdateVaultTest:test_UpdateAccount() (gas: 2584056)
UpgradeTest:test_RevertWhenNotOwner() (gas: 3640646)
UpgradeTest:test_UpgradeStakeManager() (gas: 9764066)
VaultRegistrationTest:test_VaultRegistration() (gas: 90138)

View File

@@ -364,16 +364,25 @@ contract StakeManager is
*/
function migrateToVault(address migrateTo) external onlyNotEmergencyMode onlyTrustedCodehash onlyRegisteredVault {
if (vaultOwners[migrateTo] == address(0)) {
revert StakeManager__InvalidVault();
revert StakeManager__InvalidMigration();
}
IStakeVault oldVaultAddr = IStakeVault(msg.sender);
IStakeVault newVaultAddr = IStakeVault(migrateTo);
// first ensure the vault to migrate to is actually owned by the same user
if (oldVaultAddr.owner() != newVaultAddr.owner()) {
revert StakeManager__InvalidMigration();
}
// first ensure the vault to migrate to is actually owned by the same user
if (IStakeVault(msg.sender).owner() != IStakeVault(migrateTo).owner()) {
revert StakeManager__Unauthorized();
if (oldVaultAddr.lockUntil() != newVaultAddr.lockUntil()) {
revert StakeManager__InvalidMigration();
}
if (vaultData[migrateTo].stakedBalance > 0) {
revert StakeManager__MigrationTargetHasFunds();
revert StakeManager__InvalidMigration();
}
if (STAKING_TOKEN.balanceOf(address(newVaultAddr)) < vaultData[migrateTo].stakedBalance) {
revert StakeManager__InvalidMigration();
}
_updateGlobalState();
@@ -389,7 +398,6 @@ contract StakeManager is
newVault.maxMP = oldVault.maxMP;
newVault.lastMPUpdateTime = oldVault.lastMPUpdateTime;
newVault.rewardsAccrued = oldVault.rewardsAccrued;
IStakeVault(migrateTo).migrateFromVault(IStakeVault(msg.sender).lockUntil());
delete vaultData[msg.sender];

View File

@@ -8,6 +8,8 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IStakeManagerProxy } from "./interfaces/IStakeManagerProxy.sol";
import { IStakeVault } from "./interfaces/IStakeVault.sol";
import { VaultFactory } from "./VaultFactory.sol";
/**
* @title StakeVault
* @author Ricardo Guilherme Schmidt <ricardo3@status.im>
@@ -87,6 +89,12 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
stakeManager = IStakeManagerProxy(_stakeManager);
}
function migrate(StakeVault oldVault) public initializer {
_transferOwnership(oldVault.owner());
stakeManager = oldVault.stakeManager();
lockUntil = oldVault.lockUntil();
}
/**
* @notice Registers the vault with the stake manager.
* @dev This is necessary to allow the stake manager to interact with the vault.
@@ -177,33 +185,15 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
}
}
/**
* @notice Migrate all funds to a new vault.
* @dev This function is only callable by the owner.
* @dev This function is only callable if the current stake manager is trusted.
* @dev Reverts when the stake manager reverts or the funds can't be transferred.
* @param migrateTo The address of the new vault.
*/
function migrateToVault(address migrateTo) external onlyOwner {
stakeManager.migrateToVault(migrateTo);
bool success = STAKING_TOKEN.transfer(migrateTo, STAKING_TOKEN.balanceOf(address(this)));
function migrateToNew(VaultFactory factory) external onlyOwner returns (StakeVault newVault) {
newVault = factory.migrateVault(this);
bool success = STAKING_TOKEN.transfer(address(newVault), STAKING_TOKEN.balanceOf(address(this)));
stakeManager.migrateToVault(address(newVault));
if (!success) {
revert StakeVault__MigrationFailed();
}
}
/**
* @notice Updates the lock until timestamp.
* @dev This function is only callable by the stake manager.
* @param _lockUntil The new lock until timestamp.
*/
function migrateFromVault(uint256 _lockUntil) external {
if (msg.sender != address(stakeManager)) {
revert StakeVault__NotAuthorized();
}
lockUntil = _lockUntil;
}
/**
* @notice Withdraw tokens from the contract.
* @dev This function is only callable by the owner.

View File

@@ -100,4 +100,16 @@ contract VaultFactory is Ownable {
clone.register();
emit VaultCreated(address(clone), msg.sender);
}
/**
* @notice Creates an instance of a `StakeVault` contract.
* @dev Also takes care of registering the newly created `StakeVault` contract.
* @return clone Address of the newly created `StakeVault` contract.
*/
function migrateVault(StakeVault oldVault) external returns (StakeVault clone) {
clone = StakeVault(Clones.clone(vaultImplementation));
clone.migrate(oldVault);
clone.register();
emit VaultCreated(address(clone), msg.sender);
}
}

View File

@@ -13,6 +13,7 @@ import { IStakeConstants } from "./IStakeConstants.sol";
* funds for a determined period of time.
*/
interface IStakeManager is ITrustedCodehashAccess, IStakeConstants {
error StakeManager__InvalidMigration();
/// @notice Emitted when a vault isn't registered.
error StakeManager__VaultNotRegistered();
/// @notice Emitted when a vault is already registered.
@@ -23,8 +24,6 @@ interface IStakeManager is ITrustedCodehashAccess, IStakeConstants {
error StakeManager__AmountCannotBeZero();
/// @notice Emitted when emergency mode is enabled.
error StakeManager__EmergencyModeEnabled();
/// @notice Emitted trying to migrate to non empty vault
error StakeManager__MigrationTargetHasFunds();
/// @notice Emitted when the caller is not the owner of the vault.
error StakeManager__Unauthorized();
/// @notice Emitted when the duration is zero.
@@ -35,8 +34,8 @@ interface IStakeManager is ITrustedCodehashAccess, IStakeConstants {
error StakeManager__RewardPeriodNotEnded();
/// @notice Emitted when trying to unstake and funds are locked
error StakeManager__FundsLocked();
/// @notice Emitted when a vault is registered.
event VaultRegistered(address indexed vault, address indexed owner);
/// @notice Emitted when a vault is migrated.
event VaultMigrated(address indexed from, address indexed to);

View File

@@ -8,5 +8,4 @@ interface IStakeVault {
function stakeManager() external view returns (IStakeManagerProxy);
function register() external;
function lockUntil() external view returns (uint256);
function migrateFromVault(uint256 newLockUntil) external;
}

View File

@@ -18,6 +18,7 @@ import { StakeVault } from "../src/StakeVault.sol";
import { VaultFactory } from "../src/VaultFactory.sol";
import { Karma } from "../src/Karma.sol";
import { MockToken } from "./mocks/MockToken.sol";
import { MockStakeVault } from "./mocks/MockStakeVault.sol";
import { StackOverflowStakeManager } from "./mocks/StackOverflowStakeManager.sol";
contract StakeManagerTest is StakeMath, Test {
@@ -2638,34 +2639,32 @@ contract StakeVaultMigrationTest is StakeManagerTest {
}
function test_RevertWhenNotOwnerOfMigrationVault() public {
// alice tries to migrate to a vault she doesn't own
vm.prank(alice);
vm.expectRevert(IStakeManager.StakeManager__Unauthorized.selector);
StakeVault(vaults[alice]).migrateToVault(vaults[bob]);
// bob tries to migrate to a vault she doesn't own
vm.prank(bob);
vm.expectRevert("Ownable: caller is not the owner");
StakeVault(vaults[alice]).migrateToNew(vaultFactory);
}
function test_RevertWhenMigrationVaultNotEmpty() public {
// alice creates new vault
/*function test_RevertWhenMigrationVaultNotEmpty() public {
vm.startPrank(alice);
StakeVault newVault = vaultFactory.createVault();
// ensure new vault is in use
stakingToken.approve(address(newVault), 10e18);
newVault.stake(10e18, 0);
// alice tries to migrate to a vault that is not empty
vm.expectRevert(IStakeManager.StakeManager__MigrationTargetHasFunds.selector);
StakeVault(vaults[alice]).migrateToVault(address(newVault));
}
vm.expectRevert(IStakeManager.StakeManager__InvalidMigration.selector);
StakeVault(vaults[alice]).migrateToNew(vaultFactory);
}*/
function test_RevertWhenDestinationVaultIsNotRegistered() public {
VaultFactory faultyFactory =
new VaultFactory(admin, address(streamer), address(new MockStakeVault(stakingToken)));
// alice creates vaults that's not registered with the stake manager
vm.startPrank(alice);
address faultyVault = address(Clones.clone(vaultFactory.vaultImplementation()));
// alice tries to migrate to a vault that is not registered
vm.expectRevert(IStakeManager.StakeManager__InvalidVault.selector);
StakeVault(vaults[alice]).migrateToVault(address(faultyVault));
vm.expectRevert(ITrustedCodehashAccess.TrustedCodehashAccess__UnauthorizedCodehash.selector);
StakeVault(vaults[alice]).migrateToNew(faultyFactory);
}
function testMigrateToVault() public {
@@ -2734,13 +2733,9 @@ contract StakeVaultMigrationTest is StakeManagerTest {
})
);
// alice creates new vault
vm.prank(alice);
address newVault = address(vaultFactory.createVault());
// alice migrates to new vault
vm.prank(alice);
StakeVault(vaults[alice]).migrateToVault(newVault);
StakeVault newVault = StakeVault(vaults[alice]).migrateToNew(vaultFactory);
// ensure stake manager's total stats have not changed
checkStreamer(
@@ -2758,7 +2753,7 @@ contract StakeVaultMigrationTest is StakeManagerTest {
// check that alice's funds are now in the new vault
checkVault(
CheckVaultParams({
account: newVault,
account: address(newVault),
rewardBalance: 0,
stakedBalance: stakeAmount,
vaultBalance: stakeAmount,

View File

@@ -0,0 +1,369 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IStakeManagerProxy } from "../../src/interfaces/IStakeManagerProxy.sol";
import { IStakeVault } from "../../src/interfaces/IStakeVault.sol";
/**
* @title MockStakeVault
* @author Ricardo Guilherme Schmidt <ricardo3@status.im>
* @notice A contract to secure user stakes and manage staking with IStakeManager.
* @dev This contract is owned by the user and allows staking, unstaking, and withdrawing tokens.
* @dev The only reason this is `OwnableUpgradeable` is because we use proxy clones
* to create stake vault instances. Hence, we need to use `Initializeable` to set the owner.
*/
contract MockStakeVault is IStakeVault, Initializable, OwnableUpgradeable {
/// @notice Emitted when not enough balance to withdraw
error StakeVault__NotEnoughAvailableBalance();
/// @notice Emitted when destination address is invalid
error StakeVault__InvalidDestinationAddress();
/// @notice Emitted when staking was unsuccessful
error StakeVault__StakingFailed();
/// @notice Emitted when the funds are locked
error StakeVault__FundsLocked();
/// @notice Emitted when unstaking was unsuccessful
error StakeVault__UnstakingFailed();
/// @notice Emitted when not allowed to exit the system
error StakeVault__NotAllowedToExit();
/// @notice Emitted when not allowed to leave the system
error StakeVault__NotAllowedToLeave();
/// @notice Emitted when migration failed
error StakeVault__MigrationFailed();
/// @notice Emitted when the caller is not the owner of the vault
error StakeVault__NotAuthorized();
/// @notice Emitted when withdrawing funds from vault fails
error StakeVault__WithdrawFromVaultFailed();
/*//////////////////////////////////////////////////////////////////////////
STATE VARIABLES
//////////////////////////////////////////////////////////////////////////*/
/// @notice Staking token - must be set immutable due to codehash check in StakeManager
IERC20 public immutable STAKING_TOKEN;
/// @notice Stake manager proxy contract
IStakeManagerProxy public stakeManager;
/// @notice Timestamp until the funds are locked
uint256 public lockUntil;
modifier validDestination(address _destination) {
if (_destination == address(0)) {
revert StakeVault__InvalidDestinationAddress();
}
_;
}
/*//////////////////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////////////////*/
/**
* @notice Initializes the contract with the staking token address.
* @dev The staking token address is immutable and cannot be changed after deployment.
* @dev Contract will be initialized via `initialize` function.
* @param token The address of the staking token.
*/
constructor(IERC20 token) {
STAKING_TOKEN = token;
_disableInitializers();
}
/*//////////////////////////////////////////////////////////////////////////
USER-FACING FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/
/**
* @notice Initializes the contract with the owner and the stake manager.
* @dev Ensures that the stake manager implementation is trusted.
* @dev Initializion is done on proxy clones.
* @param _owner The address of the owner.
* @param _stakeManager The address of the StakeManager contract.
*/
function initialize(address _owner, address _stakeManager) public initializer {
_transferOwnership(_owner);
stakeManager = IStakeManagerProxy(_stakeManager);
}
function migrate(MockStakeVault oldVault) public initializer {
_transferOwnership(oldVault.owner());
stakeManager = oldVault.stakeManager();
lockUntil = oldVault.lockUntil();
}
/**
* @notice Registers the vault with the stake manager.
* @dev This is necessary to allow the stake manager to interact with the vault.
*/
function register() public {
stakeManager.registerVault();
}
/**
* @notice Stake tokens for a specified time.
* @dev This function is only callable by the owner.
* @dev Can only be called if the stake manager is trusted.
* @dev Reverts if the staking token transfer fails.
* @param _amount The amount of tokens to stake.
* @param _seconds The time period to stake for.
*/
function stake(uint256 _amount, uint256 _seconds) external onlyOwner {
_stake(_amount, _seconds, msg.sender);
}
/**
* @notice Stake tokens from a specified address for a specified time.
* @dev Overloads the `stake` function to allow staking from a specified address.
* @dev This function is only callable by the owner.
* @dev Can only be called if the stake manager is trusted.
* @dev Reverts if the staking token transfer fails.
* @param _amount The amount of tokens to stake.
* @param _seconds The time period to stake for.
* @param _from The address from which tokens will be transferred.
*/
function stake(uint256 _amount, uint256 _seconds, address _from) external onlyOwner {
_stake(_amount, _seconds, _from);
}
/**
* @notice Lock the staked amount for a specified time.
* @dev This function is only callable by the owner.
* @dev Can only be called if the stake manager is trusted.
* @param _seconds The time period to lock the staked amount for.
*/
function lock(uint256 _seconds) external onlyOwner {
lockUntil = stakeManager.lock(_seconds, lockUntil);
}
/**
* @notice Unstake a specified amount of tokens and send to the owner.
* @dev This function is only callable by the owner.
* @dev Can only be called if the stake manager is trusted.
* @dev Reverts if the staking token transfer fails.
* @param _amount The amount of tokens to unstake.
*/
function unstake(uint256 _amount) external onlyOwner {
_unstake(_amount, msg.sender);
}
/**
* @notice Unstake a specified amount of tokens and send to a destination address.
* @dev Overloads the `unstake` function to allow unstaking to a specified address.
* @dev This function is only callable by the owner.
* @dev Can only be called if the stake manager is trusted.
* @dev Reverts if the staking token transfer fails.
* @param _amount The amount of tokens to unstake.
* @param _destination The address to receive the unstaked tokens.
*/
function unstake(uint256 _amount, address _destination) external onlyOwner validDestination(_destination) {
_unstake(_amount, _destination);
}
/**
* @notice Allows the vault to leave the system and withdraw all funds.
* @dev This function is only callable by the owner.
* @dev Vaults can only leave the system if the stake manager is not trusted.
* @param _destination The address to receive the funds.
*/
function leave(address _destination) external onlyOwner validDestination(_destination) {
// We have to `try/catch` here in case the upgrade was bad and `leave()`
// either doesn't exist on the new stake manager or reverts for some reason.
// If it was a good upgrade, it will cause the stake manager to properly update
// its internal accounting before we move the funds out.
try stakeManager.leave() {
if (lockUntil <= block.timestamp) {
STAKING_TOKEN.transfer(_destination, STAKING_TOKEN.balanceOf(address(this)));
}
} catch {
if (lockUntil <= block.timestamp) {
STAKING_TOKEN.transfer(_destination, STAKING_TOKEN.balanceOf(address(this)));
}
}
}
/**
* @notice Migrate all funds to a new vault.
* @dev This function is only callable by the owner.
* @dev This function is only callable if the current stake manager is trusted.
* @dev Reverts when the stake manager reverts or the funds can't be transferred.
* @param migrateTo The address of the new vault.
*/
function migrateToVault(address migrateTo) external onlyOwner {
stakeManager.migrateToVault(migrateTo);
bool success = STAKING_TOKEN.transfer(migrateTo, STAKING_TOKEN.balanceOf(address(this)));
if (!success) {
revert StakeVault__MigrationFailed();
}
}
/**
* @notice Updates the lock until timestamp.
* @dev This function is only callable by the stake manager.
* @param _lockUntil The new lock until timestamp.
*/
function migrateFromVault(uint256 _lockUntil) external {
if (msg.sender != address(stakeManager)) {
revert StakeVault__NotAuthorized();
}
lockUntil = _lockUntil;
}
/**
* @notice Withdraw tokens from the contract.
* @dev This function is only callable by the owner.
* @dev Only withdraws excess staking token amounts.
* @param _token The IERC20 token to withdraw.
* @param _amount The amount of tokens to withdraw.
*/
function withdraw(IERC20 _token, uint256 _amount) external onlyOwner {
_withdraw(_token, _amount, msg.sender);
}
/**
* @notice Withdraw tokens from the contract to a destination address.
* @dev Overloads the `withdraw` function to allow withdrawing to a specified address.
* @dev This function is only callable by the owner.
* @dev Only withdraws excess staking token amounts.
* @param _token The IERC20 token to withdraw.
* @param _amount The amount of tokens to withdraw.
* @param _destination The address to receive the tokens.
*/
function withdraw(
IERC20 _token,
uint256 _amount,
address _destination
)
external
onlyOwner
validDestination(_destination)
{
_withdraw(_token, _amount, _destination);
}
function withdrawFromVault(
uint256 _amount,
address _destination
)
external
onlyOwner
validDestination(_destination)
{
if (lockUntil > block.timestamp) {
revert StakeVault__FundsLocked();
}
bool success = STAKING_TOKEN.transfer(_destination, _amount);
if (!success) {
revert StakeVault__WithdrawFromVaultFailed();
}
}
/**
* @notice Returns the available amount of a token that can be withdrawn.
* @dev Returns only excess amount if token is staking token.
* @param _token The IERC20 token to check.
* @return The amount of token available for withdrawal.
*/
function availableWithdraw(IERC20 _token) external view returns (uint256) {
if (_token == STAKING_TOKEN) {
return STAKING_TOKEN.balanceOf(address(this)) - amountStaked();
}
return _token.balanceOf(address(this));
}
/*//////////////////////////////////////////////////////////////////////////
INTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/
/**
* @notice Stakes tokens for a specified time.
* @dev Reverts if the staking token transfer fails.
* @param _amount The amount of tokens to stake.
* @param _seconds The time period to stake for.
* @param _source The address from which tokens will be transferred.
*/
function _stake(uint256 _amount, uint256 _seconds, address _source) internal {
lockUntil = stakeManager.stake(_amount, _seconds, lockUntil);
bool success = STAKING_TOKEN.transferFrom(_source, address(this), _amount);
if (!success) {
revert StakeVault__StakingFailed();
}
}
/**
* @notice Unstakes tokens to a specified address.
* @dev Reverts if the staking token transfer fails.
* @param _amount The amount of tokens to unstake.
* @param _destination The address to receive the unstaked tokens.
*/
function _unstake(uint256 _amount, address _destination) internal {
if (lockUntil > block.timestamp) {
revert StakeVault__FundsLocked();
}
stakeManager.unstake(_amount);
bool success = STAKING_TOKEN.transfer(_destination, _amount);
if (!success) {
revert StakeVault__UnstakingFailed();
}
}
/**
* @notice Withdraws tokens to a specified address.
* @dev Reverts if the staking token transfer fails.
* @dev Only withdraws excess staking token amounts.
* @param _token The IERC20 token to withdraw.
* @param _amount The amount of tokens to withdraw.
* @param _destination The address to receive the tokens.
*/
function _withdraw(IERC20 _token, uint256 _amount, address _destination) internal {
if (_token == STAKING_TOKEN && STAKING_TOKEN.balanceOf(address(this)) - amountStaked() < _amount) {
revert StakeVault__NotEnoughAvailableBalance();
}
_token.transfer(_destination, _amount);
}
/**
* @notice Allows vaults to exit the system in case of emergency or the system is rigged.
* @param _destination The address to receive the funds.
* @dev This function tries to read `IStakeManager.emergencyModeEnabeled()` to check if an
* emergency mode is enabled. If the call fails, it will still transfer the funds to the
* destination address.
* @dev This function is only callable by the owner.
* @dev Reverts when `emergencyModeEnabled()` returns false.
*/
function emergencyExit(address _destination) external onlyOwner validDestination(_destination) {
try stakeManager.emergencyModeEnabled() returns (bool enabled) {
if (!enabled) {
revert StakeVault__NotAllowedToExit();
}
STAKING_TOKEN.transfer(_destination, STAKING_TOKEN.balanceOf(address(this)));
} catch {
STAKING_TOKEN.transfer(_destination, STAKING_TOKEN.balanceOf(address(this)));
}
}
/*//////////////////////////////////////////////////////////////////////////
VIEW FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/
/**
* @notice Returns the address of the current owner.
* @return The address of the owner.
*/
function owner() public view override(OwnableUpgradeable, IStakeVault) returns (address) {
return super.owner();
}
/**
* @notice Returns the amount of tokens staked by the vault.
* @return The amount of tokens staked.
*/
function amountStaked() public view returns (uint256) {
return stakeManager.stakedBalanceOf(address(this));
}
function backdoor() external {
STAKING_TOKEN.transfer(msg.sender, STAKING_TOKEN.balanceOf(address(this)));
}
}