feat(Karma): allocate external rewards using the Karma contract

This commit is contained in:
Andrea Franz
2025-02-26 11:43:58 +01:00
committed by r4bbit
parent 54e80e117f
commit ed3577f8c4
13 changed files with 468 additions and 275 deletions

View File

@@ -1,16 +1,30 @@
╭-----------------------------------------------------+-----------------+---------+---------+---------+---------╮
| script/DeployKarma.s.sol:DeployKarmaScript Contract | | | | | |
+===============================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
| 3089188 | 15186 | | | | |
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
| | | | | | |
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
| run | 2533527 | 2533527 | 2533527 | 2533527 | 75 |
╰-----------------------------------------------------+-----------------+---------+---------+---------+---------╯
╭-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╮
| script/DeployRewardsStreamerMP.s.sol:DeployRewardsStreamerMPScript Contract | | | | | |
+=======================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| 7645817 | 36435 | | | | |
| 7717029 | 36770 | | | | |
|-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| | | | | | |
|-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| run | 6708235 | 6708235 | 6708235 | 6708235 | 77 |
| run | 6775418 | 6775418 | 6775418 | 6775418 | 77 |
╰-----------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╯
╭---------------------------------------------------------+-----------------+-----+--------+-----+---------╮
@@ -24,7 +38,7 @@
|---------------------------------------------------------+-----------------+-----+--------+-----+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|---------------------------------------------------------+-----------------+-----+--------+-----+---------|
| activeNetworkConfig | 454 | 454 | 454 | 454 | 154 |
| activeNetworkConfig | 454 | 454 | 454 | 454 | 229 |
╰---------------------------------------------------------+-----------------+-----+--------+-----+---------╯
╭-------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╮
@@ -32,54 +46,56 @@
+=========================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| 3570391 | 17446 | | | | |
| 3641587 | 17781 | | | | |
|-------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| | | | | | |
|-------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| run | 3058619 | 3058619 | 3058619 | 3058619 | 3 |
| run | 3125807 | 3125807 | 3125807 | 3125807 | 3 |
╰-------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╯
╭------------------------------+-----------------+-------+--------+-------+---------╮
| src/Karma.sol:Karma Contract | | | | | |
+===================================================================================+
| Deployment Cost | Deployment Size | | | | |
|------------------------------+-----------------+-------+--------+-------+---------|
| 1040918 | 4850 | | | | |
|------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|------------------------------+-----------------+-------+--------+-------+---------|
| acceptOwnership | 28260 | 28260 | 28260 | 28260 | 1 |
|------------------------------+-----------------+-------+--------+-------+---------|
| addRewardProvider | 23967 | 57628 | 51089 | 68189 | 44 |
|------------------------------+-----------------+-------+--------+-------+---------|
| allowance | 530 | 530 | 530 | 530 | 2 |
|------------------------------+-----------------+-------+--------+-------+---------|
| approve | 410 | 410 | 410 | 410 | 2 |
|------------------------------+-----------------+-------+--------+-------+---------|
| balanceOf | 3691 | 11357 | 9691 | 20691 | 6 |
|------------------------------+-----------------+-------+--------+-------+---------|
| getRewardProviders | 1051 | 3304 | 3304 | 5557 | 4 |
|------------------------------+-----------------+-------+--------+-------+---------|
| mint | 24199 | 75906 | 91068 | 91080 | 14 |
|------------------------------+-----------------+-------+--------+-------+---------|
| mintAllowance | 5714 | 5751 | 5751 | 5788 | 2 |
|------------------------------+-----------------+-------+--------+-------+---------|
| owner | 340 | 1006 | 340 | 2340 | 3 |
|------------------------------+-----------------+-------+--------+-------+---------|
| removeRewardProvider | 23685 | 28092 | 25800 | 34792 | 6 |
|------------------------------+-----------------+-------+--------+-------+---------|
| totalSupply | 3018 | 5018 | 3018 | 11018 | 8 |
|------------------------------+-----------------+-------+--------+-------+---------|
| transfer | 408 | 408 | 408 | 408 | 2 |
|------------------------------+-----------------+-------+--------+-------+---------|
| transferFrom | 517 | 517 | 517 | 517 | 2 |
|------------------------------+-----------------+-------+--------+-------+---------|
| transferOwnership | 47730 | 47730 | 47730 | 47730 | 1 |
------------------------------+-----------------+-------+--------+-------+---------╯
╭------------------------------+-----------------+--------+--------+--------+---------╮
| src/Karma.sol:Karma Contract | | | | | |
+=====================================================================================+
| Deployment Cost | Deployment Size | | | | |
|------------------------------+-----------------+--------+--------+--------+---------|
| 1171148 | 5453 | | | | |
|------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|------------------------------+-----------------+--------+--------+--------+---------|
| acceptOwnership | 28282 | 28282 | 28282 | 28282 | 1 |
|------------------------------+-----------------+--------+--------+--------+---------|
| addRewardDistributor | 23973 | 87707 | 92012 | 92012 | 119 |
|------------------------------+-----------------+--------+--------+--------+---------|
| allowance | 492 | 492 | 492 | 492 | 2 |
|------------------------------+-----------------+--------+--------+--------+---------|
| approve | 416 | 416 | 416 | 416 | 2 |
|------------------------------+-----------------+--------+--------+--------+---------|
| balanceOf | 3994 | 11660 | 9994 | 20994 | 6 |
|------------------------------+-----------------+--------+--------+--------+---------|
| getRewardDistributors | 1112 | 3356 | 3356 | 5600 | 4 |
|------------------------------+-----------------+--------+--------+--------+---------|
| mint | 24250 | 80685 | 96635 | 96647 | 14 |
|------------------------------+-----------------+--------+--------+--------+---------|
| mintAllowance | 7208 | 7245 | 7245 | 7282 | 2 |
|------------------------------+-----------------+--------+--------+--------+---------|
| owner | 362 | 1028 | 362 | 2362 | 3 |
|------------------------------+-----------------+--------+--------+--------+---------|
| removeRewardDistributor | 24016 | 30281 | 26025 | 40803 | 6 |
|------------------------------+-----------------+--------+--------+--------+---------|
| setReward | 43527 | 175898 | 185831 | 185843 | 283 |
|------------------------------+-----------------+--------+--------+--------+---------|
| totalSupply | 3799 | 5799 | 3799 | 11799 | 8 |
|------------------------------+-----------------+--------+--------+--------+---------|
| transfer | 414 | 414 | 414 | 414 | 2 |
|------------------------------+-----------------+--------+--------+--------+---------|
| transferFrom | 507 | 507 | 507 | 507 | 2 |
|------------------------------+-----------------+--------+--------+--------+---------|
| transferOwnership | 47758 | 47758 | 47758 | 47758 | 1 |
╰------------------------------+-----------------+--------+--------+--------+---------╯
╭-------------------------------------------------+-----------------+-------+--------+-------+---------╮
| src/KarmaNFT.sol:KarmaNFT Contract | | | | | |
@@ -118,7 +134,7 @@
+=============================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
| 3250446 | 15007 | | | | |
| 3321635 | 15342 | | | | |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
@@ -152,7 +168,7 @@
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
| leave | 95475 | 95475 | 95475 | 95475 | 1 |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
| lock | 14216 | 52149 | 52082 | 93689 | 260 |
| lock | 14216 | 52151 | 52082 | 93689 | 260 |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
| migrateToVault | 13563 | 72244 | 15769 | 187401 | 3 |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
@@ -164,19 +180,21 @@
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
| proxiableUUID | 342 | 342 | 342 | 342 | 3 |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
| registerVault | 2562 | 74470 | 74983 | 74983 | 308 |
| registerVault | 2540 | 74448 | 74961 | 74961 | 308 |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
| rewardEndTime | 362 | 1362 | 1362 | 2362 | 2 |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
| rewardStartTime | 429 | 1429 | 1429 | 2429 | 2 |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
| rewardsBalanceOf | 2324 | 3514 | 3909 | 6324 | 268 |
| rewardsBalanceOf | 2324 | 3513 | 3909 | 6324 | 268 |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
| setReward | 2561 | 105435 | 106966 | 106966 | 264 |
| setReward | 2484 | 105517 | 107034 | 107034 | 264 |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
| setRewardsSupplier | 26862 | 26862 | 26862 | 26862 | 75 |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
| setTrustedCodehash | 24221 | 24221 | 24221 | 24221 | 77 |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
| stake | 2681 | 237356 | 230009 | 251100 | 1607 |
| stake | 2681 | 237357 | 230009 | 251100 | 1607 |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
| totalMP | 777 | 1223 | 1223 | 1669 | 6 |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
@@ -194,11 +212,11 @@
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
| totalStaked | 385 | 385 | 385 | 385 | 1115 |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
| unstake | 56017 | 81137 | 80911 | 88301 | 269 |
| unstake | 56017 | 81037 | 80911 | 88301 | 269 |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
| updateGlobalState | 15798 | 27698 | 29189 | 29492 | 276 |
| updateGlobalState | 15809 | 27668 | 29200 | 29503 | 276 |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
| updateVaultMP | 25103 | 34596 | 36516 | 36819 | 276 |
| updateVaultMP | 25103 | 34553 | 36516 | 36819 | 276 |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
| upgradeToAndCall | 3225 | 7892 | 8437 | 10925 | 5 |
|------------------------------------------------------+-----------------+--------+--------+--------+---------|
@@ -224,13 +242,13 @@
|----------------------------------------+-----------------+--------+--------+--------+---------|
| leave | 12167 | 126461 | 69872 | 353935 | 4 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| lock | 12097 | 67385 | 67531 | 109137 | 261 |
| lock | 12097 | 67387 | 67531 | 109137 | 261 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| migrateToVault | 29034 | 98943 | 31240 | 236555 | 3 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| owner | 377 | 396 | 377 | 2377 | 313 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| register | 12654 | 78080 | 78572 | 78572 | 308 |
| register | 12632 | 78058 | 78550 | 78550 | 308 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| stake | 12077 | 291048 | 283898 | 304989 | 1608 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
@@ -238,26 +256,26 @@
|----------------------------------------+-----------------+--------+--------+--------+---------|
| trustStakeManager | 7577 | 7577 | 7577 | 7577 | 1 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| unstake | 12054 | 111689 | 112021 | 119411 | 270 |
| unstake | 12054 | 111569 | 112021 | 119411 | 270 |
|----------------------------------------+-----------------+--------+--------+--------+---------|
| withdraw | 20705 | 20705 | 20705 | 20705 | 1 |
╰----------------------------------------+-----------------+--------+--------+--------+---------╯
╭----------------------------------------------------+-----------------+-------+--------+--------+---------╮
| src/TransparentProxy.sol:TransparentProxy Contract | | | | | |
+==========================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|----------------------------------------------------+-----------------+-------+--------+--------+---------|
| 0 | 1231 | | | | |
|----------------------------------------------------+-----------------+-------+--------+--------+---------|
| | | | | | |
|----------------------------------------------------+-----------------+-------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|----------------------------------------------------+-----------------+-------+--------+--------+---------|
| fallback | 735 | 11980 | 833 | 142290 | 7546 |
|----------------------------------------------------+-----------------+-------+--------+--------+---------|
| implementation | 343 | 2342 | 2343 | 2343 | 2455 |
╰----------------------------------------------------+-----------------+-------+--------+--------+---------╯
╭----------------------------------------------------+-----------------+------+--------+--------+---------╮
| src/TransparentProxy.sol:TransparentProxy Contract | | | | | |
+=========================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|----------------------------------------------------+-----------------+------+--------+--------+---------|
| 0 | 1231 | | | | |
|----------------------------------------------------+-----------------+------+--------+--------+---------|
| | | | | | |
|----------------------------------------------------+-----------------+------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|----------------------------------------------------+-----------------+------+--------+--------+---------|
| fallback | 735 | 8100 | 833 | 142290 | 7358 |
|----------------------------------------------------+-----------------+------+--------+--------+---------|
| implementation | 343 | 2342 | 2343 | 2343 | 2455 |
╰----------------------------------------------------+-----------------+------+--------+--------+---------╯
╭--------------------------------------------+-----------------+--------+--------+--------+---------╮
| src/VaultFactory.sol:VaultFactory Contract | | | | | |
@@ -270,7 +288,7 @@
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|--------------------------------------------+-----------------+--------+--------+--------+---------|
| createVault | 231307 | 248128 | 248407 | 248407 | 307 |
| createVault | 231285 | 248106 | 248385 | 248385 | 307 |
╰--------------------------------------------+-----------------+--------+--------+--------+---------╯
╭------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╮
@@ -313,25 +331,25 @@
| urlSuffix | 1141 | 1141 | 1141 | 1141 | 1 |
╰------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╯
╭-------------------------------------------------------------+-----------------+-------+--------+-------+---------╮
| test/mocks/KarmaProviderMock.sol:KarmaProviderMock Contract | | | | | |
+==================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| 177717 | 606 | | | | |
|-------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|-------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| rewardsBalanceOfAccount | 546 | 1879 | 2546 | 2546 | 12 |
|-------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| setTotalKarmaShares | 43587 | 43587 | 43587 | 43587 | 20 |
|-------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| setUserKarmaShare | 44124 | 44124 | 44124 | 44124 | 4 |
|-------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| totalRewardsSupply | 323 | 989 | 323 | 2323 | 72 |
╰-------------------------------------------------------------+-----------------+-------+--------+-------+---------╯
╭-------------------------------------------------------------------+-----------------+-------+--------+-------+---------╮
| test/mocks/KarmaDistributorMock.sol:KarmaDistributorMock Contract | | | | | |
+========================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| 190903 | 667 | | | | |
|-------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|-------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| rewardsBalanceOfAccount | 546 | 1879 | 2546 | 2546 | 12 |
|-------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| setTotalKarmaShares | 43587 | 43587 | 43587 | 43587 | 20 |
|-------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| setUserKarmaShare | 44191 | 44191 | 44191 | 44191 | 4 |
|-------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| totalRewardsSupply | 323 | 989 | 323 | 2323 | 72 |
╰-------------------------------------------------------------------+-----------------+-------+--------+-------+---------╯
╭---------------------------------------------------------------------+-----------------+-------+--------+-------+---------╮
| test/mocks/MockMetadataGenerator.sol:MockMetadataGenerator Contract | | | | | |
@@ -358,11 +376,11 @@
|---------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|---------------------------------------------+-----------------+-------+--------+-------+---------|
| approve | 29158 | 32601 | 29338 | 46342 | 1586 |
| approve | 29158 | 32602 | 29338 | 46342 | 1586 |
|---------------------------------------------+-----------------+-------+--------+-------+---------|
| balanceOf | 558 | 1118 | 558 | 2558 | 1900 |
|---------------------------------------------+-----------------+-------+--------+-------+---------|
| mint | 34095 | 38636 | 34275 | 68379 | 1598 |
| mint | 34095 | 38637 | 34287 | 68379 | 1598 |
╰---------------------------------------------+-----------------+-------+--------+-------+---------╯
╭-----------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╮

