Core Contracts

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

Rewards Distribution Vulnerability in StabilityPool Allows Reward Dilution

Relevant Context

The StabilityPool contract implements a rewards distribution system where users can deposit rToken to receive deToken and earn RAAC rewards. The rewards are calculated based on the user's proportion of total deposits.

Finding Description

The current implementation of rewards distribution in StabilityPool is vulnerable to manipulation through deposit/withdraw cycling. The root cause lies in the calculateRaacRewards() function, which calculates rewards based on the current snapshot of deposits rather than accounting for the time-weighted value of deposits.

The function calculates rewards as:

(totalRewards * userDeposit) / totalDeposits

This simple proportional distribution allows users to claim a disproportionate share of rewards by repeatedly depositing and withdrawing funds, claiming rewards each time. Each withdrawal claims a portion of the total reward pool based on the user's current share, regardless of how long they've held that position.

Impact Explanation

High. This vulnerability allows malicious users to extract more rewards than they should fairly receive, directly reducing the rewards available to honest users who maintain long-term deposits.

Likelihood Explanation

High. The attack requires no special conditions or permissions, just normal deposit/withdraw functionality. The potential profit makes it likely that this would be exploited if discovered.

Proof of Concept

Initial state:

  • Alice has 100 deToken

  • Bob has 100 deToken

  • Total RAAC rewards in pool = 100

  • The rewards for Alice and Bob would be 50 RAAC

Attack sequence:

  1. Bob withdraws 50 deToken

    • Receives 50 RAAC (50% of 100 rewards)

  2. Bob deposits 50 deToken again

  3. Bob withdraws 50 deToken

    • Receives 25 RAAC (50% of remaining 50 rewards)

  4. Bob can repeat steps 2-3 to extract additional rewards

Final state:

  • Bob has received significantly more than his fair share of rewards

  • Alice's rewards are diluted despite maintaining her position

Recommendation

Implement a MasterChef-style reward distribution system using reward debt and accumulated rewards per share. This approach ensures rewards are distributed based on the duration and size of deposits.

Key changes needed:

contract StabilityPool {
uint256 public accRewardPerShare; // Accumulated rewards per share, scaled by 1e12
mapping(address => uint256) public rewardDebt; // User's reward debt
function deposit(uint256 amount) external {
updatePool(); // Update accRewardPerShare
// ... existing deposit logic ...
rewardDebt[msg.sender] = userDeposits[msg.sender] * accRewardPerShare / 1e12;
}
function withdraw(uint256 amount) external {
updatePool(); // Update accRewardPerShare
uint256 pending = (userDeposits[msg.sender] * accRewardPerShare / 1e12) - rewardDebt[msg.sender];
// ... transfer pending rewards ...
// ... existing withdrawal logic ...
rewardDebt[msg.sender] = userDeposits[msg.sender] * accRewardPerShare / 1e12;
}
}

This ensures rewards are distributed proportionally to the time and amount of user deposits.

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!