mirror of
https://github.com/vacp2p/staking-reward-streamer.git
synced 2026-01-08 04:33:52 -05:00
feat: implement KarmaTiers
This commit introduces a new contract `KarmaTiers` that allows for maintaing tiers for gasless transactions. The owner of the contract can add tiers, update tiers and deactivate or activate them. Tier names can only be 32 bytes long and there's no overlap allowed between min and max Karma bounds of the tiers. Closes #216
This commit is contained in:
78
.gas-report
78
.gas-report
@@ -41,6 +41,20 @@
|
||||
| runForTest | 3759238 | 3759238 | 3759238 | 3759238 | 10 |
|
||||
╰-----------------------------------------------------------+-----------------+---------+---------+---------+---------╯
|
||||
|
||||
╭---------------------------------------------------------------+-----------------+---------+---------+---------+---------╮
|
||||
| script/DeployKarmaTiers.s.sol:DeployKarmaTiersScript Contract | | | | | |
|
||||
+=========================================================================================================================+
|
||||
| Deployment Cost | Deployment Size | | | | |
|
||||
|---------------------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| 3542177 | 17392 | | | | |
|
||||
|---------------------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| | | | | | |
|
||||
|---------------------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|---------------------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| run | 2968362 | 2968362 | 2968362 | 2968362 | 33 |
|
||||
╰---------------------------------------------------------------+-----------------+---------+---------+---------+---------╯
|
||||
|
||||
╭-------------------------------------------------------------------+-----------------+---------+---------+---------+---------╮
|
||||
| script/DeployStakeManager.s.sol:DeployStakeManagerScript Contract | | | | | |
|
||||
+=============================================================================================================================+
|
||||
@@ -66,7 +80,7 @@
|
||||
|---------------------------------------------------------+-----------------+------+--------+------+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|---------------------------------------------------------+-----------------+------+--------+------+---------|
|
||||
| activeNetworkConfig | 455 | 2022 | 455 | 4455 | 462 |
|
||||
| activeNetworkConfig | 455 | 2076 | 455 | 4455 | 528 |
|
||||
╰---------------------------------------------------------+-----------------+------+--------+------+---------╯
|
||||
|
||||
╭---------------------------------------------------------------------+-----------------+---------+---------+---------+---------╮
|
||||
@@ -173,6 +187,36 @@
|
||||
| transferFrom | 530 | 530 | 530 | 530 | 1 |
|
||||
╰-------------------------------------------------+-----------------+-------+--------+-------+---------╯
|
||||
|
||||
╭----------------------------------------+-----------------+--------+--------+--------+---------╮
|
||||
| src/KarmaTiers.sol:KarmaTiers Contract | | | | | |
|
||||
+===============================================================================================+
|
||||
| Deployment Cost | Deployment Size | | | | |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| 0 | 5856 | | | | |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| | | | | | |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| MAX_TIER_NAME_LENGTH | 240 | 240 | 240 | 240 | 1 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| activateTier | 23752 | 27234 | 25870 | 32081 | 3 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| addTier | 24619 | 138647 | 140518 | 163301 | 563 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| currentTierId | 2326 | 2326 | 2326 | 2326 | 2 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| deactivateTier | 23787 | 30495 | 32110 | 32110 | 9 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| getTierById | 555 | 12473 | 12448 | 14510 | 520 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| getTierCount | 2365 | 2365 | 2365 | 2365 | 5 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| getTierIdByKarmaBalance | 50511 | 50598 | 50618 | 50645 | 4 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| updateTier | 25139 | 52773 | 51895 | 74613 | 261 |
|
||||
╰----------------------------------------+-----------------+--------+--------+--------+---------╯
|
||||
|
||||
╭--------------------------------------------+-----------------+--------+--------+--------+---------╮
|
||||
| src/StakeManager.sol:StakeManager Contract | | | | | |
|
||||
+===================================================================================================+
|
||||
@@ -200,7 +244,7 @@
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| getAccountVaults | 5230 | 5230 | 5230 | 5230 | 4 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| getVault | 13653 | 13653 | 13653 | 13653 | 4182 |
|
||||
| getVault | 13653 | 13653 | 13653 | 13653 | 4181 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| initialize | 92752 | 92752 | 92752 | 92752 | 95 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
@@ -208,7 +252,7 @@
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| leave | 66348 | 66348 | 66348 | 66348 | 2 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| lock | 7040 | 43452 | 46713 | 87964 | 1034 |
|
||||
| lock | 7040 | 43275 | 46713 | 87673 | 1034 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| migrateToVault | 9294 | 53513 | 17021 | 170715 | 4 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
@@ -236,17 +280,17 @@
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| setTrustedCodehash | 24238 | 24238 | 24238 | 24238 | 95 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| stake | 2639 | 131319 | 60725 | 228623 | 2670 |
|
||||
| stake | 2639 | 130108 | 60725 | 228623 | 2670 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| stakedBalanceOf | 2622 | 2622 | 2622 | 2622 | 1 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| totalMP | 6805 | 8257 | 8257 | 9710 | 6 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| totalMPAccrued | 2385 | 2385 | 2385 | 2385 | 4162 |
|
||||
| totalMPAccrued | 2385 | 2385 | 2385 | 2385 | 4161 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| totalMPStaked | 2429 | 2429 | 2429 | 2429 | 4165 |
|
||||
| totalMPStaked | 2429 | 2429 | 2429 | 2429 | 4164 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| totalMaxMP | 2407 | 2407 | 2407 | 2407 | 4162 |
|
||||
| totalMaxMP | 2407 | 2407 | 2407 | 2407 | 4161 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| totalRewardsAccrued | 2407 | 2407 | 2407 | 2407 | 3 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
@@ -254,15 +298,15 @@
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| totalShares | 4597 | 4597 | 4597 | 4597 | 6 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| totalStaked | 2408 | 2408 | 2408 | 2408 | 4169 |
|
||||
| totalStaked | 2408 | 2408 | 2408 | 2408 | 4168 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| unstake | 9886 | 41365 | 39781 | 79550 | 271 |
|
||||
| unstake | 9886 | 41581 | 39781 | 79550 | 271 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| updateAccount | 347677 | 347677 | 347677 | 347677 | 1 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| updateGlobalState | 15820 | 25876 | 29230 | 29230 | 8 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| updateVault | 31948 | 34373 | 31948 | 110579 | 1024 |
|
||||
| updateVault | 31948 | 34036 | 31948 | 110579 | 1023 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| upgradeTo | 10279 | 10772 | 10279 | 12745 | 5 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
@@ -290,7 +334,7 @@
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| leave | 12223 | 113137 | 84120 | 356508 | 5 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| lock | 12151 | 58945 | 62251 | 103499 | 1035 |
|
||||
| lock | 12151 | 58767 | 62251 | 103208 | 1035 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| lockUntil | 2363 | 2363 | 2363 | 2363 | 7768 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
@@ -300,15 +344,15 @@
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| register | 12742 | 78218 | 78761 | 78761 | 374 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| stake | 12131 | 165586 | 76290 | 284275 | 2671 |
|
||||
| stake | 12131 | 164075 | 76290 | 284275 | 2671 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| stakeManager | 393 | 393 | 393 | 393 | 373 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| trustStakeManager | 7650 | 7650 | 7650 | 7650 | 1 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| unstake | 12108 | 58033 | 55296 | 110656 | 272 |
|
||||
| unstake | 12108 | 58192 | 55296 | 110656 | 272 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| updateLockUntil | 4432 | 20797 | 21532 | 21532 | 508 |
|
||||
| updateLockUntil | 4432 | 20802 | 21532 | 21532 | 488 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| withdraw | 20817 | 20817 | 20817 | 20817 | 1 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
@@ -326,9 +370,9 @@
|
||||
|----------------------------------------------------+-----------------+-------+--------+--------+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|----------------------------------------------------+-----------------+-------+--------+--------+---------|
|
||||
| fallback | 5208 | 12834 | 7353 | 374054 | 23167 |
|
||||
| fallback | 5208 | 12818 | 7353 | 374054 | 23161 |
|
||||
|----------------------------------------------------+-----------------+-------+--------+--------+---------|
|
||||
| implementation | 346 | 2137 | 2346 | 2346 | 4870 |
|
||||
| implementation | 346 | 2144 | 2346 | 2346 | 4850 |
|
||||
╰----------------------------------------------------+-----------------+-------+--------+--------+---------╯
|
||||
|
||||
╭--------------------------------------------+-----------------+--------+--------+--------+---------╮
|
||||
@@ -510,7 +554,7 @@
|
||||
|---------------------------------------------+-----------------+-------+--------+-------+---------|
|
||||
| approve | 29075 | 31545 | 29183 | 46259 | 2676 |
|
||||
|---------------------------------------------+-----------------+-------+--------+-------+---------|
|
||||
| balanceOf | 2561 | 2561 | 2561 | 2561 | 4960 |
|
||||
| balanceOf | 2561 | 2561 | 2561 | 2561 | 4959 |
|
||||
|---------------------------------------------+-----------------+-------+--------+-------+---------|
|
||||
| mint | 33964 | 37190 | 34072 | 68248 | 2685 |
|
||||
╰---------------------------------------------+-----------------+-------+--------+-------+---------╯
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
ActivateTierTests:test_ActivateTier_RevertWhen_InvalidTierId() (gas: 36310)
|
||||
ActivateTierTests:test_ActivateTier_RevertWhen_NotOwner() (gas: 210441)
|
||||
ActivateTierTests:test_ActivateTier_Success() (gas: 234495)
|
||||
AddRewardDistributorTest:testAddKarmaDistributorOnlyAdmin() (gas: 438258)
|
||||
AddRewardDistributorTest:testAddRewardDistributorAsOtherAdmin() (gas: 182935)
|
||||
AddRewardDistributorTest:testBalanceOf() (gas: 456642)
|
||||
@@ -8,6 +11,20 @@ AddRewardDistributorTest:testRemoveUnknownKarmaDistributor() (gas: 41666)
|
||||
AddRewardDistributorTest:testTotalSupply() (gas: 359391)
|
||||
AddRewardDistributorTest:testTransfersNotAllowed() (gas: 61947)
|
||||
AddRewardDistributorTest:test_RevertWhen_SenderIsNotDefaultAdmin() (gas: 68406)
|
||||
AddTierTests:test_AddTier_MultipleSuccessiveTiers() (gas: 421808)
|
||||
AddTierTests:test_AddTier_RevertWhen_EmptyName() (gas: 35216)
|
||||
AddTierTests:test_AddTier_RevertWhen_InvalidRange() (gas: 36148)
|
||||
AddTierTests:test_AddTier_RevertWhen_InvalidRangeEqual() (gas: 36214)
|
||||
AddTierTests:test_AddTier_RevertWhen_NotOwner() (gas: 35540)
|
||||
AddTierTests:test_AddTier_RevertWhen_OverlappingTiers() (gas: 189527)
|
||||
AddTierTests:test_AddTier_RevertWhen_TierNameTooLong() (gas: 42578)
|
||||
AddTierTests:test_AddTier_Success() (gas: 180523)
|
||||
AddTierTests:test_AddTier_UnlimitedMaxKarma() (gas: 147634)
|
||||
DeactivateActivateTierTests:test_DeactivateTier_RevertWhen_InvalidTierId() (gas: 36377)
|
||||
DeactivateActivateTierTests:test_DeactivateTier_RevertWhen_NotOwner() (gas: 177408)
|
||||
DeactivateActivateTierTests:test_DeactivateTier_Success() (gas: 201619)
|
||||
EdgeCasesTest:test_OverlapValidation_EdgeCases() (gas: 312965)
|
||||
EdgeCasesTest:test_UnlimitedTierOverlap() (gas: 208274)
|
||||
EmergencyExitTest:test_CannotEnableEmergencyModeTwice() (gas: 93554)
|
||||
EmergencyExitTest:test_CannotLeaveBeforeEmergencyMode() (gas: 336067)
|
||||
EmergencyExitTest:test_EmergencyExitBasic() (gas: 524580)
|
||||
@@ -16,15 +33,21 @@ EmergencyExitTest:test_EmergencyExitToAlternateAddress() (gas: 479110)
|
||||
EmergencyExitTest:test_EmergencyExitWithLock() (gas: 452444)
|
||||
EmergencyExitTest:test_EmergencyExitWithRewards() (gas: 484810)
|
||||
EmergencyExitTest:test_OnlyOwnerCanEnableEmergencyMode() (gas: 39176)
|
||||
FuzzTests:testFuzz_AccrueMP(uint128,uint64,uint64) (runs: 1009, μ: 583242, ~: 549046)
|
||||
FuzzTests:testFuzz_AccrueMP_Relock(uint128,uint64,uint64,uint64) (runs: 1009, μ: 808244, ~: 777237)
|
||||
FuzzTests:testFuzz_EmergencyExit(uint256,uint256) (runs: 1001, μ: 588167, ~: 578267)
|
||||
FuzzTests:testFuzz_Lock(uint256,uint64) (runs: 1008, μ: 961506, ~: 961235)
|
||||
FuzzTests:testFuzz_Relock(uint256,uint64,uint64) (runs: 1008, μ: 600126, ~: 574225)
|
||||
FuzzTests:testFuzz_Rewards(uint256,uint256,uint256,uint16,uint16) (runs: 1001, μ: 650444, ~: 653254)
|
||||
FuzzTests:testFuzz_Stake(uint256,uint64) (runs: 1008, μ: 377931, ~: 346087)
|
||||
FuzzTests:testFuzz_Unstake(uint128,uint64,uint16,uint128) (runs: 1009, μ: 803049, ~: 780598)
|
||||
FuzzTests:testFuzz_UpdateVault(uint128,uint64,uint64) (runs: 1009, μ: 583265, ~: 549069)
|
||||
FuzzTests:testFuzz_AccrueMP(uint128,uint64,uint64) (runs: 1002, μ: 581651, ~: 549041)
|
||||
FuzzTests:testFuzz_AccrueMP_Relock(uint128,uint64,uint64,uint64) (runs: 1002, μ: 806522, ~: 777234)
|
||||
FuzzTests:testFuzz_AddTier_ValidInputs(string,uint256,uint256,uint32) (runs: 1001, μ: 171310, ~: 171538)
|
||||
FuzzTests:testFuzz_EmergencyExit(uint256,uint256) (runs: 1000, μ: 588178, ~: 578267)
|
||||
FuzzTests:testFuzz_Lock(uint256,uint64) (runs: 1002, μ: 961278, ~: 961235)
|
||||
FuzzTests:testFuzz_Relock(uint256,uint64,uint64) (runs: 1002, μ: 598418, ~: 574225)
|
||||
FuzzTests:testFuzz_Rewards(uint256,uint256,uint256,uint16,uint16) (runs: 1000, μ: 650441, ~: 653254)
|
||||
FuzzTests:testFuzz_Stake(uint256,uint64) (runs: 1002, μ: 376429, ~: 346087)
|
||||
FuzzTests:testFuzz_Unstake(uint128,uint64,uint16,uint128) (runs: 1002, μ: 801209, ~: 780598)
|
||||
FuzzTests:testFuzz_UpdateTier_ValidInputs(string,uint256,uint256,string,uint256,uint256,uint32,uint32) (runs: 1000, μ: 226513, ~: 225288)
|
||||
FuzzTests:testFuzz_UpdateVault(uint128,uint64,uint64) (runs: 1002, μ: 581674, ~: 549064)
|
||||
GetTierIdByKarmaBalanceTest:test_GetTierIdByKarmaBalance_BelowMinKarma() (gas: 58622)
|
||||
GetTierIdByKarmaBalanceTest:test_GetTierIdByKarmaBalance_InBronzeTier() (gas: 58727)
|
||||
GetTierIdByKarmaBalanceTest:test_GetTierIdByKarmaBalance_InGoldTier() (gas: 58767)
|
||||
GetTierIdByKarmaBalanceTest:test_GetTierIdByKarmaBalance_InSilverTier() (gas: 58759)
|
||||
IntegrationTest:testStakeFoo() (gas: 2348931)
|
||||
KarmaNFTTest:testApproveNotAllowed() (gas: 10507)
|
||||
KarmaNFTTest:testGetApproved() (gas: 10531)
|
||||
@@ -58,7 +81,7 @@ LeaveTest:test_LeaveShouldKeepFundsLockedInStakeVault() (gas: 9938411)
|
||||
LeaveTest:test_LeaveShouldProperlyUpdateAccounting() (gas: 10011059)
|
||||
LeaveTest:test_RevertWhenStakeManagerIsTrusted() (gas: 333238)
|
||||
LeaveTest:test_TrustNewStakeManager() (gas: 9944491)
|
||||
LockTest:test_LockFailsWithInvalidPeriod(uint256) (runs: 1008, μ: 384560, ~: 384588)
|
||||
LockTest:test_LockFailsWithInvalidPeriod(uint256) (runs: 1002, μ: 384561, ~: 384588)
|
||||
LockTest:test_LockFailsWithNoStake() (gas: 89700)
|
||||
LockTest:test_LockFailsWithZero() (gas: 343310)
|
||||
LockTest:test_LockMultipleTimesExceedMaxLock() (gas: 746921)
|
||||
@@ -133,7 +156,7 @@ SetRewardTest:test_RevertWhen_SenderIsNotOperator() (gas: 61893)
|
||||
SlashAmountOfTest:testAddKarmaDistributorOnlyAdmin() (gas: 438224)
|
||||
SlashAmountOfTest:testBalanceOf() (gas: 456642)
|
||||
SlashAmountOfTest:testBalanceOfWithNoSystemTotalKarma() (gas: 83783)
|
||||
SlashAmountOfTest:testFuzz_SlashAmountOf(uint256,uint256,uint256) (runs: 1002, μ: 407788, ~: 408571)
|
||||
SlashAmountOfTest:testFuzz_SlashAmountOf(uint256,uint256,uint256) (runs: 1000, μ: 407786, ~: 408571)
|
||||
SlashAmountOfTest:testMintOnlyAdmin() (gas: 429075)
|
||||
SlashAmountOfTest:testRemoveKarmaDistributorOnlyOwner() (gas: 163437)
|
||||
SlashAmountOfTest:testRemoveUnknownKarmaDistributor() (gas: 41654)
|
||||
@@ -143,7 +166,7 @@ SlashAmountOfTest:test_SlashAmountOf() (gas: 327608)
|
||||
SlashTest:testAddKarmaDistributorOnlyAdmin() (gas: 438270)
|
||||
SlashTest:testBalanceOf() (gas: 456648)
|
||||
SlashTest:testBalanceOfWithNoSystemTotalKarma() (gas: 83827)
|
||||
SlashTest:testFuzz_Slash(uint256) (runs: 1009, μ: 280204, ~: 280146)
|
||||
SlashTest:testFuzz_Slash(uint256) (runs: 1002, μ: 280204, ~: 280146)
|
||||
SlashTest:testMintOnlyAdmin() (gas: 429131)
|
||||
SlashTest:testRemoveKarmaDistributorOnlyOwner() (gas: 163461)
|
||||
SlashTest:testRemoveRewardDistributorShouldReduceSlashAmount() (gas: 610762)
|
||||
@@ -206,9 +229,19 @@ UnstakeTest:test_UnstakeOneAccount() (gas: 759178)
|
||||
UnstakeTest:test_UnstakeOneAccountAndAccruedMP() (gas: 719489)
|
||||
UnstakeTest:test_UnstakeOneAccountAndRewards() (gas: 673681)
|
||||
UnstakeTest:test_UnstakeOneAccountWithLockUpAndAccruedMP() (gas: 722241)
|
||||
UpdateTierTests:test_UpdateTier_RevertWhen_InvalidRange() (gas: 38505)
|
||||
UpdateTierTests:test_UpdateTier_RevertWhen_InvalidTierId() (gas: 37814)
|
||||
UpdateTierTests:test_UpdateTier_RevertWhen_NotOwner() (gas: 35753)
|
||||
UpdateTierTests:test_UpdateTier_RevertWhen_OverlapWithOtherTier() (gas: 183290)
|
||||
UpdateTierTests:test_UpdateTier_Success() (gas: 83795)
|
||||
UpdateVaultTest:test_UpdateAccount() (gas: 2587427)
|
||||
UpgradeTest:test_RevertWhenNotOwner() (gas: 3696209)
|
||||
UpgradeTest:test_UpgradeStakeManager() (gas: 9855347)
|
||||
VaultRegistrationTest:test_VaultRegistration() (gas: 90138)
|
||||
ViewFunctionsTest:test_GetTierById_RevertWhen_InvalidTierId() (gas: 13153)
|
||||
ViewFunctionsTest:test_GetTierById_RevertWhen_TierIdZero() (gas: 11056)
|
||||
ViewFunctionsTest:test_GetTierById_Success() (gas: 169210)
|
||||
ViewFunctionsTest:test_GetTierCount_IncreasesWithTiers() (gas: 299987)
|
||||
ViewFunctionsTest:test_GetTierCount_InitiallyZero() (gas: 10505)
|
||||
WithdrawTest:testOwner() (gas: 15365)
|
||||
WithdrawTest:test_CannotWithdrawStakedFunds() (gas: 373408)
|
||||
22
script/DeployKarmaTiers.s.sol
Normal file
22
script/DeployKarmaTiers.s.sol
Normal file
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import { BaseScript } from "./Base.s.sol";
|
||||
import { DeploymentConfig } from "./DeploymentConfig.s.sol";
|
||||
|
||||
import { KarmaTiers } from "../src/KarmaTiers.sol";
|
||||
|
||||
contract DeployKarmaTiersScript is BaseScript {
|
||||
function run() public returns (KarmaTiers, DeploymentConfig) {
|
||||
DeploymentConfig deploymentConfig = new DeploymentConfig(broadcaster);
|
||||
(address deployer,) = deploymentConfig.activeNetworkConfig();
|
||||
|
||||
vm.startBroadcast(deployer);
|
||||
|
||||
KarmaTiers karmaTiers = new KarmaTiers();
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
return (karmaTiers, deploymentConfig);
|
||||
}
|
||||
}
|
||||
233
src/KarmaTiers.sol
Normal file
233
src/KarmaTiers.sol
Normal file
@@ -0,0 +1,233 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.26;
|
||||
|
||||
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
|
||||
|
||||
/**
|
||||
* @title KarmaTiers
|
||||
* @dev Manages tier system based on Karma token balance thresholds
|
||||
* @notice This contract allows efficient tier lookup for L2 nodes and tier management
|
||||
*/
|
||||
contract KarmaTiers is Ownable {
|
||||
/// @notice Emitted when a new tier is added
|
||||
event TierAdded(uint8 indexed tierId, string name, uint256 minKarma, uint256 maxKarma, uint32 txPerEpoch);
|
||||
/// @notice Emitted when a tier is updated
|
||||
event TierUpdated(uint8 indexed tierId, string name, uint256 minKarma, uint256 maxKarma, uint32 txPerEpoch);
|
||||
/// @notice Emitted when a tier is deactivated
|
||||
event TierDeactivated(uint8 indexed tierId);
|
||||
/// @notice Emitted when a tier is activated
|
||||
event TierActivated(uint8 indexed tierId);
|
||||
|
||||
/// @notice Emitted when a transaction amount is invalid
|
||||
error InvalidTxAmount();
|
||||
/// @notice Emitted when a tier name is empty
|
||||
error EmptyTierName();
|
||||
/// @notice Emitted when a tier is not found
|
||||
error TierNotFound();
|
||||
/// @notice Emitted when a tier name exceeds maximum length
|
||||
error TierNameTooLong(uint256 nameLength, uint256 maxLength);
|
||||
/// @notice Emitted when a new tier overlaps with an existing one
|
||||
error OverlappingTiers(uint8 existingTierId, uint256 newMinKarma, uint256 newMaxKarma);
|
||||
/// @notice Emitted when a tier's minKarma is greater than or equal to maxKarma
|
||||
error InvalidTierRange(uint256 minKarma, uint256 maxKarma);
|
||||
|
||||
struct Tier {
|
||||
uint256 minKarma;
|
||||
uint256 maxKarma;
|
||||
string name;
|
||||
uint32 txPerEpoch;
|
||||
bool active;
|
||||
}
|
||||
|
||||
modifier onlyValidTierId(uint8 tierId) {
|
||||
if (tierId == 0 || tierId > currentTierId) {
|
||||
revert TierNotFound();
|
||||
}
|
||||
_;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
CONSTANTS
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/// @notice Maximum length for tier names
|
||||
uint256 public constant MAX_TIER_NAME_LENGTH = 32;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
STATE VARIABLES
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/// @notice Mapping of tier IDs to Tier structs
|
||||
mapping(uint8 id => Tier tier) public tiers;
|
||||
/// @notice Current tier ID, incremented with each new tier added
|
||||
uint8 public currentTierId;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
CONSTRUCTOR
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
constructor() {
|
||||
transferOwnership(msg.sender);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
USER-FACING FUNCTIONS
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* @dev Add a new tier to the system
|
||||
* @param name The name of the tier
|
||||
* @param minKarma Minimum Karma required for this tier
|
||||
* @param maxKarma Maximum Karma for this tier (0 for unlimited)
|
||||
*/
|
||||
function addTier(string calldata name, uint256 minKarma, uint256 maxKarma, uint32 txPerEpoch) external onlyOwner {
|
||||
if (bytes(name).length == 0) revert EmptyTierName();
|
||||
if (maxKarma != 0 && maxKarma <= minKarma) revert InvalidTierRange(minKarma, maxKarma);
|
||||
if (txPerEpoch == 0) revert InvalidTxAmount();
|
||||
|
||||
// Check for overlaps with existing tiers
|
||||
_validateNoOverlap(minKarma, maxKarma, type(uint8).max);
|
||||
_validateTierName(name);
|
||||
|
||||
currentTierId++;
|
||||
|
||||
tiers[currentTierId] =
|
||||
Tier({ minKarma: minKarma, maxKarma: maxKarma, name: name, active: true, txPerEpoch: txPerEpoch });
|
||||
|
||||
emit TierAdded(currentTierId, name, minKarma, maxKarma, txPerEpoch);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Update an existing tier
|
||||
* @param name The name of the tier to update
|
||||
* @param newMinKarma New minimum Karma requirement
|
||||
* @param newMaxKarma New maximum Karma (0 for unlimited)
|
||||
*/
|
||||
function updateTier(
|
||||
uint8 tierId,
|
||||
string calldata name,
|
||||
uint256 newMinKarma,
|
||||
uint256 newMaxKarma,
|
||||
uint32 newTxPerEpoch
|
||||
)
|
||||
external
|
||||
onlyOwner
|
||||
onlyValidTierId(tierId)
|
||||
{
|
||||
if (newMaxKarma != 0 && newMaxKarma <= newMinKarma) revert InvalidTierRange(newMinKarma, newMaxKarma);
|
||||
if (newTxPerEpoch == 0) revert InvalidTxAmount();
|
||||
|
||||
// Check for overlaps with other tiers (excluding the one being updated)
|
||||
_validateNoOverlap(newMinKarma, newMaxKarma, tierId);
|
||||
_validateTierName(name);
|
||||
|
||||
tiers[tierId].name = name;
|
||||
tiers[tierId].minKarma = newMinKarma;
|
||||
tiers[tierId].maxKarma = newMaxKarma;
|
||||
tiers[tierId].txPerEpoch = newTxPerEpoch;
|
||||
|
||||
emit TierUpdated(tierId, name, newMinKarma, newMaxKarma, newTxPerEpoch);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Deactivate a tier (keeps it in storage but marks as inactive)
|
||||
* @param tierId The ID of the tier to deactivate
|
||||
*/
|
||||
function deactivateTier(uint8 tierId) external onlyOwner onlyValidTierId(tierId) {
|
||||
tiers[tierId].active = false;
|
||||
emit TierDeactivated(tierId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Reactivate a tier
|
||||
* @param tierId The ID of the tier to reactivate
|
||||
*/
|
||||
function activateTier(uint8 tierId) external onlyOwner onlyValidTierId(tierId) {
|
||||
tiers[tierId].active = true;
|
||||
emit TierActivated(tierId);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
INTERNAL FUNCTIONS
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* @dev Validate tier name length and content
|
||||
* @param name The tier name to validate
|
||||
*/
|
||||
function _validateTierName(string calldata name) internal pure {
|
||||
bytes memory nameBytes = bytes(name);
|
||||
if (nameBytes.length == 0) revert EmptyTierName();
|
||||
if (nameBytes.length > MAX_TIER_NAME_LENGTH) {
|
||||
revert TierNameTooLong(nameBytes.length, MAX_TIER_NAME_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
VIEW FUNCTIONS
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* @notice Get tier by karma balance.
|
||||
* @dev This function returns the highest tier ID that the user qualifies for based on their karma balance.
|
||||
* @param karmaBalance The karma balance to check
|
||||
* @return tierId The tier id that matches the karma balance
|
||||
*/
|
||||
function getTierIdByKarmaBalance(uint256 karmaBalance) external view returns (uint8) {
|
||||
uint8 bestTierId = 0;
|
||||
uint256 bestMinKarma = 0;
|
||||
|
||||
for (uint8 i = 1; i <= currentTierId; i++) {
|
||||
Tier memory currentTier = tiers[i];
|
||||
if (!currentTier.active) continue;
|
||||
|
||||
// Check if user meets the minimum requirement for this tier
|
||||
if (karmaBalance >= currentTier.minKarma) {
|
||||
// Only update if this tier has a higher minKarma requirement
|
||||
if (currentTier.minKarma > bestMinKarma) {
|
||||
bestTierId = i;
|
||||
bestMinKarma = currentTier.minKarma;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bestTierId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get tier count
|
||||
* @return count Total number of tiers (including inactive)
|
||||
*/
|
||||
function getTierCount() external view returns (uint256 count) {
|
||||
return currentTierId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get tier by id
|
||||
* @param tierId The ID of the tier to retrieve
|
||||
* @return tier The tier information
|
||||
*/
|
||||
function getTierById(uint8 tierId) external view onlyValidTierId(tierId) returns (Tier memory tier) {
|
||||
return tiers[tierId];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function to validate no overlap exists
|
||||
* @param minKarma Minimum Karma for the tier
|
||||
* @param maxKarma Maximum Karma for the tier (0 = unlimited)
|
||||
*/
|
||||
function _validateNoOverlap(uint256 minKarma, uint256 maxKarma, uint8 excludeTierId) internal view {
|
||||
for (uint8 i = 1; i <= currentTierId; i++) {
|
||||
if (i == excludeTierId || !tiers[i].active) continue;
|
||||
|
||||
Tier memory existingTier = tiers[i];
|
||||
uint256 existingMax = existingTier.maxKarma == 0 ? type(uint256).max : existingTier.maxKarma;
|
||||
uint256 newMax = maxKarma == 0 ? type(uint256).max : maxKarma;
|
||||
|
||||
// Check for overlap using: NOT (no overlap) = overlap
|
||||
// No overlap means: newMax < existingMin OR newMin > existingMax
|
||||
if (!(newMax < existingTier.minKarma || minKarma > existingMax)) {
|
||||
revert OverlappingTiers(i, minKarma, maxKarma);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
436
test/KarmaTiers.t.sol
Normal file
436
test/KarmaTiers.t.sol
Normal file
@@ -0,0 +1,436 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.26;
|
||||
|
||||
import { Test } from "forge-std/Test.sol";
|
||||
import { DeploymentConfig } from "../script/DeploymentConfig.s.sol";
|
||||
import { DeployKarmaTiersScript } from "../script/DeployKarmaTiers.s.sol";
|
||||
import { KarmaTiers } from "../src/KarmaTiers.sol";
|
||||
|
||||
contract KarmaTiersTest is Test {
|
||||
KarmaTiers public karmaTiers;
|
||||
address public deployer;
|
||||
address public nonOwner = makeAddr("nonOwner");
|
||||
|
||||
event TierAdded(uint8 indexed tierId, string name, uint256 minKarma, uint256 maxKarma, uint32 txPerEpoch);
|
||||
event TierUpdated(uint8 indexed tierId, string name, uint256 minKarma, uint256 maxKarma, uint32 txPerEpoch);
|
||||
event TierDeactivated(uint8 indexed tierId);
|
||||
event TierActivated(uint8 indexed tierId);
|
||||
|
||||
function setUp() public virtual {
|
||||
DeployKarmaTiersScript deployment = new DeployKarmaTiersScript();
|
||||
(KarmaTiers _karmaTiers, DeploymentConfig deploymentConfig) = deployment.run();
|
||||
(address _deployer,) = deploymentConfig.activeNetworkConfig();
|
||||
deployer = _deployer;
|
||||
karmaTiers = _karmaTiers;
|
||||
}
|
||||
}
|
||||
|
||||
contract AddTierTests is KarmaTiersTest {
|
||||
function setUp() public override {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
function test_AddTier_RevertWhen_EmptyName() public {
|
||||
vm.prank(deployer);
|
||||
vm.expectRevert(KarmaTiers.EmptyTierName.selector);
|
||||
karmaTiers.addTier("", 100, 500, 5);
|
||||
}
|
||||
|
||||
function test_AddTier_RevertWhen_InvalidRange() public {
|
||||
vm.prank(deployer);
|
||||
vm.expectRevert(abi.encodeWithSelector(KarmaTiers.InvalidTierRange.selector, 500, 100));
|
||||
karmaTiers.addTier("Invalid", 500, 100, 5);
|
||||
}
|
||||
|
||||
function test_AddTier_RevertWhen_InvalidRangeEqual() public {
|
||||
vm.prank(deployer);
|
||||
vm.expectRevert(abi.encodeWithSelector(KarmaTiers.InvalidTierRange.selector, 500, 500));
|
||||
karmaTiers.addTier("Invalid", 500, 500, 5);
|
||||
}
|
||||
|
||||
function test_AddTier_RevertWhen_OverlappingTiers() public {
|
||||
vm.prank(deployer);
|
||||
karmaTiers.addTier("Bronze", 100, 500, 5);
|
||||
|
||||
vm.prank(deployer);
|
||||
vm.expectRevert(abi.encodeWithSelector(KarmaTiers.OverlappingTiers.selector, 1, 400, 600));
|
||||
karmaTiers.addTier("Silver", 400, 600, 5);
|
||||
}
|
||||
|
||||
function test_AddTier_RevertWhen_NotOwner() public {
|
||||
vm.prank(nonOwner);
|
||||
vm.expectRevert("Ownable: caller is not the owner");
|
||||
karmaTiers.addTier("Bronze", 100, 500, 5);
|
||||
}
|
||||
|
||||
function test_AddTier_RevertWhen_TierNameTooLong() public {
|
||||
string memory longName = "ThisIsAVeryLongTierNameThatExceedsTheMaximumAllowedLength";
|
||||
|
||||
vm.expectRevert(
|
||||
abi.encodeWithSelector(
|
||||
KarmaTiers.TierNameTooLong.selector, bytes(longName).length, karmaTiers.MAX_TIER_NAME_LENGTH()
|
||||
)
|
||||
);
|
||||
vm.prank(deployer);
|
||||
karmaTiers.addTier(longName, 100, 500, 5);
|
||||
}
|
||||
|
||||
function test_AddTier_Success() public {
|
||||
string memory tierName = "Bronze";
|
||||
uint256 minKarma = 100;
|
||||
uint256 maxKarma = 500;
|
||||
uint32 txPerEpoch = 5;
|
||||
|
||||
vm.expectEmit(true, false, false, true);
|
||||
emit TierAdded(1, tierName, minKarma, maxKarma, txPerEpoch);
|
||||
|
||||
vm.prank(deployer);
|
||||
karmaTiers.addTier(tierName, minKarma, maxKarma, txPerEpoch);
|
||||
|
||||
assertEq(karmaTiers.currentTierId(), 1);
|
||||
|
||||
KarmaTiers.Tier memory tier = karmaTiers.getTierById(1);
|
||||
assertEq(tier.name, tierName);
|
||||
assertEq(tier.minKarma, minKarma);
|
||||
assertEq(tier.maxKarma, maxKarma);
|
||||
assertTrue(tier.active);
|
||||
}
|
||||
|
||||
function test_AddTier_UnlimitedMaxKarma() public {
|
||||
string memory tierName = "Unlimited";
|
||||
uint256 minKarma = 1000;
|
||||
uint256 maxKarma = 0; // 0 means unlimited
|
||||
uint32 txPerEpoch = 5;
|
||||
|
||||
vm.prank(deployer);
|
||||
karmaTiers.addTier(tierName, minKarma, maxKarma, txPerEpoch);
|
||||
|
||||
KarmaTiers.Tier memory tier = karmaTiers.getTierById(1);
|
||||
assertEq(tier.maxKarma, 0);
|
||||
}
|
||||
|
||||
function test_AddTier_MultipleSuccessiveTiers() public {
|
||||
vm.startPrank(deployer);
|
||||
karmaTiers.addTier("Bronze", 0, 100, 5);
|
||||
karmaTiers.addTier("Silver", 101, 500, 5);
|
||||
karmaTiers.addTier("Gold", 501, 1000, 5);
|
||||
vm.stopPrank();
|
||||
|
||||
assertEq(karmaTiers.currentTierId(), 3);
|
||||
assertEq(karmaTiers.getTierCount(), 3);
|
||||
}
|
||||
}
|
||||
|
||||
contract UpdateTierTests is KarmaTiersTest {
|
||||
function setUp() public override {
|
||||
super.setUp();
|
||||
vm.prank(deployer);
|
||||
karmaTiers.addTier("Bronze", 100, 500, 5); // Add a tier to update
|
||||
}
|
||||
|
||||
function test_UpdateTier_RevertWhen_InvalidTierId() public {
|
||||
vm.expectRevert(KarmaTiers.TierNotFound.selector);
|
||||
vm.prank(deployer);
|
||||
karmaTiers.updateTier(2, "Bronze", 100, 500, 5);
|
||||
}
|
||||
|
||||
function test_UpdateTier_RevertWhen_InvalidRange() public {
|
||||
vm.expectRevert(abi.encodeWithSelector(KarmaTiers.InvalidTierRange.selector, 600, 400));
|
||||
vm.prank(deployer);
|
||||
karmaTiers.updateTier(1, "Bronze", 600, 400, 5);
|
||||
}
|
||||
|
||||
function test_UpdateTier_RevertWhen_OverlapWithOtherTier() public {
|
||||
vm.startPrank(deployer);
|
||||
karmaTiers.addTier("Silver", 600, 1000, 5);
|
||||
vm.stopPrank();
|
||||
|
||||
vm.expectRevert(abi.encodeWithSelector(KarmaTiers.OverlappingTiers.selector, 2, 550, 800));
|
||||
vm.prank(deployer);
|
||||
karmaTiers.updateTier(1, "Bronze", 550, 800, 5);
|
||||
}
|
||||
|
||||
function test_UpdateTier_RevertWhen_NotOwner() public {
|
||||
vm.prank(nonOwner);
|
||||
vm.expectRevert("Ownable: caller is not the owner");
|
||||
karmaTiers.updateTier(1, "Updated Bronze", 150, 600, 5);
|
||||
}
|
||||
|
||||
function test_UpdateTier_Success() public {
|
||||
string memory newName = "Updated Bronze";
|
||||
uint256 newMinKarma = 150;
|
||||
uint256 newMaxKarma = 600;
|
||||
uint32 newTxPerEpoch = 10;
|
||||
|
||||
vm.expectEmit(true, false, false, true);
|
||||
emit TierUpdated(1, newName, newMinKarma, newMaxKarma, newTxPerEpoch);
|
||||
|
||||
vm.prank(deployer);
|
||||
karmaTiers.updateTier(1, newName, newMinKarma, newMaxKarma, newTxPerEpoch);
|
||||
|
||||
KarmaTiers.Tier memory tier = karmaTiers.getTierById(1);
|
||||
assertEq(tier.name, newName);
|
||||
assertEq(tier.minKarma, newMinKarma);
|
||||
assertEq(tier.maxKarma, newMaxKarma);
|
||||
}
|
||||
}
|
||||
|
||||
contract DeactivateActivateTierTests is KarmaTiersTest {
|
||||
function setUp() public override {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
function test_DeactivateTier_RevertWhen_InvalidTierId() public {
|
||||
vm.expectRevert(KarmaTiers.TierNotFound.selector);
|
||||
vm.prank(deployer);
|
||||
karmaTiers.deactivateTier(1);
|
||||
}
|
||||
|
||||
function test_DeactivateTier_RevertWhen_NotOwner() public {
|
||||
vm.prank(deployer);
|
||||
karmaTiers.addTier("Bronze", 100, 500, 5);
|
||||
|
||||
vm.prank(nonOwner);
|
||||
vm.expectRevert("Ownable: caller is not the owner");
|
||||
karmaTiers.deactivateTier(1);
|
||||
}
|
||||
|
||||
function test_DeactivateTier_Success() public {
|
||||
vm.prank(deployer);
|
||||
karmaTiers.addTier("Bronze", 100, 500, 5);
|
||||
|
||||
vm.expectEmit(true, false, false, false);
|
||||
emit TierDeactivated(1);
|
||||
|
||||
vm.prank(deployer);
|
||||
karmaTiers.deactivateTier(1);
|
||||
|
||||
KarmaTiers.Tier memory tier = karmaTiers.getTierById(1);
|
||||
assertFalse(tier.active);
|
||||
}
|
||||
}
|
||||
|
||||
contract ActivateTierTests is KarmaTiersTest {
|
||||
function setUp() public override {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
function test_ActivateTier_Success() public {
|
||||
vm.startPrank(deployer);
|
||||
karmaTiers.addTier("Bronze", 100, 500, 5);
|
||||
karmaTiers.deactivateTier(1);
|
||||
vm.stopPrank();
|
||||
|
||||
vm.expectEmit(true, false, false, false);
|
||||
emit TierActivated(1);
|
||||
|
||||
vm.prank(deployer);
|
||||
karmaTiers.activateTier(1);
|
||||
|
||||
KarmaTiers.Tier memory tier = karmaTiers.getTierById(1);
|
||||
assertTrue(tier.active);
|
||||
}
|
||||
|
||||
function test_ActivateTier_RevertWhen_InvalidTierId() public {
|
||||
vm.expectRevert(KarmaTiers.TierNotFound.selector);
|
||||
vm.prank(deployer);
|
||||
karmaTiers.activateTier(1);
|
||||
}
|
||||
|
||||
function test_ActivateTier_RevertWhen_NotOwner() public {
|
||||
vm.prank(deployer);
|
||||
karmaTiers.addTier("Bronze", 100, 500, 5);
|
||||
vm.prank(deployer);
|
||||
karmaTiers.deactivateTier(1);
|
||||
|
||||
vm.prank(nonOwner);
|
||||
vm.expectRevert("Ownable: caller is not the owner");
|
||||
karmaTiers.activateTier(1);
|
||||
}
|
||||
}
|
||||
|
||||
contract ViewFunctionsTest is KarmaTiersTest {
|
||||
function setUp() public override {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
function test_GetTierCount_InitiallyZero() public {
|
||||
assertEq(karmaTiers.getTierCount(), 0);
|
||||
}
|
||||
|
||||
function test_GetTierCount_IncreasesWithTiers() public {
|
||||
vm.prank(deployer);
|
||||
karmaTiers.addTier("Bronze", 100, 500, 5);
|
||||
assertEq(karmaTiers.getTierCount(), 1);
|
||||
|
||||
vm.prank(deployer);
|
||||
karmaTiers.addTier("Silver", 600, 1000, 5);
|
||||
assertEq(karmaTiers.getTierCount(), 2);
|
||||
}
|
||||
|
||||
function test_GetTierById_Success() public {
|
||||
string memory tierName = "Bronze";
|
||||
uint256 minKarma = 100;
|
||||
uint256 maxKarma = 500;
|
||||
uint32 txPerEpoch = 5;
|
||||
|
||||
vm.prank(deployer);
|
||||
karmaTiers.addTier(tierName, minKarma, maxKarma, txPerEpoch);
|
||||
|
||||
KarmaTiers.Tier memory tier = karmaTiers.getTierById(1);
|
||||
assertEq(tier.name, tierName);
|
||||
assertEq(tier.minKarma, minKarma);
|
||||
assertEq(tier.maxKarma, maxKarma);
|
||||
assertTrue(tier.active);
|
||||
}
|
||||
|
||||
function test_GetTierById_RevertWhen_InvalidTierId() public {
|
||||
vm.expectRevert(KarmaTiers.TierNotFound.selector);
|
||||
karmaTiers.getTierById(1);
|
||||
}
|
||||
|
||||
function test_GetTierById_RevertWhen_TierIdZero() public {
|
||||
vm.expectRevert(KarmaTiers.TierNotFound.selector);
|
||||
karmaTiers.getTierById(0);
|
||||
}
|
||||
}
|
||||
|
||||
contract EdgeCasesTest is KarmaTiersTest {
|
||||
function setUp() public override {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
function test_OverlapValidation_EdgeCases() public {
|
||||
// Test adjacent ranges (should not overlap)
|
||||
vm.startPrank(deployer);
|
||||
karmaTiers.addTier("Tier1", 0, 100, 5);
|
||||
karmaTiers.addTier("Tier2", 101, 200, 5);
|
||||
vm.stopPrank();
|
||||
|
||||
// Test touching ranges (100 and 101 are adjacent, should not overlap)
|
||||
assertEq(karmaTiers.getTierCount(), 2);
|
||||
|
||||
// Test exact boundary overlap (should fail)
|
||||
vm.expectRevert(abi.encodeWithSelector(KarmaTiers.OverlappingTiers.selector, 1, 100, 150));
|
||||
vm.prank(deployer);
|
||||
karmaTiers.addTier("Tier3", 100, 150, 5);
|
||||
}
|
||||
|
||||
function test_UnlimitedTierOverlap() public {
|
||||
// Add unlimited tier
|
||||
vm.prank(deployer);
|
||||
karmaTiers.addTier("Unlimited", 1000, 0, 5);
|
||||
|
||||
// Try to add tier that overlaps with unlimited tier
|
||||
vm.expectRevert(abi.encodeWithSelector(KarmaTiers.OverlappingTiers.selector, 1, 1500, 2000));
|
||||
vm.prank(deployer);
|
||||
karmaTiers.addTier("Overlap", 1500, 2000, 5);
|
||||
|
||||
// Try to add tier that starts before unlimited tier
|
||||
vm.expectRevert(abi.encodeWithSelector(KarmaTiers.OverlappingTiers.selector, 1, 500, 1500));
|
||||
vm.prank(deployer);
|
||||
karmaTiers.addTier("Before", 500, 1500, 5);
|
||||
}
|
||||
}
|
||||
|
||||
contract GetTierIdByKarmaBalanceTest is KarmaTiersTest {
|
||||
function setUp() public override {
|
||||
super.setUp();
|
||||
vm.startPrank(deployer);
|
||||
karmaTiers.addTier("Bronze", 100, 500, 5);
|
||||
karmaTiers.addTier("Silver", 501, 1000, 5);
|
||||
karmaTiers.addTier("Gold", 1001, 1500, 5);
|
||||
karmaTiers.addTier("Platinum", 5001, 10_000, 5); // creating a gap
|
||||
// let's also take into account that tiers aren't sorted
|
||||
karmaTiers.addTier("Wood", 10, 99, 5);
|
||||
|
||||
karmaTiers.deactivateTier(3); // Deactivate Gold tier for testing
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function test_GetTierIdByKarmaBalance_BelowMinKarma() public {
|
||||
uint256 karmaBalance = 5;
|
||||
uint8 tierId = karmaTiers.getTierIdByKarmaBalance(karmaBalance);
|
||||
assertEq(tierId, 0); // Should return 0 for no tier
|
||||
}
|
||||
|
||||
function test_GetTierIdByKarmaBalance_InBronzeTier() public {
|
||||
uint256 karmaBalance = 300;
|
||||
uint8 tierId = karmaTiers.getTierIdByKarmaBalance(karmaBalance);
|
||||
assertEq(tierId, 1);
|
||||
}
|
||||
|
||||
function test_GetTierIdByKarmaBalance_InSilverTier() public {
|
||||
uint256 karmaBalance = 800;
|
||||
uint8 tierId = karmaTiers.getTierIdByKarmaBalance(karmaBalance);
|
||||
assertEq(tierId, 2);
|
||||
}
|
||||
|
||||
function test_GetTierIdByKarmaBalance_InGoldTier() public {
|
||||
uint256 karmaBalance = 1200;
|
||||
uint8 tierId = karmaTiers.getTierIdByKarmaBalance(karmaBalance);
|
||||
assertEq(tierId, 2); // Since Gold is deactivated, should return 2 for Silver
|
||||
}
|
||||
}
|
||||
|
||||
contract FuzzTests is KarmaTiersTest {
|
||||
function setUp() public override {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
function testFuzz_AddTier_ValidInputs(
|
||||
string calldata name,
|
||||
uint256 minKarma,
|
||||
uint256 maxKarma,
|
||||
uint32 txPerEpoch
|
||||
)
|
||||
public
|
||||
{
|
||||
vm.assume(bytes(name).length > 0 && bytes(name).length <= 32);
|
||||
vm.assume(maxKarma == 0 || maxKarma > minKarma);
|
||||
vm.assume(minKarma < type(uint256).max);
|
||||
vm.assume(txPerEpoch > 0);
|
||||
|
||||
vm.prank(deployer);
|
||||
karmaTiers.addTier(name, minKarma, maxKarma, txPerEpoch);
|
||||
|
||||
KarmaTiers.Tier memory tier = karmaTiers.getTierById(1);
|
||||
assertEq(tier.name, name);
|
||||
assertEq(tier.minKarma, minKarma);
|
||||
assertEq(tier.maxKarma, maxKarma);
|
||||
assertTrue(tier.active);
|
||||
}
|
||||
|
||||
function testFuzz_UpdateTier_ValidInputs(
|
||||
string calldata initialName,
|
||||
uint256 initialMinKarma,
|
||||
uint256 initialMaxKarma,
|
||||
string calldata newName,
|
||||
uint256 newMinKarma,
|
||||
uint256 newMaxKarma,
|
||||
uint32 initialTxPerEpoch,
|
||||
uint32 newTxPerEpoch
|
||||
)
|
||||
public
|
||||
{
|
||||
// Setup constraints for initial tier
|
||||
vm.assume(bytes(initialName).length > 0 && bytes(initialName).length <= 32);
|
||||
vm.assume(initialMaxKarma == 0 || initialMaxKarma > initialMinKarma);
|
||||
|
||||
// Setup constraints for new tier
|
||||
vm.assume(bytes(newName).length > 0 && bytes(newName).length <= 32);
|
||||
vm.assume(newMaxKarma == 0 || newMaxKarma > newMinKarma);
|
||||
vm.assume(initialTxPerEpoch > 0);
|
||||
vm.assume(newTxPerEpoch > 0);
|
||||
|
||||
vm.startPrank(deployer);
|
||||
karmaTiers.addTier(initialName, initialMinKarma, initialMaxKarma, initialTxPerEpoch);
|
||||
karmaTiers.updateTier(1, newName, newMinKarma, newMaxKarma, newTxPerEpoch);
|
||||
vm.stopPrank();
|
||||
|
||||
KarmaTiers.Tier memory tier = karmaTiers.getTierById(1);
|
||||
assertEq(tier.name, newName);
|
||||
assertEq(tier.minKarma, newMinKarma);
|
||||
assertEq(tier.maxKarma, newMaxKarma);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user