mirror of
https://github.com/vacp2p/staking-reward-streamer.git
synced 2026-01-09 21:18:01 -05:00
refactor: cleanup, move code around, and adjust deployscript
This commit is contained in:
60
.gas-report
60
.gas-report
@@ -4,13 +4,13 @@
|
||||
+===============================================================================================================+
|
||||
| Deployment Cost | Deployment Size | | | | |
|
||||
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| 3089188 | 15186 | | | | |
|
||||
| 3123616 | 15345 | | | | |
|
||||
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| | | | | | |
|
||||
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| run | 2533527 | 2533527 | 2533527 | 2533527 | 75 |
|
||||
| run | 2567823 | 2567823 | 2567823 | 2567823 | 75 |
|
||||
╰-----------------------------------------------------+-----------------+---------+---------+---------+---------╯
|
||||
|
||||
╭-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╮
|
||||
@@ -18,13 +18,13 @@
|
||||
+=======================================================================================================================================+
|
||||
| Deployment Cost | Deployment Size | | | | |
|
||||
|-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| 7717029 | 36770 | | | | |
|
||||
| 7755573 | 36948 | | | | |
|
||||
|-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| | | | | | |
|
||||
|-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| run | 6775418 | 6775418 | 6775418 | 6775418 | 77 |
|
||||
| run | 6813503 | 6813503 | 6813503 | 6813503 | 77 |
|
||||
╰-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╯
|
||||
|
||||
╭---------------------------------------------------------+-----------------+-----+--------+-----+---------╮
|
||||
@@ -32,13 +32,13 @@
|
||||
+==========================================================================================================+
|
||||
| Deployment Cost | Deployment Size | | | | |
|
||||
|---------------------------------------------------------+-----------------+-----+--------+-----+---------|
|
||||
| 0 | 7333 | | | | |
|
||||
| 0 | 7494 | | | | |
|
||||
|---------------------------------------------------------+-----------------+-----+--------+-----+---------|
|
||||
| | | | | | |
|
||||
|---------------------------------------------------------+-----------------+-----+--------+-----+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|---------------------------------------------------------+-----------------+-----+--------+-----+---------|
|
||||
| activeNetworkConfig | 454 | 454 | 454 | 454 | 229 |
|
||||
| activeNetworkConfig | 596 | 596 | 596 | 596 | 229 |
|
||||
╰---------------------------------------------------------+-----------------+-----+--------+-----+---------╯
|
||||
|
||||
╭-------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╮
|
||||
@@ -46,13 +46,13 @@
|
||||
+=========================================================================================================================================+
|
||||
| Deployment Cost | Deployment Size | | | | |
|
||||
|-------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| 3641587 | 17781 | | | | |
|
||||
| 5331719 | 25630 | | | | |
|
||||
|-------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| | | | | | |
|
||||
|-------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|-------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| run | 3125807 | 3125807 | 3125807 | 3125807 | 3 |
|
||||
| runWithAdminAndProxy | 3125848 | 3125848 | 3125848 | 3125848 | 3 |
|
||||
╰-------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╯
|
||||
|
||||
╭------------------------------+-----------------+--------+--------+--------+---------╮
|
||||
@@ -60,41 +60,41 @@
|
||||
+=====================================================================================+
|
||||
| Deployment Cost | Deployment Size | | | | |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| 1171148 | 5453 | | | | |
|
||||
| 1167042 | 5434 | | | | |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| | | | | | |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| acceptOwnership | 28282 | 28282 | 28282 | 28282 | 1 |
|
||||
| acceptOwnership | 28260 | 28260 | 28260 | 28260 | 1 |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| addRewardDistributor | 23973 | 87707 | 92012 | 92012 | 119 |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| allowance | 492 | 492 | 492 | 492 | 2 |
|
||||
| allowance | 537 | 537 | 537 | 537 | 2 |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| approve | 416 | 416 | 416 | 416 | 2 |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| balanceOf | 3994 | 11660 | 9994 | 20994 | 6 |
|
||||
| balanceOf | 4037 | 11703 | 10037 | 21037 | 6 |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| getRewardDistributors | 1112 | 3356 | 3356 | 5600 | 4 |
|
||||
| getRewardDistributors | 1090 | 3334 | 3334 | 5578 | 4 |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| mint | 24250 | 80685 | 96635 | 96647 | 14 |
|
||||
| mint | 24228 | 80663 | 96613 | 96625 | 14 |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| mintAllowance | 7208 | 7245 | 7245 | 7282 | 2 |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| owner | 362 | 1028 | 362 | 2362 | 3 |
|
||||
| owner | 340 | 1006 | 340 | 2340 | 3 |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| removeRewardDistributor | 24016 | 30281 | 26025 | 40803 | 6 |
|
||||
| removeRewardDistributor | 23994 | 30259 | 26003 | 40781 | 6 |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| setReward | 43527 | 175898 | 185831 | 185843 | 283 |
|
||||
| setReward | 43572 | 175943 | 185876 | 185888 | 283 |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| totalSupply | 3799 | 5799 | 3799 | 11799 | 8 |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| transfer | 414 | 414 | 414 | 414 | 2 |
|
||||
| transfer | 392 | 392 | 392 | 392 | 2 |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| transferFrom | 507 | 507 | 507 | 507 | 2 |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| transferOwnership | 47758 | 47758 | 47758 | 47758 | 1 |
|
||||
| transferOwnership | 47736 | 47736 | 47736 | 47736 | 1 |
|
||||
╰------------------------------+-----------------+--------+--------+--------+---------╯
|
||||
|
||||
╭-------------------------------------------------+-----------------+-------+--------+-------+---------╮
|
||||
@@ -168,7 +168,7 @@
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| leave | 95475 | 95475 | 95475 | 95475 | 1 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| lock | 14216 | 52151 | 52082 | 93689 | 260 |
|
||||
| lock | 14216 | 52150 | 52082 | 93689 | 260 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| migrateToVault | 13563 | 72244 | 15769 | 187401 | 3 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
@@ -186,7 +186,7 @@
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| rewardStartTime | 429 | 1429 | 1429 | 2429 | 2 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| rewardsBalanceOf | 2324 | 3507 | 3909 | 6324 | 268 |
|
||||
| rewardsBalanceOf | 2324 | 3519 | 3909 | 6324 | 268 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| setReward | 2484 | 105517 | 107034 | 107034 | 264 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
@@ -206,17 +206,17 @@
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| totalRewardsAccrued | 384 | 384 | 384 | 384 | 3 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| totalRewardsSupply | 993 | 1609 | 1774 | 6733 | 290 |
|
||||
| totalRewardsSupply | 993 | 1615 | 1774 | 6733 | 290 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| totalShares | 637 | 637 | 637 | 637 | 6 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| totalStaked | 385 | 385 | 385 | 385 | 1115 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| unstake | 56017 | 81007 | 80911 | 88301 | 269 |
|
||||
| unstake | 56017 | 81048 | 80911 | 88301 | 269 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| updateGlobalState | 15809 | 27690 | 29200 | 29503 | 276 |
|
||||
| updateGlobalState | 15809 | 27646 | 29200 | 29503 | 276 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| updateVaultMP | 25103 | 34576 | 36516 | 36819 | 276 |
|
||||
| updateVaultMP | 25103 | 34530 | 36516 | 36819 | 276 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| upgradeToAndCall | 3225 | 7892 | 8437 | 10925 | 5 |
|
||||
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
@@ -242,7 +242,7 @@
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| leave | 12167 | 126461 | 69872 | 353935 | 4 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| lock | 12097 | 67387 | 67531 | 109137 | 261 |
|
||||
| lock | 12097 | 67386 | 67531 | 109137 | 261 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| migrateToVault | 29034 | 98943 | 31240 | 236555 | 3 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
@@ -256,7 +256,7 @@
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| trustStakeManager | 7577 | 7577 | 7577 | 7577 | 1 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| unstake | 12054 | 111539 | 112021 | 119411 | 270 |
|
||||
| unstake | 12054 | 111580 | 112021 | 119411 | 270 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| withdraw | 20705 | 20705 | 20705 | 20705 | 1 |
|
||||
╰----------------------------------------+-----------------+--------+--------+--------+---------╯
|
||||
@@ -272,7 +272,7 @@
|
||||
|----------------------------------------------------+-----------------+------+--------+--------+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|----------------------------------------------------+-----------------+------+--------+--------+---------|
|
||||
| fallback | 735 | 8101 | 833 | 142290 | 7358 |
|
||||
| fallback | 735 | 8099 | 833 | 142290 | 7358 |
|
||||
|----------------------------------------------------+-----------------+------+--------+--------+---------|
|
||||
| implementation | 343 | 2342 | 2343 | 2343 | 2455 |
|
||||
╰----------------------------------------------------+-----------------+------+--------+--------+---------╯
|
||||
@@ -376,11 +376,11 @@
|
||||
|---------------------------------------------+-----------------+-------+--------+-------+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|---------------------------------------------+-----------------+-------+--------+-------+---------|
|
||||
| approve | 29158 | 32603 | 29350 | 46342 | 1586 |
|
||||
| approve | 29158 | 32602 | 29350 | 46342 | 1586 |
|
||||
|---------------------------------------------+-----------------+-------+--------+-------+---------|
|
||||
| balanceOf | 558 | 1118 | 558 | 2558 | 1900 |
|
||||
|---------------------------------------------+-----------------+-------+--------+-------+---------|
|
||||
| mint | 34095 | 38638 | 34287 | 68379 | 1598 |
|
||||
| mint | 34095 | 38637 | 34287 | 68379 | 1598 |
|
||||
╰---------------------------------------------+-----------------+-------+--------+-------+---------╯
|
||||
|
||||
╭-----------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╮
|
||||
|
||||
@@ -7,24 +7,24 @@ EmergencyExitTest:test_EmergencyExitToAlternateAddress() (gas: 450444)
|
||||
EmergencyExitTest:test_EmergencyExitWithLock() (gas: 448187)
|
||||
EmergencyExitTest:test_EmergencyExitWithRewards() (gas: 435625)
|
||||
EmergencyExitTest:test_OnlyOwnerCanEnableEmergencyMode() (gas: 39462)
|
||||
FuzzTests:testFuzz_AccrueMP(uint256,uint256,uint16) (runs: 1000, μ: 521104, ~: 515988)
|
||||
FuzzTests:testFuzz_EmergencyExit(uint256,uint256) (runs: 1000, μ: 510621, ~: 501981)
|
||||
FuzzTests:testFuzz_Rewards(uint256,uint256,uint256,uint16,uint16) (runs: 1000, μ: 604657, ~: 605935)
|
||||
FuzzTests:testFuzz_Stake(uint256,uint256) (runs: 1000, μ: 404073, ~: 395433)
|
||||
FuzzTests:testFuzz_Unstake(uint256,uint256,uint16,uint256) (runs: 1000, μ: 530258, ~: 529949)
|
||||
FuzzTests:testFuzz_AccrueMP(uint256,uint256,uint16) (runs: 1000, μ: 521120, ~: 515988)
|
||||
FuzzTests:testFuzz_EmergencyExit(uint256,uint256) (runs: 1000, μ: 510818, ~: 502017)
|
||||
FuzzTests:testFuzz_Rewards(uint256,uint256,uint256,uint16,uint16) (runs: 1000, μ: 604742, ~: 605988)
|
||||
FuzzTests:testFuzz_Stake(uint256,uint256) (runs: 1000, μ: 404270, ~: 395469)
|
||||
FuzzTests:testFuzz_Unstake(uint256,uint256,uint16,uint256) (runs: 1000, μ: 530267, ~: 529967)
|
||||
IntegrationTest:testStakeFoo() (gas: 1403381)
|
||||
KarmaMintAllowanceTest:testAddKarmaDistributorOnlyOwner() (gas: 348463)
|
||||
KarmaMintAllowanceTest:testBalanceOf() (gas: 428643)
|
||||
KarmaMintAllowanceTest:testBalanceOfWithNoSystemTotalKarma() (gas: 44170)
|
||||
KarmaMintAllowanceTest:testMintAllowance_Available() (gas: 340314)
|
||||
KarmaMintAllowanceTest:testMintAllowance_NotAvailable() (gas: 340317)
|
||||
KarmaMintAllowanceTest:testMintOnlyOwner() (gas: 377209)
|
||||
KarmaMintAllowanceTest:testMint_Ok() (gas: 405049)
|
||||
KarmaMintAllowanceTest:testMint_RevertWithAllowanceExceeded() (gas: 385796)
|
||||
KarmaMintAllowanceTest:testRemoveKarmaDistributorOnlyOwner() (gas: 76009)
|
||||
KarmaMintAllowanceTest:testRemoveUnknownKarmaDistributor() (gas: 36519)
|
||||
KarmaMintAllowanceTest:testTotalSupply() (gas: 336830)
|
||||
KarmaMintAllowanceTest:testTransfersNotAllowed() (gas: 20640)
|
||||
KarmaMintAllowanceTest:testAddKarmaDistributorOnlyOwner() (gas: 348441)
|
||||
KarmaMintAllowanceTest:testBalanceOf() (gas: 428754)
|
||||
KarmaMintAllowanceTest:testBalanceOfWithNoSystemTotalKarma() (gas: 44256)
|
||||
KarmaMintAllowanceTest:testMintAllowance_Available() (gas: 340382)
|
||||
KarmaMintAllowanceTest:testMintAllowance_NotAvailable() (gas: 340385)
|
||||
KarmaMintAllowanceTest:testMintOnlyOwner() (gas: 377255)
|
||||
KarmaMintAllowanceTest:testMint_Ok() (gas: 405095)
|
||||
KarmaMintAllowanceTest:testMint_RevertWithAllowanceExceeded() (gas: 385842)
|
||||
KarmaMintAllowanceTest:testRemoveKarmaDistributorOnlyOwner() (gas: 75943)
|
||||
KarmaMintAllowanceTest:testRemoveUnknownKarmaDistributor() (gas: 36497)
|
||||
KarmaMintAllowanceTest:testTotalSupply() (gas: 336898)
|
||||
KarmaMintAllowanceTest:testTransfersNotAllowed() (gas: 20663)
|
||||
KarmaNFTTest:testApproveNotAllowed() (gas: 10500)
|
||||
KarmaNFTTest:testGetApproved() (gas: 10523)
|
||||
KarmaNFTTest:testIsApprovedForAll() (gas: 10698)
|
||||
@@ -35,20 +35,20 @@ KarmaNFTTest:testSetMetadataGenerator() (gas: 966687)
|
||||
KarmaNFTTest:testSetMetadataGeneratorRevert() (gas: 963218)
|
||||
KarmaNFTTest:testTokenURI() (gas: 102963)
|
||||
KarmaNFTTest:testTransferNotAllowed() (gas: 10715)
|
||||
KarmaOwnershipTest:testInitialOwner() (gas: 12634)
|
||||
KarmaOwnershipTest:testOwnershipTransfer() (gas: 87258)
|
||||
KarmaTest:testAddKarmaDistributorOnlyOwner() (gas: 348451)
|
||||
KarmaTest:testBalanceOf() (gas: 428613)
|
||||
KarmaTest:testBalanceOfWithNoSystemTotalKarma() (gas: 44214)
|
||||
KarmaTest:testMintOnlyOwner() (gas: 377173)
|
||||
KarmaTest:testRemoveKarmaDistributorOnlyOwner() (gas: 75952)
|
||||
KarmaTest:testRemoveUnknownKarmaDistributor() (gas: 36513)
|
||||
KarmaTest:testTotalSupply() (gas: 336800)
|
||||
KarmaTest:testTransfersNotAllowed() (gas: 20662)
|
||||
LeaveTest:test_LeaveShouldProperlyUpdateAccounting() (gas: 7249868)
|
||||
KarmaOwnershipTest:testInitialOwner() (gas: 12612)
|
||||
KarmaOwnershipTest:testOwnershipTransfer() (gas: 87170)
|
||||
KarmaTest:testAddKarmaDistributorOnlyOwner() (gas: 348429)
|
||||
KarmaTest:testBalanceOf() (gas: 428724)
|
||||
KarmaTest:testBalanceOfWithNoSystemTotalKarma() (gas: 44300)
|
||||
KarmaTest:testMintOnlyOwner() (gas: 377219)
|
||||
KarmaTest:testRemoveKarmaDistributorOnlyOwner() (gas: 75886)
|
||||
KarmaTest:testRemoveUnknownKarmaDistributor() (gas: 36491)
|
||||
KarmaTest:testTotalSupply() (gas: 336868)
|
||||
KarmaTest:testTransfersNotAllowed() (gas: 20685)
|
||||
LeaveTest:test_LeaveShouldProperlyUpdateAccounting() (gas: 8942756)
|
||||
LeaveTest:test_RevertWhenStakeManagerIsTrusted() (gas: 350352)
|
||||
LeaveTest:test_TrustNewStakeManager() (gas: 7302750)
|
||||
LockTest:test_LockFailsWithInvalidPeriod(uint256) (runs: 1000, μ: 406918, ~: 406944)
|
||||
LeaveTest:test_TrustNewStakeManager() (gas: 8995615)
|
||||
LockTest:test_LockFailsWithInvalidPeriod(uint256) (runs: 1000, μ: 406917, ~: 406944)
|
||||
LockTest:test_LockFailsWithNoStake() (gas: 114574)
|
||||
LockTest:test_LockFailsWithZero() (gas: 367631)
|
||||
LockTest:test_LockWithoutPriorLock() (gas: 465087)
|
||||
@@ -67,12 +67,12 @@ NFTMetadataGeneratorSVGTest:testSetImageStringsRevert() (gas: 35804)
|
||||
NFTMetadataGeneratorURLTest:testGenerateMetadata() (gas: 101558)
|
||||
NFTMetadataGeneratorURLTest:testSetBaseURL() (gas: 49555)
|
||||
NFTMetadataGeneratorURLTest:testSetBaseURLRevert() (gas: 35979)
|
||||
RewardsStreamerMP_RewardsTest:testRewardsBalanceOf() (gas: 1309798)
|
||||
RewardsStreamerMP_RewardsTest:testSetRewards() (gas: 219337)
|
||||
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsBadAmount() (gas: 56162)
|
||||
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsBadDuration() (gas: 95940)
|
||||
RewardsStreamerMP_RewardsTest:testRewardsBalanceOf() (gas: 1309888)
|
||||
RewardsStreamerMP_RewardsTest:testSetRewards() (gas: 219382)
|
||||
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsBadAmount() (gas: 56207)
|
||||
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsBadDuration() (gas: 95985)
|
||||
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsNotAuthorized() (gas: 39295)
|
||||
RewardsStreamerMP_RewardsTest:testTotalRewardsSupply() (gas: 746903)
|
||||
RewardsStreamerMP_RewardsTest:testTotalRewardsSupply() (gas: 746993)
|
||||
StakeTest:test_StakeMultipleAccounts() (gas: 591097)
|
||||
StakeTest:test_StakeMultipleAccountsAndRewards() (gas: 599025)
|
||||
StakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 1024300)
|
||||
@@ -110,6 +110,6 @@ UnstakeTest:test_UnstakeOneAccountAndAccruedMP() (gas: 592850)
|
||||
UnstakeTest:test_UnstakeOneAccountAndRewards() (gas: 488388)
|
||||
UnstakeTest:test_UnstakeOneAccountWithLockUpAndAccruedMP() (gas: 622983)
|
||||
UpgradeTest:test_RevertWhenNotOwner() (gas: 3399068)
|
||||
UpgradeTest:test_UpgradeStakeManager() (gas: 7137669)
|
||||
UpgradeTest:test_UpgradeStakeManager() (gas: 8830553)
|
||||
VaultRegistrationTest:test_VaultRegistration() (gas: 62040)
|
||||
WithdrawTest:test_CannotWithdrawStakedFunds() (gas: 365961)
|
||||
@@ -9,7 +9,7 @@ import { Karma } from "../src/Karma.sol";
|
||||
contract DeployKarmaScript is BaseScript {
|
||||
function run() public returns (Karma) {
|
||||
DeploymentConfig deploymentConfig = new DeploymentConfig(broadcaster);
|
||||
(address deployer,) = deploymentConfig.activeNetworkConfig();
|
||||
(address deployer,,) = deploymentConfig.activeNetworkConfig();
|
||||
|
||||
vm.startBroadcast(deployer);
|
||||
address karma = address(new Karma());
|
||||
|
||||
@@ -15,7 +15,7 @@ import { VaultFactory } from "../src/VaultFactory.sol";
|
||||
contract DeployRewardsStreamerMPScript is BaseScript {
|
||||
function run() public returns (RewardsStreamerMP, VaultFactory, DeploymentConfig) {
|
||||
DeploymentConfig deploymentConfig = new DeploymentConfig(broadcaster);
|
||||
(address deployer, address stakingToken) = deploymentConfig.activeNetworkConfig();
|
||||
(address deployer, address stakingToken,) = deploymentConfig.activeNetworkConfig();
|
||||
|
||||
bytes memory initializeData = abi.encodeCall(RewardsStreamerMP.initialize, (deployer, stakingToken));
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ contract DeploymentConfig is Script {
|
||||
struct NetworkConfig {
|
||||
address deployer;
|
||||
address stakingToken;
|
||||
address currentImplProxy;
|
||||
}
|
||||
|
||||
NetworkConfig public activeNetworkConfig;
|
||||
@@ -22,6 +23,9 @@ contract DeploymentConfig is Script {
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
address internal SNT_ADDRESS_SEPOLIA = 0xE452027cdEF746c7Cd3DB31CB700428b16cD8E51;
|
||||
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
address internal STAKING_MANAGER_PROXY_ADDRESS_SEPOLIA = 0xD302Bd9F60c5192e46258028a2F3b4B2B846F61F;
|
||||
|
||||
constructor(address _broadcaster) {
|
||||
if (_broadcaster == address(0)) revert DeploymentConfig_InvalidDeployerAddress();
|
||||
deployer = _broadcaster;
|
||||
@@ -36,11 +40,15 @@ contract DeploymentConfig is Script {
|
||||
|
||||
function getOrCreateAnvilEthConfig() public returns (NetworkConfig memory) {
|
||||
MockToken stakingToken = new MockToken("Staking Token", "ST");
|
||||
return NetworkConfig({ deployer: deployer, stakingToken: address(stakingToken) });
|
||||
return NetworkConfig({ deployer: deployer, stakingToken: address(stakingToken), currentImplProxy: address(0) });
|
||||
}
|
||||
|
||||
function getSepoliaConfig() public view returns (NetworkConfig memory) {
|
||||
return NetworkConfig({ deployer: deployer, stakingToken: SNT_ADDRESS_SEPOLIA });
|
||||
return NetworkConfig({
|
||||
deployer: deployer,
|
||||
stakingToken: SNT_ADDRESS_SEPOLIA,
|
||||
currentImplProxy: STAKING_MANAGER_PROXY_ADDRESS_SEPOLIA
|
||||
});
|
||||
}
|
||||
|
||||
// This function is a hack to have it excluded by `forge coverage` until
|
||||
|
||||
@@ -5,9 +5,16 @@ import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils
|
||||
import { BaseScript } from "./Base.s.sol";
|
||||
import { RewardsStreamerMP } from "../src/RewardsStreamerMP.sol";
|
||||
import { IStakeManagerProxy } from "../src/interfaces/IStakeManagerProxy.sol";
|
||||
import { DeploymentConfig } from "./DeploymentConfig.s.sol";
|
||||
|
||||
contract UpgradeRewardsStreamerMPScript is BaseScript {
|
||||
function run(address admin, IStakeManagerProxy currentImplProxy) public {
|
||||
function run() public returns (address) {
|
||||
DeploymentConfig deploymentConfig = new DeploymentConfig(broadcaster);
|
||||
(address deployer,, address currentImplProxy) = deploymentConfig.activeNetworkConfig();
|
||||
return runWithAdminAndProxy(deployer, IStakeManagerProxy(currentImplProxy));
|
||||
}
|
||||
|
||||
function runWithAdminAndProxy(address admin, IStakeManagerProxy currentImplProxy) public returns (address) {
|
||||
address deployer = broadcaster;
|
||||
if (admin != address(0)) {
|
||||
deployer = admin;
|
||||
@@ -18,5 +25,6 @@ contract UpgradeRewardsStreamerMPScript is BaseScript {
|
||||
bytes memory initializeData;
|
||||
UUPSUpgradeable(address(currentImplProxy)).upgradeToAndCall(nextImpl, initializeData);
|
||||
vm.stopBroadcast();
|
||||
return nextImpl;
|
||||
}
|
||||
}
|
||||
|
||||
117
src/Karma.sol
117
src/Karma.sol
@@ -14,6 +14,17 @@ import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableS
|
||||
contract Karma is ERC20, Ownable2Step {
|
||||
using EnumerableSet for EnumerableSet.AddressSet;
|
||||
|
||||
error Karma__TransfersNotAllowed();
|
||||
error Karma__MintAllowanceExceeded();
|
||||
error Karma__DistributorAlreadyAdded();
|
||||
error Karma__UnknownDistributor();
|
||||
|
||||
event RewardDistributorAdded(address distributor);
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
STATE VARIABLES
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/// @notice The name of the token
|
||||
string public constant NAME = "Karma";
|
||||
/// @notice The symbol of the token
|
||||
@@ -26,15 +37,16 @@ contract Karma is ERC20, Ownable2Step {
|
||||
/// @notice Mapping of reward distributor to allocation
|
||||
mapping(address distributor => uint256 allocation) public rewardDistributorAllocations;
|
||||
|
||||
error Karma__TransfersNotAllowed();
|
||||
error Karma__MintAllowanceExceeded();
|
||||
error Karma__DistributorAlreadyAdded();
|
||||
error Karma__UnknownDistributor();
|
||||
|
||||
event RewardDistributorAdded(address distributor);
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
CONSTRUCTOR
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
constructor() ERC20(NAME, SYMBOL) Ownable(msg.sender) { }
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
USER-FACING FUNCTIONS
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* @notice Adds a reward distributor to the set of reward distributors.
|
||||
* @dev Only the owner can add a reward distributor.
|
||||
@@ -81,27 +93,6 @@ contract Karma is ERC20, Ownable2Step {
|
||||
IRewardDistributor(rewardsDistributor).setReward(amount, duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the reward distributors.
|
||||
* @return The reward distributors.
|
||||
*/
|
||||
function getRewardDistributors() external view returns (address[] memory) {
|
||||
return rewardDistributors.values();
|
||||
}
|
||||
|
||||
function _totalSupply() public view returns (uint256) {
|
||||
return super.totalSupply() + _externalSupply();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the total supply of the token.
|
||||
* @dev The total supply is the sum of the token supply and the external supply.
|
||||
* @return The total supply of the token.
|
||||
*/
|
||||
function totalSupply() public view override returns (uint256) {
|
||||
return _totalSupply();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Mints tokens to an account.
|
||||
* @dev Only the owner can mint tokens.
|
||||
@@ -117,6 +108,26 @@ contract Karma is ERC20, Ownable2Step {
|
||||
_mint(account, amount);
|
||||
}
|
||||
|
||||
function transfer(address, uint256) public pure override returns (bool) {
|
||||
revert Karma__TransfersNotAllowed();
|
||||
}
|
||||
|
||||
function approve(address, uint256) public pure override returns (bool) {
|
||||
revert Karma__TransfersNotAllowed();
|
||||
}
|
||||
|
||||
function transferFrom(address, address, uint256) public pure override returns (bool) {
|
||||
revert Karma__TransfersNotAllowed();
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
INTERNAL FUNCTIONS
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
function _totalSupply() internal view returns (uint256) {
|
||||
return super.totalSupply() + _externalSupply();
|
||||
}
|
||||
|
||||
function _mintAllowance() internal view returns (uint256) {
|
||||
uint256 maxSupply = _externalSupply() * 3;
|
||||
uint256 fullTotalSupply = _totalSupply();
|
||||
@@ -127,15 +138,6 @@ contract Karma is ERC20, Ownable2Step {
|
||||
return maxSupply - fullTotalSupply;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the mint allowance.
|
||||
* @dev The mint allowance is the difference between the external supply and the total supply.
|
||||
* @return The mint allowance.
|
||||
*/
|
||||
function mintAllowance() public view returns (uint256) {
|
||||
return _mintAllowance();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the external supply of the token.
|
||||
* @dev The external supply is the sum of the rewards from all reward distributors.
|
||||
@@ -153,10 +155,39 @@ contract Karma is ERC20, Ownable2Step {
|
||||
|
||||
externalSupply += supply;
|
||||
}
|
||||
|
||||
return externalSupply;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
VIEW FUNCTIONS
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* @notice Returns the total supply of the token.
|
||||
* @dev The total supply is the sum of the token supply and the external supply.
|
||||
* @return The total supply of the token.
|
||||
*/
|
||||
function totalSupply() public view override returns (uint256) {
|
||||
return _totalSupply();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the reward distributors.
|
||||
* @return The reward distributors.
|
||||
*/
|
||||
function getRewardDistributors() external view returns (address[] memory) {
|
||||
return rewardDistributors.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the mint allowance.
|
||||
* @dev The mint allowance is the difference between the external supply and the total supply.
|
||||
* @return The mint allowance.
|
||||
*/
|
||||
function mintAllowance() public view returns (uint256) {
|
||||
return _mintAllowance();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the balance of an account.
|
||||
* @dev The balance of an account is the sum of the balance of the account and the external rewards
|
||||
@@ -174,18 +205,6 @@ contract Karma is ERC20, Ownable2Step {
|
||||
return super.balanceOf(account) + externalBalance;
|
||||
}
|
||||
|
||||
function transfer(address, uint256) public pure override returns (bool) {
|
||||
revert Karma__TransfersNotAllowed();
|
||||
}
|
||||
|
||||
function approve(address, uint256) public pure override returns (bool) {
|
||||
revert Karma__TransfersNotAllowed();
|
||||
}
|
||||
|
||||
function transferFrom(address, address, uint256) public pure override returns (bool) {
|
||||
revert Karma__TransfersNotAllowed();
|
||||
}
|
||||
|
||||
function allowance(address, address) public pure override returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -27,33 +27,6 @@ contract RewardsStreamerMP is
|
||||
IRewardDistributor,
|
||||
StakeMath
|
||||
{
|
||||
/// @notice Token that is staked in the vaults (SNT).
|
||||
IERC20 public STAKING_TOKEN;
|
||||
/// @notice Scale factor used for rewards calculation.
|
||||
uint256 public constant SCALE_FACTOR = 1e27;
|
||||
|
||||
uint256 public totalStaked;
|
||||
/// @notice Total multiplier points accrued.
|
||||
uint256 public totalMPAccrued;
|
||||
/// @notice Total maximum multiplier points that can be accrued.
|
||||
uint256 public totalMaxMP;
|
||||
/// @notice Index of the current reward period.
|
||||
uint256 public rewardIndex;
|
||||
/// @notice Time of the last multiplier points update.
|
||||
uint256 public lastMPUpdatedTime;
|
||||
/// @notice Flag to enable emergency mode.
|
||||
bool public emergencyModeEnabled;
|
||||
/// @notice Total rewards accrued in the system.
|
||||
uint256 public totalRewardsAccrued;
|
||||
/// @notice Amount of rewards available for distribution.
|
||||
uint256 public rewardAmount;
|
||||
/// @notice Time of the last reward update.
|
||||
uint256 public lastRewardTime;
|
||||
/// @notice Time when rewards start.
|
||||
uint256 public rewardStartTime;
|
||||
/// @notice Time when rewards end.
|
||||
uint256 public rewardEndTime;
|
||||
|
||||
struct VaultData {
|
||||
uint256 stakedBalance;
|
||||
uint256 rewardIndex;
|
||||
@@ -65,17 +38,46 @@ contract RewardsStreamerMP is
|
||||
uint256 rewardsAccrued;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
STATE VARIABLES
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/// @notice Token that is staked in the vaults (SNT).
|
||||
IERC20 public STAKING_TOKEN;
|
||||
/// @notice Scale factor used for rewards calculation.
|
||||
uint256 public constant SCALE_FACTOR = 1e27;
|
||||
/// @notice Total staked balance in the system.
|
||||
uint256 public totalStaked;
|
||||
/// @notice Total amount of staked multiplier points
|
||||
uint256 public totalMPStaked;
|
||||
/// @notice Total multiplier points accrued.
|
||||
uint256 public totalMPAccrued;
|
||||
/// @notice Total rewards accrued in the system.
|
||||
uint256 public totalRewardsAccrued;
|
||||
/// @notice Total maximum multiplier points that can be accrued.
|
||||
uint256 public totalMaxMP;
|
||||
/// @notice Time of the last multiplier points update.
|
||||
uint256 public lastMPUpdatedTime;
|
||||
/// @notice Index of the current reward period.
|
||||
uint256 public rewardIndex;
|
||||
/// @notice The address that can set rewards
|
||||
address public rewardsSupplier;
|
||||
/// @notice Amount of rewards available for distribution.
|
||||
uint256 public rewardAmount;
|
||||
/// @notice Time of the last reward update.
|
||||
uint256 public lastRewardTime;
|
||||
/// @notice Time when rewards start.
|
||||
uint256 public rewardStartTime;
|
||||
/// @notice Time when rewards end.
|
||||
uint256 public rewardEndTime;
|
||||
/// @notice Maps vault addresses to vault data
|
||||
mapping(address vault => VaultData data) public vaultData;
|
||||
/// @notice Maps Account address to a list of vaults
|
||||
mapping(address owner => address[] vault) public vaults;
|
||||
/// @notice Maps vault addresses to their owners
|
||||
mapping(address vault => address owner) public vaultOwners;
|
||||
/// @notice Total amount of staked multiplier points
|
||||
uint256 public totalMPStaked;
|
||||
|
||||
/// @notice The address that can set rewards
|
||||
address public rewardsSupplier;
|
||||
/// @notice Flag to enable emergency mode.
|
||||
bool public emergencyModeEnabled;
|
||||
|
||||
modifier onlyRegisteredVault() {
|
||||
if (vaultOwners[msg.sender] == address(0)) {
|
||||
@@ -98,6 +100,10 @@ contract RewardsStreamerMP is
|
||||
_;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
CONSTRUCTOR
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* @notice Initializes the contract.
|
||||
* @dev Disables initializers to prevent reinitialization.
|
||||
@@ -106,13 +112,17 @@ contract RewardsStreamerMP is
|
||||
_disableInitializers();
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
USER-FACING FUNCTIONS
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* @notice Initializes the contract with the provided owner and staking token.
|
||||
* @dev Also sets the initial `lastMPUpdatedTime`
|
||||
* @param _owner Address of the owner of the contract.
|
||||
* @param _stakingToken Address of the staking token.
|
||||
*/
|
||||
function initialize(address _owner, address _stakingToken) public initializer {
|
||||
function initialize(address _owner, address _stakingToken) external initializer {
|
||||
__TrustedCodehashAccess_init(_owner);
|
||||
__UUPSUpgradeable_init();
|
||||
__ReentrancyGuard_init();
|
||||
@@ -130,14 +140,6 @@ contract RewardsStreamerMP is
|
||||
rewardsSupplier = _rewardsSupplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Authorizes contract upgrades via UUPS.
|
||||
* @dev This function is only callable by the owner.
|
||||
*/
|
||||
function _authorizeUpgrade(address) internal view override {
|
||||
_checkOwner();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Registers a vault with its owner. Called by the vault itself during initialization.
|
||||
* @dev Only callable by contracts with trusted codehash
|
||||
@@ -160,64 +162,6 @@ contract RewardsStreamerMP is
|
||||
emit VaultRegistered(vault, owner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get the vaults owned by a user
|
||||
* @param account The address of the user
|
||||
* @return The vaults owned by the user
|
||||
*/
|
||||
function getAccountVaults(address account) external view returns (address[] memory) {
|
||||
return vaults[account];
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get the total multiplier points for a user
|
||||
* @dev Iterates over all vaults owned by the user and sums the multiplier points
|
||||
* @param account The address of the user
|
||||
* @return The total multiplier points for the user
|
||||
*/
|
||||
function mpBalanceOfAccount(address account) external view returns (uint256) {
|
||||
address[] memory accountVaults = vaults[account];
|
||||
uint256 accountTotalMP = 0;
|
||||
|
||||
for (uint256 i = 0; i < accountVaults.length; i++) {
|
||||
VaultData storage vault = vaultData[accountVaults[i]];
|
||||
accountTotalMP += vault.mpAccrued + _getVaultPendingMP(vault);
|
||||
}
|
||||
return accountTotalMP;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get the total maximum multiplier points for a user
|
||||
* @dev Iterates over all vaults owned by the user and sums the maximum multiplier points
|
||||
* @param account The address of the user
|
||||
* @return The total maximum multiplier points for the user
|
||||
*/
|
||||
function getAccountTotalMaxMP(address account) external view returns (uint256) {
|
||||
address[] memory accountVaults = vaults[account];
|
||||
uint256 accountTotalMaxMP = 0;
|
||||
|
||||
for (uint256 i = 0; i < accountVaults.length; i++) {
|
||||
accountTotalMaxMP += vaultData[accountVaults[i]].maxMP;
|
||||
}
|
||||
return accountTotalMaxMP;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get the total staked balance for a user
|
||||
* @dev Iterates over all vaults owned by the user and sums the staked balances
|
||||
* @param account The address of the user
|
||||
* @return The total staked balance for the user
|
||||
*/
|
||||
function getAccountTotalStakedBalance(address account) external view returns (uint256) {
|
||||
address[] memory accountVaults = vaults[account];
|
||||
uint256 accountTotalStake = 0;
|
||||
|
||||
for (uint256 i = 0; i < accountVaults.length; i++) {
|
||||
accountTotalStake += vaultData[accountVaults[i]].stakedBalance;
|
||||
}
|
||||
return accountTotalStake;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Allows users to stake and start accruing MPs.
|
||||
* @dev Called by trusted `StakeVault`.
|
||||
@@ -337,31 +281,6 @@ contract RewardsStreamerMP is
|
||||
emit Unstaked(msg.sender, amount);
|
||||
}
|
||||
|
||||
function _unstake(uint256 amount, VaultData storage vault, address vaultAddress) internal {
|
||||
_updateGlobalState();
|
||||
_updateVault(vaultAddress, true);
|
||||
|
||||
(uint256 _deltaMpTotal, uint256 _deltaMpMax) = _calculateUnstake(
|
||||
vault.stakedBalance, vault.lockUntil, block.timestamp, vault.mpAccrued, vault.maxMP, amount
|
||||
);
|
||||
vault.stakedBalance -= amount;
|
||||
vault.maxMP -= _deltaMpMax;
|
||||
vault.rewardIndex = rewardIndex;
|
||||
vault.mpAccrued -= _deltaMpTotal;
|
||||
|
||||
// A vault's "staked" MP will be reduced if the accrued MP is less than the staked MP.
|
||||
// This is because the accrued MP represents the vault's total MP
|
||||
if (vault.mpAccrued < vault.mpStaked) {
|
||||
totalMPStaked -= vault.mpStaked - vault.mpAccrued;
|
||||
vault.mpStaked = vault.mpAccrued;
|
||||
totalMPStaked -= vault.mpStaked - vault.mpAccrued;
|
||||
}
|
||||
|
||||
totalMPAccrued -= _deltaMpTotal;
|
||||
totalMaxMP -= _deltaMpMax;
|
||||
totalStaked -= amount;
|
||||
}
|
||||
|
||||
// @notice Allows an account to leave the system. This can happen when a
|
||||
// user doesn't agree with an upgrade of the stake manager.
|
||||
// @dev This function is protected by whitelisting the codehash of the caller.
|
||||
@@ -384,52 +303,15 @@ contract RewardsStreamerMP is
|
||||
emit AccountLeft(msg.sender);
|
||||
}
|
||||
|
||||
function _updateGlobalState() internal {
|
||||
updateGlobalMP();
|
||||
updateRewardIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Allows the owner to update the global state.
|
||||
* @dev This function is only callable when emergency mode is disabled.
|
||||
* @dev Takes care of updating the global MP and reward index.
|
||||
*/
|
||||
function updateGlobalState() external onlyNotEmergencyMode {
|
||||
_updateGlobalState();
|
||||
}
|
||||
|
||||
function updateGlobalMP() internal {
|
||||
uint256 newTotalMPAccrued = _liveTotalMP();
|
||||
if (newTotalMPAccrued > totalMPAccrued) {
|
||||
totalMPAccrued = newTotalMPAccrued;
|
||||
lastMPUpdatedTime = block.timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the total multiplier points accrued in the system.
|
||||
* @return The total multiplier points accrued in the system.
|
||||
*/
|
||||
function totalMP() external view returns (uint256) {
|
||||
return _liveTotalMP();
|
||||
}
|
||||
|
||||
function _liveTotalMP() internal view returns (uint256) {
|
||||
if (totalMaxMP == 0) {
|
||||
return totalMPAccrued;
|
||||
}
|
||||
|
||||
uint256 currentTime = block.timestamp;
|
||||
uint256 timeDiff = currentTime - lastMPUpdatedTime;
|
||||
if (timeDiff == 0) {
|
||||
return totalMPAccrued;
|
||||
}
|
||||
|
||||
uint256 accruedMP = _accrueMP(totalStaked, timeDiff);
|
||||
if (totalMPAccrued + accruedMP > totalMaxMP) {
|
||||
accruedMP = totalMaxMP - totalMPAccrued;
|
||||
}
|
||||
|
||||
uint256 newTotalMPAccrued = totalMPAccrued + accruedMP;
|
||||
|
||||
return newTotalMPAccrued;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Allows an admin to set the reward amount and duration.
|
||||
* @dev This function is only callable by the owner.
|
||||
@@ -460,65 +342,6 @@ contract RewardsStreamerMP is
|
||||
rewardEndTime = block.timestamp + duration;
|
||||
}
|
||||
|
||||
function _calculatePendingRewards() internal view returns (uint256) {
|
||||
if (rewardEndTime <= rewardStartTime) {
|
||||
// No active reward period
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint256 currentTime = block.timestamp < rewardEndTime ? block.timestamp : rewardEndTime;
|
||||
|
||||
if (currentTime <= lastRewardTime) {
|
||||
// No new rewards have accrued since lastRewardTime
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint256 timeElapsed = currentTime - lastRewardTime;
|
||||
uint256 duration = rewardEndTime - rewardStartTime;
|
||||
|
||||
if (duration == 0) {
|
||||
// Prevent division by zero
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint256 accruedRewards = Math.mulDiv(timeElapsed, rewardAmount, duration);
|
||||
return accruedRewards;
|
||||
}
|
||||
|
||||
function updateRewardIndex() internal {
|
||||
uint256 accruedRewards;
|
||||
uint256 newRewardIndex;
|
||||
|
||||
(accruedRewards, newRewardIndex) = _liveRewardIndex();
|
||||
totalRewardsAccrued += accruedRewards;
|
||||
|
||||
if (newRewardIndex > rewardIndex) {
|
||||
rewardIndex = newRewardIndex;
|
||||
lastRewardTime = block.timestamp < rewardEndTime ? block.timestamp : rewardEndTime;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the total shares in the system.
|
||||
* @dev Total shares are total staked tokens and total multiplier points staked.
|
||||
* @return The total shares in the system.
|
||||
*/
|
||||
function totalShares() external view returns (uint256) {
|
||||
return _totalShares();
|
||||
}
|
||||
|
||||
function _totalShares() internal view returns (uint256) {
|
||||
return totalStaked + totalMPStaked;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the total shares of a given vault.
|
||||
* @return The total vault shares
|
||||
*/
|
||||
function vaultShares(address vaultAddress) external view returns (uint256) {
|
||||
return _vaultShares(vaultAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Allows users to compound their accrued MP.
|
||||
* @dev This function is only callable when emergency mode is disabled.
|
||||
@@ -541,64 +364,6 @@ contract RewardsStreamerMP is
|
||||
emit Compound(vaultAddress, mpToStake);
|
||||
}
|
||||
|
||||
function _vaultShares(address vaultAddress) internal view returns (uint256) {
|
||||
VaultData storage vault = vaultData[vaultAddress];
|
||||
return vault.stakedBalance + vault.mpStaked;
|
||||
}
|
||||
|
||||
function _liveRewardIndex() internal view returns (uint256, uint256) {
|
||||
uint256 shares = _totalShares();
|
||||
|
||||
if (shares == 0) {
|
||||
return (0, rewardIndex);
|
||||
}
|
||||
|
||||
uint256 currentTime = block.timestamp;
|
||||
uint256 applicableTime = rewardEndTime > currentTime ? currentTime : rewardEndTime;
|
||||
uint256 elapsedTime = applicableTime - lastRewardTime;
|
||||
|
||||
if (elapsedTime == 0) {
|
||||
return (0, rewardIndex);
|
||||
}
|
||||
|
||||
uint256 accruedRewards = _calculatePendingRewards();
|
||||
if (accruedRewards == 0) {
|
||||
return (0, rewardIndex);
|
||||
}
|
||||
|
||||
uint256 newRewardIndex = rewardIndex + Math.mulDiv(accruedRewards, SCALE_FACTOR, shares);
|
||||
|
||||
return (accruedRewards, newRewardIndex);
|
||||
}
|
||||
|
||||
function _getVaultPendingMP(VaultData storage vault) internal view returns (uint256) {
|
||||
if (block.timestamp == vault.lastMPUpdateTime) {
|
||||
return 0;
|
||||
}
|
||||
if (vault.maxMP == 0 || vault.stakedBalance == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint256 deltaMP = _calculateAccrual(
|
||||
vault.stakedBalance, vault.mpAccrued, vault.maxMP, vault.lastMPUpdateTime, block.timestamp
|
||||
);
|
||||
|
||||
return deltaMP;
|
||||
}
|
||||
|
||||
function _updateVault(address vaultAddress, bool forceMPUpdate) internal {
|
||||
VaultData storage vault = vaultData[vaultAddress];
|
||||
uint256 accruedMP = _getVaultPendingMP(vault);
|
||||
if (accruedMP > 0 || forceMPUpdate) {
|
||||
vault.mpAccrued += accruedMP;
|
||||
vault.lastMPUpdateTime = block.timestamp;
|
||||
}
|
||||
|
||||
uint256 rewardsAccrued = _vaultPendingRewards(vault);
|
||||
vault.rewardsAccrued += rewardsAccrued;
|
||||
vault.rewardIndex = rewardIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Allows users to claim their accrued rewards.
|
||||
* @dev This function is only callable when emergency mode is disabled.
|
||||
@@ -618,87 +383,6 @@ contract RewardsStreamerMP is
|
||||
emit EmergencyModeEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the staked balance of a vault.
|
||||
* @param vaultAddress The address of the vault.
|
||||
*/
|
||||
function getStakedBalance(address vaultAddress) public view returns (uint256) {
|
||||
return vaultData[vaultAddress].stakedBalance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns vault data for a given vault address.
|
||||
* @return Vault data for the given vault address
|
||||
*/
|
||||
function getVault(address vaultAddress) external view returns (VaultData memory) {
|
||||
return vaultData[vaultAddress];
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns total rewards supply in the system.
|
||||
* @return Total rewards supply in the system.
|
||||
*/
|
||||
function totalRewardsSupply() public view returns (uint256) {
|
||||
return totalRewardsAccrued + _calculatePendingRewards();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the rewards balance of a vault.
|
||||
* @return Rewards balance of the vault.
|
||||
*/
|
||||
function rewardsBalanceOf(address vaultAddress) public view returns (uint256) {
|
||||
VaultData storage vault = vaultData[vaultAddress];
|
||||
return vault.rewardsAccrued + _vaultPendingRewards(vault);
|
||||
}
|
||||
|
||||
function _vaultPendingRewards(VaultData storage vault) internal view returns (uint256) {
|
||||
uint256 newRewardIndex;
|
||||
(, newRewardIndex) = _liveRewardIndex();
|
||||
|
||||
uint256 accountShares = vault.stakedBalance + vault.mpStaked;
|
||||
uint256 deltaRewardIndex = newRewardIndex - vault.rewardIndex;
|
||||
|
||||
return (accountShares * deltaRewardIndex) / SCALE_FACTOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the rewards balance of an account.
|
||||
* @dev Iterates over all vaults owned by the account and sums the rewards.
|
||||
* @return Rewards balance of the account.
|
||||
*/
|
||||
function rewardsBalanceOfAccount(address account) external view returns (uint256) {
|
||||
address[] memory accountVaults = vaults[account];
|
||||
uint256 accountTotalRewards = 0;
|
||||
|
||||
for (uint256 i = 0; i < accountVaults.length; i++) {
|
||||
accountTotalRewards += rewardsBalanceOf(accountVaults[i]);
|
||||
}
|
||||
|
||||
return accountTotalRewards;
|
||||
}
|
||||
|
||||
function _mpBalanceOf(address vaultAddress) internal view returns (uint256) {
|
||||
VaultData storage vault = vaultData[vaultAddress];
|
||||
return vault.mpAccrued + _getVaultPendingMP(vault);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the multiplier points balance of a vault.
|
||||
* @return Multiplier points balance of the vault.
|
||||
*/
|
||||
function mpBalanceOf(address vaultAddress) external view returns (uint256) {
|
||||
return _mpBalanceOf(vaultAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns staked multiplier points of a vault.
|
||||
* @return Staked multiplier points of the vault.
|
||||
*/
|
||||
function mpStakedOf(address vaultAddress) external view returns (uint256) {
|
||||
VaultData storage vault = vaultData[vaultAddress];
|
||||
return vault.mpStaked;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Migrate the staked balance of a vault to another vault.
|
||||
* @param migrateTo The address of the vault to migrate to.
|
||||
@@ -736,4 +420,342 @@ contract RewardsStreamerMP is
|
||||
|
||||
emit VaultMigrated(msg.sender, migrateTo);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
INTERNAL FUNCTIONS
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
function _updateGlobalState() internal {
|
||||
_updateGlobalMP();
|
||||
updateRewardIndex();
|
||||
}
|
||||
|
||||
function _updateGlobalMP() internal {
|
||||
uint256 newTotalMPAccrued = _liveTotalMP();
|
||||
if (newTotalMPAccrued > totalMPAccrued) {
|
||||
totalMPAccrued = newTotalMPAccrued;
|
||||
lastMPUpdatedTime = block.timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
function _updateVault(address vaultAddress, bool forceMPUpdate) internal {
|
||||
VaultData storage vault = vaultData[vaultAddress];
|
||||
uint256 accruedMP = _getVaultPendingMP(vault);
|
||||
if (accruedMP > 0 || forceMPUpdate) {
|
||||
vault.mpAccrued += accruedMP;
|
||||
vault.lastMPUpdateTime = block.timestamp;
|
||||
}
|
||||
|
||||
uint256 rewardsAccrued = _vaultPendingRewards(vault);
|
||||
vault.rewardsAccrued += rewardsAccrued;
|
||||
vault.rewardIndex = rewardIndex;
|
||||
}
|
||||
|
||||
function updateRewardIndex() internal {
|
||||
uint256 accruedRewards;
|
||||
uint256 newRewardIndex;
|
||||
|
||||
(accruedRewards, newRewardIndex) = _liveRewardIndex();
|
||||
totalRewardsAccrued += accruedRewards;
|
||||
|
||||
if (newRewardIndex > rewardIndex) {
|
||||
rewardIndex = newRewardIndex;
|
||||
lastRewardTime = block.timestamp < rewardEndTime ? block.timestamp : rewardEndTime;
|
||||
}
|
||||
}
|
||||
|
||||
function _unstake(uint256 amount, VaultData storage vault, address vaultAddress) internal {
|
||||
_updateGlobalState();
|
||||
_updateVault(vaultAddress, true);
|
||||
|
||||
(uint256 _deltaMpTotal, uint256 _deltaMpMax) = _calculateUnstake(
|
||||
vault.stakedBalance, vault.lockUntil, block.timestamp, vault.mpAccrued, vault.maxMP, amount
|
||||
);
|
||||
vault.stakedBalance -= amount;
|
||||
vault.maxMP -= _deltaMpMax;
|
||||
vault.rewardIndex = rewardIndex;
|
||||
vault.mpAccrued -= _deltaMpTotal;
|
||||
|
||||
// A vault's "staked" MP will be reduced if the accrued MP is less than the staked MP.
|
||||
// This is because the accrued MP represents the vault's total MP
|
||||
if (vault.mpAccrued < vault.mpStaked) {
|
||||
totalMPStaked -= vault.mpStaked - vault.mpAccrued;
|
||||
vault.mpStaked = vault.mpAccrued;
|
||||
totalMPStaked -= vault.mpStaked - vault.mpAccrued;
|
||||
}
|
||||
|
||||
totalMPAccrued -= _deltaMpTotal;
|
||||
totalMaxMP -= _deltaMpMax;
|
||||
totalStaked -= amount;
|
||||
}
|
||||
|
||||
function _totalShares() internal view returns (uint256) {
|
||||
return totalStaked + totalMPStaked;
|
||||
}
|
||||
|
||||
function _vaultShares(address vaultAddress) internal view returns (uint256) {
|
||||
VaultData storage vault = vaultData[vaultAddress];
|
||||
return vault.stakedBalance + vault.mpStaked;
|
||||
}
|
||||
|
||||
function _liveTotalMP() internal view returns (uint256) {
|
||||
if (totalMaxMP == 0) {
|
||||
return totalMPAccrued;
|
||||
}
|
||||
|
||||
uint256 currentTime = block.timestamp;
|
||||
uint256 timeDiff = currentTime - lastMPUpdatedTime;
|
||||
if (timeDiff == 0) {
|
||||
return totalMPAccrued;
|
||||
}
|
||||
|
||||
uint256 accruedMP = _accrueMP(totalStaked, timeDiff);
|
||||
if (totalMPAccrued + accruedMP > totalMaxMP) {
|
||||
accruedMP = totalMaxMP - totalMPAccrued;
|
||||
}
|
||||
|
||||
uint256 newTotalMPAccrued = totalMPAccrued + accruedMP;
|
||||
|
||||
return newTotalMPAccrued;
|
||||
}
|
||||
|
||||
function _liveRewardIndex() internal view returns (uint256, uint256) {
|
||||
uint256 shares = _totalShares();
|
||||
|
||||
if (shares == 0) {
|
||||
return (0, rewardIndex);
|
||||
}
|
||||
|
||||
uint256 currentTime = block.timestamp;
|
||||
uint256 applicableTime = rewardEndTime > currentTime ? currentTime : rewardEndTime;
|
||||
uint256 elapsedTime = applicableTime - lastRewardTime;
|
||||
|
||||
if (elapsedTime == 0) {
|
||||
return (0, rewardIndex);
|
||||
}
|
||||
|
||||
uint256 accruedRewards = _calculatePendingRewards();
|
||||
if (accruedRewards == 0) {
|
||||
return (0, rewardIndex);
|
||||
}
|
||||
|
||||
uint256 newRewardIndex = rewardIndex + Math.mulDiv(accruedRewards, SCALE_FACTOR, shares);
|
||||
|
||||
return (accruedRewards, newRewardIndex);
|
||||
}
|
||||
|
||||
function _calculatePendingRewards() internal view returns (uint256) {
|
||||
if (rewardEndTime <= rewardStartTime) {
|
||||
// No active reward period
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint256 currentTime = block.timestamp < rewardEndTime ? block.timestamp : rewardEndTime;
|
||||
|
||||
if (currentTime <= lastRewardTime) {
|
||||
// No new rewards have accrued since lastRewardTime
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint256 timeElapsed = currentTime - lastRewardTime;
|
||||
uint256 duration = rewardEndTime - rewardStartTime;
|
||||
|
||||
if (duration == 0) {
|
||||
// Prevent division by zero
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint256 accruedRewards = Math.mulDiv(timeElapsed, rewardAmount, duration);
|
||||
return accruedRewards;
|
||||
}
|
||||
|
||||
function _getVaultPendingMP(VaultData storage vault) internal view returns (uint256) {
|
||||
if (block.timestamp == vault.lastMPUpdateTime) {
|
||||
return 0;
|
||||
}
|
||||
if (vault.maxMP == 0 || vault.stakedBalance == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint256 deltaMP = _calculateAccrual(
|
||||
vault.stakedBalance, vault.mpAccrued, vault.maxMP, vault.lastMPUpdateTime, block.timestamp
|
||||
);
|
||||
|
||||
return deltaMP;
|
||||
}
|
||||
|
||||
function _mpBalanceOf(address vaultAddress) internal view returns (uint256) {
|
||||
VaultData storage vault = vaultData[vaultAddress];
|
||||
return vault.mpAccrued + _getVaultPendingMP(vault);
|
||||
}
|
||||
|
||||
function _vaultPendingRewards(VaultData storage vault) internal view returns (uint256) {
|
||||
uint256 newRewardIndex;
|
||||
(, newRewardIndex) = _liveRewardIndex();
|
||||
|
||||
uint256 accountShares = vault.stakedBalance + vault.mpStaked;
|
||||
uint256 deltaRewardIndex = newRewardIndex - vault.rewardIndex;
|
||||
|
||||
return (accountShares * deltaRewardIndex) / SCALE_FACTOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Authorizes contract upgrades via UUPS.
|
||||
* @dev This function is only callable by the owner.
|
||||
*/
|
||||
function _authorizeUpgrade(address) internal view override {
|
||||
_checkOwner();
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
VIEW FUNCTIONS
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* @notice Get the vaults owned by a user
|
||||
* @param account The address of the user
|
||||
* @return The vaults owned by the user
|
||||
*/
|
||||
function getAccountVaults(address account) external view returns (address[] memory) {
|
||||
return vaults[account];
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the total multiplier points accrued in the system.
|
||||
* @return The total multiplier points accrued in the system.
|
||||
*/
|
||||
function totalMP() external view returns (uint256) {
|
||||
return _liveTotalMP();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the total shares in the system.
|
||||
* @dev Total shares are total staked tokens and total multiplier points staked.
|
||||
* @return The total shares in the system.
|
||||
*/
|
||||
function totalShares() external view returns (uint256) {
|
||||
return _totalShares();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns total rewards supply in the system.
|
||||
* @return Total rewards supply in the system.
|
||||
*/
|
||||
function totalRewardsSupply() external view returns (uint256) {
|
||||
return totalRewardsAccrued + _calculatePendingRewards();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the total shares of a given vault.
|
||||
* @return The total vault shares
|
||||
*/
|
||||
function vaultShares(address vaultAddress) external view returns (uint256) {
|
||||
return _vaultShares(vaultAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns vault data for a given vault address.
|
||||
* @return Vault data for the given vault address
|
||||
*/
|
||||
function getVault(address vaultAddress) external view returns (VaultData memory) {
|
||||
return vaultData[vaultAddress];
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the staked balance of a vault.
|
||||
* @param vaultAddress The address of the vault.
|
||||
*/
|
||||
function getStakedBalance(address vaultAddress) external view returns (uint256) {
|
||||
return vaultData[vaultAddress].stakedBalance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the rewards balance of a vault.
|
||||
* @return Rewards balance of the vault.
|
||||
*/
|
||||
function rewardsBalanceOf(address vaultAddress) public view returns (uint256) {
|
||||
VaultData storage vault = vaultData[vaultAddress];
|
||||
return vault.rewardsAccrued + _vaultPendingRewards(vault);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the multiplier points balance of a vault.
|
||||
* @return Multiplier points balance of the vault.
|
||||
*/
|
||||
function mpBalanceOf(address vaultAddress) external view returns (uint256) {
|
||||
return _mpBalanceOf(vaultAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns staked multiplier points of a vault.
|
||||
* @return Staked multiplier points of the vault.
|
||||
*/
|
||||
function mpStakedOf(address vaultAddress) external view returns (uint256) {
|
||||
VaultData storage vault = vaultData[vaultAddress];
|
||||
return vault.mpStaked;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get the total multiplier points for a user
|
||||
* @dev Iterates over all vaults owned by the user and sums the multiplier points
|
||||
* @param account The address of the user
|
||||
* @return The total multiplier points for the user
|
||||
*/
|
||||
function mpBalanceOfAccount(address account) external view returns (uint256) {
|
||||
address[] memory accountVaults = vaults[account];
|
||||
uint256 accountTotalMP = 0;
|
||||
|
||||
for (uint256 i = 0; i < accountVaults.length; i++) {
|
||||
VaultData storage vault = vaultData[accountVaults[i]];
|
||||
accountTotalMP += vault.mpAccrued + _getVaultPendingMP(vault);
|
||||
}
|
||||
return accountTotalMP;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get the total maximum multiplier points for a user
|
||||
* @dev Iterates over all vaults owned by the user and sums the maximum multiplier points
|
||||
* @param account The address of the user
|
||||
* @return The total maximum multiplier points for the user
|
||||
*/
|
||||
function getAccountTotalMaxMP(address account) external view returns (uint256) {
|
||||
address[] memory accountVaults = vaults[account];
|
||||
uint256 accountTotalMaxMP = 0;
|
||||
|
||||
for (uint256 i = 0; i < accountVaults.length; i++) {
|
||||
accountTotalMaxMP += vaultData[accountVaults[i]].maxMP;
|
||||
}
|
||||
return accountTotalMaxMP;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get the total staked balance for a user
|
||||
* @dev Iterates over all vaults owned by the user and sums the staked balances
|
||||
* @param account The address of the user
|
||||
* @return The total staked balance for the user
|
||||
*/
|
||||
function getAccountTotalStakedBalance(address account) external view returns (uint256) {
|
||||
address[] memory accountVaults = vaults[account];
|
||||
uint256 accountTotalStake = 0;
|
||||
|
||||
for (uint256 i = 0; i < accountVaults.length; i++) {
|
||||
accountTotalStake += vaultData[accountVaults[i]].stakedBalance;
|
||||
}
|
||||
return accountTotalStake;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the rewards balance of an account.
|
||||
* @dev Iterates over all vaults owned by the account and sums the rewards.
|
||||
* @return Rewards balance of the account.
|
||||
*/
|
||||
function rewardsBalanceOfAccount(address account) external view returns (uint256) {
|
||||
address[] memory accountVaults = vaults[account];
|
||||
uint256 accountTotalRewards = 0;
|
||||
|
||||
for (uint256 i = 0; i < accountVaults.length; i++) {
|
||||
accountTotalRewards += rewardsBalanceOf(accountVaults[i]);
|
||||
}
|
||||
return accountTotalRewards;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,10 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
|
||||
/// @notice Emitted when migration failed
|
||||
error StakeVault__MigrationFailed();
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
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
|
||||
@@ -55,6 +59,10 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
|
||||
_;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
CONSTRUCTOR
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* @notice Initializes the contract with the staking token address.
|
||||
* @dev The staking token address is immutable and cannot be changed after deployment.
|
||||
@@ -66,6 +74,10 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
|
||||
_disableInitializers();
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
USER-FACING FUNCTIONS
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* @notice Initializes the contract with the owner and the stake manager.
|
||||
* @dev Ensures that the stake manager implementation is trusted.
|
||||
@@ -96,14 +108,6 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
|
||||
stakeManager.registerVault();
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 Stake tokens for a specified time.
|
||||
* @dev This function is only callable by the owner.
|
||||
@@ -201,6 +205,21 @@ 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 onlyTrustedStakeManager {
|
||||
stakeManager.migrateToVault(migrateTo);
|
||||
bool success = STAKING_TOKEN.transfer(migrateTo, STAKING_TOKEN.balanceOf(address(this)));
|
||||
if (!success) {
|
||||
revert StakeVault__MigrationFailed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Withdraw tokens from the contract.
|
||||
* @dev This function is only callable by the owner.
|
||||
@@ -246,6 +265,10 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
|
||||
return _token.balanceOf(address(this));
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
INTERNAL FUNCTIONS
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* @notice Stakes tokens for a specified time.
|
||||
* @dev Reverts if the staking token transfer fails.
|
||||
@@ -290,14 +313,6 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
|
||||
_token.transfer(_destination, _amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the amount of tokens staked by the vault.
|
||||
* @return The amount of tokens staked.
|
||||
*/
|
||||
function amountStaked() public view returns (uint256) {
|
||||
return stakeManager.getStakedBalance(address(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Allows vaults to exit the system in case of emergency or the system is rigged.
|
||||
* @param _destination The address to receive the funds.
|
||||
@@ -328,18 +343,23 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
|
||||
return stakeManagerImplementationAddress == stakeManager.implementation();
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
VIEW FUNCTIONS
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* @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.
|
||||
* @notice Returns the address of the current owner.
|
||||
* @return The address of the owner.
|
||||
*/
|
||||
function migrateToVault(address migrateTo) external onlyOwner onlyTrustedStakeManager {
|
||||
stakeManager.migrateToVault(migrateTo);
|
||||
bool success = STAKING_TOKEN.transfer(migrateTo, STAKING_TOKEN.balanceOf(address(this)));
|
||||
if (!success) {
|
||||
revert StakeVault__MigrationFailed();
|
||||
}
|
||||
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.getStakedBalance(address(this));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,19 +26,27 @@ import { StakeVault } from "./StakeVault.sol";
|
||||
contract VaultFactory is Ownable {
|
||||
/// @notice Emitted when the provided `StakeManager` address is zero.
|
||||
error VaultFactory__InvalidStakeManagerAddress();
|
||||
|
||||
/// @notice Emitted when a new vault is created.
|
||||
|
||||
event VaultCreated(address indexed vault, address indexed owner);
|
||||
/// @notice Emitted when the `StakeManager` contract address is changed.
|
||||
event StakeManagerAddressChanged(address indexed newStakeManagerAddress);
|
||||
/// @notice Emitted when the `StakeVault` implementation contract address is changed.
|
||||
event VaultImplementationChanged(address indexed newVaultImplementation);
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
STATE VARIABLES
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/// @dev Address of the `StakeManager` contract instance.
|
||||
address public stakeManager;
|
||||
/// @dev Address of the `StakeVault` implementation contract.
|
||||
address public vaultImplementation;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
CONSTRUCTOR
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* @notice Creates a new `VaultFactory` contract.
|
||||
* @dev Reverts if the provided `_stakeManager` address is zero.
|
||||
@@ -54,6 +62,10 @@ contract VaultFactory is Ownable {
|
||||
vaultImplementation = _vaultImplementation;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
USER-FACING FUNCTIONS
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* @notice Sets the `StakeManager` contract address.
|
||||
* @dev Only the owner can call this function.
|
||||
|
||||
@@ -6,13 +6,24 @@ import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
|
||||
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import { INFTMetadataGenerator } from "../interfaces/INFTMetadataGenerator.sol";
|
||||
|
||||
/**
|
||||
* @title BaseNFTMetadataGenerator
|
||||
*
|
||||
* @dev Base contract for generating NFT metadata
|
||||
*/
|
||||
abstract contract BaseNFTMetadataGenerator is INFTMetadataGenerator, Ownable {
|
||||
/// @notice NFT contract address
|
||||
address public nft;
|
||||
|
||||
constructor(address _nft) Ownable(msg.sender) {
|
||||
nft = _nft;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Generates metadata for the NFT based on the owner's address and balance
|
||||
* @param account The address of the NFT owner
|
||||
* @param balance The balance of the NFT owner
|
||||
*/
|
||||
function generate(address account, uint256 balance) external view returns (string memory) {
|
||||
string memory baseName = "KarmaNFT ";
|
||||
string memory baseDescription = "This is a KarmaNFT for address ";
|
||||
@@ -32,5 +43,10 @@ abstract contract BaseNFTMetadataGenerator is INFTMetadataGenerator, Ownable {
|
||||
return string(abi.encodePacked("data:application/json;base64,", jsonBase64));
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Generates the image URI for the NFT based on the owner's address and balance
|
||||
* @param account The address of the NFT owner
|
||||
* @param balance The balance of the NFT owner
|
||||
*/
|
||||
function generateImageURI(address account, uint256 balance) internal view virtual returns (string memory);
|
||||
}
|
||||
|
||||
@@ -5,8 +5,15 @@ import { Base64 } from "@openzeppelin/contracts/utils/Base64.sol";
|
||||
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
|
||||
import { BaseNFTMetadataGenerator } from "./BaseNFTMetadataGenerator.sol";
|
||||
|
||||
/**
|
||||
* @title NFTMetadataGeneratorSVG
|
||||
* @notice NFT metadata generator contract that generates SVG image URIs.
|
||||
* @dev Generates SVG image URIs with a balance number.
|
||||
*/
|
||||
contract NFTMetadataGeneratorSVG is BaseNFTMetadataGenerator {
|
||||
/// @notice SVG image prefix
|
||||
string public imagePrefix = "";
|
||||
/// @notice SVG image suffix
|
||||
string public imageSuffix = "";
|
||||
|
||||
constructor(address nft, string memory _imagePrefix, string memory _imageSuffix) BaseNFTMetadataGenerator(nft) {
|
||||
@@ -14,11 +21,21 @@ contract NFTMetadataGeneratorSVG is BaseNFTMetadataGenerator {
|
||||
imageSuffix = _imageSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Sets the SVG image prefix and suffix
|
||||
* @dev Only the owner can call this function
|
||||
* @param _imagePrefix The SVG image prefix
|
||||
* @param _imageSuffix The SVG image suffix
|
||||
*/
|
||||
function setImageStrings(string memory _imagePrefix, string memory _imageSuffix) external onlyOwner {
|
||||
imagePrefix = _imagePrefix;
|
||||
imageSuffix = _imageSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Generates the image URI for the NFT based on the owner's address and balance
|
||||
* @param balance The balance of the NFT owner
|
||||
*/
|
||||
function generateImageURI(address, uint256 balance) internal view override returns (string memory) {
|
||||
string memory text = Strings.toString(balance / 1e18);
|
||||
bytes memory svg = abi.encodePacked(imagePrefix, text, imageSuffix);
|
||||
|
||||
@@ -4,8 +4,14 @@ pragma solidity ^0.8.26;
|
||||
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
|
||||
import { BaseNFTMetadataGenerator } from "./BaseNFTMetadataGenerator.sol";
|
||||
|
||||
/**
|
||||
* @title NFTMetadataGeneratorURL
|
||||
* @notice NFT metadata generator contract that generates image URI based on account address.
|
||||
*/
|
||||
contract NFTMetadataGeneratorURL is BaseNFTMetadataGenerator {
|
||||
/// @notice URL prefix
|
||||
string public urlPrefix;
|
||||
/// @notice URL suffix
|
||||
string public urlSuffix;
|
||||
|
||||
constructor(address nft, string memory _urlPrefix, string memory _urlSuffix) BaseNFTMetadataGenerator(nft) {
|
||||
@@ -13,11 +19,21 @@ contract NFTMetadataGeneratorURL is BaseNFTMetadataGenerator {
|
||||
urlSuffix = _urlSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Sets the URL prefix and suffix
|
||||
* @dev Only the owner can call this function
|
||||
* @param _urlPrefix The URL prefix
|
||||
* @param _urlSuffix The URL suffix
|
||||
*/
|
||||
function setURLStrings(string memory _urlPrefix, string memory _urlSuffix) external onlyOwner {
|
||||
urlPrefix = _urlPrefix;
|
||||
urlSuffix = _urlSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Generates the image URI for the NFT based on the owner's address and balance
|
||||
* @param account The address of the NFT owner
|
||||
*/
|
||||
function generateImageURI(address account, uint256) internal view override returns (string memory) {
|
||||
return string(abi.encodePacked(urlPrefix, Strings.toHexString(account), urlSuffix));
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ contract RewardsStreamerMPTest is StakeMath, Test {
|
||||
(RewardsStreamerMP stakeManager, VaultFactory _vaultFactory, DeploymentConfig deploymentConfig) =
|
||||
deployment.run();
|
||||
|
||||
(address _deployer, address _stakingToken) = deploymentConfig.activeNetworkConfig();
|
||||
(address _deployer, address _stakingToken,) = deploymentConfig.activeNetworkConfig();
|
||||
|
||||
streamer = stakeManager;
|
||||
stakingToken = MockToken(_stakingToken);
|
||||
@@ -169,7 +169,7 @@ contract RewardsStreamerMPTest is StakeMath, Test {
|
||||
|
||||
function _upgradeStakeManager() internal {
|
||||
UpgradeRewardsStreamerMPScript upgrade = new UpgradeRewardsStreamerMPScript();
|
||||
upgrade.run(admin, IStakeManagerProxy(address(streamer)));
|
||||
upgrade.runWithAdminAndProxy(admin, IStakeManagerProxy(address(streamer)));
|
||||
}
|
||||
|
||||
function _setRewards(uint256 amount, uint256 period) internal {
|
||||
|
||||
@@ -36,7 +36,7 @@ contract StakeVaultTest is Test {
|
||||
DeployRewardsStreamerMPScript deployment = new DeployRewardsStreamerMPScript();
|
||||
(RewardsStreamerMP stakeManager, VaultFactory _vaultFactory, DeploymentConfig deploymentConfig) =
|
||||
deployment.run();
|
||||
(, address _stakingToken) = deploymentConfig.activeNetworkConfig();
|
||||
(, address _stakingToken,) = deploymentConfig.activeNetworkConfig();
|
||||
|
||||
streamer = stakeManager;
|
||||
stakingToken = MockToken(_stakingToken);
|
||||
|
||||
Reference in New Issue
Block a user