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

Failed to process rewards from multiple Epochs, resulting in inaccurate calculation of user rewards

Summary

The _redeem function in the staking contract does not handle multiple unclaimed reward epochs correctly, which can lead to incorrect reward calculations for users with staked tokens across multiple epochs. This issue arises because the function only processes a single unredeemed epoch at a time and does not account for cases where users have multiple unclaimed epochs.

Vulnerability Details

https://github.com/Cyfrin/2024-08-fjord/blob/main/src/FjordStaking.sol#L726-L749

The _redeem function in the staking contract does not handle multiple unclaimed reward epochs correctly, which can lead to incorrect reward calculations for users with staked tokens across multiple epochs. This issue arises because the function only processes a single unredeemed epoch at a time and does not account for cases where users have multiple unclaimed epochs.

  1. Epoch 1: User stakes 1000 tokens.

  2. Epoch 2: User stakes 500 tokens.

  3. Epoch 3: User stakes 300 tokens.

  4. Epoch 4: User stakes 200 tokens.

Suppose at the end of Epoch 4, the user calls the _redeem function, but the function only processes rewards before Epoch 4 and does not correctly calculate rewards for Epoch 2 and Epoch 3. This will cause the user's reward calculation to be incomplete. Assuming that the rewards in Epoch 3 are not accumulated correctly, the user may miss this part of the reward.

Specific problem points:

• If ud.unredeemedEpoch is Epoch 2, the function will only calculate the rewards for Epoch 2, but may not take into account the additional stakes in Epoch 3.

• calculateReward may only process the rewards between the current Epoch and the most recent claim, without covering all historical Epochs.

Impact

Incorrect Reward Calculations: Users may not receive rewards for all their staked epochs if their staked tokens span multiple epochs without redeeming rewards in between.

Tools Used

Manual review

Recommendations

Handle Multiple Unclaimed Epochs:

function _redeem(address sender) internal {
UserData storage ud = userData[sender];
// Calculate rewards from the last claimed epoch to the current epoch
ud.unclaimedRewards += calculateReward(ud.totalStaked, ud.lastClaimedEpoch, currentEpoch - 1);
ud.lastClaimedEpoch = currentEpoch - 1;
// Process rewards for all unclaimed epochs
uint16 epoch = ud.unredeemedEpoch;
while (epoch > 0 && epoch < currentEpoch) {
DepositReceipt memory deposit = deposits[sender][epoch];
ud.unclaimedRewards += calculateReward(
deposit.staked + deposit.vestedStaked, epoch, currentEpoch - 1
);
ud.totalStaked += (deposit.staked + deposit.vestedStaked);
epoch++;
}
// Update the unredeemed epoch status
if (epoch >= currentEpoch) {
ud.unredeemedEpoch = 0;
} else {
ud.unredeemedEpoch = epoch;
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge
10 months ago
inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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