Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: high
Valid

Missing lastClaimTime Update in claimRewards::FeeCollector.sol

Summary

The claimRewards function in the protocol does not update the lastClaimTime mapping after a user successfully claims their rewards. This omission allows users to exploit the rewards system in several ways, including rapid repeated claims, front-running reward distribution, bot-driven reward farming, network congestion attacks, and Sybil attacks. These vulnerabilities can lead to unfair reward distribution, depletion of the reward pool, and economic instability within the protocol.

Vulnerability Details

function claimRewards(address user) external override nonReentrant whenNotPaused returns (uint256) {
if (user == address(0)) revert InvalidAddress();
uint256 pendingReward = _calculatePendingRewards(user);
if (pendingReward == 0) revert InsufficientBalance();
// Reset user rewards before transfer
userRewards[user] = totalDistributed;
// Transfer rewards
raacToken.safeTransfer(user, pendingReward);
//@audit, _updateLastClaimTime not updated
emit RewardClaimed(user, pendingReward);
return pendingReward;
}

The function fails to update lastClaimTime[user] after a claim is made, which allows users to claim rewards continuously without any time restriction. The expected behavior is to record the timestamp of the last successful claim to prevent excessive and unfair claims.

Impact

Front-running :

  • Users can monitor on-chain reward distributions and front-run transactions by claiming immediately before and after rewards are added.

  • This allows them to double-claim rewards unfairly, concentrating funds in the hands of a few actors.

Bot-Driven Reward Farming:

Automated scripts and bots can be programmed to claim rewards every block if there is no time restriction.

This increases gas costs for other users and depletes the protocol’s funds rapidly, leading to an unbalanced and unfair reward system.

Tools Used

Manual review

Recommendations

Modify claimRewards to update lastClaimTime after a successful claim and initialize a waiting period for the next claim:

+ uint256 waitingPeriod = 1 days;
function claimRewards(address user) external override nonReentrant whenNotPaused returns (uint256) {
if (user == address(0)) revert InvalidAddress();
+ if (block.timestamp < _updateLastClaimTime(user) + waitingPeriod ) revert InvalidDuration();
uint256 pendingReward = _calculatePendingRewards(user);
if (pendingReward == 0) revert InsufficientBalance();
// Update last claim time
+ _updateLastClaimTime(user);
// Reset user rewards before transfer
userRewards[user] = totalDistributed;
// Transfer rewards
raacToken.safeTransfer(user, pendingReward);
emit RewardClaimed(user, pendingReward);
return pendingReward;
}
function _updateLastClaimTime(address user) internal {
lastClaimTime[user] = block.timestamp;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Time-Weighted Average Logic is Not Applied to Reward Distribution in `FeeCollector`

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Time-Weighted Average Logic is Not Applied to Reward Distribution in `FeeCollector`

Support

FAQs

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