Skip to content

Commit

Permalink
👔 staking: restrict deposit to another receiver with allowance
Browse files Browse the repository at this point in the history
  • Loading branch information
itofarina committed Aug 8, 2024
1 parent dae2b41 commit ec2fe7a
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 60 deletions.
123 changes: 63 additions & 60 deletions .gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -460,92 +460,95 @@ 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: 43884)
StakedEXATest:testAvgIndex(uint256[3],uint256[2]) (runs: 256, μ: 1216267, ~: 1249579)
StakedEXATest:testAvgStartTime(uint256[3],uint256[2]) (runs: 256, μ: 1202673, ~: 1235985)
StakedEXATest:testBalanceOfDeposit(uint80) (runs: 256, μ: 355406, ~: 362451)
StakedEXATest:testBalanceOfWithdraw(uint256) (runs: 256, μ: 60558, ~: 60565)
StakedEXATest:testAlreadyListedError() (gas: 43906)
StakedEXATest:testAvgIndex(uint256[3],uint256[2]) (runs: 256, μ: 1214747, ~: 1249353)
StakedEXATest:testAvgStartTime(uint256[3],uint256[2]) (runs: 256, μ: 1201153, ~: 1235759)
StakedEXATest:testBalanceOfDeposit(uint80) (runs: 256, μ: 355470, ~: 362517)
StakedEXATest:testBalanceOfWithdraw(uint256) (runs: 256, μ: 60470, ~: 60477)
StakedEXATest:testCanChangeRewardsDurationWhenDisabled() (gas: 168917)
StakedEXATest:testClaimAfterHarvest() (gas: 840853)
StakedEXATest:testClaimAndUnstake() (gas: 1486466)
StakedEXATest:testClaimAndWithdrawAfterRefTime() (gas: 1091565)
StakedEXATest:testClaimBeforeFirstHarvest() (gas: 539888)
StakedEXATest:testDepositClaimsRewardsToReceiver() (gas: 1050445)
StakedEXATest:testDepositEvent(uint256) (runs: 256, μ: 364333, ~: 364044)
StakedEXATest:testDepositShouldClaim(uint256[2],uint32) (runs: 256, μ: 819344, ~: 742180)
StakedEXATest:testDepositWithdrawAvgStartTimeAndIndex(uint256[3],uint256,uint256[5]) (runs: 256, μ: 1748331, ~: 1809795)
StakedEXATest:testEarnedWithTime(uint256) (runs: 256, μ: 35436, ~: 35711)
StakedEXATest:testEmergencyAdminCanPauseNotUnpause() (gas: 159039)
StakedEXATest:testClaimAfterHarvest() (gas: 840919)
StakedEXATest:testClaimAndUnstake() (gas: 1541315)
StakedEXATest:testClaimAndWithdrawAfterRefTime() (gas: 1091631)
StakedEXATest:testClaimBeforeFirstHarvest() (gas: 539932)
StakedEXATest:testDepositClaimsRewardsToReceiver() (gas: 1104891)
StakedEXATest:testDepositEvent(uint256) (runs: 256, μ: 364421, ~: 364120)
StakedEXATest:testDepositShouldClaim(uint256[2],uint32) (runs: 256, μ: 820656, ~: 742277)
StakedEXATest:testDepositToAnotherWithAllowance() (gas: 409123)
StakedEXATest:testDepositToAnotherWithoutAllowanceShouldFail() (gas: 122812)
StakedEXATest:testDepositWithdrawAvgStartTimeAndIndex(uint256[3],uint256,uint256[5]) (runs: 256, μ: 1748412, ~: 1809494)
StakedEXATest:testEarnedWithTime(uint256) (runs: 256, μ: 35439, ~: 35711)
StakedEXATest:testEmergencyAdminCanPauseNotUnpause() (gas: 159017)
StakedEXATest:testFinishDistributionEmitEvent() (gas: 402683)
StakedEXATest:testFinishDistributionLetsClaimUnclaimed() (gas: 1516914)
StakedEXATest:testFinishDistributionStopsEmission() (gas: 1496500)
StakedEXATest:testFinishDistributionThatAlreadyFinished() (gas: 436014)
StakedEXATest:testFinishDistributionLetsClaimUnclaimed() (gas: 1571740)
StakedEXATest:testFinishDistributionStopsEmission() (gas: 1551371)
StakedEXATest:testFinishDistributionThatAlreadyFinished() (gas: 436103)
StakedEXATest:testFinishDistributionTransfersRemainingToSavings() (gas: 112201)
StakedEXATest:testGrantRevokeEmergencyAdmin() (gas: 107216)
StakedEXATest:testGrantRevokePauser() (gas: 107191)
StakedEXATest:testHandlerClaim(uint8) (runs: 256, μ: 302903, ~: 302903)
StakedEXATest:testHandlerDeposit(uint80) (runs: 256, μ: 798727, ~: 810004)
StakedEXATest:testHandlerHarvest(uint64) (runs: 256, μ: 343431, ~: 342608)
StakedEXATest:testHandlerNotifyRewardAmount(uint64) (runs: 256, μ: 127022, ~: 123274)
StakedEXATest:testHandlerSetDuration(uint32) (runs: 256, μ: 145941, ~: 164475)
StakedEXATest:testHandlerClaim(uint8) (runs: 256, μ: 302881, ~: 302881)
StakedEXATest:testHandlerDeposit(uint80) (runs: 256, μ: 799902, ~: 826633)
StakedEXATest:testHandlerHarvest(uint64) (runs: 256, μ: 343793, ~: 342644)
StakedEXATest:testHandlerNotifyRewardAmount(uint64) (runs: 256, μ: 127922, ~: 123298)
StakedEXATest:testHandlerSetDuration(uint32) (runs: 256, μ: 144043, ~: 164563)
StakedEXATest:testHandlerSetMarket() (gas: 157950)
StakedEXATest:testHandlerWithdraw(uint256) (runs: 256, μ: 69973, ~: 69980)
StakedEXATest:testHarvest() (gas: 197944)
StakedEXATest:testHarvestAmountWithReducedAllowance() (gas: 215363)
StakedEXATest:testHarvest() (gas: 197966)
StakedEXATest:testHarvestAmountWithReducedAllowance() (gas: 215386)
StakedEXATest:testHarvestEffectOnRewardData() (gas: 190945)
StakedEXATest:testHarvestEmitsRewardAmountNotified() (gas: 188920)
StakedEXATest:testHarvestEmitsRewardAmountNotified() (gas: 188943)
StakedEXATest:testHarvestZero() (gas: 236746)
StakedEXATest:testInitialValues() (gas: 89269)
StakedEXATest:testInsufficientBalanceError(uint256) (runs: 256, μ: 64211, ~: 64353)
StakedEXATest:testMaxRewardsGasConsumption() (gas: 138555933)
StakedEXATest:testMultipleClaimsVsOne() (gas: 26048842)
StakedEXATest:testMultipleHarvests() (gas: 461971)
StakedEXATest:testNoRewardsAfterPeriod(uint256) (runs: 256, μ: 1569438, ~: 1576150)
StakedEXATest:testInsufficientBalanceError(uint256) (runs: 256, μ: 64186, ~: 64331)
StakedEXATest:testMaxRewardsGasConsumption() (gas: 138555912)
StakedEXATest:testMultipleClaimsVsOne() (gas: 26103669)
StakedEXATest:testMultipleHarvests() (gas: 462059)
StakedEXATest:testNoRewardsAfterPeriod(uint256) (runs: 256, μ: 1569710, ~: 1576305)
StakedEXATest:testNotPausingRoleError() (gas: 39481)
StakedEXATest:testNotifyRewardAmount(uint256,uint256) (runs: 256, μ: 129968, ~: 129918)
StakedEXATest:testNotifyRewardWithUnderlyingAsset() (gas: 497597)
StakedEXATest:testNotifyRewardAmount(uint256,uint256) (runs: 256, μ: 129996, ~: 129940)
StakedEXATest:testNotifyRewardWithUnderlyingAsset() (gas: 497663)
StakedEXATest:testOnlyAdminEnableReward() (gas: 1199166)
StakedEXATest:testOnlyAdminFinishDistribution() (gas: 191108)
StakedEXATest:testOnlyAdminNotifyRewardAmount() (gas: 203497)
StakedEXATest:testOnlyAdminNotifyRewardAmount() (gas: 203519)
StakedEXATest:testOnlyAdminSetProvider() (gas: 143746)
StakedEXATest:testOnlyAdminSetProviderRatio() (gas: 143405)
StakedEXATest:testOnlyAdminSetRewardsDuration() (gas: 153043)
StakedEXATest:testOnlyAdminSetSavings() (gas: 141186)
StakedEXATest:testPausable() (gas: 1154861)
StakedEXATest:testPausableClaim() (gas: 639455)
StakedEXATest:testOnlyAdminSetRewardsDuration() (gas: 153065)
StakedEXATest:testOnlyAdminSetSavings() (gas: 141208)
StakedEXATest:testPausable() (gas: 1154949)
StakedEXATest:testPausableClaim() (gas: 639521)
StakedEXATest:testPausableHarvest() (gas: 344626)
StakedEXATest:testPauserCanPauseUnpause() (gas: 157877)
StakedEXATest:testPenaltyGrowthRange() (gas: 67233)
StakedEXATest:testPenaltyThresholdRange() (gas: 37156)
StakedEXATest:testPermitAndDeposit() (gas: 373086)
StakedEXATest:testResetDepositAfterRefTime(uint256) (runs: 256, μ: 1020687, ~: 1020389)
StakedEXATest:testRewardAmountNotifiedEvent(uint256) (runs: 256, μ: 104741, ~: 105543)
StakedEXATest:testPenaltyGrowthRange() (gas: 67211)
StakedEXATest:testPenaltyThresholdRange() (gas: 37134)
StakedEXATest:testPermitAndDeposit() (gas: 373108)
StakedEXATest:testRemoveDepositAllowance() (gas: 501636)
StakedEXATest:testResetDepositAfterRefTime(uint256) (runs: 256, μ: 1020731, ~: 1020409)
StakedEXATest:testRewardAmountNotifiedEvent(uint256) (runs: 256, μ: 104709, ~: 105499)
StakedEXATest:testRewardNotListedError() (gas: 1109565)
StakedEXATest:testRewardPaidEvent(uint256,uint256) (runs: 256, μ: 813598, ~: 862521)
StakedEXATest:testRewardsAmounts(uint256) (runs: 256, μ: 1576995, ~: 1576585)
StakedEXATest:testRewardsDurationSetEvent(uint40) (runs: 256, μ: 52072, ~: 52056)
StakedEXATest:testSetDuration(uint256,uint40) (runs: 256, μ: 58965, ~: 59226)
StakedEXATest:testRewardPaidEvent(uint256,uint256) (runs: 256, μ: 812237, ~: 754793)
StakedEXATest:testRewardsAmounts(uint256) (runs: 256, μ: 1577106, ~: 1576695)
StakedEXATest:testRewardsDurationSetEvent(uint40) (runs: 256, μ: 52073, ~: 52056)
StakedEXATest:testSetDuration(uint256,uint40) (runs: 256, μ: 58976, ~: 59226)
StakedEXATest:testSetMarketAddressZero() (gas: 37124)
StakedEXATest:testSetMarketOnlyAdmin() (gas: 1300351)
StakedEXATest:testSetMaxRewardsTokensExceeded() (gas: 104946678)
StakedEXATest:testSetMinTime() (gas: 81960)
StakedEXATest:testSetMinTime() (gas: 81938)
StakedEXATest:testSetPenaltyGrowth() (gas: 82148)
StakedEXATest:testSetPenaltyThreshold() (gas: 81925)
StakedEXATest:testSetProviderRatioOverOneError() (gas: 37179)
StakedEXATest:testSetProviderZeroAddressError() (gas: 37131)
StakedEXATest:testSetSavingsZeroAddressError() (gas: 37240)
StakedEXATest:testTotalSupplyDeposit(uint80) (runs: 256, μ: 354921, ~: 361966)
StakedEXATest:testTotalSupplyWithdraw(uint256) (runs: 256, μ: 62006, ~: 62013)
StakedEXATest:testUntransferable(uint80) (runs: 256, μ: 374574, ~: 382518)
StakedEXATest:testWithdrawEvent(uint256) (runs: 256, μ: 520326, ~: 520033)
StakedEXATest:testWithdrawSameAmountRewardsShouldEqual(uint256,uint256) (runs: 256, μ: 1076739, ~: 1143249)
StakedEXATest:testWithdrawWithRewards(uint256) (runs: 256, μ: 879743, ~: 879450)
StakedEXATest:testZeroRateError() (gas: 58047)
StakingPreviewerTest:testAllClaimable() (gas: 431263)
StakingPreviewerTest:testAllClaimed() (gas: 633003)
StakingPreviewerTest:testAllEarned() (gas: 316369)
StakingPreviewerTest:testAllRewards() (gas: 485770)
StakingPreviewerTest:testStaking() (gas: 528490)
StakedEXATest:testTotalSupplyDeposit(uint80) (runs: 256, μ: 354985, ~: 362032)
StakedEXATest:testTotalSupplyWithdraw(uint256) (runs: 256, μ: 61961, ~: 61968)
StakedEXATest:testUntransferable(uint80) (runs: 256, μ: 374660, ~: 382606)
StakedEXATest:testWithdrawEvent(uint256) (runs: 256, μ: 520415, ~: 520103)
StakedEXATest:testWithdrawSameAmountRewardsShouldEqual(uint256,uint256) (runs: 256, μ: 1074152, ~: 1143271)
StakedEXATest:testWithdrawWithRewards(uint256) (runs: 256, μ: 879810, ~: 879498)
StakedEXATest:testZeroRateError() (gas: 58070)
StakingPreviewerTest:testAllClaimable() (gas: 431329)
StakingPreviewerTest:testAllClaimed() (gas: 633069)
StakingPreviewerTest:testAllEarned() (gas: 316435)
StakingPreviewerTest:testAllRewards() (gas: 485836)
StakingPreviewerTest:testStaking() (gas: 528556)
SwapperTest:testSwapBasic() (gas: 216831)
SwapperTest:testSwapWithAllowance() (gas: 481530)
SwapperTest:testSwapWithInaccurateSlippageSendsETHToAccount() (gas: 297968)
Expand Down
2 changes: 2 additions & 0 deletions contracts/StakedEXA.sol
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ contract StakedEXA is
function _update(address from, address to, uint256 amount) internal override whenNotPaused {
if (amount == 0) revert ZeroAmount();
if (from == address(0)) {
if (to != msg.sender && allowance(to, msg.sender) == 0) revert NotAllowed();
uint256 start = avgStart[to];
uint256 time = start != 0 ? block.timestamp * 1e18 - start : 0;
uint256 memRefTime = refTime * 1e18;
Expand Down Expand Up @@ -568,6 +569,7 @@ error InsufficientBalance();
error InvalidRange();
error InvalidRatio();
error MaxRewardsTokensExceeded();
error NotAllowed();
error NotFinished();
error NotPausingRole();
error RewardNotListed();
Expand Down
47 changes: 47 additions & 0 deletions test/StakedEXA.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
Market,
Math,
MaxRewardsTokensExceeded,
NotAllowed,
NotFinished,
NotPausingRole,
Parameters,
Expand Down Expand Up @@ -1203,6 +1204,8 @@ contract StakedEXATest is Test {
uint256 assets = 1_000e18;
exa.mint(address(this), assets * 2);
stEXA.deposit(assets, address(this));
vm.prank(BOB);
stEXA.approve(address(this), 1);
stEXA.deposit(assets, BOB);
skip(minTime + 1);

Expand All @@ -1229,6 +1232,8 @@ contract StakedEXATest is Test {
uint256 assets = 1_000e18;
exa.mint(address(this), assets * 2);
stEXA.deposit(assets, address(this));
vm.prank(BOB);
stEXA.approve(address(this), 1);
stEXA.deposit(assets, BOB);
skip(minTime + 1);

Expand Down Expand Up @@ -1426,6 +1431,8 @@ contract StakedEXATest is Test {
uint256 assets = 1_000e18;
exa.mint(address(this), assets * 2);
stEXA.deposit(assets, address(this));
vm.prank(BOB);
stEXA.approve(address(this), 1);
stEXA.deposit(assets, BOB);

skip(minTime + 2 weeks);
Expand All @@ -1449,6 +1456,10 @@ contract StakedEXATest is Test {
uint256 assets = 1_000e18;
exa.mint(address(this), assets * 2);
stEXA.deposit(assets, address(this));

vm.prank(BOB);
stEXA.approve(address(this), 1);

stEXA.deposit(assets, BOB);

uint256 claimableAcc = 0;
Expand Down Expand Up @@ -1720,6 +1731,8 @@ contract StakedEXATest is Test {

uint256 claimableAmount = claimable(rA, address(this));
uint256 balanceBefore = rA.balanceOf(address(this));

stEXA.approve(BOB, 1);

exa.mint(BOB, assets);
vm.startPrank(BOB);
Expand All @@ -1731,6 +1744,40 @@ contract StakedEXATest is Test {

}

function testDepositToAnotherWithoutAllowanceShouldFail() external {
uint256 assets = 1_000e18;
exa.mint(address(this), assets);

vm.expectRevert(NotAllowed.selector);
stEXA.deposit(assets, BOB);
}

function testDepositToAnotherWithAllowance() external {
uint256 assets = 1_000e18;
exa.mint(address(this), assets);

vm.prank(BOB);
stEXA.approve(address(this), 1);

stEXA.deposit(assets, BOB);
}

function testRemoveDepositAllowance() external {
uint256 assets = 1_000e18;
exa.mint(address(this), assets * 2);

vm.prank(BOB);
stEXA.approve(address(this), 1);

stEXA.deposit(assets, BOB);

vm.prank(BOB);
stEXA.approve(address(this), 0);

vm.expectRevert(NotAllowed.selector);
stEXA.deposit(assets, BOB);
}

function minMaxWithdrawAllowance() internal view returns (uint256) {
return Math.min(market.convertToAssets(market.allowance(PROVIDER, address(stEXA))), market.maxWithdraw(PROVIDER));
}
Expand Down

0 comments on commit ec2fe7a

Please sign in to comment.