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

Incorrect check for checking if user have claimed from the last epoch or not

Summary

Incorrect check for checking if user have claimed from the last epoch or not

Vulnerability Details

User can claim their rewards using claimReward(), which gives them 2 options to either withdraw early by paying penaltyAmount or after claimCycle(no penalty)

function claimReward(bool _isClaimEarly)
external
checkEpochRollover
redeemPendingRewards
returns (uint256 rewardAmount, uint256 penaltyAmount)
{
//CHECK
UserData storage ud = userData[msg.sender];
// do not allow to claimReward while user have pending claimReceipt
// or user have claimed from the last epoch
@> if (
claimReceipts[msg.sender].requestEpoch > 0
|| claimReceipts[msg.sender].requestEpoch >= currentEpoch - 1
) revert ClaimTooEarly();
if (ud.unclaimedRewards == 0) revert NothingToClaim();
//EFFECT
@> if (!_isClaimEarly) {
claimReceipts[msg.sender] =
ClaimReceipt({ requestEpoch: currentEpoch, amount: ud.unclaimedRewards });
emit ClaimReceiptCreated(msg.sender, currentEpoch);
return (0, 0);
}
rewardAmount = ud.unclaimedRewards;
penaltyAmount = rewardAmount / 2;
rewardAmount -= penaltyAmount;
if (rewardAmount == 0) return (0, 0);
totalRewards -= (rewardAmount + penaltyAmount);
userData[msg.sender].unclaimedRewards -= (rewardAmount + penaltyAmount);
//INTERACT
@> fjordToken.safeTransfer(msg.sender, rewardAmount);
emit EarlyRewardClaimed(msg.sender, rewardAmount, penaltyAmount);
}

Now there is a check, which ensures user doesn't have pending claimReceipt & user have not claimed from the last epoch. The problem is with later check as this will never be checked. Lets see how..

  1. If user claimed early then claimReceipt is not created, directly funds are transferred to msg.sender. So therefore, claimReceipts[msg.sender].requestEpoch = 0, which means when next time user will come in same epoch or next epoch to claimReward, above check will not revert because requestEpoch is 0(zero)

  2. If user claimed after claimCycle then claimReceipt is created with requestEpoch = currentEpoch. But the problem is when user completes his claim then claimReceipt is deleted, which means claimReceipts[msg.sender].requestEpoch = 0 As result when user claims again then above check will not revert because requestEpoch is 0(zero)

Impact

User will be able to claim rewards in the same epoch or next epoch, which is against the protocol working

Tools Used

Manual Review

Recommendations

Don't delete the claimReceipt or store the last claimed epoch of user in a mapping and check if this is last epoch or not

Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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