mirror of
https://github.com/vacp2p/staking-reward-streamer.git
synced 2026-01-06 19:53:52 -05:00
refactor: migrate KarmaTiers to contiguous array-based tier management (#228)
* refactor: migrate KarmaTiers to contiguous array-based tier management - Replaced mapping-based tier storage with a contiguous Tier[] array - Introduced batch update via updateTiers(), enforcing non-overlapping, gapless ranges - Removed individual tier operations (add, update, deactivate, activate) - Simplified tier resolution with linear lookup test: rewrite test suite for new KarmaTiers structure - Added tests for ownership, empty input, non-contiguous tiers, invalid names - Validated proper behavior for unlimited tiers (maxKarma = type(uint256).max) - Included edge case checks for getTierIdByKarmaBalance - Added event verification for TiersUpdated * ci: update python version to fix bug in certora --------- Co-authored-by: r4bbit <445106+0x-r4bbit@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
22ba4ff130
commit
7d2e4a810d
46
.gas-report
46
.gas-report
@@ -46,13 +46,13 @@
|
||||
+=========================================================================================================================+
|
||||
| Deployment Cost | Deployment Size | | | | |
|
||||
|---------------------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| 3542177 | 17392 | | | | |
|
||||
| 3233361 | 15956 | | | | |
|
||||
|---------------------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| | | | | | |
|
||||
|---------------------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|---------------------------------------------------------------+-----------------+---------+---------+---------+---------|
|
||||
| run | 2968362 | 2968362 | 2968362 | 2968362 | 33 |
|
||||
| run | 2680741 | 2680741 | 2680741 | 2680741 | 9 |
|
||||
╰---------------------------------------------------------------+-----------------+---------+---------+---------+---------╯
|
||||
|
||||
╭-------------------------------------------------------------------+-----------------+---------+---------+---------+---------╮
|
||||
@@ -80,7 +80,7 @@
|
||||
|---------------------------------------------------------+-----------------+------+--------+------+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|---------------------------------------------------------+-----------------+------+--------+------+---------|
|
||||
| activeNetworkConfig | 455 | 2084 | 455 | 4455 | 540 |
|
||||
| activeNetworkConfig | 455 | 2048 | 455 | 4455 | 492 |
|
||||
╰---------------------------------------------------------+-----------------+------+--------+------+---------╯
|
||||
|
||||
╭---------------------------------------------------------------------+-----------------+---------+---------+---------+---------╮
|
||||
@@ -144,7 +144,7 @@
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| setReward | 4845 | 144102 | 166754 | 166754 | 319 |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| slash | 4803 | 103655 | 85757 | 123125 | 520 |
|
||||
| slash | 4803 | 103656 | 85757 | 123125 | 520 |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| slashedAmountOf | 17682 | 28099 | 28120 | 28120 | 516 |
|
||||
|------------------------------+-----------------+--------+--------+--------+---------|
|
||||
@@ -192,29 +192,17 @@
|
||||
+===============================================================================================+
|
||||
| Deployment Cost | Deployment Size | | | | |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| 0 | 5856 | | | | |
|
||||
| 0 | 4420 | | | | |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| | | | | | |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| MAX_TIER_NAME_LENGTH | 240 | 240 | 240 | 240 | 1 |
|
||||
| getTierCount | 2337 | 2337 | 2337 | 2337 | 2 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| activateTier | 23752 | 27234 | 25870 | 32081 | 3 |
|
||||
| getTierIdByKarmaBalance | 7460 | 7942 | 7784 | 10020 | 8 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| 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 |
|
||||
| updateTiers | 23978 | 107929 | 28296 | 301092 | 9 |
|
||||
╰----------------------------------------+-----------------+--------+--------+--------+---------╯
|
||||
|
||||
╭--------------------------------------------+-----------------+--------+--------+--------+---------╮
|
||||
@@ -252,7 +240,7 @@
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| leave | 66348 | 66348 | 66348 | 66348 | 2 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| lock | 7040 | 43275 | 46713 | 87673 | 1034 |
|
||||
| lock | 7040 | 43229 | 46713 | 87673 | 1034 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| migrateToVault | 9294 | 53513 | 17021 | 170715 | 4 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
@@ -280,7 +268,7 @@
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| setTrustedCodehash | 24238 | 24238 | 24238 | 24238 | 95 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| stake | 2639 | 130108 | 60725 | 228623 | 2670 |
|
||||
| stake | 2639 | 129983 | 60725 | 228623 | 2670 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| stakedBalanceOf | 2622 | 2622 | 2622 | 2622 | 1 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
@@ -306,7 +294,7 @@
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| updateGlobalState | 15820 | 25876 | 29230 | 29230 | 8 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| updateVault | 31948 | 34036 | 31948 | 110579 | 1023 |
|
||||
| updateVault | 31948 | 34013 | 31948 | 110579 | 1023 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| upgradeTo | 10279 | 10772 | 10279 | 12745 | 5 |
|
||||
|--------------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
@@ -334,7 +322,7 @@
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| leave | 12223 | 113137 | 84120 | 356508 | 5 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| lock | 12151 | 58767 | 62251 | 103208 | 1035 |
|
||||
| lock | 12151 | 58722 | 62251 | 103208 | 1035 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| lockUntil | 2363 | 2363 | 2363 | 2363 | 7768 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
@@ -344,7 +332,7 @@
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| register | 12742 | 78218 | 78761 | 78761 | 374 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| stake | 12131 | 164075 | 76290 | 284275 | 2671 |
|
||||
| stake | 12131 | 163920 | 76290 | 284275 | 2671 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| stakeManager | 393 | 393 | 393 | 393 | 373 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
@@ -352,7 +340,7 @@
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| unstake | 12108 | 58192 | 55296 | 110656 | 272 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| updateLockUntil | 4432 | 20802 | 21532 | 21532 | 488 |
|
||||
| updateLockUntil | 4432 | 20798 | 21532 | 21532 | 485 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
| withdraw | 20817 | 20817 | 20817 | 20817 | 1 |
|
||||
|----------------------------------------+-----------------+--------+--------+--------+---------|
|
||||
@@ -370,9 +358,9 @@
|
||||
|----------------------------------------------------+-----------------+-------+--------+--------+---------|
|
||||
| Function Name | Min | Avg | Median | Max | # Calls |
|
||||
|----------------------------------------------------+-----------------+-------+--------+--------+---------|
|
||||
| fallback | 5208 | 12818 | 7353 | 374054 | 23161 |
|
||||
| fallback | 5208 | 12817 | 7353 | 374054 | 23161 |
|
||||
|----------------------------------------------------+-----------------+-------+--------+--------+---------|
|
||||
| implementation | 346 | 2144 | 2346 | 2346 | 4850 |
|
||||
| implementation | 346 | 2145 | 2346 | 2346 | 4847 |
|
||||
╰----------------------------------------------------+-----------------+-------+--------+--------+---------╯
|
||||
|
||||
╭--------------------------------------------+-----------------+--------+--------+--------+---------╮
|
||||
@@ -396,7 +384,7 @@
|
||||
+===============================================================================================================================================+
|
||||
| Deployment Cost | Deployment Size | | | | |
|
||||
|------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
|
||||
| 1204853 | 6207 | | | | |
|
||||
| 1204853 | 6015 | | | | |
|
||||
|------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
|
||||
| | | | | | |
|
||||
|------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
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)
|
||||
@@ -11,20 +8,6 @@ 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)
|
||||
@@ -33,21 +16,15 @@ 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: 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_AccrueMP(uint128,uint64,uint64) (runs: 1006, μ: 581521, ~: 549037)
|
||||
FuzzTests:testFuzz_AccrueMP_Relock(uint128,uint64,uint64,uint64) (runs: 1006, μ: 806405, ~: 777234)
|
||||
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_Lock(uint256,uint64) (runs: 1006, μ: 961274, ~: 961235)
|
||||
FuzzTests:testFuzz_Relock(uint256,uint64,uint64) (runs: 1006, μ: 598321, ~: 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)
|
||||
FuzzTests:testFuzz_Stake(uint256,uint64) (runs: 1006, μ: 376307, ~: 346086)
|
||||
FuzzTests:testFuzz_Unstake(uint128,uint64,uint16,uint128) (runs: 1006, μ: 801126, ~: 780593)
|
||||
FuzzTests:testFuzz_UpdateVault(uint128,uint64,uint64) (runs: 1006, μ: 581544, ~: 549060)
|
||||
IntegrationTest:testStakeFoo() (gas: 2348931)
|
||||
KarmaNFTTest:testApproveNotAllowed() (gas: 10507)
|
||||
KarmaNFTTest:testGetApproved() (gas: 10531)
|
||||
@@ -77,11 +54,20 @@ KarmaTest:testRemoveKarmaDistributorOnlyOwner() (gas: 163437)
|
||||
KarmaTest:testRemoveUnknownKarmaDistributor() (gas: 41654)
|
||||
KarmaTest:testTotalSupply() (gas: 359391)
|
||||
KarmaTest:testTransfersNotAllowed() (gas: 61925)
|
||||
KarmaTiersTest:test_GetTierIdByKarmaBalance_EdgeCases() (gas: 297868)
|
||||
KarmaTiersTest:test_Revert_When_TierNameEmpty() (gas: 39361)
|
||||
KarmaTiersTest:test_Revert_When_TierNameTooLong() (gas: 40510)
|
||||
KarmaTiersTest:test_Revert_When_TiersAreEmpty() (gas: 34673)
|
||||
KarmaTiersTest:test_Revert_When_TiersNotContiguous() (gas: 132711)
|
||||
KarmaTiersTest:test_Revert_When_TiersNotStartingAtZero() (gas: 37667)
|
||||
KarmaTiersTest:test_Revert_When_UpdateTiersCalledByNonOwner() (gas: 36642)
|
||||
KarmaTiersTest:test_Success_When_LastTierIsUnlimited() (gas: 242295)
|
||||
KarmaTiersTest:test_Success_When_TiersAreContiguous() (gas: 336294)
|
||||
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: 1002, μ: 384561, ~: 384588)
|
||||
LockTest:test_LockFailsWithInvalidPeriod(uint256) (runs: 1006, μ: 384561, ~: 384588)
|
||||
LockTest:test_LockFailsWithNoStake() (gas: 89700)
|
||||
LockTest:test_LockFailsWithZero() (gas: 343310)
|
||||
LockTest:test_LockMultipleTimesExceedMaxLock() (gas: 746921)
|
||||
@@ -145,7 +131,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: 1000, μ: 408297, ~: 409081)
|
||||
SlashAmountOfTest:testFuzz_SlashAmountOf(uint256,uint256,uint256) (runs: 1002, μ: 408298, ~: 409081)
|
||||
SlashAmountOfTest:testMintOnlyAdmin() (gas: 429075)
|
||||
SlashAmountOfTest:testRemoveKarmaDistributorOnlyOwner() (gas: 163437)
|
||||
SlashAmountOfTest:testRemoveUnknownKarmaDistributor() (gas: 41654)
|
||||
@@ -155,7 +141,7 @@ SlashAmountOfTest:test_SlashAmountOf() (gas: 327608)
|
||||
SlashTest:testAddKarmaDistributorOnlyAdmin() (gas: 438270)
|
||||
SlashTest:testBalanceOf() (gas: 456648)
|
||||
SlashTest:testBalanceOfWithNoSystemTotalKarma() (gas: 83827)
|
||||
SlashTest:testFuzz_Slash(uint256) (runs: 1002, μ: 280204, ~: 280146)
|
||||
SlashTest:testFuzz_Slash(uint256) (runs: 1006, μ: 280204, ~: 280146)
|
||||
SlashTest:testMintOnlyAdmin() (gas: 429131)
|
||||
SlashTest:testRemoveKarmaDistributorOnlyOwner() (gas: 163461)
|
||||
SlashTest:testRemoveRewardDistributorShouldReduceSlashAmount() (gas: 610762)
|
||||
@@ -218,19 +204,9 @@ 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)
|
||||
5
.github/workflows/ci.yml
vendored
5
.github/workflows/ci.yml
vendored
@@ -133,9 +133,8 @@ jobs:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install Python
|
||||
uses: actions/setup-python@v2
|
||||
with: { python-version: 3.9 }
|
||||
|
||||
uses: actions/setup-python@v4
|
||||
with: { python-version: "3.10" }
|
||||
- name: Install Java
|
||||
uses: actions/setup-java@v1
|
||||
with: { java-version: "11", java-package: jre }
|
||||
|
||||
@@ -9,25 +9,21 @@ import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
|
||||
* @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 tier list is updated
|
||||
event TiersUpdated();
|
||||
/// @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 array is empty
|
||||
error EmptyTiersArray();
|
||||
/// @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 tiers are not contiguous
|
||||
error NonContiguousTiers(uint8 index, uint256 expectedMinKarma, uint256 actualMinKarma);
|
||||
/// @notice Emitted when a tier's minKarma is greater than or equal to maxKarma
|
||||
error InvalidTierRange(uint256 minKarma, uint256 maxKarma);
|
||||
|
||||
@@ -36,11 +32,10 @@ contract KarmaTiers is Ownable {
|
||||
uint256 maxKarma;
|
||||
string name;
|
||||
uint32 txPerEpoch;
|
||||
bool active;
|
||||
}
|
||||
|
||||
modifier onlyValidTierId(uint8 tierId) {
|
||||
if (tierId == 0 || tierId > currentTierId) {
|
||||
if (tierId >= tiers.length) {
|
||||
revert TierNotFound();
|
||||
}
|
||||
_;
|
||||
@@ -57,10 +52,8 @@ contract KarmaTiers is Ownable {
|
||||
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;
|
||||
/// @notice Array of tiers
|
||||
Tier[] public tiers;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
CONSTRUCTOR
|
||||
@@ -74,77 +67,37 @@ contract KarmaTiers is Ownable {
|
||||
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();
|
||||
function updateTiers(Tier[] calldata newTiers) external onlyOwner {
|
||||
if (newTiers.length == 0) {
|
||||
revert EmptyTiersArray();
|
||||
}
|
||||
// Ensure the first tier starts at minKarma = 0
|
||||
if (newTiers[0].minKarma != 0) {
|
||||
revert NonContiguousTiers(0, 0, newTiers[0].minKarma);
|
||||
}
|
||||
|
||||
// Check for overlaps with existing tiers
|
||||
_validateNoOverlap(minKarma, maxKarma, type(uint8).max);
|
||||
_validateTierName(name);
|
||||
delete tiers; // Clear existing tiers
|
||||
|
||||
currentTierId++;
|
||||
uint256 lastMaxKarma = 0;
|
||||
for (uint8 i = 0; i < newTiers.length; i++) {
|
||||
Tier calldata input = newTiers[i];
|
||||
|
||||
tiers[currentTierId] =
|
||||
Tier({ minKarma: minKarma, maxKarma: maxKarma, name: name, active: true, txPerEpoch: txPerEpoch });
|
||||
_validateTierName(input.name);
|
||||
if (input.maxKarma <= input.minKarma) {
|
||||
revert InvalidTierRange(input.minKarma, input.maxKarma);
|
||||
}
|
||||
|
||||
emit TierAdded(currentTierId, name, minKarma, maxKarma, txPerEpoch);
|
||||
}
|
||||
if (i > 0) {
|
||||
uint256 expectedMinKarma = lastMaxKarma + 1;
|
||||
if (input.minKarma != expectedMinKarma) {
|
||||
revert NonContiguousTiers(i, expectedMinKarma, input.minKarma);
|
||||
}
|
||||
}
|
||||
lastMaxKarma = input.maxKarma;
|
||||
tiers.push(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
emit TiersUpdated();
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
@@ -174,23 +127,14 @@ contract KarmaTiers is Ownable {
|
||||
* @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;
|
||||
|
||||
for (uint8 i = 0; i < tiers.length; i++) {
|
||||
// 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;
|
||||
}
|
||||
if (karmaBalance < tiers[i].minKarma) {
|
||||
// Can't run into underflow here because `karmaBalance == 0 => karmaBalance < tiers[0].minKarma`
|
||||
return i - 1; // Return the previous tier if this one is not met
|
||||
}
|
||||
}
|
||||
return bestTierId;
|
||||
return uint8(tiers.length - 1); // If all tiers are met, return the highest tier
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,7 +142,7 @@ contract KarmaTiers is Ownable {
|
||||
* @return count Total number of tiers (including inactive)
|
||||
*/
|
||||
function getTierCount() external view returns (uint256 count) {
|
||||
return currentTierId;
|
||||
return tiers.length;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,25 +153,4 @@ contract KarmaTiers is Ownable {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,429 +8,118 @@ 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);
|
||||
address public owner;
|
||||
address public nonOwner = address(0xBEEF);
|
||||
|
||||
function setUp() public virtual {
|
||||
DeployKarmaTiersScript deployment = new DeployKarmaTiersScript();
|
||||
(KarmaTiers _karmaTiers, DeploymentConfig deploymentConfig) = deployment.run();
|
||||
(address _deployer,) = deploymentConfig.activeNetworkConfig();
|
||||
deployer = _deployer;
|
||||
owner = _deployer;
|
||||
karmaTiers = _karmaTiers;
|
||||
}
|
||||
}
|
||||
|
||||
contract AddTierTests is KarmaTiersTest {
|
||||
function setUp() public override {
|
||||
super.setUp();
|
||||
function test_Revert_When_UpdateTiersCalledByNonOwner() public {
|
||||
KarmaTiers.Tier[] memory newTiers = new KarmaTiers.Tier[](1);
|
||||
newTiers[0] = KarmaTiers.Tier({ minKarma: 0, maxKarma: 100, name: "Bronze", txPerEpoch: 5 });
|
||||
|
||||
vm.prank(nonOwner);
|
||||
vm.expectRevert("Ownable: caller is not the owner");
|
||||
karmaTiers.updateTiers(newTiers);
|
||||
}
|
||||
|
||||
function test_AddTier_RevertWhen_EmptyName() public {
|
||||
vm.prank(deployer);
|
||||
function test_Revert_When_TiersAreEmpty() public {
|
||||
KarmaTiers.Tier[] memory newTiers = new KarmaTiers.Tier[](0);
|
||||
|
||||
vm.prank(owner);
|
||||
vm.expectRevert(); // generic revert
|
||||
karmaTiers.updateTiers(newTiers);
|
||||
}
|
||||
|
||||
function test_Revert_When_TiersNotStartingAtZero() public {
|
||||
KarmaTiers.Tier[] memory newTiers = new KarmaTiers.Tier[](1);
|
||||
newTiers[0] = KarmaTiers.Tier({ minKarma: 1, maxKarma: 100, name: "Bronze", txPerEpoch: 5 });
|
||||
|
||||
vm.prank(owner);
|
||||
vm.expectRevert(abi.encodeWithSelector(KarmaTiers.NonContiguousTiers.selector, 0, 0, 1));
|
||||
karmaTiers.updateTiers(newTiers);
|
||||
}
|
||||
|
||||
function test_Revert_When_TierNameEmpty() public {
|
||||
KarmaTiers.Tier[] memory newTiers = new KarmaTiers.Tier[](1);
|
||||
newTiers[0] = KarmaTiers.Tier({ minKarma: 0, maxKarma: 100, name: "", txPerEpoch: 5 });
|
||||
|
||||
vm.prank(owner);
|
||||
vm.expectRevert(KarmaTiers.EmptyTierName.selector);
|
||||
karmaTiers.addTier("", 100, 500, 5);
|
||||
karmaTiers.updateTiers(newTiers);
|
||||
}
|
||||
|
||||
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_Revert_When_TierNameTooLong() public {
|
||||
string memory longName = new string(33);
|
||||
KarmaTiers.Tier[] memory newTiers = new KarmaTiers.Tier[](1);
|
||||
newTiers[0] = KarmaTiers.Tier({ minKarma: 0, maxKarma: 100, name: longName, txPerEpoch: 5 });
|
||||
|
||||
vm.prank(owner);
|
||||
vm.expectRevert(abi.encodeWithSelector(KarmaTiers.TierNameTooLong.selector, 33, 32));
|
||||
karmaTiers.updateTiers(newTiers);
|
||||
}
|
||||
|
||||
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_Revert_When_TiersNotContiguous() public {
|
||||
KarmaTiers.Tier[] memory newTiers = new KarmaTiers.Tier[](2);
|
||||
newTiers[0] = KarmaTiers.Tier({ minKarma: 0, maxKarma: 100, name: "Bronze", txPerEpoch: 5 });
|
||||
newTiers[1] = KarmaTiers.Tier({ minKarma: 102, maxKarma: 200, name: "Silver", txPerEpoch: 5 });
|
||||
|
||||
vm.prank(owner);
|
||||
vm.expectRevert(abi.encodeWithSelector(KarmaTiers.NonContiguousTiers.selector, 1, 101, 102));
|
||||
karmaTiers.updateTiers(newTiers);
|
||||
}
|
||||
|
||||
function test_AddTier_RevertWhen_OverlappingTiers() public {
|
||||
vm.prank(deployer);
|
||||
karmaTiers.addTier("Bronze", 100, 500, 5);
|
||||
function test_Success_When_TiersAreContiguous() public {
|
||||
KarmaTiers.Tier[] memory newTiers = new KarmaTiers.Tier[](3);
|
||||
newTiers[0] = KarmaTiers.Tier({ minKarma: 0, maxKarma: 100, name: "Bronze", txPerEpoch: 5 });
|
||||
newTiers[1] = KarmaTiers.Tier({ minKarma: 101, maxKarma: 200, name: "Silver", txPerEpoch: 10 });
|
||||
newTiers[2] = KarmaTiers.Tier({ minKarma: 201, maxKarma: 999, name: "Gold", txPerEpoch: 15 });
|
||||
|
||||
vm.prank(deployer);
|
||||
vm.expectRevert(abi.encodeWithSelector(KarmaTiers.OverlappingTiers.selector, 1, 400, 600));
|
||||
karmaTiers.addTier("Silver", 400, 600, 5);
|
||||
}
|
||||
vm.expectEmit(false, false, false, true);
|
||||
emit KarmaTiers.TiersUpdated();
|
||||
|
||||
function test_AddTier_RevertWhen_NotOwner() public {
|
||||
vm.prank(nonOwner);
|
||||
vm.expectRevert("Ownable: caller is not the owner");
|
||||
karmaTiers.addTier("Bronze", 100, 500, 5);
|
||||
}
|
||||
vm.prank(owner);
|
||||
karmaTiers.updateTiers(newTiers);
|
||||
|
||||
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);
|
||||
(uint8 tierId) = karmaTiers.getTierIdByKarmaBalance(150);
|
||||
assertEq(tierId, 1);
|
||||
}
|
||||
|
||||
function test_GetTierIdByKarmaBalance_InSilverTier() public {
|
||||
uint256 karmaBalance = 800;
|
||||
uint8 tierId = karmaTiers.getTierIdByKarmaBalance(karmaBalance);
|
||||
assertEq(tierId, 2);
|
||||
function test_Success_When_LastTierIsUnlimited() public {
|
||||
KarmaTiers.Tier[] memory newTiers = new KarmaTiers.Tier[](2);
|
||||
newTiers[0] = KarmaTiers.Tier({ minKarma: 0, maxKarma: 100, name: "Bronze", txPerEpoch: 5 });
|
||||
newTiers[1] =
|
||||
KarmaTiers.Tier({ minKarma: 101, maxKarma: type(uint256).max, name: "Unlimited", txPerEpoch: 100 });
|
||||
|
||||
vm.expectEmit(false, false, false, true);
|
||||
emit KarmaTiers.TiersUpdated();
|
||||
|
||||
vm.prank(owner);
|
||||
karmaTiers.updateTiers(newTiers);
|
||||
|
||||
assertEq(karmaTiers.getTierCount(), 2);
|
||||
assertEq(karmaTiers.getTierIdByKarmaBalance(500_000), 1);
|
||||
}
|
||||
|
||||
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);
|
||||
function test_GetTierIdByKarmaBalance_EdgeCases() public {
|
||||
KarmaTiers.Tier[] memory newTiers = new KarmaTiers.Tier[](2);
|
||||
newTiers[0] = KarmaTiers.Tier({ minKarma: 0, maxKarma: 100, name: "Bronze", txPerEpoch: 5 });
|
||||
newTiers[1] = KarmaTiers.Tier({ minKarma: 101, maxKarma: 200, name: "Silver", txPerEpoch: 5 });
|
||||
|
||||
vm.prank(owner);
|
||||
karmaTiers.updateTiers(newTiers);
|
||||
|
||||
assertEq(karmaTiers.getTierIdByKarmaBalance(0), 0);
|
||||
assertEq(karmaTiers.getTierIdByKarmaBalance(99), 0);
|
||||
assertEq(karmaTiers.getTierIdByKarmaBalance(100), 0);
|
||||
assertEq(karmaTiers.getTierIdByKarmaBalance(101), 1);
|
||||
assertEq(karmaTiers.getTierIdByKarmaBalance(200), 1);
|
||||
assertEq(karmaTiers.getTierIdByKarmaBalance(250), 1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user