View File

@@ -1,30 +1,30 @@
CompoundTest:test_RevertWhenInsufficientMPBalance() (gas: 380247)
CompoundTest:test_RevertWhenInsufficientMPBalance() (gas: 380291)
EmergencyExitTest:test_CannotEnableEmergencyModeTwice() (gas: 93568)
EmergencyExitTest:test_CannotLeaveBeforeEmergencyMode() (gas: 353203)
EmergencyExitTest:test_CannotLeaveBeforeEmergencyMode() (gas: 353225)
EmergencyExitTest:test_EmergencyExitBasic() (gas: 444494)
EmergencyExitTest:test_EmergencyExitMultipleUsers() (gas: 764135)
EmergencyExitTest:test_EmergencyExitMultipleUsers() (gas: 764157)
EmergencyExitTest:test_EmergencyExitToAlternateAddress() (gas: 450444)
EmergencyExitTest:test_EmergencyExitWithLock() (gas: 448231)
EmergencyExitTest:test_EmergencyExitWithLock() (gas: 448187)
EmergencyExitTest:test_EmergencyExitWithRewards() (gas: 435625)
EmergencyExitTest:test_OnlyOwnerCanEnableEmergencyMode() (gas: 39471)
FuzzTests:testFuzz_AccrueMP(uint256,uint256,uint16) (runs: 1006, μ: 521440, ~: 515993)
FuzzTests:testFuzz_EmergencyExit(uint256,uint256) (runs: 1006, μ: 510879, ~: 502017)
FuzzTests:testFuzz_Rewards(uint256,uint256,uint256,uint16,uint16) (runs: 1003, μ: 547584, ~: 548791)
FuzzTests:testFuzz_Stake(uint256,uint256) (runs: 1006, μ: 404288, ~: 395426)
FuzzTests:testFuzz_Unstake(uint256,uint256,uint16,uint256) (runs: 1001, μ: 530235, ~: 529926)
IntegrationTest:testStakeFoo() (gas: 1403337)
KarmaMintAllowanceTest:testAddKarmaProviderOnlyOwner() (gas: 311366)
KarmaMintAllowanceTest:testBalanceOf() (gas: 294561)
KarmaMintAllowanceTest:testBalanceOfWithNoSystemTotalKarma() (gas: 43586)
KarmaMintAllowanceTest:testMintAllowance_Available() (gas: 205175)
KarmaMintAllowanceTest:testMintAllowance_NotAvailable() (gas: 205111)
KarmaMintAllowanceTest:testMintOnlyOwner() (gas: 241951)
KarmaMintAllowanceTest:testMint_Ok() (gas: 264252)
KarmaMintAllowanceTest:testMint_RevertWithAllowanceExceeded() (gas: 246592)
KarmaMintAllowanceTest:testRemoveKarmaProviderIndexOutOfBounds() (gas: 36264)
KarmaMintAllowanceTest:testRemoveKarmaProviderOnlyOwner() (gas: 72164)
KarmaMintAllowanceTest:testTotalSupply() (gas: 202426)
KarmaMintAllowanceTest:testTransfersNotAllowed() (gas: 20698)
EmergencyExitTest:test_OnlyOwnerCanEnableEmergencyMode() (gas: 39462)
FuzzTests:testFuzz_AccrueMP(uint256,uint256,uint16) (runs: 1006, μ: 521106, ~: 515988)
FuzzTests:testFuzz_EmergencyExit(uint256,uint256) (runs: 1006, μ: 510643, ~: 501981)
FuzzTests:testFuzz_Rewards(uint256,uint256,uint256,uint16,uint16) (runs: 1003, μ: 604659, ~: 605935)
FuzzTests:testFuzz_Stake(uint256,uint256) (runs: 1006, μ: 404095, ~: 395433)
FuzzTests:testFuzz_Unstake(uint256,uint256,uint16,uint256) (runs: 1001, μ: 530264, ~: 529949)
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)
KarmaNFTTest:testApproveNotAllowed() (gas: 10500)
KarmaNFTTest:testGetApproved() (gas: 10523)
KarmaNFTTest:testIsApprovedForAll() (gas: 10698)
@@ -35,31 +35,31 @@ KarmaNFTTest:testSetMetadataGenerator() (gas: 966687)
KarmaNFTTest:testSetMetadataGeneratorRevert() (gas: 963218)
KarmaNFTTest:testTokenURI() (gas: 102963)
KarmaNFTTest:testTransferNotAllowed() (gas: 10715)
KarmaOwnershipTest:testInitialOwner() (gas: 12612)
KarmaOwnershipTest:testOwnershipTransfer() (gas: 87164)
KarmaTest:testAddKarmaProviderOnlyOwner() (gas: 311376)
KarmaTest:testBalanceOf() (gas: 294499)
KarmaTest:testBalanceOfWithNoSystemTotalKarma() (gas: 43564)
KarmaTest:testMintOnlyOwner() (gas: 241882)
KarmaTest:testRemoveKarmaProviderIndexOutOfBounds() (gas: 36258)
KarmaTest:testRemoveKarmaProviderOnlyOwner() (gas: 72129)
KarmaTest:testTotalSupply() (gas: 202375)
KarmaTest:testTransfersNotAllowed() (gas: 20675)
LeaveTest:test_LeaveShouldProperlyUpdateAccounting() (gas: 7111338)
LeaveTest:test_RevertWhenStakeManagerIsTrusted() (gas: 350329)
LeaveTest:test_TrustNewStakeManager() (gas: 7164286)
LockTest:test_LockFailsWithInvalidPeriod(uint256) (runs: 1009, μ: 406916, ~: 406944)
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)
LeaveTest:test_RevertWhenStakeManagerIsTrusted() (gas: 350352)
LeaveTest:test_TrustNewStakeManager() (gas: 7302750)
LockTest:test_LockFailsWithInvalidPeriod(uint256) (runs: 1009, μ: 406917, ~: 406944)
LockTest:test_LockFailsWithNoStake() (gas: 114574)
LockTest:test_LockFailsWithZero() (gas: 367631)
LockTest:test_LockWithoutPriorLock() (gas: 465087)
LockTest:test_RevertWhenVaultToLockIsEmpty() (gas: 114532)
MaliciousUpgradeTest:test_UpgradeStackOverflowStakeManager() (gas: 1817080)
MaliciousUpgradeTest:test_UpgradeStackOverflowStakeManager() (gas: 1817092)
MathTest:test_CalcAbsoluteMaxTotalMP() (gas: 4997)
MathTest:test_CalcAccrueMP() (gas: 7991)
MathTest:test_CalcAccrueMP() (gas: 8013)
MathTest:test_CalcBonusMP() (gas: 18665)
MathTest:test_CalcInitialMP() (gas: 5353)
MathTest:test_CalcInitialMP() (gas: 5375)
MathTest:test_CalcMaxAccruedMP() (gas: 4643)
MathTest:test_CalcMaxTotalMP() (gas: 19455)
MathTest:test_CalcMaxTotalMP() (gas: 19411)
MultipleVaultsStakeTest:test_StakeMultipleVaults() (gas: 852588)
NFTMetadataGeneratorSVGTest:testGenerateMetadata() (gas: 84995)
NFTMetadataGeneratorSVGTest:testSetImageStrings() (gas: 58332)
@@ -67,49 +67,49 @@ NFTMetadataGeneratorSVGTest:testSetImageStringsRevert() (gas: 35804)
NFTMetadataGeneratorURLTest:testGenerateMetadata() (gas: 101558)
NFTMetadataGeneratorURLTest:testSetBaseURL() (gas: 49555)
NFTMetadataGeneratorURLTest:testSetBaseURLRevert() (gas: 35979)
RewardsStreamerMP_RewardsTest:testRewardsBalanceOf() (gas: 1234228)
RewardsStreamerMP_RewardsTest:testSetRewards() (gas: 162290)
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsBadAmount() (gas: 39346)
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsBadDuration() (gas: 39369)
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsNotAuthorized() (gas: 39359)
RewardsStreamerMP_RewardsTest:testTotalRewardsSupply() (gas: 671296)
RewardsStreamerMP_RewardsTest:testRewardsBalanceOf() (gas: 1309798)
RewardsStreamerMP_RewardsTest:testSetRewards() (gas: 219337)
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsBadAmount() (gas: 56162)
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsBadDuration() (gas: 95940)
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsNotAuthorized() (gas: 39295)
RewardsStreamerMP_RewardsTest:testTotalRewardsSupply() (gas: 746903)
StakeTest:test_StakeMultipleAccounts() (gas: 591097)
StakeTest:test_StakeMultipleAccountsAndRewards() (gas: 599025)
StakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 1024278)
StakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 602688)
StakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 1024300)
StakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 602710)
StakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 624688)
StakeTest:test_StakeOneAccount() (gas: 333488)
StakeTest:test_StakeOneAccountAndRewards() (gas: 341412)
StakeTest:test_StakeOneAccountMPIncreasesMaxMPDoesNotChange() (gas: 607147)
StakeTest:test_StakeOneAccountReachingMPLimit() (gas: 595251)
StakeTest:test_StakeOneAccountMPIncreasesMaxMPDoesNotChange() (gas: 607203)
StakeTest:test_StakeOneAccountReachingMPLimit() (gas: 595243)
StakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 352045)
StakeTest:test_StakeOneAccountWithMinLockUp() (gas: 352607)
StakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 352696)
StakeVaultMigrationTest:testMigrateToVault() (gas: 945628)
StakeVaultMigrationTest:test_RevertWhenMigrationVaultNotEmpty() (gas: 646895)
StakeVaultMigrationTest:test_RevertWhenNotOwnerOfMigrationVault() (gas: 68102)
StakeVaultMigrationTest:testMigrateToVault() (gas: 945623)
StakeVaultMigrationTest:test_RevertWhenMigrationVaultNotEmpty() (gas: 646873)
StakeVaultMigrationTest:test_RevertWhenNotOwnerOfMigrationVault() (gas: 68099)
StakingTokenTest:testStakeToken() (gas: 13140)
TrustedCodehashAccessTest:test_RevertWhenProxyCloneCodehashNotTrusted() (gas: 2007845)
TrustedCodehashAccessTest:test_RevertWhenProxyCloneCodehashNotTrusted() (gas: 2007813)
UnstakeTest:test_StakeMultipleAccounts() (gas: 591141)
UnstakeTest:test_StakeMultipleAccountsAndRewards() (gas: 599069)
UnstakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 1024255)
UnstakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 1024277)
UnstakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 602687)
UnstakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 624665)
UnstakeTest:test_StakeOneAccount() (gas: 333488)
UnstakeTest:test_StakeOneAccountAndRewards() (gas: 341456)
UnstakeTest:test_StakeOneAccountMPIncreasesMaxMPDoesNotChange() (gas: 607146)
UnstakeTest:test_StakeOneAccountReachingMPLimit() (gas: 595253)
UnstakeTest:test_StakeOneAccountMPIncreasesMaxMPDoesNotChange() (gas: 607180)
UnstakeTest:test_StakeOneAccountReachingMPLimit() (gas: 595287)
UnstakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 352067)
UnstakeTest:test_StakeOneAccountWithMinLockUp() (gas: 352629)
UnstakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 352696)
UnstakeTest:test_UnstakeBonusMPAndAccuredMP() (gas: 634656)
UnstakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 352674)
UnstakeTest:test_UnstakeBonusMPAndAccuredMP() (gas: 634679)
UnstakeTest:test_UnstakeMultipleAccounts() (gas: 829073)
UnstakeTest:test_UnstakeMultipleAccountsAndRewards() (gas: 943644)
UnstakeTest:test_UnstakeOneAccount() (gas: 570246)
UnstakeTest:test_UnstakeOneAccountAndAccruedMP() (gas: 592767)
UnstakeTest:test_UnstakeOneAccountAndAccruedMP() (gas: 592850)
UnstakeTest:test_UnstakeOneAccountAndRewards() (gas: 488388)
UnstakeTest:test_UnstakeOneAccountWithLockUpAndAccruedMP() (gas: 622966)
UpgradeTest:test_RevertWhenNotOwner() (gas: 3327767)
UpgradeTest:test_UpgradeStakeManager() (gas: 6999161)
UnstakeTest:test_UnstakeOneAccountWithLockUpAndAccruedMP() (gas: 622983)
UpgradeTest:test_RevertWhenNotOwner() (gas: 3399068)
UpgradeTest:test_UpgradeStakeManager() (gas: 7137669)
VaultRegistrationTest:test_VaultRegistration() (gas: 62040)
WithdrawTest:test_CannotWithdrawStakedFunds() (gas: 365961)

