diff --git a/.gas-report b/.gas-report index 15b69d0..998a02b 100644 --- a/.gas-report +++ b/.gas-report @@ -10,7 +10,7 @@ |-------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------| | Function Name | Min | Avg | Median | Max | # Calls | |-------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------| -| fallback | 746 | 142734 | 190919 | 190943 | 447 | +| fallback | 644 | 133029 | 190946 | 190982 | 492 | ╰-------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╯ ╭-----------------------------------------------------+-----------------+---------+---------+---------+---------╮ @@ -18,13 +18,13 @@ +===============================================================================================================+ | Deployment Cost | Deployment Size | | | | | |-----------------------------------------------------+-----------------+---------+---------+---------+---------| -| 4734998 | 22941 | | | | | +| 4741258 | 22970 | | | | | |-----------------------------------------------------+-----------------+---------+---------+---------+---------| | | | | | | | |-----------------------------------------------------+-----------------+---------+---------+---------+---------| | Function Name | Min | Avg | Median | Max | # Calls | |-----------------------------------------------------+-----------------+---------+---------+---------+---------| -| run | 3956429 | 3956429 | 3956429 | 3956429 | 106 | +| run | 3962239 | 3962239 | 3962239 | 3962239 | 121 | ╰-----------------------------------------------------+-----------------+---------+---------+---------+---------╯ ╭-----------------------------------------------------------+-----------------+---------+---------+---------+---------╮ @@ -66,7 +66,7 @@ |---------------------------------------------------------+-----------------+-----+--------+-----+---------| | Function Name | Min | Avg | Median | Max | # Calls | |---------------------------------------------------------+-----------------+-----+--------+-----+---------| -| activeNetworkConfig | 455 | 455 | 455 | 455 | 320 | +| activeNetworkConfig | 455 | 455 | 455 | 455 | 350 | ╰---------------------------------------------------------+-----------------+-----+--------+-----+---------╯ ╭---------------------------------------------------------------------+-----------------+---------+---------+---------+---------╮ @@ -83,12 +83,26 @@ | runWithAdminAndProxy | 3282174 | 3282174 | 3282174 | 3282174 | 3 | ╰---------------------------------------------------------------------+-----------------+---------+---------+---------+---------╯ +╭---------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╮ +| script/UpgradeToKarmaWithAccessControl.s.sol:UpgradeToKarmaWithAccessControlScript Contract | | | | | | ++=======================================================================================================================================================+ +| Deployment Cost | Deployment Size | | | | | +|---------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------| +| 5058566 | 24463 | | | | | +|---------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------| +| | | | | | | +|---------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------| +| Function Name | Min | Avg | Median | Max | # Calls | +|---------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------| +| runWithAdminAndProxy | 2535537 | 2535537 | 2535537 | 2535537 | 15 | +╰---------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╯ + ╭------------------------------+-----------------+--------+--------+--------+---------╮ | src/Karma.sol:Karma Contract | | | | | | +=====================================================================================+ | Deployment Cost | Deployment Size | | | | | |------------------------------+-----------------+--------+--------+--------+---------| -| 0 | 9823 | | | | | +| 0 | 9852 | | | | | |------------------------------+-----------------+--------+--------+--------+---------| | | | | | | | |------------------------------+-----------------+--------+--------+--------+---------| @@ -96,7 +110,7 @@ |------------------------------+-----------------+--------+--------+--------+---------| | acceptOwnership | 12020 | 12020 | 12020 | 12020 | 1 | |------------------------------+-----------------+--------+--------+--------+---------| -| addRewardDistributor | 2589 | 66851 | 70586 | 70586 | 128 | +| addRewardDistributor | 2589 | 66880 | 70615 | 70615 | 128 | |------------------------------+-----------------+--------+--------+--------+---------| | allowance | 482 | 482 | 482 | 482 | 2 | |------------------------------+-----------------+--------+--------+--------+---------| @@ -106,15 +120,15 @@ |------------------------------+-----------------+--------+--------+--------+---------| | getRewardDistributors | 1140 | 3384 | 3384 | 5628 | 4 | |------------------------------+-----------------+--------+--------+--------+---------| -| initialize | 95872 | 95872 | 95872 | 95872 | 106 | +| initialize | 95872 | 95872 | 95872 | 95872 | 121 | |------------------------------+-----------------+--------+--------+--------+---------| | mint | 2632 | 37252 | 48792 | 48792 | 8 | |------------------------------+-----------------+--------+--------+--------+---------| | owner | 363 | 1029 | 363 | 2363 | 3 | |------------------------------+-----------------+--------+--------+--------+---------| -| removeRewardDistributor | 2632 | 12148 | 4824 | 28990 | 6 | +| removeRewardDistributor | 2632 | 12164 | 4842 | 29019 | 6 | |------------------------------+-----------------+--------+--------+--------+---------| -| setReward | 22021 | 157523 | 164219 | 164219 | 276 | +| setReward | 22045 | 157562 | 164258 | 164258 | 276 | |------------------------------+-----------------+--------+--------+--------+---------| | totalSupply | 3545 | 8211 | 9545 | 11545 | 6 | |------------------------------+-----------------+--------+--------+--------+---------| @@ -123,6 +137,8 @@ | transferFrom | 511 | 511 | 511 | 511 | 2 | |------------------------------+-----------------+--------+--------+--------+---------| | transferOwnership | 26328 | 26328 | 26328 | 26328 | 1 | +|------------------------------+-----------------+--------+--------+--------+---------| +| upgradeTo | 10165 | 10165 | 10165 | 10165 | 15 | ╰------------------------------+-----------------+--------+--------+--------+---------╯ ╭-------------------------------------------------+-----------------+-------+--------+-------+---------╮ @@ -157,6 +173,38 @@ | transferFrom | 530 | 530 | 530 | 530 | 1 | ╰-------------------------------------------------+-----------------+-------+--------+-------+---------╯ +╭----------------------------------------------------------------+-----------------+-------+--------+-------+---------╮ +| src/KarmaWithAccessControl.sol:KarmaWithAccessControl Contract | | | | | | ++=====================================================================================================================+ +| Deployment Cost | Deployment Size | | | | | +|----------------------------------------------------------------+-----------------+-------+--------+-------+---------| +| 0 | 12264 | | | | | +|----------------------------------------------------------------+-----------------+-------+--------+-------+---------| +| | | | | | | +|----------------------------------------------------------------+-----------------+-------+--------+-------+---------| +| Function Name | Min | Avg | Median | Max | # Calls | +|----------------------------------------------------------------+-----------------+-------+--------+-------+---------| +| DEFAULT_ADMIN_ROLE | 262 | 262 | 262 | 262 | 8 | +|----------------------------------------------------------------+-----------------+-------+--------+-------+---------| +| OPERATOR_ROLE | 261 | 261 | 261 | 261 | 2 | +|----------------------------------------------------------------+-----------------+-------+--------+-------+---------| +| addRewardDistributor | 29953 | 67170 | 70892 | 70892 | 11 | +|----------------------------------------------------------------+-----------------+-------+--------+-------+---------| +| getRewardDistributors | 825 | 1043 | 1152 | 1152 | 6 | +|----------------------------------------------------------------+-----------------+-------+--------+-------+---------| +| grantRole | 29490 | 29490 | 29490 | 29490 | 4 | +|----------------------------------------------------------------+-----------------+-------+--------+-------+---------| +| hasRole | 2710 | 2710 | 2710 | 2710 | 6 | +|----------------------------------------------------------------+-----------------+-------+--------+-------+---------| +| initializeAccessControl | 31896 | 31896 | 31896 | 31896 | 15 | +|----------------------------------------------------------------+-----------------+-------+--------+-------+---------| +| proxiableUUID | 342 | 342 | 342 | 342 | 15 | +|----------------------------------------------------------------+-----------------+-------+--------+-------+---------| +| removeRewardDistributor | 18762 | 22499 | 18762 | 29974 | 3 | +|----------------------------------------------------------------+-----------------+-------+--------+-------+---------| +| setReward | 4889 | 10075 | 12805 | 14987 | 5 | +╰----------------------------------------------------------------+-----------------+-------+--------+-------+---------╯ + ╭--------------------------------------------+-----------------+--------+--------+--------+---------╮ | src/StakeManager.sol:StakeManager Contract | | | | | | +===================================================================================================+ @@ -184,7 +232,7 @@ |--------------------------------------------+-----------------+--------+--------+--------+---------| | getAccountVaults | 5230 | 5230 | 5230 | 5230 | 4 | |--------------------------------------------+-----------------+--------+--------+--------+---------| -| getVault | 1823 | 6596 | 1823 | 15823 | 4182 | +| getVault | 1823 | 6603 | 1823 | 15823 | 4182 | |--------------------------------------------+-----------------+--------+--------+--------+---------| | initialize | 92752 | 92752 | 92752 | 92752 | 93 | |--------------------------------------------+-----------------+--------+--------+--------+---------| @@ -192,7 +240,7 @@ |--------------------------------------------+-----------------+--------+--------+--------+---------| | leave | 88837 | 88837 | 88837 | 88837 | 1 | |--------------------------------------------+-----------------+--------+--------+--------+---------| -| lock | 7040 | 42498 | 45950 | 84893 | 1034 | +| lock | 7040 | 42444 | 45950 | 84893 | 1034 | |--------------------------------------------+-----------------+--------+--------+--------+---------| | migrateToVault | 9294 | 51723 | 16883 | 163832 | 4 | |--------------------------------------------+-----------------+--------+--------+--------+---------| @@ -220,17 +268,17 @@ |--------------------------------------------+-----------------+--------+--------+--------+---------| | setTrustedCodehash | 24238 | 24238 | 24238 | 24238 | 93 | |--------------------------------------------+-----------------+--------+--------+--------+---------| -| stake | 2639 | 129085 | 59967 | 225838 | 2668 | +| stake | 2639 | 128982 | 59967 | 225838 | 2668 | |--------------------------------------------+-----------------+--------+--------+--------+---------| | stakedBalanceOf | 2622 | 2622 | 2622 | 2622 | 1 | |--------------------------------------------+-----------------+--------+--------+--------+---------| | totalMP | 805 | 1257 | 1257 | 1710 | 6 | |--------------------------------------------+-----------------+--------+--------+--------+---------| -| totalMPAccrued | 385 | 1070 | 385 | 2385 | 4162 | +| totalMPAccrued | 385 | 1071 | 385 | 2385 | 4162 | |--------------------------------------------+-----------------+--------+--------+--------+---------| -| totalMPStaked | 429 | 1113 | 429 | 2429 | 4165 | +| totalMPStaked | 429 | 1114 | 429 | 2429 | 4165 | |--------------------------------------------+-----------------+--------+--------+--------+---------| -| totalMaxMP | 407 | 1092 | 407 | 2407 | 4162 | +| totalMaxMP | 407 | 1093 | 407 | 2407 | 4162 | |--------------------------------------------+-----------------+--------+--------+--------+---------| | totalRewardsAccrued | 407 | 407 | 407 | 407 | 3 | |--------------------------------------------+-----------------+--------+--------+--------+---------| @@ -238,15 +286,15 @@ |--------------------------------------------+-----------------+--------+--------+--------+---------| | totalShares | 597 | 597 | 597 | 597 | 6 | |--------------------------------------------+-----------------+--------+--------+--------+---------| -| totalStaked | 408 | 1092 | 408 | 2408 | 4169 | +| totalStaked | 408 | 1093 | 408 | 2408 | 4169 | |--------------------------------------------+-----------------+--------+--------+--------+---------| -| unstake | 38969 | 41472 | 38995 | 75006 | 269 | +| unstake | 38969 | 41322 | 38995 | 75006 | 269 | |--------------------------------------------+-----------------+--------+--------+--------+---------| | updateAccount | 347677 | 347677 | 347677 | 347677 | 1 | |--------------------------------------------+-----------------+--------+--------+--------+---------| | updateGlobalState | 15820 | 25876 | 29230 | 29230 | 8 | |--------------------------------------------+-----------------+--------+--------+--------+---------| -| updateVault | 31948 | 34054 | 31948 | 110579 | 1024 | +| updateVault | 31948 | 34040 | 31948 | 110579 | 1024 | |--------------------------------------------+-----------------+--------+--------+--------+---------| | upgradeTo | 10279 | 10895 | 10279 | 12745 | 4 | |--------------------------------------------+-----------------+--------+--------+--------+---------| @@ -274,7 +322,7 @@ |----------------------------------------+-----------------+--------+--------+--------+---------| | leave | 12161 | 124868 | 66517 | 354279 | 4 | |----------------------------------------+-----------------+--------+--------+--------+---------| -| lock | 12091 | 57919 | 61416 | 100356 | 1035 | +| lock | 12091 | 57865 | 61416 | 100356 | 1035 | |----------------------------------------+-----------------+--------+--------+--------+---------| | migrateToVault | 24782 | 75606 | 32371 | 212902 | 4 | |----------------------------------------+-----------------+--------+--------+--------+---------| @@ -282,13 +330,13 @@ |----------------------------------------+-----------------+--------+--------+--------+---------| | register | 12718 | 78090 | 78644 | 78644 | 366 | |----------------------------------------+-----------------+--------+--------+--------+---------| -| stake | 12071 | 163003 | 75460 | 281406 | 2669 | +| stake | 12071 | 162871 | 75460 | 281406 | 2669 | |----------------------------------------+-----------------+--------+--------+--------+---------| | stakeManager | 369 | 369 | 369 | 369 | 365 | |----------------------------------------+-----------------+--------+--------+--------+---------| | trustStakeManager | 7580 | 7580 | 7580 | 7580 | 1 | |----------------------------------------+-----------------+--------+--------+--------+---------| -| unstake | 12048 | 57787 | 54438 | 106028 | 270 | +| unstake | 12048 | 57580 | 54438 | 106028 | 270 | |----------------------------------------+-----------------+--------+--------+--------+---------| | withdraw | 20733 | 20733 | 20733 | 20733 | 1 | ╰----------------------------------------+-----------------+--------+--------+--------+---------╯ @@ -304,7 +352,7 @@ |----------------------------------------------------+-----------------+------+--------+--------+---------| | Function Name | Min | Avg | Median | Max | # Calls | |----------------------------------------------------+-----------------+------+--------+--------+---------| -| fallback | 708 | 6326 | 2301 | 374054 | 23163 | +| fallback | 708 | 6327 | 2301 | 374054 | 23163 | |----------------------------------------------------+-----------------+------+--------+--------+---------| | implementation | 346 | 2345 | 2346 | 2346 | 4349 | ╰----------------------------------------------------+-----------------+------+--------+--------+---------╯ @@ -410,7 +458,7 @@ |---------------------------------------------+-----------------+-------+--------+-------+---------| | Function Name | Min | Avg | Median | Max | # Calls | |---------------------------------------------+-----------------+-------+--------+-------+---------| -| approve | 29075 | 31502 | 29183 | 46259 | 2668 | +| approve | 29075 | 31501 | 29183 | 46259 | 2668 | |---------------------------------------------+-----------------+-------+--------+-------+---------| | balanceOf | 561 | 1351 | 561 | 2561 | 4956 | |---------------------------------------------+-----------------+-------+--------+-------+---------| diff --git a/.gas-snapshot b/.gas-snapshot index bdfca93..92cd4cb 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,3 +1,7 @@ +AddRewardDistributorTest:testAddRewardDistributor() (gas: 112981) +AddRewardDistributorTest:testAddRewardDistributorAsOtherAdmin() (gas: 177093) +AddRewardDistributorTest:test_InitializeAccessControl() (gas: 15963) +AddRewardDistributorTest:test_RevertWhen_SenderIsNotDefaultAdmin() (gas: 68316) EmergencyExitTest:test_CannotEnableEmergencyModeTwice() (gas: 93554) EmergencyExitTest:test_CannotLeaveBeforeEmergencyMode() (gas: 335172) EmergencyExitTest:test_EmergencyExitBasic() (gas: 426892) @@ -6,15 +10,15 @@ EmergencyExitTest:test_EmergencyExitToAlternateAddress() (gas: 432421) EmergencyExitTest:test_EmergencyExitWithLock() (gas: 430501) EmergencyExitTest:test_EmergencyExitWithRewards() (gas: 418391) EmergencyExitTest:test_OnlyOwnerCanEnableEmergencyMode() (gas: 39176) -FuzzTests:testFuzz_AccrueMP(uint128,uint64,uint64) (runs: 1000, μ: 373456, ~: 342655) -FuzzTests:testFuzz_AccrueMP_Relock(uint128,uint64,uint64,uint64) (runs: 1000, μ: 472165, ~: 444746) -FuzzTests:testFuzz_EmergencyExit(uint256,uint256) (runs: 1000, μ: 495256, ~: 486543) -FuzzTests:testFuzz_Lock(uint256,uint64) (runs: 1000, μ: 726736, ~: 725709) -FuzzTests:testFuzz_Relock(uint256,uint64,uint64) (runs: 1000, μ: 384630, ~: 362893) -FuzzTests:testFuzz_Rewards(uint256,uint256,uint256,uint16,uint16) (runs: 1000, μ: 594630, ~: 595934) -FuzzTests:testFuzz_Stake(uint256,uint64) (runs: 1000, μ: 288633, ~: 260818) -FuzzTests:testFuzz_Unstake(uint128,uint64,uint16,uint128) (runs: 1000, μ: 476844, ~: 448237) -FuzzTests:testFuzz_UpdateVault(uint128,uint64,uint64) (runs: 1000, μ: 373479, ~: 342678) +FuzzTests:testFuzz_AccrueMP(uint128,uint64,uint64) (runs: 1000, μ: 374272, ~: 342651) +FuzzTests:testFuzz_AccrueMP_Relock(uint128,uint64,uint64,uint64) (runs: 1000, μ: 473669, ~: 444743) +FuzzTests:testFuzz_EmergencyExit(uint256,uint256) (runs: 1000, μ: 495317, ~: 486543) +FuzzTests:testFuzz_Lock(uint256,uint64) (runs: 1000, μ: 726546, ~: 725709) +FuzzTests:testFuzz_Relock(uint256,uint64,uint64) (runs: 1000, μ: 384705, ~: 362893) +FuzzTests:testFuzz_Rewards(uint256,uint256,uint256,uint16,uint16) (runs: 1000, μ: 594669, ~: 595973) +FuzzTests:testFuzz_Stake(uint256,uint64) (runs: 1000, μ: 289279, ~: 260823) +FuzzTests:testFuzz_Unstake(uint128,uint64,uint16,uint128) (runs: 1000, μ: 476251, ~: 448228) +FuzzTests:testFuzz_UpdateVault(uint128,uint64,uint64) (runs: 1000, μ: 374295, ~: 342674) IntegrationTest:testStakeFoo() (gas: 1362727) KarmaNFTTest:testApproveNotAllowed() (gas: 10507) KarmaNFTTest:testGetApproved() (gas: 10531) @@ -26,28 +30,29 @@ KarmaNFTTest:testSetMetadataGenerator() (gas: 1010377) KarmaNFTTest:testSetMetadataGeneratorRevert() (gas: 1006937) KarmaNFTTest:testTokenURI() (gas: 1105935) KarmaNFTTest:testTransferNotAllowed() (gas: 10701) -KarmaOwnershipTest:testAddKarmaDistributorOnlyOwner() (gas: 364768) -KarmaOwnershipTest:testBalanceOf() (gas: 423830) +KarmaOwnershipTest:testAddKarmaDistributorOnlyOwner() (gas: 364797) +KarmaOwnershipTest:testBalanceOf() (gas: 423908) KarmaOwnershipTest:testBalanceOfWithNoSystemTotalKarma() (gas: 49479) KarmaOwnershipTest:testInitialOwner() (gas: 17601) -KarmaOwnershipTest:testMintOnlyOwner() (gas: 371195) +KarmaOwnershipTest:testMintOnlyOwner() (gas: 371273) KarmaOwnershipTest:testOwnershipTransfer() (gas: 98047) -KarmaOwnershipTest:testRemoveKarmaDistributorOnlyOwner() (gas: 88820) -KarmaOwnershipTest:testRemoveUnknownKarmaDistributor() (gas: 41398) -KarmaOwnershipTest:testTotalSupply() (gas: 331725) +KarmaOwnershipTest:testRemoveKarmaDistributorOnlyOwner() (gas: 88849) +KarmaOwnershipTest:testRemoveUnknownKarmaDistributor() (gas: 41416) +KarmaOwnershipTest:testTotalSupply() (gas: 331803) KarmaOwnershipTest:testTransfersNotAllowed() (gas: 40196) -KarmaTest:testAddKarmaDistributorOnlyOwner() (gas: 364768) -KarmaTest:testBalanceOf() (gas: 423830) +KarmaTest:testAddKarmaDistributorOnlyOwner() (gas: 364797) +KarmaTest:testBalanceOf() (gas: 423908) KarmaTest:testBalanceOfWithNoSystemTotalKarma() (gas: 49545) -KarmaTest:testMintOnlyOwner() (gas: 371195) -KarmaTest:testRemoveKarmaDistributorOnlyOwner() (gas: 88798) -KarmaTest:testRemoveUnknownKarmaDistributor() (gas: 41398) -KarmaTest:testTotalSupply() (gas: 331725) +KarmaTest:testMintOnlyOwner() (gas: 371273) +KarmaTest:testRemoveKarmaDistributorOnlyOwner() (gas: 88827) +KarmaTest:testRemoveUnknownKarmaDistributor() (gas: 41416) +KarmaTest:testTotalSupply() (gas: 331803) KarmaTest:testTransfersNotAllowed() (gas: 40241) +KarmaWithAccessControlTest:test_InitializeAccessControl() (gas: 15940) LeaveTest:test_LeaveShouldProperlyUpdateAccounting() (gas: 9617526) LeaveTest:test_RevertWhenStakeManagerIsTrusted() (gas: 332331) LeaveTest:test_TrustNewStakeManager() (gas: 9673268) -LockTest:test_LockFailsWithInvalidPeriod(uint256) (runs: 1000, μ: 382886, ~: 382908) +LockTest:test_LockFailsWithInvalidPeriod(uint256) (runs: 1000, μ: 382881, ~: 382908) LockTest:test_LockFailsWithNoStake() (gas: 88865) LockTest:test_LockFailsWithZero() (gas: 342393) LockTest:test_LockMultipleTimesExceedMaxLock() (gas: 624582) @@ -68,12 +73,22 @@ NFTMetadataGeneratorSVGTest:testSetImageStringsRevert() (gas: 35891) NFTMetadataGeneratorURLTest:testGenerateMetadata() (gas: 108341) NFTMetadataGeneratorURLTest:testSetBaseURL() (gas: 50631) NFTMetadataGeneratorURLTest:testSetBaseURLRevert() (gas: 36066) -StakeManager_RewardsTest:testRewardsBalanceOf() (gas: 1274873) -StakeManager_RewardsTest:testSetRewards() (gas: 224614) -StakeManager_RewardsTest:testSetRewards_RevertsBadAmount() (gas: 61280) -StakeManager_RewardsTest:testSetRewards_RevertsBadDuration() (gas: 101038) +RemoveRewardDistributorTest:testRemoveRewardDistributor() (gas: 143601) +RemoveRewardDistributorTest:testRemoveRewardDistributorAsOtherAdmin() (gas: 203358) +RemoveRewardDistributorTest:test_InitializeAccessControl() (gas: 15987) +RemoveRewardDistributorTest:test_RevertWhen_SenderIsNotDefaultAdmin() (gas: 66455) +SetRewardTest:testSetRewardAsAdmin() (gas: 51660) +SetRewardTest:testSetRewardAsOperator() (gas: 123793) +SetRewardTest:testSetRewardAsOtherAdmin() (gas: 116509) +SetRewardTest:test_InitializeAccessControl() (gas: 15940) +SetRewardTest:test_RevertWhen_SenderIsNotDefaultAdmin() (gas: 43560) +SetRewardTest:test_RevertWhen_SenderIsNotOperator() (gas: 53343) +StakeManager_RewardsTest:testRewardsBalanceOf() (gas: 1274951) +StakeManager_RewardsTest:testSetRewards() (gas: 224653) +StakeManager_RewardsTest:testSetRewards_RevertsBadAmount() (gas: 61304) +StakeManager_RewardsTest:testSetRewards_RevertsBadDuration() (gas: 101062) StakeManager_RewardsTest:testSetRewards_RevertsNotAuthorized() (gas: 39367) -StakeManager_RewardsTest:testTotalRewardsSupply() (gas: 740407) +StakeManager_RewardsTest:testTotalRewardsSupply() (gas: 740485) StakeTest:test_StakeMultipleAccounts() (gas: 555080) StakeTest:test_StakeMultipleAccountsAndRewards() (gas: 563572) StakeTest:test_StakeMultipleAccountsMPIncreasesMaxMPDoesNotChange() (gas: 942163) @@ -119,7 +134,7 @@ UnstakeTest:test_UnstakeOneAccount() (gas: 543645) UnstakeTest:test_UnstakeOneAccountAndAccruedMP() (gas: 543156) UnstakeTest:test_UnstakeOneAccountAndRewards() (gas: 467580) UnstakeTest:test_UnstakeOneAccountWithLockUpAndAccruedMP() (gas: 560332) -UpdateVaultTest:test_UpdateAccount() (gas: 2391077) +UpdateVaultTest:test_UpdateAccount() (gas: 2391116) UpgradeTest:test_RevertWhenNotOwner() (gas: 3562509) UpgradeTest:test_UpgradeStakeManager() (gas: 9509435) VaultRegistrationTest:test_VaultRegistration() (gas: 63138) diff --git a/script/UpgradeToKarmaWithAccessControl.s.sol b/script/UpgradeToKarmaWithAccessControl.s.sol new file mode 100644 index 0000000..27417d0 --- /dev/null +++ b/script/UpgradeToKarmaWithAccessControl.s.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; + +import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; +import { BaseScript } from "./Base.s.sol"; +import { DeploymentConfig } from "./DeploymentConfig.s.sol"; +import { KarmaWithAccessControl } from "../src/KarmaWithAccessControl.sol"; + +contract UpgradeToKarmaWithAccessControlScript is BaseScript { + error ProxyAddressNotSet(); + + function run() public returns (address) { + address currentImplProxy = vm.envAddress("KARMA_PROXY_ADDRESS"); + if (currentImplProxy == address(0)) { + revert ProxyAddressNotSet(); + } + DeploymentConfig deploymentConfig = new DeploymentConfig(broadcaster); + (address deployer,) = deploymentConfig.activeNetworkConfig(); + return runWithAdminAndProxy(deployer, currentImplProxy); + } + + function runWithAdminAndProxy(address admin, address currentImplProxy) public returns (address) { + address deployer = broadcaster; + if (admin != address(0)) { + deployer = admin; + } + vm.startBroadcast(deployer); + address nextImpl = address(new KarmaWithAccessControl()); + UUPSUpgradeable(address(currentImplProxy)).upgradeTo(nextImpl); + KarmaWithAccessControl(currentImplProxy).initializeAccessControl(); + vm.stopBroadcast(); + return nextImpl; + } +} diff --git a/src/Karma.sol b/src/Karma.sol index 0967718..c293761 100644 --- a/src/Karma.sol +++ b/src/Karma.sol @@ -37,6 +37,9 @@ contract Karma is Initializable, ERC20Upgradeable, Ownable2StepUpgradeable, UUPS EnumerableSet.AddressSet private rewardDistributors; /// @notice Mapping of reward distributor to allocation mapping(address distributor => uint256 allocation) public rewardDistributorAllocations; + /// @notice Gap for upgrade safety. + // solhint-disable-next-line + uint256[30] private __gap_Karma; /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR @@ -66,13 +69,8 @@ contract Karma is Initializable, ERC20Upgradeable, Ownable2StepUpgradeable, UUPS * @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(); - } - - rewardDistributors.add(address(distributor)); - emit RewardDistributorAdded(distributor); + function addRewardDistributor(address distributor) public virtual onlyOwner { + _addRewardDistributor(distributor); } /** @@ -80,12 +78,8 @@ contract Karma is Initializable, ERC20Upgradeable, Ownable2StepUpgradeable, UUPS * @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); + function removeRewardDistributor(address distributor) public virtual onlyOwner { + _removeRewardDistributor(distributor); } /** @@ -96,14 +90,8 @@ contract Karma is Initializable, ERC20Upgradeable, Ownable2StepUpgradeable, UUPS * @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); + function setReward(address rewardsDistributor, uint256 amount, uint256 duration) public virtual onlyOwner { + _setReward(rewardsDistributor, amount, duration); } /** @@ -113,7 +101,7 @@ contract Karma is Initializable, ERC20Upgradeable, Ownable2StepUpgradeable, UUPS * @param account The account to mint tokens to. * @param amount The amount of tokens to mint. */ - function mint(address account, uint256 amount) external onlyOwner { + function mint(address account, uint256 amount) public virtual onlyOwner { _mint(account, amount); } @@ -162,10 +150,47 @@ contract Karma is Initializable, ERC20Upgradeable, Ownable2StepUpgradeable, UUPS * @notice Authorizes contract upgrades via UUPS. * @dev This function is only callable by the owner. */ - function _authorizeUpgrade(address) internal view override { + function _authorizeUpgrade(address) internal view virtual override { _checkOwner(); } + /** + * @notice Adds a reward distributor to the set of reward distributors. + * @param distributor The address of the reward distributor. + */ + function _addRewardDistributor(address distributor) internal virtual { + if (rewardDistributors.contains(distributor)) { + revert Karma__DistributorAlreadyAdded(); + } + + rewardDistributors.add(distributor); + emit RewardDistributorAdded(distributor); + } + + /** + * @notice Removes a reward distributor from the set of reward distributors. + * @param distributor The address of the reward distributor. + */ + function _removeRewardDistributor(address distributor) internal virtual { + if (!rewardDistributors.contains(distributor)) { + revert Karma__UnknownDistributor(); + } + rewardDistributors.remove(distributor); + } + + /** + * @notice Sets the reward for a reward distributor. + */ + function _setReward(address rewardsDistributor, uint256 amount, uint256 duration) internal virtual { + if (!rewardDistributors.contains(rewardsDistributor)) { + revert Karma__UnknownDistributor(); + } + + rewardDistributorAllocations[rewardsDistributor] += amount; + totalDistributorAllocation += amount; + IRewardDistributor(rewardsDistributor).setReward(amount, duration); + } + /*////////////////////////////////////////////////////////////////////////// VIEW FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ diff --git a/src/KarmaWithAccessControl.sol b/src/KarmaWithAccessControl.sol new file mode 100644 index 0000000..403222e --- /dev/null +++ b/src/KarmaWithAccessControl.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { Karma } from "./Karma.sol"; +import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; + +contract KarmaWithAccessControl is Karma, AccessControlUpgradeable { + /// @notice Emitted sender does not have the required role + error KarmaWithAccessControl__Unauthorized(); + + /// @notice Operator role keccak256("OPERATOR_ROLE") + bytes32 public constant OPERATOR_ROLE = 0x97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929; + /// @notice Gap for future variable additions + // solhint-disable-next-line var-name-mixedcase + uint256[15] private __gap_KarmaWithAccessControl; + + /// @notice Modifier to check if sender is admin or operator + modifier onlyAdminOrOperator() { + if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender) && !hasRole(OPERATOR_ROLE, msg.sender)) { + revert KarmaWithAccessControl__Unauthorized(); + } + _; + } + + /*////////////////////////////////////////////////////////////////////////// + USER-FACING FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /** + * @notice Initializes the contract with the provided owner. + * @dev This function needs to be called after the contract has been upgraded. + * @dev Sets up the `DEFAULT_ADMIN_ROLE` for the current owner. + */ + // function initializeAccessControl() external reinitializer(2) onlyOwner { + function initializeAccessControl() external reinitializer(2) onlyOwner { + __AccessControl_init(); + _setupRole(DEFAULT_ADMIN_ROLE, owner()); + } + + /** + * @inheritdoc Karma + * @dev Added role-based access control with DEFAULT_ADMIN_ROLE. + */ + function addRewardDistributor(address distributor) public override onlyRole(DEFAULT_ADMIN_ROLE) { + _addRewardDistributor(distributor); + } + + /** + * @inheritdoc Karma + * @dev Added role-based access control with DEFAULT_ADMIN_ROLE. + */ + function removeRewardDistributor(address distributor) public override onlyRole(DEFAULT_ADMIN_ROLE) { + _removeRewardDistributor(distributor); + } + + /** + * @inheritdoc Karma + * @dev Added role-based access control with DEFAULT_ADMIN_ROLE and OPERATOR_ROLE. + */ + function setReward(address distributor, uint256 amount, uint256 duration) public override onlyAdminOrOperator { + _setReward(distributor, amount, duration); + } + + /** + * @inheritdoc Karma + * @dev Added role-based access control with DEFAULT_ADMIN_ROLE and OPERATOR_ROLE. + */ + function mint(address account, uint256 amount) public override onlyAdminOrOperator { + _mint(account, amount); + } + + /*////////////////////////////////////////////////////////////////////////// + INTERNAL FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /** + * @notice Authorizes the upgrade of the contract. + * @dev Enables owner and accounts with DEFAULT_ADMIN_ROLE to upgrade the contract. + */ + function _authorizeUpgrade(address) internal view virtual override { + if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) { + revert KarmaWithAccessControl__Unauthorized(); + } + } +} diff --git a/test/KarmaWithAccessControl.t.sol b/test/KarmaWithAccessControl.t.sol new file mode 100644 index 0000000..fa6d6cf --- /dev/null +++ b/test/KarmaWithAccessControl.t.sol @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; + +import { Test } from "forge-std/Test.sol"; +import { Karma } from "../src/Karma.sol"; +import { KarmaWithAccessControl } from "../src/KarmaWithAccessControl.sol"; +import { DeploymentConfig } from "../script/DeploymentConfig.s.sol"; +import { DeployKarmaScript } from "../script/DeployKarma.s.sol"; +import { UpgradeToKarmaWithAccessControlScript } from "../script/UpgradeToKarmaWithAccessControl.s.sol"; +import { KarmaDistributorMock } from "./mocks/KarmaDistributorMock.sol"; + +contract KarmaWithAccessControlTest is Test { + KarmaWithAccessControl public karma; + + address public deployer; + + address public operator = makeAddr("operator"); + + address public distributor; + + function setUp() public virtual { + // Deploy the original Karma contract + DeployKarmaScript karmaDeployment = new DeployKarmaScript(); + (Karma _karma, DeploymentConfig config) = karmaDeployment.run(); + (deployer,) = config.activeNetworkConfig(); + + // upgrade to KarmaWithAccessControl + UpgradeToKarmaWithAccessControlScript upgrade = new UpgradeToKarmaWithAccessControlScript(); + upgrade.runWithAdminAndProxy(deployer, address(_karma)); + karma = KarmaWithAccessControl(address(_karma)); + + distributor = address(new KarmaDistributorMock()); + } + + function test_InitializeAccessControl() public { + assert(karma.hasRole(karma.DEFAULT_ADMIN_ROLE(), deployer)); + } +} + +contract AddRewardDistributorTest is KarmaWithAccessControlTest { + function setUp() public virtual override { + super.setUp(); + } + + function test_RevertWhen_SenderIsNotDefaultAdmin() public { + vm.prank(makeAddr("someone")); + vm.expectRevert(); + karma.addRewardDistributor(distributor); + } + + function testAddRewardDistributor() public { + vm.prank(deployer); + karma.addRewardDistributor(distributor); + address[] memory distributors = karma.getRewardDistributors(); + assertEq(distributors.length, 1); + assertEq(distributors[0], distributor); + } + + function testAddRewardDistributorAsOtherAdmin() public { + address otherAdmin = makeAddr("otherAdmin"); + vm.startPrank(deployer); + karma.grantRole(karma.DEFAULT_ADMIN_ROLE(), otherAdmin); + vm.stopPrank(); + + vm.prank(otherAdmin); + karma.addRewardDistributor(distributor); + address[] memory distributors = karma.getRewardDistributors(); + assertEq(distributors.length, 1); + assertEq(distributors[0], distributor); + } +} + +contract RemoveRewardDistributorTest is KarmaWithAccessControlTest { + function setUp() public virtual override { + super.setUp(); + } + + function test_RevertWhen_SenderIsNotDefaultAdmin() public { + vm.expectRevert(); + karma.removeRewardDistributor(distributor); + } + + function testRemoveRewardDistributor() public { + // add a distributor + vm.prank(deployer); + karma.addRewardDistributor(distributor); + address[] memory distributors = karma.getRewardDistributors(); + assertEq(distributors.length, 1); + assertEq(distributors[0], distributor); + + // remove the distributor + vm.prank(deployer); + karma.removeRewardDistributor(distributor); + distributors = karma.getRewardDistributors(); + assertEq(distributors.length, 0); + } + + function testRemoveRewardDistributorAsOtherAdmin() public { + // add a distributor + vm.prank(deployer); + karma.addRewardDistributor(distributor); + address[] memory distributors = karma.getRewardDistributors(); + assertEq(distributors.length, 1); + assertEq(distributors[0], distributor); + + // grant admin role + address otherAdmin = makeAddr("otherAdmin"); + vm.startPrank(deployer); + karma.grantRole(karma.DEFAULT_ADMIN_ROLE(), otherAdmin); + vm.stopPrank(); + + // remove the distributor + vm.prank(otherAdmin); + karma.removeRewardDistributor(distributor); + distributors = karma.getRewardDistributors(); + assertEq(distributors.length, 0); + } +} + +contract SetRewardTest is KarmaWithAccessControlTest { + function setUp() public virtual override { + super.setUp(); + vm.prank(deployer); + karma.addRewardDistributor(distributor); + } + + function test_RevertWhen_SenderIsNotDefaultAdmin() public { + vm.prank(makeAddr("someone")); + vm.expectRevert(); + karma.setReward(distributor, 0, 0); + } + + function test_RevertWhen_SenderIsNotOperator() public { + assert(karma.hasRole(karma.OPERATOR_ROLE(), operator) == false); + + vm.prank(operator); + vm.expectRevert(); + karma.setReward(distributor, 0, 0); + } + + function testSetRewardAsAdmin() public { + vm.prank(deployer); + karma.setReward(distributor, 0, 0); + } + + function testSetRewardAsOtherAdmin() public { + vm.startPrank(deployer); + karma.grantRole(karma.DEFAULT_ADMIN_ROLE(), operator); + vm.stopPrank(); + + vm.prank(operator); + karma.setReward(distributor, 0, 0); + } + + function testSetRewardAsOperator() public { + // grant operator role + assert(karma.hasRole(karma.DEFAULT_ADMIN_ROLE(), deployer)); + + // actually `vm.prank()` should be used here, but for some reason + // foundry seems to mess up the context for what `deployer` is + vm.startPrank(deployer); + karma.grantRole(karma.OPERATOR_ROLE(), operator); + vm.stopPrank(); + + // set reward as operator + vm.prank(operator); + karma.setReward(distributor, 0, 0); + } +}