Core Contracts

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

StabilityPool vulnerable to reward farming RAAC token through deposit/withdraw cycling

Summary

The StabilityPool's reward calculation mechanism allows users to farm RAAC rewards by repeatedly depositing and withdrawing funds, as there's no minimum deposit duration or reward checkpointing system.

Vulnerability Details

function calculateRaacRewards(address user) public view returns (uint256) {
uint256 userDeposit = userDeposits[user];
uint256 totalDeposits = deToken.totalSupply();
uint256 totalRewards = raacToken.balanceOf(address(this));
return (totalRewards * userDeposit) / totalDeposits;
}
function withdraw(uint256 deCRVUSDAmount) external nonReentrant whenNotPaused {
// ...
uint256 raacRewards = calculateRaacRewards(msg.sender);
if (raacRewards > 0) {
raacToken.safeTransfer(msg.sender, raacRewards);
}
}

The issue is that:

  • No minimum deposit duration is enforced

  • Rewards are calculated based on current deposit amount only

  • No historical tracking of deposits/rewards

  • User can deposit right before rewards are distributed and withdraw immediately after

Impact

High. This vulnerability:

  • Allows unfair distribution of RAAC rewards

  • Enables reward farming through spamming deposit&withdraw to drain all the raac rewards

  • Undermines the incentive mechanism for long-term liquidity providers

Recommended Mitigation

Implement a reward checkpointing system:

UserRewardInfo {
uint256 lastRewardTimestamp;
uint256 rewardPerSharePaid;
uint256 rewards;
}
mapping(address => UserRewardInfo) public userRewardInfo;

Add minimum deposit duration:

mapping(address => uint256) public depositTimestamp;
function deposit(uint256 amount) external {
// ...
depositTimestamp[msg.sender] = block.timestamp;
}
function withdraw(uint256 amount) external {
require(block.timestamp >= depositTimestamp[msg.sender] + MIN_DEPOSIT_DURATION, "Lock period not elapsed");
// ...
}

Calculate rewards based on time-weighted deposits:

function updateReward(address account) internal {
uint256 duration = block.timestamp - userRewardInfo[account].lastRewardTimestamp;
userRewardInfo[account].rewards += userDeposits[account] * duration;
userRewardInfo[account].lastRewardTimestamp = block.timestamp;
}
Updates

Lead Judging Commences

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

StabilityPool::calculateRaacRewards is vulnerable to just in time deposits

Support

FAQs

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

Give us feedback!