DeFiFoundry
20,000 USDC
View results
Submission Details
Severity: high
Invalid

users can stake and unstake in the same epoch and are able to steal rewards

Details

There is currently some wrong implementation logic within the redeemPendingRewards modifier which allows a user to claim rewards for epoch in which they have unstaked. This exploit can be categorised as an exploit by which users can steal rewards from the protocol.

By default users aren't allowed to claim rewards for epoch in which they didnt stake. But this vulnerability allows users to claim rewards by manipulating the system. Users can stake in specific epochs in order to accumulate their rewards while they quickly unstake in the same epocha and are able to steal rewards. This is as a result of some bugs within the redeemPendingRewards and how the unredeemedEpoch is being updated.

Impact

  • Loss of funds to the protocol and other users.

  • claiming of rewards that would have meant for other users

POC

function testUnstakeImmediately() external { //@audit user can stake and unstake in the same epoch just to claim rewards
vm.prank(minter);
fjordStaking.addReward(1 ether);
vm.prank(bob);
fjordStaking.stake(1 ether); // By defaulting no one gets rewarded in the first epoch so unclaimedRewards is 0
(
uint256 totalStaked,
uint256 unclaimedRewards,
uint16 unredeemedEpoch,
uint16 lastClaimedEpoch
) = fjordStaking.userData(address(bob));
console.log("unclaimedRewards", unclaimedRewards);
console.log("unredeemedEpoch", unredeemedEpoch);
_addRewardAndEpochRollover(1 ether, 2); // roll over 2 epochs and adding 1 ether rewards in each epoch making total of 3 ether rewards
assertEq(fjordStaking.currentEpoch(), 3); // Now at epoch 3
vm.prank(bob); //
fjordStaking.stake(1 ether); // Bob stakes 1 ether and is now entitled to the total reward of 3 ether
vm.prank(bob);
fjordStaking.unstake(3, 1 ether); // Bob unstakes his 1 ether
(
totalStaked,
unclaimedRewards,
unredeemedEpoch,
lastClaimedEpoch
) = fjordStaking.userData(address(bob));
console.log("unclaimedRewards", unclaimedRewards);
console.log("unredeemedEpoch", unredeemedEpoch);
vm.prank(bob);
fjordStaking.claimReward(false); // Bob can claim his rewards
}

Recommendation

I really cant say a proper fix for now as there are lots of abstractions and internal logics going on so as not to distrup other part of the system.

Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 year ago
inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Appeal created

mansa11 Submitter
about 1 year ago
mansa11 Submitter
about 1 year ago
inallhonesty Lead Judge
about 1 year ago
inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.