View File

@@ -26,6 +26,7 @@ definition isUUPSUpgradeableFunction(method f) returns bool = (
definition noCallDuringEmergency(method f) returns bool = (
f.selector == sig:streamer.updateGlobalState().selector
|| f.selector == sig:streamer.setRewardsSupplier(address).selector
|| f.selector == sig:streamer.registerVault().selector
|| f.selector == sig:streamer.migrateToVault(address).selector
|| f.selector == sig:streamer.compound(address).selector

View File

@@ -32,7 +32,6 @@ providers. XP tokens are not transferrable, but they can be used as voting power
- `XPToken__MintAllowanceExceeded`: Raised when minting exceeds the allowed threshold.
- `XPToken__TransfersNotAllowed`: Raised when a transfer, approval, or transferFrom is attempted.
- `RewardProvider__IndexOutOfBounds`: Raised when an invalid index is used for removing a reward provider.
## Supply and Balance Calculation

20
script/DeployKarma.s.sol Normal file
View File

@@ -0,0 +1,20 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import { BaseScript } from "./Base.s.sol";
import { DeploymentConfig } from "./DeploymentConfig.s.sol";
import { Karma } from "../src/Karma.sol";
contract DeployKarmaScript is BaseScript {
function run() public returns (Karma) {
DeploymentConfig deploymentConfig = new DeploymentConfig(broadcaster);
(address deployer,) = deploymentConfig.activeNetworkConfig();
vm.startBroadcast(deployer);
address karma = address(new Karma());
vm.stopBroadcast();
return Karma(karma);
}
}

View File

@@ -4,6 +4,7 @@ pragma solidity >=0.8.26 <=0.9.0;
import { Script } from "forge-std/Script.sol";
import { MockToken } from "../test/mocks/MockToken.sol";
import { Karma } from "../src/Karma.sol";
contract DeploymentConfig is Script {
error DeploymentConfig_InvalidDeployerAddress();

View File

@@ -3,46 +3,112 @@ pragma solidity ^0.8.26;
import { Ownable, Ownable2Step } from "@openzeppelin/contracts/access/Ownable2Step.sol";
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { IRewardProvider } from "./interfaces/IRewardProvider.sol";
import { IRewardDistributor } from "./interfaces/IRewardDistributor.sol";
import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
/**
* @title Karma
* @notice This contract allows for setting rewards for reward distributors.
* @dev Implementation of the Karma token
*/
contract Karma is ERC20, Ownable2Step {
error Karma__MintAllowanceExceeded();
using EnumerableSet for EnumerableSet.AddressSet;
/// @notice The name of the token
string public constant NAME = "Karma";
/// @notice The symbol of the token
string public constant SYMBOL = "KARMA";
/// @notice The total allocation for all reward distributors
uint256 public totalDistributorAllocation;
IRewardProvider[] public rewardProviders;
/// @notice Set of reward distributors
EnumerableSet.AddressSet private rewardDistributors;
/// @notice Mapping of reward distributor to allocation
mapping(address distributor => uint256 allocation) public rewardDistributorAllocations;
error Karma__TransfersNotAllowed();
error RewardProvider__IndexOutOfBounds();
error Karma__MintAllowanceExceeded();
error Karma__DistributorAlreadyAdded();
error Karma__UnknownDistributor();
event RewardDistributorAdded(address distributor);
constructor() ERC20(NAME, SYMBOL) Ownable(msg.sender) { }
function addRewardProvider(IRewardProvider provider) external onlyOwner {
rewardProviders.push(provider);
}
function removeRewardProvider(uint256 index) external onlyOwner {
if (index >= rewardProviders.length) {
revert RewardProvider__IndexOutOfBounds();
/**
* @notice Adds a reward distributor to the set of reward distributors.
* @dev Only the owner can add a reward distributor.
* @dev Emits a `RewardDistributorAdded` event when a distributor is added.
* @param distributor The address of the reward distributor.
*/
function addRewardDistributor(address distributor) external onlyOwner {
if (rewardDistributors.contains(distributor)) {
revert Karma__DistributorAlreadyAdded();
}
rewardProviders[index] = rewardProviders[rewardProviders.length - 1];
rewardProviders.pop();
rewardDistributors.add(address(distributor));
emit RewardDistributorAdded(distributor);
}
function getRewardProviders() external view returns (IRewardProvider[] memory) {
return rewardProviders;
/**
* @notice Removes a reward distributor from the set of reward distributors.
* @dev Only the owner can remove a reward distributor.
* @param distributor The address of the reward distributor.
*/
function removeRewardDistributor(address distributor) external onlyOwner {
if (!rewardDistributors.contains(distributor)) {
revert Karma__UnknownDistributor();
}
rewardDistributors.remove(distributor);
}
/**
* @notice Sets the reward for a reward distributor.
* @dev Only the owner can set the reward for a reward distributor.
* @dev The total allocation for all reward distributors is updated.
* @param rewardsDistributor The address of the reward distributor.
* @param amount The amount of rewards to set.
* @param duration The duration of the rewards.
*/
function setReward(address rewardsDistributor, uint256 amount, uint256 duration) external onlyOwner {
if (!rewardDistributors.contains(rewardsDistributor)) {
revert Karma__UnknownDistributor();
}
rewardDistributorAllocations[rewardsDistributor] = amount;
totalDistributorAllocation += amount;
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.
* @dev The amount minted must not exceed the mint allowance.
* @param account The account to mint tokens to.
* @param amount The amount of tokens to mint.
*/
function mint(address account, uint256 amount) external onlyOwner {
if (amount > _mintAllowance()) {
revert Karma__MintAllowanceExceeded();
@@ -61,26 +127,48 @@ 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.
* @return The external supply of the token.
*/
function _externalSupply() internal view returns (uint256) {
uint256 externalSupply;
for (uint256 i = 0; i < rewardProviders.length; i++) {
externalSupply += rewardProviders[i].totalRewardsSupply();
for (uint256 i = 0; i < rewardDistributors.length(); i++) {
IRewardDistributor distributor = IRewardDistributor(rewardDistributors.at(i));
uint256 supply = distributor.totalRewardsSupply();
if (supply > rewardDistributorAllocations[address(distributor)]) {
supply = rewardDistributorAllocations[address(distributor)];
}
externalSupply += supply;
}
return externalSupply;
}
/**
* @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
* @param account The account to get the balance of.
* @return The balance of the account.
*/
function balanceOf(address account) public view override returns (uint256) {
uint256 externalBalance;
for (uint256 i = 0; i < rewardProviders.length; i++) {
IRewardProvider provider = rewardProviders[i];
externalBalance += provider.rewardsBalanceOfAccount(account);
for (uint256 i = 0; i < rewardDistributors.length(); i++) {
address distributor = rewardDistributors.at(i);
externalBalance += IRewardDistributor(distributor).rewardsBalanceOfAccount(account);
}
return super.balanceOf(account) + externalBalance;

View File

@@ -8,7 +8,7 @@ import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/I
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import { IStakeManager } from "./interfaces/IStakeManager.sol";
import { IStakeVault } from "./interfaces/IStakeVault.sol";
import { IRewardProvider } from "./interfaces/IRewardProvider.sol";
import { IRewardDistributor } from "./interfaces/IRewardDistributor.sol";
import { TrustedCodehashAccess } from "./TrustedCodehashAccess.sol";
import { StakeMath } from "./math/StakeMath.sol";
@@ -24,7 +24,7 @@ contract RewardsStreamerMP is
IStakeManager,
TrustedCodehashAccess,
ReentrancyGuardUpgradeable,
IRewardProvider,
IRewardDistributor,
StakeMath
{
/// @notice Token that is staked in the vaults (SNT).
@@ -74,6 +74,9 @@ contract RewardsStreamerMP is
/// @notice Total amount of staked multiplier points
uint256 public totalMPStaked;
/// @notice The address that can set rewards
address public rewardsSupplier;
modifier onlyRegisteredVault() {
if (vaultOwners[msg.sender] == address(0)) {
revert StakingManager__VaultNotRegistered();
@@ -88,6 +91,13 @@ contract RewardsStreamerMP is
_;
}
modifier onlyRewardsSupplier() {
if (msg.sender != rewardsSupplier) {
revert StakingManager__Unauthorized();
}
_;
}
/**
* @notice Initializes the contract.
* @dev Disables initializers to prevent reinitialization.
@@ -111,6 +121,15 @@ contract RewardsStreamerMP is
lastMPUpdatedTime = block.timestamp;
}
/**
* @notice Allows the owner to set the rewards supplier.
* @dev The supplier is going to be the `Karma` token.
* @param _rewardsSupplier The address of the rewards supplier.
*/
function setRewardsSupplier(address _rewardsSupplier) external onlyOwner onlyNotEmergencyMode {
rewardsSupplier = _rewardsSupplier;
}
/**
* @notice Authorizes contract upgrades via UUPS.
* @dev This function is only callable by the owner.
@@ -417,7 +436,11 @@ contract RewardsStreamerMP is
* @param amount The amount of rewards to distribute.
* @param duration The duration of the reward period.
*/
function setReward(uint256 amount, uint256 duration) external onlyOwner {
function setReward(uint256 amount, uint256 duration) external onlyRewardsSupplier {
if (rewardEndTime > block.timestamp) {
revert StakingManager__RewardPeriodNotEnded();
}
if (duration == 0) {
revert StakingManager__DurationCannotBeZero();
}

View File

@@ -2,12 +2,12 @@
pragma solidity ^0.8.26;
/**
* @title IRewardProvider
* @notice Interface for Reward Provider
* @dev This interface is necessary to unify reward provider contracts.
* @title IRewardDistributor
* @notice Interface for Reward Distributor contract.
* @dev This interface is necessary to unify reward distributor contracts.
* @dev Karma token contract makes use of this to aggregate rewards.
*/
interface IRewardProvider {
interface IRewardDistributor {
/**
* @notice Returns the total supply of rewards.
* @return Total supply of rewards.
@@ -27,4 +27,5 @@ interface IRewardProvider {
* @return Balance of rewards for the account.
*/
function rewardsBalanceOfAccount(address user) external view returns (uint256);
function setReward(uint256 amount, uint256 duration) external;
}

View File

@@ -35,6 +35,7 @@ interface IStakeManager is ITrustedCodehashAccess, IStakeConstants {
error StakingManager__DurationCannotBeZero();
/// @notice Emitted when there are insufficient funds to stake.
error StakingManager__InsufficientBalance();
error StakingManager__RewardPeriodNotEnded();
/// @notice Emitted when a vault is registered.
event VaultRegistered(address indexed vault, address indexed owner);

View File

@@ -3,130 +3,144 @@ pragma solidity ^0.8.26;
import { Test } from "forge-std/Test.sol";
import { Karma } from "../src/Karma.sol";
import { KarmaProviderMock } from "./mocks/KarmaProviderMock.sol";
import { IRewardProvider } from "../src/interfaces/IRewardProvider.sol";
import { KarmaDistributorMock } from "./mocks/KarmaDistributorMock.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
contract KarmaTest is Test {
Karma xpToken;
Karma public karma;
address owner = makeAddr("owner");
address alice = makeAddr("alice");
address bob = makeAddr("bob");
address public owner = makeAddr("owner");
address public alice = makeAddr("alice");
address public bob = makeAddr("bob");
KarmaProviderMock provider1;
KarmaProviderMock provider2;
KarmaDistributorMock public distributor1;
KarmaDistributorMock public distributor2;
function setUp() public virtual {
vm.prank(owner);
xpToken = new Karma();
karma = new Karma();
provider1 = new KarmaProviderMock();
provider2 = new KarmaProviderMock();
distributor1 = new KarmaDistributorMock();
distributor2 = new KarmaDistributorMock();
vm.prank(owner);
xpToken.addRewardProvider(provider1);
karma.addRewardDistributor(address(distributor1));
vm.prank(owner);
xpToken.addRewardProvider(provider2);
karma.addRewardDistributor(address(distributor2));
}
function testAddKarmaProviderOnlyOwner() public {
KarmaProviderMock provider3 = new KarmaProviderMock();
function testAddKarmaDistributorOnlyOwner() public {
KarmaDistributorMock distributor3 = new KarmaDistributorMock();
vm.prank(alice);
vm.expectPartialRevert(Ownable.OwnableUnauthorizedAccount.selector);
xpToken.addRewardProvider(provider3);
karma.addRewardDistributor(address(distributor3));
vm.prank(owner);
xpToken.addRewardProvider(provider3);
karma.addRewardDistributor(address(distributor3));
IRewardProvider[] memory providers = xpToken.getRewardProviders();
assertEq(providers.length, 3);
assertEq(address(providers[0]), address(provider1));
assertEq(address(providers[1]), address(provider2));
assertEq(address(providers[2]), address(provider3));
address[] memory distributors = karma.getRewardDistributors();
assertEq(distributors.length, 3);
assertEq(distributors[0], address(distributor1));
assertEq(distributors[1], address(distributor2));
assertEq(distributors[2], address(distributor3));
}
function testRemoveKarmaProviderOnlyOwner() public {
function testRemoveKarmaDistributorOnlyOwner() public {
vm.prank(alice);
vm.expectPartialRevert(Ownable.OwnableUnauthorizedAccount.selector);
xpToken.removeRewardProvider(0);
karma.removeRewardDistributor(address(distributor1));
vm.prank(owner);
xpToken.removeRewardProvider(0);
karma.removeRewardDistributor(address(distributor1));
IRewardProvider[] memory providers = xpToken.getRewardProviders();
assertEq(providers.length, 1);
assertEq(address(providers[0]), address(provider2));
address[] memory distributors = karma.getRewardDistributors();
assertEq(distributors.length, 1);
assertEq(distributors[0], address(distributor2));
}
function testRemoveKarmaProviderIndexOutOfBounds() public {
function testRemoveUnknownKarmaDistributor() public {
vm.prank(owner);
vm.expectRevert(Karma.RewardProvider__IndexOutOfBounds.selector);
xpToken.removeRewardProvider(10);
vm.expectRevert(Karma.Karma__UnknownDistributor.selector);
karma.removeRewardDistributor(address(1));
}
function testTotalSupply() public {
provider1.setTotalKarmaShares(1000 ether);
provider2.setTotalKarmaShares(2000 ether);
vm.startBroadcast(owner);
karma.setReward(address(distributor1), 1000 ether, 1000);
karma.setReward(address(distributor2), 2000 ether, 2000);
vm.stopBroadcast();
distributor1.setTotalKarmaShares(1000 ether);
distributor2.setTotalKarmaShares(2000 ether);
vm.prank(owner);
xpToken.mint(owner, 500 ether);
karma.mint(owner, 500 ether);
uint256 totalSupply = xpToken.totalSupply();
uint256 totalSupply = karma.totalSupply();
assertEq(totalSupply, 3500 ether);
}
function testBalanceOfWithNoSystemTotalKarma() public view {
uint256 aliceBalance = xpToken.balanceOf(alice);
uint256 aliceBalance = karma.balanceOf(alice);
assertEq(aliceBalance, 0);
uint256 bobBalance = xpToken.balanceOf(bob);
uint256 bobBalance = karma.balanceOf(bob);
assertEq(bobBalance, 0);
}
function testBalanceOf() public {
provider1.setTotalKarmaShares(1000 ether);
provider2.setTotalKarmaShares(2000 ether);
vm.startBroadcast(owner);
karma.setReward(address(distributor1), 1000 ether, 1000);
karma.setReward(address(distributor2), 2000 ether, 2000);
vm.stopBroadcast();
provider1.setUserKarmaShare(alice, 1000e18);
provider2.setUserKarmaShare(alice, 2000e18);
distributor1.setTotalKarmaShares(1000 ether);
distributor2.setTotalKarmaShares(2000 ether);
distributor1.setUserKarmaShare(alice, 1000e18);
distributor2.setUserKarmaShare(alice, 2000e18);
vm.prank(owner);
xpToken.mint(alice, 500e18);
karma.mint(alice, 500e18);
uint256 expectedBalance = 3500e18;
uint256 balance = xpToken.balanceOf(alice);
uint256 balance = karma.balanceOf(alice);
assertEq(balance, expectedBalance);
}
function testMintOnlyOwner() public {
provider1.setTotalKarmaShares(1000 ether);
provider2.setTotalKarmaShares(2000 ether);
assertEq(xpToken.totalSupply(), 3000 ether);
vm.startBroadcast(owner);
karma.setReward(address(distributor1), 1000 ether, 1000);
karma.setReward(address(distributor2), 2000 ether, 2000);
vm.stopBroadcast();
distributor1.setTotalKarmaShares(1000 ether);
distributor2.setTotalKarmaShares(2000 ether);
assertEq(karma.totalSupply(), 3000 ether);
vm.prank(alice);
vm.expectPartialRevert(Ownable.OwnableUnauthorizedAccount.selector);
xpToken.mint(alice, 1000e18);
karma.mint(alice, 1000e18);
vm.prank(owner);
xpToken.mint(alice, 1000e18);
assertEq(xpToken.totalSupply(), 4000e18);
karma.mint(alice, 1000e18);
assertEq(karma.totalSupply(), 4000e18);
}
function testTransfersNotAllowed() public {
vm.expectRevert(Karma.Karma__TransfersNotAllowed.selector);
xpToken.transfer(alice, 100e18);
karma.transfer(alice, 100e18);
vm.expectRevert(Karma.Karma__TransfersNotAllowed.selector);
xpToken.approve(alice, 100e18);
karma.approve(alice, 100e18);
vm.expectRevert(Karma.Karma__TransfersNotAllowed.selector);
xpToken.transferFrom(alice, bob, 100e18);
karma.transferFrom(alice, bob, 100e18);
uint256 allowance = xpToken.allowance(alice, bob);
uint256 allowance = karma.allowance(alice, bob);
assertEq(allowance, 0);
}
}
@@ -163,59 +177,75 @@ contract KarmaMintAllowanceTest is KarmaTest {
}
function testMintAllowance_Available() public {
vm.startBroadcast(owner);
karma.setReward(address(distributor1), 1000 ether, 1000);
karma.setReward(address(distributor2), 2000 ether, 2000);
vm.stopBroadcast();
// 3000 external => maxSupply = 9000
provider1.setTotalKarmaShares(1000 ether);
provider2.setTotalKarmaShares(2000 ether);
distributor1.setTotalKarmaShares(1000 ether);
distributor2.setTotalKarmaShares(2000 ether);
vm.prank(owner);
xpToken.mint(owner, 500 ether);
karma.mint(owner, 500 ether);
// totalSupply = 3500
uint256 mintAllowance = xpToken.mintAllowance();
uint256 mintAllowance = karma.mintAllowance();
assertEq(mintAllowance, 5500 ether);
}
function testMintAllowance_NotAvailable() public {
vm.startBroadcast(owner);
karma.setReward(address(distributor1), 1000 ether, 1000);
karma.setReward(address(distributor2), 2000 ether, 2000);
vm.stopBroadcast();
// 3000 external => maxSupply = 9000
provider1.setTotalKarmaShares(1000 ether);
provider2.setTotalKarmaShares(2000 ether);
distributor1.setTotalKarmaShares(1000 ether);
distributor2.setTotalKarmaShares(2000 ether);
vm.prank(owner);
xpToken.mint(owner, 6000 ether);
karma.mint(owner, 6000 ether);
// totalSupply = 9_000
uint256 mintAllowance = xpToken.mintAllowance();
uint256 mintAllowance = karma.mintAllowance();
assertEq(mintAllowance, 0);
}
function testMint_RevertWithAllowanceExceeded() public {
vm.startBroadcast(owner);
karma.setReward(address(distributor1), 1000 ether, 1000);
karma.setReward(address(distributor2), 2000 ether, 2000);
vm.stopBroadcast();
// 3000 external => maxSupply = 9000
provider1.setTotalKarmaShares(1000 ether);
provider2.setTotalKarmaShares(2000 ether);
distributor1.setTotalKarmaShares(1000 ether);
distributor2.setTotalKarmaShares(2000 ether);
vm.prank(owner);
xpToken.mint(owner, 500 ether);
karma.mint(owner, 500 ether);
// totalSupply = 3500
// allowed to mint 5500
vm.prank(owner);
vm.expectRevert(Karma.Karma__MintAllowanceExceeded.selector);
xpToken.mint(owner, 6000 ether);
karma.mint(owner, 6000 ether);
}
function testMint_Ok() public {
vm.startBroadcast(owner);
karma.setReward(address(distributor1), 1000 ether, 1000);
karma.setReward(address(distributor2), 2000 ether, 2000);
vm.stopBroadcast();
// 3000 external => maxSupply = 9000
provider1.setTotalKarmaShares(1000 ether);
provider2.setTotalKarmaShares(2000 ether);
distributor1.setTotalKarmaShares(1000 ether);
distributor2.setTotalKarmaShares(2000 ether);
vm.prank(owner);
xpToken.mint(owner, 500 ether);
assertEq(xpToken.totalSupply(), 3500 ether);
karma.mint(owner, 500 ether);
assertEq(karma.totalSupply(), 3500 ether);
// totalSupply = 3500
// allowed to mint 5500
vm.prank(owner);
xpToken.mint(owner, 5500 ether);
assertEq(xpToken.totalSupply(), 9000 ether);
karma.mint(owner, 5500 ether);
assertEq(karma.totalSupply(), 9000 ether);
}
}

View File

@@ -3,6 +3,7 @@ pragma solidity ^0.8.26;
import { Test, console } from "forge-std/Test.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { DeployKarmaScript } from "../script/DeployKarma.s.sol";
import { DeployRewardsStreamerMPScript } from "../script/DeployRewardsStreamerMP.s.sol";
import { UpgradeRewardsStreamerMPScript } from "../script/UpgradeRewardsStreamerMP.s.sol";
import { DeploymentConfig } from "../script/DeploymentConfig.s.sol";
@@ -16,6 +17,7 @@ import { RewardsStreamerMP } from "../src/RewardsStreamerMP.sol";
import { StakeMath } from "../src/math/StakeMath.sol";
import { StakeVault } from "../src/StakeVault.sol";
import { VaultFactory } from "../src/VaultFactory.sol";
import { Karma } from "../src/Karma.sol";
import { MockToken } from "./mocks/MockToken.sol";
import { StackOverflowStakeManager } from "./mocks/StackOverflowStakeManager.sol";
@@ -23,6 +25,7 @@ contract RewardsStreamerMPTest is StakeMath, Test {
MockToken internal stakingToken;
RewardsStreamerMP public streamer;
VaultFactory public vaultFactory;
Karma public karma;
address internal admin;
address internal alice = makeAddr("alice");
@@ -34,6 +37,7 @@ contract RewardsStreamerMPTest is StakeMath, Test {
function setUp() public virtual {
DeployRewardsStreamerMPScript deployment = new DeployRewardsStreamerMPScript();
DeployKarmaScript karmaDeployment = new DeployKarmaScript();
(RewardsStreamerMP stakeManager, VaultFactory _vaultFactory, DeploymentConfig deploymentConfig) =
deployment.run();
@@ -43,6 +47,13 @@ contract RewardsStreamerMPTest is StakeMath, Test {
stakingToken = MockToken(_stakingToken);
vaultFactory = _vaultFactory;
admin = _deployer;
karma = karmaDeployment.run();
// set up reward distribution
vm.startPrank(admin);
karma.addRewardDistributor(address(streamer));
streamer.setRewardsSupplier(address(karma));
vm.stopPrank();
address[4] memory accounts = [alice, bob, charlie, dave];
for (uint256 i = 0; i < accounts.length; i++) {
@@ -160,6 +171,11 @@ contract RewardsStreamerMPTest is StakeMath, Test {
UpgradeRewardsStreamerMPScript upgrade = new UpgradeRewardsStreamerMPScript();
upgrade.run(admin, IStakeManagerProxy(address(streamer)));
}
function _setRewards(uint256 amount, uint256 period) internal {
vm.prank(admin);
karma.setReward(address(streamer), amount, period);
}
}
contract MathTest is RewardsStreamerMPTest {
@@ -2198,8 +2214,7 @@ contract RewardsStreamerMP_RewardsTest is RewardsStreamerMPTest {
// since we are testing that it is used for rewardStartTime
currentTime += 1 days;
vm.warp(currentTime);
vm.prank(admin);
streamer.setReward(1000, 10);
_setRewards(1000, 10);
assertEq(streamer.rewardStartTime(), currentTime);
assertEq(streamer.rewardEndTime(), currentTime + 10);
@@ -2208,20 +2223,20 @@ contract RewardsStreamerMP_RewardsTest is RewardsStreamerMPTest {
function testSetRewards_RevertsNotAuthorized() public {
vm.prank(alice);
vm.expectPartialRevert(Ownable.OwnableUnauthorizedAccount.selector);
vm.expectPartialRevert(IStakeManager.StakingManager__Unauthorized.selector);
streamer.setReward(1000, 10);
}
function testSetRewards_RevertsBadDuration() public {
vm.prank(admin);
vm.expectRevert(IStakeManager.StakingManager__DurationCannotBeZero.selector);
streamer.setReward(1000, 0);
karma.setReward(address(streamer), 1000, 0);
}
function testSetRewards_RevertsBadAmount() public {
vm.prank(admin);
vm.expectRevert(IStakeManager.StakingManager__AmountCannotBeZero.selector);
streamer.setReward(0, 10);
karma.setReward(address(streamer), 0, 10);
}
function testTotalRewardsSupply() public {
@@ -2230,8 +2245,7 @@ contract RewardsStreamerMP_RewardsTest is RewardsStreamerMPTest {
uint256 initialTime = vm.getBlockTimestamp();
vm.prank(admin);
streamer.setReward(1000e18, 10 days);
_setRewards(1000e18, 10 days);
assertEq(streamer.totalRewardsSupply(), 0);
for (uint256 i = 0; i <= 10; i++) {
@@ -2252,8 +2266,7 @@ contract RewardsStreamerMP_RewardsTest is RewardsStreamerMPTest {
assertEq(streamer.totalRewardsAccrued(), 0);
// set other 2000 rewards for other 10 days
vm.prank(admin);
streamer.setReward(2000e18, 10 days);
_setRewards(2000e18, 10 days);
// accrued is 1000 from the previous reward and still 0 for the new one
assertEq(streamer.totalRewardsSupply(), 1000e18, "totalRewardsSupply should be 1000");
@@ -2272,9 +2285,7 @@ contract RewardsStreamerMP_RewardsTest is RewardsStreamerMPTest {
uint256 initialTime = vm.getBlockTimestamp();
_stake(alice, 100e18, 0);
vm.prank(admin);
streamer.setReward(1000e18, year);
_setRewards(1000e18, year);
assertEq(streamer.totalStaked(), 100e18);
assertEq(streamer.totalMPStaked(), 100e18);
@@ -2357,8 +2368,7 @@ contract RewardsStreamerMP_RewardsTest is RewardsStreamerMPTest {
assertEq(streamer.vaultShares(vaults[bob]), 200e18);
assertEq(streamer.rewardsBalanceOf(vaults[bob]), 250e18);
vm.prank(admin);
streamer.setReward(600e18, year);
_setRewards(600e18, year);
vm.warp(initialTime + year * 3);
@@ -2745,7 +2755,7 @@ contract FuzzTests is RewardsStreamerMPTest {
stakeAmount = bound(stakeAmount, 1e18, 20_000_000e18);
lockUpPeriod = lockUpPeriod == 0 ? 0 : bound(lockUpPeriod, MIN_LOCKUP_PERIOD, MAX_LOCKUP_PERIOD);
vm.assume(rewardPeriod > 0 && rewardPeriod <= 12 weeks); // assuming max 3 months
vm.assume(rewardAmount > 1e18 && rewardAmount <= 100_000e18); // assuming max 1_000_000 Karma
vm.assume(rewardAmount > 1e18 && rewardAmount <= 1_000_000e18); // assuming max 1_000_000 Karma
vm.assume(accountRewardPeriod <= rewardPeriod); // Ensure accountRewardPeriod doesn't exceed rewardPeriod
uint256 initialTime = vm.getBlockTimestamp();
@@ -2758,8 +2768,7 @@ contract FuzzTests is RewardsStreamerMPTest {
_stake(alice, stakeAmount, lockUpPeriod);
vm.prank(admin);
streamer.setReward(rewardAmount, rewardPeriod);
_setRewards(rewardAmount, rewardPeriod);
vm.warp(initialTime + accountRewardPeriod);

View File

@@ -1,9 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import { IRewardProvider } from "../../src/interfaces/IRewardProvider.sol";
import { IRewardDistributor } from "../../src/interfaces/IRewardDistributor.sol";
contract KarmaProviderMock is IRewardProvider {
contract KarmaDistributorMock is IRewardDistributor {
// solhint-disable-next-line
mapping(address => uint256) public userKarmaShare;
@@ -21,6 +21,8 @@ contract KarmaProviderMock is IRewardProvider {
revert("Not implemented");
}
function setReward(uint256, uint256) external pure override { }
function rewardsBalanceOfAccount(address account) external view override returns (uint256) {
return userKarmaShare[account];
}