diff --git a/.gas-snapshot b/.gas-snapshot index ca2b804b..4f3320e0 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -460,87 +460,88 @@ StakedEXATest:invariantIndexUpOnly() (runs: 10, calls: 5000, reverts: 0) StakedEXATest:invariantNoDuplicatedReward() (runs: 10, calls: 5000, reverts: 0) StakedEXATest:invariantRewardsUpOnly() (runs: 10, calls: 5000, reverts: 0) StakedEXATest:invariantShareValueIsOne() (runs: 10, calls: 5000, reverts: 0) -StakedEXATest:testAlreadyListedError() (gas: 41631) -StakedEXATest:testAvgIndex(uint256[3],uint256[2]) (runs: 256, μ: 1211584, ~: 1247057) -StakedEXATest:testAvgStartTime(uint256[3],uint256[2]) (runs: 256, μ: 1197957, ~: 1233430) -StakedEXATest:testBalanceOfDeposit(uint80) (runs: 256, μ: 355743, ~: 362801) -StakedEXATest:testBalanceOfWithdraw(uint256) (runs: 256, μ: 60525, ~: 60532) -StakedEXATest:testCanChangeRewardsDurationWhenDisabled() (gas: 168192) -StakedEXATest:testClaimAfterHarvest() (gas: 838641) -StakedEXATest:testClaimAndUnstake() (gas: 1478569) -StakedEXATest:testClaimAndWithdrawAfterRefTime() (gas: 1086141) -StakedEXATest:testClaimBeforeFirstHarvest() (gas: 540574) -StakedEXATest:testDepositEvent(uint256) (runs: 256, μ: 364782, ~: 364481) -StakedEXATest:testDepositShouldClaim(uint256[2],uint32) (runs: 256, μ: 822859, ~: 742798) -StakedEXATest:testDepositWithdrawAvgStartTimeAndIndex(uint256[3],uint256,uint256[5]) (runs: 256, μ: 1744356, ~: 1799917) -StakedEXATest:testEarnedWithTime(uint256) (runs: 256, μ: 35526, ~: 35809) -StakedEXATest:testEmergencyAdminCanPauseNotUnpause() (gas: 159061) -StakedEXATest:testFinishDistributionEmitEvent() (gas: 402002) -StakedEXATest:testFinishDistributionLetsClaimUnclaimed() (gas: 1506044) -StakedEXATest:testFinishDistributionStopsEmission() (gas: 1485719) -StakedEXATest:testFinishDistributionThatAlreadyFinished() (gas: 436322) -StakedEXATest:testFinishDistributionTransfersRemainingToSavings() (gas: 111466) -StakedEXATest:testGrantRevokeEmergencyAdmin() (gas: 107216) -StakedEXATest:testGrantRevokePauser() (gas: 107235) -StakedEXATest:testHandlerClaim(uint8) (runs: 256, μ: 302701, ~: 302701) -StakedEXATest:testHandlerDeposit(uint80) (runs: 256, μ: 800320, ~: 810889) -StakedEXATest:testHandlerHarvest(uint64) (runs: 256, μ: 333366, ~: 332862) -StakedEXATest:testHandlerNotifyRewardAmount(uint64) (runs: 256, μ: 128953, ~: 124445) -StakedEXATest:testHandlerSetDuration(uint32) (runs: 256, μ: 148161, ~: 163906) -StakedEXATest:testHandlerWithdraw(uint256) (runs: 256, μ: 69995, ~: 70002) -StakedEXATest:testHarvest() (gas: 197912) -StakedEXATest:testHarvestAmountWithReducedAllowance() (gas: 215330) -StakedEXATest:testHarvestEffectOnRewardData() (gas: 190914) -StakedEXATest:testHarvestEmitsRewardAmountNotified() (gas: 189043) -StakedEXATest:testHarvestZero() (gas: 236747) -StakedEXATest:testInitialValues() (gas: 89074) -StakedEXATest:testInsufficientBalanceError(uint256) (runs: 256, μ: 65320, ~: 65453) -StakedEXATest:testMultipleClaimsVsOne() (gas: 25922257) -StakedEXATest:testMultipleHarvests() (gas: 462094) -StakedEXATest:testNoRewardsAfterPeriod(uint256) (runs: 256, μ: 1561192, ~: 1567513) +StakedEXATest:testAlreadyListedError() (gas: 41653) +StakedEXATest:testAvgIndex(uint256[3],uint256[2]) (runs: 256, μ: 1213306, ~: 1274322) +StakedEXATest:testAvgStartTime(uint256[3],uint256[2]) (runs: 256, μ: 1199679, ~: 1260695) +StakedEXATest:testBalanceOfDeposit(uint80) (runs: 256, μ: 355442, ~: 362487) +StakedEXATest:testBalanceOfWithdraw(uint256) (runs: 256, μ: 60547, ~: 60554) +StakedEXATest:testCanChangeRewardsDurationWhenDisabled() (gas: 168929) +StakedEXATest:testClaimAfterHarvest() (gas: 840855) +StakedEXATest:testClaimAndUnstake() (gas: 1486266) +StakedEXATest:testClaimAndWithdrawAfterRefTime() (gas: 1091264) +StakedEXATest:testClaimBeforeFirstHarvest() (gas: 539902) +StakedEXATest:testDepositEvent(uint256) (runs: 256, μ: 364332, ~: 364035) +StakedEXATest:testDepositShouldClaim(uint256[2],uint32) (runs: 256, μ: 832695, ~: 742204) +StakedEXATest:testDepositWithdrawAvgStartTimeAndIndex(uint256[3],uint256,uint256[5]) (runs: 256, μ: 1751346, ~: 1809626) +StakedEXATest:testEarnedWithTime(uint256) (runs: 256, μ: 35420, ~: 35700) +StakedEXATest:testEmergencyAdminCanPauseNotUnpause() (gas: 159083) +StakedEXATest:testFinishDistributionEmitEvent() (gas: 402739) +StakedEXATest:testFinishDistributionLetsClaimUnclaimed() (gas: 1516941) +StakedEXATest:testFinishDistributionStopsEmission() (gas: 1496660) +StakedEXATest:testFinishDistributionThatAlreadyFinished() (gas: 436008) +StakedEXATest:testFinishDistributionTransfersRemainingToSavings() (gas: 112203) +StakedEXATest:testGrantRevokeEmergencyAdmin() (gas: 107238) +StakedEXATest:testGrantRevokePauser() (gas: 107257) +StakedEXATest:testHandlerClaim(uint8) (runs: 256, μ: 302723, ~: 302723) +StakedEXATest:testHandlerDeposit(uint80) (runs: 256, μ: 798962, ~: 810106) +StakedEXATest:testHandlerHarvest(uint64) (runs: 256, μ: 333417, ~: 332884) +StakedEXATest:testHandlerNotifyRewardAmount(uint64) (runs: 256, μ: 128752, ~: 124435) +StakedEXATest:testHandlerSetDuration(uint32) (runs: 256, μ: 145984, ~: 164510) +StakedEXATest:testHandlerWithdraw(uint256) (runs: 256, μ: 70017, ~: 70024) +StakedEXATest:testHarvest() (gas: 197934) +StakedEXATest:testHarvestAmountWithReducedAllowance() (gas: 215352) +StakedEXATest:testHarvestEffectOnRewardData() (gas: 190936) +StakedEXATest:testHarvestEmitsRewardAmountNotified() (gas: 188932) +StakedEXATest:testHarvestZero() (gas: 236769) +StakedEXATest:testInitialValues() (gas: 89096) +StakedEXATest:testInsufficientBalanceError(uint256) (runs: 256, μ: 65339, ~: 65475) +StakedEXATest:testMultipleClaimsVsOne() (gas: 26036303) +StakedEXATest:testMultipleHarvests() (gas: 461984) +StakedEXATest:testNoRewardsAfterPeriod(uint256) (runs: 256, μ: 1569722, ~: 1576154) StakedEXATest:testNotPausingRoleError() (gas: 39503) -StakedEXATest:testNotifyRewardAmount(uint256,uint256) (runs: 256, μ: 131150, ~: 131088) -StakedEXATest:testNotifyRewardWithUnderlyingAsset() (gas: 502122) -StakedEXATest:testOnlyAdminEnableReward() (gas: 1198741) -StakedEXATest:testOnlyAdminFinishDistribution() (gas: 190229) -StakedEXATest:testOnlyAdminNotifyRewardAmount() (gas: 204586) -StakedEXATest:testOnlyAdminSetProvider() (gas: 143570) -StakedEXATest:testOnlyAdminSetProviderRatio() (gas: 143217) -StakedEXATest:testOnlyAdminSetRewardsDuration() (gas: 152956) -StakedEXATest:testOnlyAdminSetSavings() (gas: 140988) -StakedEXATest:testPausable() (gas: 1156228) -StakedEXATest:testPausableClaim() (gas: 639652) -StakedEXATest:testPausableHarvest() (gas: 344615) -StakedEXATest:testPauserCanPauseUnpause() (gas: 157943) -StakedEXATest:testPenaltyGrowthRange() (gas: 67189) -StakedEXATest:testPenaltyThresholdRange() (gas: 37134) -StakedEXATest:testPermitAndDeposit() (gas: 373398) -StakedEXATest:testResetDepositAfterRefTime(uint256) (runs: 256, μ: 1015558, ~: 1015236) -StakedEXATest:testRewardAmountNotifiedEvent(uint256) (runs: 256, μ: 105830, ~: 106665) -StakedEXATest:testRewardNotListedError() (gas: 1114662) -StakedEXATest:testRewardPaidEvent(uint256,uint256) (runs: 256, μ: 810417, ~: 857765) -StakedEXATest:testRewardsAmounts(uint256) (runs: 256, μ: 1568304, ~: 1567893) -StakedEXATest:testRewardsDurationSetEvent(uint40) (runs: 256, μ: 52051, ~: 52034) -StakedEXATest:testSetDuration(uint256,uint40) (runs: 256, μ: 58974, ~: 59238) -StakedEXATest:testSetMarketOnlyAdmin() (gas: 1266909) -StakedEXATest:testSetMinTime() (gas: 81971) -StakedEXATest:testSetPenaltyGrowth() (gas: 82247) -StakedEXATest:testSetPenaltyThreshold() (gas: 82066) -StakedEXATest:testSetProviderRatioOverOneError() (gas: 37134) -StakedEXATest:testSetProviderZeroAddressError() (gas: 37153) -StakedEXATest:testSetSavingsZeroAddressError() (gas: 37262) -StakedEXATest:testTotalSupplyDeposit(uint80) (runs: 256, μ: 355346, ~: 362404) -StakedEXATest:testTotalSupplyWithdraw(uint256) (runs: 256, μ: 61950, ~: 61957) -StakedEXATest:testUntransferable(uint80) (runs: 256, μ: 374900, ~: 382857) -StakedEXATest:testWithdrawEvent(uint256) (runs: 256, μ: 521023, ~: 520712) -StakedEXATest:testWithdrawSameAmountRewardsShouldEqual(uint256,uint256) (runs: 256, μ: 1069655, ~: 1132756) -StakedEXATest:testWithdrawWithRewards(uint256) (runs: 256, μ: 874710, ~: 874399) -StakedEXATest:testZeroRateError() (gas: 59267) -StakingPreviewerTest:testAllClaimable() (gas: 431744) -StakingPreviewerTest:testAllClaimed() (gas: 631078) -StakingPreviewerTest:testAllEarned() (gas: 316762) -StakingPreviewerTest:testAllRewards() (gas: 486259) -StakingPreviewerTest:testStaking() (gas: 528819) +StakedEXATest:testNotifyRewardAmount(uint256,uint256) (runs: 256, μ: 131174, ~: 131110) +StakedEXATest:testNotifyRewardWithUnderlyingAsset() (gas: 501808) +StakedEXATest:testOnlyAdminEnableReward() (gas: 1198763) +StakedEXATest:testOnlyAdminFinishDistribution() (gas: 190966) +StakedEXATest:testOnlyAdminNotifyRewardAmount() (gas: 204608) +StakedEXATest:testOnlyAdminSetProvider() (gas: 143592) +StakedEXATest:testOnlyAdminSetProviderRatio() (gas: 143239) +StakedEXATest:testOnlyAdminSetRewardsDuration() (gas: 152845) +StakedEXATest:testOnlyAdminSetSavings() (gas: 141010) +StakedEXATest:testPausable() (gas: 1154913) +StakedEXATest:testPausableClaim() (gas: 639338) +StakedEXATest:testPausableHarvest() (gas: 344660) +StakedEXATest:testPauserCanPauseUnpause() (gas: 157833) +StakedEXATest:testPenaltyGrowthRange() (gas: 67211) +StakedEXATest:testPenaltyThresholdRange() (gas: 37156) +StakedEXATest:testPermitAndDeposit() (gas: 373084) +StakedEXATest:testResetDepositAfterRefTime(uint256) (runs: 256, μ: 1020699, ~: 1020382) +StakedEXATest:testRewardAmountNotifiedEvent(uint256) (runs: 256, μ: 105863, ~: 106687) +StakedEXATest:testRewardNotListedError() (gas: 1114684) +StakedEXATest:testRewardPaidEvent(uint256,uint256) (runs: 256, μ: 814120, ~: 862889) +StakedEXATest:testRewardsAmounts(uint256) (runs: 256, μ: 1577071, ~: 1576667) +StakedEXATest:testRewardsDurationSetEvent(uint40) (runs: 256, μ: 52073, ~: 52056) +StakedEXATest:testSetDuration(uint256,uint40) (runs: 256, μ: 59017, ~: 59260) +StakedEXATest:testSetMarketAddressZero() (gas: 37124) +StakedEXATest:testSetMarketOnlyAdmin() (gas: 1266966) +StakedEXATest:testSetMinTime() (gas: 81993) +StakedEXATest:testSetPenaltyGrowth() (gas: 82136) +StakedEXATest:testSetPenaltyThreshold() (gas: 81958) +StakedEXATest:testSetProviderRatioOverOneError() (gas: 37156) +StakedEXATest:testSetProviderZeroAddressError() (gas: 37175) +StakedEXATest:testSetSavingsZeroAddressError() (gas: 37284) +StakedEXATest:testTotalSupplyDeposit(uint80) (runs: 256, μ: 354935, ~: 361980) +StakedEXATest:testTotalSupplyWithdraw(uint256) (runs: 256, μ: 61972, ~: 61979) +StakedEXATest:testUntransferable(uint80) (runs: 256, μ: 374600, ~: 382543) +StakedEXATest:testWithdrawEvent(uint256) (runs: 256, μ: 520347, ~: 520040) +StakedEXATest:testWithdrawSameAmountRewardsShouldEqual(uint256,uint256) (runs: 256, μ: 1077908, ~: 1143318) +StakedEXATest:testWithdrawWithRewards(uint256) (runs: 256, μ: 879786, ~: 879479) +StakedEXATest:testZeroRateError() (gas: 59289) +StakingPreviewerTest:testAllClaimable() (gas: 431408) +StakingPreviewerTest:testAllClaimed() (gas: 632923) +StakingPreviewerTest:testAllEarned() (gas: 316426) +StakingPreviewerTest:testAllRewards() (gas: 485923) +StakingPreviewerTest:testStaking() (gas: 528483) SwapperTest:testSwapBasic() (gas: 216831) SwapperTest:testSwapWithAllowance() (gas: 481530) SwapperTest:testSwapWithInaccurateSlippageSendsETHToAccount() (gas: 297968) diff --git a/contracts/StakedEXA.sol b/contracts/StakedEXA.sol index 11801433..04413bd4 100644 --- a/contracts/StakedEXA.sol +++ b/contracts/StakedEXA.sol @@ -101,8 +101,7 @@ contract StakedEXA is setPenaltyGrowth(p.penaltyGrowth); setPenaltyThreshold(p.penaltyThreshold); - market = p.market; - + setMarket(p.market); IERC20 providerAsset = IERC20(address(p.market.asset())); enableReward(providerAsset); setRewardsDuration(providerAsset, p.duration); @@ -135,7 +134,8 @@ contract StakedEXA is uint256 balance = balanceOf(to); uint256 total = amount + balance; - for (uint256 i = 0; i < rewardsTokens.length; ++i) { + uint256 length = rewardsTokens.length; + for (uint256 i = 0; i < length; ++i) { IERC20 reward = rewardsTokens[i]; updateIndex(reward); @@ -155,7 +155,8 @@ contract StakedEXA is } harvest(); } else if (to == address(0)) { - for (uint256 i = 0; i < rewardsTokens.length; ++i) { + uint256 length = rewardsTokens.length; + for (uint256 i = 0; i < length; ++i) { IERC20 reward = rewardsTokens[i]; updateIndex(reward); claimWithdraw(reward, from, amount); @@ -192,14 +193,14 @@ contract StakedEXA is uint256 claimableAmount = Math.max(rawClaimable(reward, account, amount), claimedAmount); // due to excess exposure uint256 claimAmount = claimableAmount - claimedAmount; if (claimAmount != 0) { - reward.transfer(account, claimAmount); + reward.safeTransfer(account, claimAmount); emit RewardPaid(reward, account, claimAmount); } uint256 rawEarned = earned(reward, account, amount); // due to rounding uint256 saveAmount = rawEarned <= claimableAmount + savedAmount ? 0 : rawEarned - claimableAmount - savedAmount; - if (saveAmount != 0) reward.transfer(savings, saveAmount); + if (saveAmount != 0) reward.safeTransfer(savings, saveAmount); } /// @notice Notifies the contract about a reward amount. @@ -387,11 +388,11 @@ contract StakedEXA is if (saveAmount != 0) { saved[msg.sender][reward] = savedAmount + saveAmount; - reward.transfer(savings, saveAmount); + reward.safeTransfer(savings, saveAmount); } } if (claimAmount != 0) { - reward.transfer(msg.sender, claimAmount); + reward.safeTransfer(msg.sender, claimAmount); emit RewardPaid(reward, msg.sender, claimAmount); } } @@ -428,7 +429,7 @@ contract StakedEXA is if (block.timestamp < rewards[reward].finishAt) { uint256 finishAt = rewards[reward].finishAt; rewards[reward].finishAt = uint40(block.timestamp); - reward.transfer(savings, (finishAt - block.timestamp) * rewards[reward].rate); + reward.safeTransfer(savings, (finishAt - block.timestamp) * rewards[reward].rate); } emit DistributionFinished(reward, msg.sender); @@ -457,7 +458,8 @@ contract StakedEXA is /// @notice Sets the market. /// @param market_ The new market. - function setMarket(Market market_) external onlyRole(DEFAULT_ADMIN_ROLE) { + function setMarket(Market market_) public onlyRole(DEFAULT_ADMIN_ROLE) { + if (address(market_) == address(0)) revert ZeroAddress(); market = market_; emit MarketSet(market_, msg.sender); } diff --git a/test/StakedEXA.t.sol b/test/StakedEXA.t.sol index 485d6cf0..53c0414b 100644 --- a/test/StakedEXA.t.sol +++ b/test/StakedEXA.t.sol @@ -1314,6 +1314,11 @@ contract StakedEXATest is Test { assertEq(address(stEXA.market()), address(newMarket)); } + function testSetMarketAddressZero() external { + vm.expectRevert(ZeroAddress.selector); + stEXA.setMarket(Market(address(0))); + } + function testOnlyAdminSetProvider() external { address nonAdmin = address(0x1); address newProvider = address(0x2);