mirror of
https://github.com/vacp2p/staking-reward-streamer.git
synced 2026-01-08 23:08:19 -05:00
feat: introduce proxy clones
This commit introduces proxy clones to make create `StakeVault`s as cheap as possible. Major changes here are: - Introduce `VaultFactory` which takes care of creating clones and registering them with the stake manager - Make `StakeVault` and `Initializable` so it can be used as a "template" contract to later have proxies point to it - Adjust the deployment script to also deploy `VaultFactory` and ensure The proxy is whitelisted in the stake manager - Make use of the new proxy clones in tests - Add a test for `TrustedCodehashAccess` that ensures the proxy whitelisting works and setting up a (malicious) proxy is not going to work Closes #101
This commit is contained in:
72
.gas-report
72
.gas-report
@@ -4,13 +4,13 @@
|
||||
+=======================================================================================================================================+
|
||||
| Deployment Cost | Deployment Size | | | | |
|
||||
|-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| 6539451 | 31274 | | | | |
|
||||
| 7103409 | 33906 | | | | |
|
||||
|-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| | | | | | |
|
||||
|-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| run | 5618268 | 5618268 | 5618268 | 5618268 | 64 |
|
||||
| run | 6202546 | 6202546 | 6202546 | 6202546 | 67 |
|
||||
╰-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╯
|
||||
|
||||
╭---------------------------------------------------------+-----------------+-----+--------+-----+---------╮
|
||||
@@ -24,7 +24,7 @@
|
||||
|---------------------------------------------------------+-----------------+-----+--------+-----+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|---------------------------------------------------------+-----------------+-----+--------+-----+---------|
|
||||
| activeNetworkConfig | 454 | 454 | 454 | 454 | 128 |
|
||||
| activeNetworkConfig | 454 | 454 | 454 | 454 | 134 |
|
||||
╰---------------------------------------------------------+-----------------+-----+--------+-----+---------╯
|
||||
|
||||
╭-------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╮
|
||||
@@ -58,8 +58,6 @@
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| MIN_LOCKUP_PERIOD | 308 | 308 | 308 | 308 | 15 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| STAKING_TOKEN | 395 | 2003 | 2395 | 2395 | 327 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| emergencyModeEnabled | 2398 | 2398 | 2398 | 2398 | 7 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| enableEmergencyMode | 2507 | 19414 | 24699 | 24699 | 8 |
|
||||
@@ -74,19 +72,19 @@
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| getVault | 1621 | 1621 | 1621 | 1621 | 72 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| initialize | 115654 | 115654 | 115654 | 115654 | 66 |
|
||||
| initialize | 115654 | 115654 | 115654 | 115654 | 67 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| lastRewardTime | 428 | 1428 | 1428 | 2428 | 2 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| leave | 79955 | 79955 | 79955 | 79955 | 1 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| lock | 14282 | 42729 | 42692 | 78446 | 259 |
|
||||
| lock | 14282 | 42727 | 42692 | 78446 | 259 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| mpBalanceOfAccount | 10308 | 10308 | 10308 | 10308 | 1 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| proxiableUUID | 387 | 387 | 387 | 387 | 3 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| registerVault | 55866 | 72769 | 72966 | 72966 | 261 |
|
||||
| registerVault | 2562 | 70883 | 71335 | 71335 | 266 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| rewardEndTime | 362 | 1362 | 1362 | 2362 | 2 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
@@ -96,9 +94,9 @@
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| setReward | 2606 | 58415 | 86507 | 105754 | 7 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| setTrustedCodehash | 24199 | 24259 | 24199 | 26199 | 66 |
|
||||
| setTrustedCodehash | 24199 | 24199 | 24199 | 24199 | 67 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| stake | 136333 | 179336 | 180726 | 201200 | 322 |
|
||||
| stake | 2637 | 178788 | 180726 | 201200 | 323 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| totalMPAccrued | 384 | 384 | 384 | 384 | 81 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
@@ -124,33 +122,35 @@
|
||||
+===============================================================================================+
|
||||
| Deployment Cost | Deployment Size | | | | |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| 1420392 | 6695 | | | | |
|
||||
| 1557273 | 7323 | | | | |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| | | | | | |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| STAKING_TOKEN | 216 | 216 | 216 | 216 | 1 |
|
||||
| STAKING_TOKEN | 239 | 239 | 239 | 239 | 1 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| emergencyExit | 36353 | 48857 | 48091 | 65191 | 7 |
|
||||
| emergencyExit | 14974 | 31592 | 31512 | 48612 | 7 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| leave | 33507 | 136181 | 70120 | 370978 | 4 |
|
||||
| initialize | 98005 | 98005 | 98005 | 98005 | 266 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| lock | 33245 | 79218 | 79302 | 112243 | 260 |
|
||||
| leave | 12145 | 122559 | 62090 | 353914 | 4 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| owner | 2339 | 2339 | 2339 | 2339 | 261 |
|
||||
| lock | 12075 | 57976 | 58119 | 93872 | 260 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| register | 87015 | 103918 | 104115 | 104115 | 261 |
|
||||
| owner | 377 | 377 | 377 | 377 | 265 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| stake | 33411 | 253159 | 255230 | 275752 | 323 |
|
||||
| register | 12654 | 74497 | 74924 | 74924 | 266 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| stakeManager | 368 | 368 | 368 | 368 | 261 |
|
||||
| stake | 12077 | 233957 | 236707 | 257181 | 324 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| trustStakeManager | 28953 | 28953 | 28953 | 28953 | 1 |
|
||||
| stakeManager | 367 | 367 | 367 | 367 | 265 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| unstake | 33282 | 99858 | 105888 | 113384 | 14 |
|
||||
| trustStakeManager | 7577 | 7577 | 7577 | 7577 | 1 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| withdraw | 42278 | 42278 | 42278 | 42278 | 1 |
|
||||
| unstake | 12054 | 89644 | 94967 | 99164 | 14 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| withdraw | 20705 | 20705 | 20705 | 20705 | 1 |
|
||||
╰----------------------------------------+-----------------+--------+--------+--------+---------╯
|
||||
|
||||
╭----------------------------------------------------+-----------------+------+--------+--------+---------╮
|
||||
@@ -158,17 +158,31 @@
|
||||
+=========================================================================================================+
|
||||
| Deployment Cost | Deployment Size | | | | |
|
||||
|----------------------------------------------------+-----------------+------+--------+--------+---------|
|
||||
| 256510 | 1231 | | | | |
|
||||
| 0 | 1231 | | | | |
|
||||
|----------------------------------------------------+-----------------+------+--------+--------+---------|
|
||||
| | | | | | |
|
||||
|----------------------------------------------------+-----------------+------+--------+--------+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|----------------------------------------------------+-----------------+------+--------+--------+---------|
|
||||
| fallback | 689 | 7187 | 2075 | 132112 | 790 |
|
||||
| fallback | 689 | 7797 | 854 | 132112 | 461 |
|
||||
|----------------------------------------------------+-----------------+------+--------+--------+---------|
|
||||
| implementation | 343 | 1636 | 2343 | 2343 | 929 |
|
||||
| implementation | 343 | 2340 | 2343 | 2343 | 869 |
|
||||
╰----------------------------------------------------+-----------------+------+--------+--------+---------╯
|
||||
|
||||
╭--------------------------------------------+-----------------+--------+--------+--------+---------╮
|
||||
| src/VaultFactory.sol:VaultFactory Contract | | | | | |
|
||||
+===================================================================================================+
|
||||
| Deployment Cost | Deployment Size | | | | |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| 0 | 1991 | | | | |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| | | | | | |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| createVault | 227659 | 244565 | 244759 | 244759 | 265 |
|
||||
╰--------------------------------------------+-----------------+--------+--------+--------+---------╯
|
||||
|
||||
╭-------------------------------------------------+-----------------+-------+--------+-------+---------╮
|
||||
| src/XPNFTToken.sol:XPNFTToken Contract | | | | | |
|
||||
+======================================================================================================+
|
||||
@@ -300,17 +314,17 @@
|
||||
+==================================================================================================+
|
||||
| Deployment Cost | Deployment Size | | | | |
|
||||
|---------------------------------------------+-----------------+-------+--------+-------+---------|
|
||||
| 625454 | 3260 | | | | |
|
||||
| 625370 | 3260 | | | | |
|
||||
|---------------------------------------------+-----------------+-------+--------+-------+---------|
|
||||
| | | | | | |
|
||||
|---------------------------------------------+-----------------+-------+--------+-------+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|---------------------------------------------+-----------------+-------+--------+-------+---------|
|
||||
| approve | 46330 | 46339 | 46342 | 46342 | 261 |
|
||||
| approve | 46342 | 46342 | 46342 | 46342 | 265 |
|
||||
|---------------------------------------------+-----------------+-------+--------+-------+---------|
|
||||
| balanceOf | 558 | 926 | 558 | 2558 | 103 |
|
||||
|---------------------------------------------+-----------------+-------+--------+-------+---------|
|
||||
| mint | 51279 | 56395 | 51279 | 68379 | 274 |
|
||||
| mint | 51279 | 56383 | 51279 | 68379 | 278 |
|
||||
╰---------------------------------------------+-----------------+-------+--------+-------+---------╯
|
||||
|
||||
╭-----------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╮
|
||||
@@ -324,7 +338,7 @@
|
||||
|-----------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|-----------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| leave | 391 | 161316 | 161316 | 322322 | 334 |
|
||||
| leave | 845 | 161317 | 161317 | 321839 | 333 |
|
||||
|-----------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| proxiableUUID | 330 | 330 | 330 | 330 | 1 |
|
||||
╰-----------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╯
|
||||
|
||||
121
.gas-snapshot
121
.gas-snapshot
@@ -1,75 +1,76 @@
|
||||
EmergencyExitTest:test_CannotEnableEmergencyModeTwice() (gas: 92757)
|
||||
EmergencyExitTest:test_CannotLeaveBeforeEmergencyMode() (gas: 300544)
|
||||
EmergencyExitTest:test_EmergencyExitBasic() (gas: 387340)
|
||||
EmergencyExitTest:test_EmergencyExitMultipleUsers() (gas: 667427)
|
||||
EmergencyExitTest:test_EmergencyExitToAlternateAddress() (gas: 395139)
|
||||
EmergencyExitTest:test_EmergencyExitWithLock() (gas: 394708)
|
||||
EmergencyExitTest:test_EmergencyExitWithRewards() (gas: 380241)
|
||||
EmergencyExitTest:test_CannotLeaveBeforeEmergencyMode() (gas: 306012)
|
||||
EmergencyExitTest:test_EmergencyExitBasic() (gas: 392806)
|
||||
EmergencyExitTest:test_EmergencyExitMultipleUsers() (gas: 678359)
|
||||
EmergencyExitTest:test_EmergencyExitToAlternateAddress() (gas: 400605)
|
||||
EmergencyExitTest:test_EmergencyExitWithLock() (gas: 400174)
|
||||
EmergencyExitTest:test_EmergencyExitWithRewards() (gas: 385707)
|
||||
EmergencyExitTest:test_OnlyOwnerCanEnableEmergencyMode() (gas: 39471)
|
||||
IntegrationTest:testStakeFoo() (gas: 1218594)
|
||||
LeaveTest:test_LeaveShouldProperlyUpdateAccounting() (gas: 6214173)
|
||||
LeaveTest:test_RevertWhenStakeManagerIsTrusted() (gas: 297675)
|
||||
LeaveTest:test_TrustNewStakeManager() (gas: 6269901)
|
||||
LockTest:test_LockFailsWithInvalidPeriod(uint256) (runs: 1000, μ: 344783, ~: 344801)
|
||||
LockTest:test_LockFailsWithNoStake() (gas: 102637)
|
||||
LockTest:test_LockFailsWithZero() (gas: 315022)
|
||||
LockTest:test_LockWithoutPriorLock() (gas: 393335)
|
||||
MaliciousUpgradeTest:test_UpgradeStackOverflowStakeManager() (gas: 1752531)
|
||||
IntegrationTest:testStakeFoo() (gas: 1232258)
|
||||
LeaveTest:test_LeaveShouldProperlyUpdateAccounting() (gas: 6218572)
|
||||
LeaveTest:test_RevertWhenStakeManagerIsTrusted() (gas: 303138)
|
||||
LeaveTest:test_TrustNewStakeManager() (gas: 6286362)
|
||||
LockTest:test_LockFailsWithInvalidPeriod(uint256) (runs: 1000, μ: 350272, ~: 350297)
|
||||
LockTest:test_LockFailsWithNoStake() (gas: 105377)
|
||||
LockTest:test_LockFailsWithZero() (gas: 320506)
|
||||
LockTest:test_LockWithoutPriorLock() (gas: 398817)
|
||||
MaliciousUpgradeTest:test_UpgradeStackOverflowStakeManager() (gas: 1757478)
|
||||
MathTest:test_CalcAbsoluteMaxTotalMP() (gas: 4996)
|
||||
MathTest:test_CalcAccrueMP() (gas: 7990)
|
||||
MathTest:test_CalcBonusMP() (gas: 18676)
|
||||
MathTest:test_CalcInitialMP() (gas: 5352)
|
||||
MathTest:test_CalcAccrueMP() (gas: 8013)
|
||||
MathTest:test_CalcBonusMP() (gas: 18644)
|
||||
MathTest:test_CalcInitialMP() (gas: 5375)
|
||||
MathTest:test_CalcMaxAccruedMP() (gas: 4642)
|
||||
MathTest:test_CalcMaxTotalMP() (gas: 19449)
|
||||
MultipleVaultsStakeTest:test_StakeMultipleVaults() (gas: 731369)
|
||||
MathTest:test_CalcMaxTotalMP() (gas: 19411)
|
||||
MultipleVaultsStakeTest:test_StakeMultipleVaults() (gas: 739601)
|
||||
NFTMetadataGeneratorSVGTest:testGenerateMetadata() (gas: 85934)
|
||||
NFTMetadataGeneratorSVGTest:testSetImageStrings() (gas: 58332)
|
||||
NFTMetadataGeneratorSVGTest:testSetImageStringsRevert() (gas: 35804)
|
||||
NFTMetadataGeneratorURLTest:testGenerateMetadata() (gas: 102512)
|
||||
NFTMetadataGeneratorURLTest:testSetBaseURL() (gas: 49555)
|
||||
NFTMetadataGeneratorURLTest:testSetBaseURLRevert() (gas: 35979)
|
||||
RewardsStreamerMP_RewardsTest:testRewardsBalanceOf() (gas: 490632)
|
||||
RewardsStreamerMP_RewardsTest:testRewardsBalanceOf() (gas: 493376)
|
||||
RewardsStreamerMP_RewardsTest:testSetRewards() (gas: 160880)
|
||||
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsBadAmount() (gas: 39384)
|
||||
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsBadDuration() (gas: 39407)
|
||||
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsNotAuthorized() (gas: 39442)
|
||||
RewardsStreamerMP_RewardsTest:testTotalRewardsSupply() (gas: 620722)
|
||||
StakeTest:test_StakeMultipleAccounts() (gas: 502561)
|
||||
StakeTest:test_StakeMultipleAccountsAndRewards() (gas: 508596)
|
||||
StakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 847390)
|
||||
StakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 517705)
|
||||
StakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 539649)
|
||||
StakeTest:test_StakeOneAccount() (gas: 279841)
|
||||
StakeTest:test_StakeOneAccountAndRewards() (gas: 285896)
|
||||
StakeTest:test_StakeOneAccountMPIncreasesMaxMPDoesNotChange() (gas: 510467)
|
||||
StakeTest:test_StakeOneAccountReachingMPLimit() (gas: 500009)
|
||||
StakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 300111)
|
||||
StakeTest:test_StakeOneAccountWithMinLockUp() (gas: 300696)
|
||||
StakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 300763)
|
||||
StakingTokenTest:testStakeToken() (gas: 10422)
|
||||
UnstakeTest:test_StakeMultipleAccounts() (gas: 502560)
|
||||
UnstakeTest:test_StakeMultipleAccountsAndRewards() (gas: 508640)
|
||||
UnstakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 847367)
|
||||
UnstakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 517704)
|
||||
UnstakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 539693)
|
||||
UnstakeTest:test_StakeOneAccount() (gas: 279841)
|
||||
UnstakeTest:test_StakeOneAccountAndRewards() (gas: 285874)
|
||||
UnstakeTest:test_StakeOneAccountMPIncreasesMaxMPDoesNotChange() (gas: 510511)
|
||||
UnstakeTest:test_StakeOneAccountReachingMPLimit() (gas: 500008)
|
||||
UnstakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 300111)
|
||||
UnstakeTest:test_StakeOneAccountWithMinLockUp() (gas: 300718)
|
||||
UnstakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 300762)
|
||||
UnstakeTest:test_UnstakeBonusMPAndAccuredMP() (gas: 546541)
|
||||
UnstakeTest:test_UnstakeMultipleAccounts() (gas: 707663)
|
||||
UnstakeTest:test_UnstakeMultipleAccountsAndRewards() (gas: 803659)
|
||||
UnstakeTest:test_UnstakeOneAccount() (gas: 481480)
|
||||
UnstakeTest:test_UnstakeOneAccountAndAccruedMP() (gas: 505028)
|
||||
UnstakeTest:test_UnstakeOneAccountAndRewards() (gas: 410671)
|
||||
UnstakeTest:test_UnstakeOneAccountWithLockUpAndAccruedMP() (gas: 530083)
|
||||
UpgradeTest:test_RevertWhenNotOwner() (gas: 2897740)
|
||||
UpgradeTest:test_UpgradeStakeManager() (gas: 6114750)
|
||||
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsBadAmount() (gas: 39407)
|
||||
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsBadDuration() (gas: 39385)
|
||||
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsNotAuthorized() (gas: 39420)
|
||||
RewardsStreamerMP_RewardsTest:testTotalRewardsSupply() (gas: 623466)
|
||||
StakeTest:test_StakeMultipleAccounts() (gas: 508049)
|
||||
StakeTest:test_StakeMultipleAccountsAndRewards() (gas: 514084)
|
||||
StakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 852890)
|
||||
StakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 523193)
|
||||
StakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 545137)
|
||||
StakeTest:test_StakeOneAccount() (gas: 282585)
|
||||
StakeTest:test_StakeOneAccountAndRewards() (gas: 288640)
|
||||
StakeTest:test_StakeOneAccountMPIncreasesMaxMPDoesNotChange() (gas: 513211)
|
||||
StakeTest:test_StakeOneAccountReachingMPLimit() (gas: 502753)
|
||||
StakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 302900)
|
||||
StakeTest:test_StakeOneAccountWithMinLockUp() (gas: 303440)
|
||||
StakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 303507)
|
||||
StakingTokenTest:testStakeToken() (gas: 13140)
|
||||
TrustedCodehashAccessTest:test_RevertWhenProxyCloneCodehashNotTrusted() (gas: 1896237)
|
||||
UnstakeTest:test_StakeMultipleAccounts() (gas: 508026)
|
||||
UnstakeTest:test_StakeMultipleAccountsAndRewards() (gas: 514106)
|
||||
UnstakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 852867)
|
||||
UnstakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 523170)
|
||||
UnstakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 545159)
|
||||
UnstakeTest:test_StakeOneAccount() (gas: 282585)
|
||||
UnstakeTest:test_StakeOneAccountAndRewards() (gas: 288662)
|
||||
UnstakeTest:test_StakeOneAccountMPIncreasesMaxMPDoesNotChange() (gas: 513233)
|
||||
UnstakeTest:test_StakeOneAccountReachingMPLimit() (gas: 502797)
|
||||
UnstakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 302900)
|
||||
UnstakeTest:test_StakeOneAccountWithMinLockUp() (gas: 303462)
|
||||
UnstakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 303551)
|
||||
UnstakeTest:test_UnstakeBonusMPAndAccuredMP() (gas: 551979)
|
||||
UnstakeTest:test_UnstakeMultipleAccounts() (gas: 718583)
|
||||
UnstakeTest:test_UnstakeMultipleAccountsAndRewards() (gas: 816209)
|
||||
UnstakeTest:test_UnstakeOneAccount() (gas: 488546)
|
||||
UnstakeTest:test_UnstakeOneAccountAndAccruedMP() (gas: 510466)
|
||||
UnstakeTest:test_UnstakeOneAccountAndRewards() (gas: 416131)
|
||||
UnstakeTest:test_UnstakeOneAccountWithLockUpAndAccruedMP() (gas: 535543)
|
||||
UpgradeTest:test_RevertWhenNotOwner() (gas: 2897728)
|
||||
UpgradeTest:test_UpgradeStakeManager() (gas: 6117494)
|
||||
VaultRegistrationTest:test_VaultRegistration() (gas: 62154)
|
||||
WithdrawTest:test_CannotWithdrawStakedFunds() (gas: 313397)
|
||||
WithdrawTest:test_CannotWithdrawStakedFunds() (gas: 318812)
|
||||
XPNFTTokenTest:testApproveNotAllowed() (gas: 10500)
|
||||
XPNFTTokenTest:testGetApproved() (gas: 10523)
|
||||
XPNFTTokenTest:testIsApprovedForAll() (gas: 10698)
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol";
|
||||
|
||||
import { BaseScript } from "./Base.s.sol";
|
||||
import { DeploymentConfig } from "./DeploymentConfig.s.sol";
|
||||
|
||||
import { TransparentProxy } from "../src/TransparentProxy.sol";
|
||||
import { IStakeManagerProxy } from "../src/interfaces/IStakeManagerProxy.sol";
|
||||
import { RewardsStreamerMP } from "../src/RewardsStreamerMP.sol";
|
||||
import { StakeVault } from "../src/StakeVault.sol";
|
||||
import { VaultFactory } from "../src/VaultFactory.sol";
|
||||
|
||||
contract DeployRewardsStreamerMPScript is BaseScript {
|
||||
function run() public returns (RewardsStreamerMP, DeploymentConfig) {
|
||||
function run() public returns (RewardsStreamerMP, VaultFactory, DeploymentConfig) {
|
||||
DeploymentConfig deploymentConfig = new DeploymentConfig(broadcaster);
|
||||
(address deployer, address stakingToken) = deploymentConfig.activeNetworkConfig();
|
||||
|
||||
@@ -21,16 +25,19 @@ contract DeployRewardsStreamerMPScript is BaseScript {
|
||||
address impl = address(new RewardsStreamerMP());
|
||||
// Create upgradeable proxy
|
||||
address proxy = address(new TransparentProxy(impl, initializeData));
|
||||
|
||||
// Create vault implementation for proxy clones
|
||||
address vaultImplementation = address(new StakeVault(IERC20(stakingToken)));
|
||||
address proxyClone = Clones.clone(vaultImplementation);
|
||||
|
||||
// Whitelist vault implementation codehash
|
||||
RewardsStreamerMP(proxy).setTrustedCodehash(proxyClone.codehash, true);
|
||||
|
||||
// Create vault factory
|
||||
VaultFactory vaultFactory = new VaultFactory(deployer, proxy, vaultImplementation);
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
RewardsStreamerMP stakeManager = RewardsStreamerMP(proxy);
|
||||
StakeVault tempVault = new StakeVault(address(this), IStakeManagerProxy(proxy));
|
||||
bytes32 vaultCodeHash = address(tempVault).codehash;
|
||||
|
||||
vm.startBroadcast(deployer);
|
||||
stakeManager.setTrustedCodehash(vaultCodeHash, true);
|
||||
vm.stopBroadcast();
|
||||
|
||||
return (stakeManager, deploymentConfig);
|
||||
return (RewardsStreamerMP(proxy), vaultFactory, deploymentConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
|
||||
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 "./interfaces/IStakeManagerProxy.sol";
|
||||
import { IStakeVault } from "./interfaces/IStakeVault.sol";
|
||||
@@ -12,8 +13,10 @@ import { IStakeVault } from "./interfaces/IStakeVault.sol";
|
||||
* @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 StakeVault is IStakeVault, Ownable {
|
||||
contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
|
||||
error StakeVault__NotEnoughAvailableBalance();
|
||||
error StakeVault__InvalidDestinationAddress();
|
||||
error StakeVault__UpdateNotAvailable();
|
||||
@@ -55,13 +58,20 @@ contract StakeVault is IStakeVault, Ownable {
|
||||
|
||||
/**
|
||||
* @notice Initializes the contract with the owner, staked token, and stake manager.
|
||||
*/
|
||||
constructor(IERC20 token) {
|
||||
STAKING_TOKEN = token;
|
||||
_disableInitializers();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param _owner The address of the owner.
|
||||
* @param _stakeManager The address of the StakeManager contract.
|
||||
*/
|
||||
constructor(address _owner, IStakeManagerProxy _stakeManager) Ownable(_owner) {
|
||||
STAKING_TOKEN = _stakeManager.STAKING_TOKEN();
|
||||
stakeManager = _stakeManager;
|
||||
stakeManagerImplementationAddress = _stakeManager.implementation();
|
||||
function initialize(address _owner, address _stakeManager) public initializer {
|
||||
__Ownable_init(_owner);
|
||||
stakeManager = IStakeManagerProxy(_stakeManager);
|
||||
stakeManagerImplementationAddress = stakeManager.implementation();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,7 +92,7 @@ contract StakeVault is IStakeVault, Ownable {
|
||||
/**
|
||||
* @notice Returns the address of the current owner.
|
||||
*/
|
||||
function owner() public view override(Ownable, IStakeVault) returns (address) {
|
||||
function owner() public view override(OwnableUpgradeable, IStakeVault) returns (address) {
|
||||
return super.owner();
|
||||
}
|
||||
|
||||
|
||||
76
src/VaultFactory.sol
Normal file
76
src/VaultFactory.sol
Normal file
@@ -0,0 +1,76 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
|
||||
// import { TransparentClones } from "./TransparentClones.sol";
|
||||
import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol";
|
||||
import { StakeVault } from "./StakeVault.sol";
|
||||
|
||||
/**
|
||||
* @title VaultFactory
|
||||
* @author 0x-r4bbit
|
||||
*
|
||||
* This contract is reponsible for creating staking vaults for users.
|
||||
* A user of the staking protocol is able to create multiple vaults to facilitate
|
||||
* different strategies. For example, a user may want to create a vault for
|
||||
* a long-term lock period, while also creating a vault that has no lock period
|
||||
* at all.
|
||||
*
|
||||
* @notice This contract is used by users to create staking vaults.
|
||||
* @dev This contract will be deployed by Status, making Status the owner of the contract.
|
||||
* @dev A contract address for a `StakeManager` has to be provided to create this contract.
|
||||
* @dev Reverts with {VaultFactory__InvalidStakeManagerAddress} if the provided
|
||||
* `StakeManager` address is zero.
|
||||
* @dev The `StakeManager` contract address can be changed by the owner.
|
||||
*/
|
||||
contract VaultFactory is Ownable {
|
||||
error VaultFactory__InvalidStakeManagerAddress();
|
||||
|
||||
event VaultCreated(address indexed vault, address indexed owner);
|
||||
event StakeManagerAddressChanged(address indexed newStakeManagerAddress);
|
||||
event VaultImplementationChanged(address indexed newVaultImplementation);
|
||||
|
||||
/// @dev Address of the `StakeManager` contract instance.
|
||||
address public stakeManager;
|
||||
/// @dev Address of the `StakeVault` implementation contract.
|
||||
address public vaultImplementation;
|
||||
|
||||
/// @param _stakeManager Address of the `StakeManager` contract instance.
|
||||
constructor(address _owner, address _stakeManager, address _vaultImplementation) Ownable(_owner) {
|
||||
if (_stakeManager == address(0)) {
|
||||
revert VaultFactory__InvalidStakeManagerAddress();
|
||||
}
|
||||
stakeManager = _stakeManager;
|
||||
vaultImplementation = _vaultImplementation;
|
||||
}
|
||||
|
||||
/// @notice Sets the `StakeManager` contract address.
|
||||
/// @dev Only the owner can call this function.
|
||||
/// @dev Emits a {StakeManagerAddressChanged} event.
|
||||
/// @param _stakeManager Address of the `StakeManager` contract instance.
|
||||
function setStakeManager(address _stakeManager) external onlyOwner {
|
||||
stakeManager = _stakeManager;
|
||||
emit StakeManagerAddressChanged(_stakeManager);
|
||||
}
|
||||
|
||||
/// @notice Sets the `StakeVault` implementation contract address.
|
||||
/// @dev Only the owner can call this function.
|
||||
/// @dev Emits a {VaultImplementationChanged} event.
|
||||
/// @param _vaultImplementation Address of the `StakeVault` implementation contract.
|
||||
/// @dev This function is used to change the implementation of the `StakeVault` contract.
|
||||
function setVaultImplementation(address _vaultImplementation) external onlyOwner {
|
||||
vaultImplementation = _vaultImplementation;
|
||||
emit VaultImplementationChanged(_vaultImplementation);
|
||||
}
|
||||
|
||||
/// @notice Creates an instance of a `StakeVault` contract.
|
||||
/// @dev Anyone can call this function.
|
||||
/// @dev Emits a {VaultCreated} event.
|
||||
function createVault() external returns (StakeVault clone) {
|
||||
clone = StakeVault(Clones.clone(vaultImplementation));
|
||||
clone.initialize(msg.sender, stakeManager);
|
||||
clone.register();
|
||||
emit VaultCreated(address(clone), msg.sender);
|
||||
}
|
||||
}
|
||||
@@ -7,34 +7,41 @@ import { DeployRewardsStreamerMPScript } from "../script/DeployRewardsStreamerMP
|
||||
import { UpgradeRewardsStreamerMPScript } from "../script/UpgradeRewardsStreamerMP.s.sol";
|
||||
import { DeploymentConfig } from "../script/DeploymentConfig.s.sol";
|
||||
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
||||
import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol";
|
||||
import { IStakeManagerProxy } from "../src/interfaces/IStakeManagerProxy.sol";
|
||||
import { ITrustedCodehashAccess } from "../src/interfaces/ITrustedCodehashAccess.sol";
|
||||
import { RewardsStreamerMP } from "../src/RewardsStreamerMP.sol";
|
||||
import { StakeMath } from "../src/math/StakeMath.sol";
|
||||
import { StakeVault } from "../src/StakeVault.sol";
|
||||
import { IStakeManagerProxy } from "../src/interfaces/IStakeManagerProxy.sol";
|
||||
import { VaultFactory } from "../src/VaultFactory.sol";
|
||||
import { MockToken } from "./mocks/MockToken.sol";
|
||||
import { StackOverflowStakeManager } from "./mocks/StackOverflowStakeManager.sol";
|
||||
|
||||
contract RewardsStreamerMPTest is StakeMath, Test {
|
||||
MockToken stakingToken;
|
||||
MockToken internal stakingToken;
|
||||
RewardsStreamerMP public streamer;
|
||||
VaultFactory public vaultFactory;
|
||||
|
||||
address admin;
|
||||
address alice = makeAddr("alice");
|
||||
address bob = makeAddr("bob");
|
||||
address charlie = makeAddr("charlie");
|
||||
address dave = makeAddr("dave");
|
||||
address internal admin;
|
||||
address internal alice = makeAddr("alice");
|
||||
address internal bob = makeAddr("bob");
|
||||
address internal charlie = makeAddr("charlie");
|
||||
address internal dave = makeAddr("dave");
|
||||
|
||||
mapping(address owner => address vault) public vaults;
|
||||
|
||||
function setUp() public virtual {
|
||||
DeployRewardsStreamerMPScript deployment = new DeployRewardsStreamerMPScript();
|
||||
(RewardsStreamerMP stakeManager, DeploymentConfig deploymentConfig) = deployment.run();
|
||||
(RewardsStreamerMP stakeManager, VaultFactory _vaultFactory, DeploymentConfig deploymentConfig) =
|
||||
deployment.run();
|
||||
|
||||
(address _deployer, address _stakingToken) = deploymentConfig.activeNetworkConfig();
|
||||
|
||||
streamer = stakeManager;
|
||||
stakingToken = MockToken(_stakingToken);
|
||||
vaultFactory = _vaultFactory;
|
||||
admin = _deployer;
|
||||
|
||||
address[4] memory accounts = [alice, bob, charlie, dave];
|
||||
@@ -105,8 +112,7 @@ contract RewardsStreamerMPTest is StakeMath, Test {
|
||||
|
||||
function _createTestVault(address owner) internal returns (StakeVault vault) {
|
||||
vm.prank(owner);
|
||||
vault = new StakeVault(owner, IStakeManagerProxy(address(streamer)));
|
||||
vault.register();
|
||||
vault = vaultFactory.createVault();
|
||||
}
|
||||
|
||||
function _stake(address account, uint256 amount, uint256 lockupTime) public {
|
||||
@@ -203,6 +209,27 @@ contract VaultRegistrationTest is RewardsStreamerMPTest {
|
||||
}
|
||||
}
|
||||
|
||||
contract TrustedCodehashAccessTest is RewardsStreamerMPTest {
|
||||
function setUp() public virtual override {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
function test_RevertWhenProxyCloneCodehashNotTrusted() public {
|
||||
// create independent (possibly malicious) StakeVault
|
||||
address vaultTpl = address(new StakeVault(stakingToken));
|
||||
StakeVault proxyClone = StakeVault(Clones.clone(vaultTpl));
|
||||
proxyClone.initialize(address(this), address(streamer));
|
||||
|
||||
// registering already fails as codehash is not trusted
|
||||
vm.expectRevert(ITrustedCodehashAccess.TrustedCodehashAccess__UnauthorizedCodehash.selector);
|
||||
proxyClone.register();
|
||||
|
||||
// staking fails as codehash is not trusted
|
||||
vm.expectRevert(ITrustedCodehashAccess.TrustedCodehashAccess__UnauthorizedCodehash.selector);
|
||||
proxyClone.stake(10e10, 0);
|
||||
}
|
||||
}
|
||||
|
||||
contract IntegrationTest is RewardsStreamerMPTest {
|
||||
function setUp() public virtual override {
|
||||
super.setUp();
|
||||
|
||||
@@ -4,12 +4,16 @@ pragma solidity ^0.8.26;
|
||||
import { Test } from "forge-std/Test.sol";
|
||||
|
||||
import { IStakeManagerProxy } from "../src/interfaces/IStakeManagerProxy.sol";
|
||||
import { TransparentProxy } from "../src/TransparentProxy.sol";
|
||||
import { DeploymentConfig } from "../script/DeploymentConfig.s.sol";
|
||||
import { DeployRewardsStreamerMPScript } from "../script/DeployRewardsStreamerMP.s.sol";
|
||||
import { VaultFactory } from "../src/VaultFactory.sol";
|
||||
import { RewardsStreamerMP } from "../src/RewardsStreamerMP.sol";
|
||||
import { StakeVault } from "../src/StakeVault.sol";
|
||||
import { MockToken } from "./mocks/MockToken.sol";
|
||||
|
||||
contract StakeVaultTest is Test {
|
||||
VaultFactory internal vaultFactory;
|
||||
|
||||
RewardsStreamerMP internal streamer;
|
||||
|
||||
StakeVault internal stakeVault;
|
||||
@@ -22,29 +26,24 @@ contract StakeVaultTest is Test {
|
||||
|
||||
function _createTestVault(address owner) internal returns (StakeVault vault) {
|
||||
vm.prank(owner);
|
||||
vault = new StakeVault(owner, IStakeManagerProxy(address(streamer)));
|
||||
vault.register();
|
||||
vault = vaultFactory.createVault();
|
||||
}
|
||||
|
||||
function setUp() public virtual {
|
||||
rewardToken = new MockToken("Reward Token", "RT");
|
||||
stakingToken = new MockToken("Staking Token", "ST");
|
||||
address impl = address(new RewardsStreamerMP());
|
||||
bytes memory initializeData = abi.encodeWithSelector(
|
||||
RewardsStreamerMP.initialize.selector, address(this), address(stakingToken), address(rewardToken)
|
||||
);
|
||||
address proxy = address(new TransparentProxy(impl, initializeData));
|
||||
streamer = RewardsStreamerMP(proxy);
|
||||
|
||||
DeployRewardsStreamerMPScript deployment = new DeployRewardsStreamerMPScript();
|
||||
(RewardsStreamerMP stakeManager, VaultFactory _vaultFactory, DeploymentConfig deploymentConfig) =
|
||||
deployment.run();
|
||||
(, address _stakingToken) = deploymentConfig.activeNetworkConfig();
|
||||
|
||||
streamer = stakeManager;
|
||||
stakingToken = MockToken(_stakingToken);
|
||||
vaultFactory = _vaultFactory;
|
||||
|
||||
stakingToken.mint(alice, 10_000e18);
|
||||
|
||||
// Create a temporary vault just to get the codehash
|
||||
StakeVault tempVault = new StakeVault(address(this), IStakeManagerProxy(address(streamer)));
|
||||
bytes32 vaultCodeHash = address(tempVault).codehash;
|
||||
|
||||
// Register the codehash before creating any user vaults
|
||||
streamer.setTrustedCodehash(vaultCodeHash, true);
|
||||
|
||||
stakeVault = _createTestVault(alice);
|
||||
|
||||
vm.prank(alice);
|
||||
|
||||
Reference in New Issue
Block a user