Core Contracts

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

Managers lose rewards

Summary

The contract is designed to distribute RAAC rewards to users (based on their deposits) and managers (based on their allocations). However, the code only distributes rewards to users, completely ignoring managers.

Vulnerability Details

/**
* @notice Allows a user to deposit rToken and receive deToken.
* @param amount Amount of rToken to deposit.
*/
function deposit(uint256 amount) external nonReentrant whenNotPaused validAmount(amount) {
_update();
rToken.safeTransferFrom(msg.sender, address(this), amount);
uint256 deCRVUSDAmount = calculateDeCRVUSDAmount(amount);
deToken.mint(msg.sender, deCRVUSDAmount);
userDeposits[msg.sender] += amount;
_mintRAACRewards();
emit Deposit(msg.sender, amount, deCRVUSDAmount);
}
/**
* @notice Calculates the pending RAAC rewards for a user.
* @param user Address of the user.
* @return Amount of RAAC rewards.
*/
function calculateRaacRewards(address user) public view returns (uint256) {
uint256 userDeposit = userDeposits[user];
uint256 totalDeposits = deToken.totalSupply();
uint256 totalRewards = raacToken.balanceOf(address(this));
if (totalDeposits < 1e6) return 0;
return (totalRewards * userDeposit) / totalDeposits;
}

Assume:

  • Liquidity Pool deposits 1000 RAAC into the StabilityPool.

  • Total manager allocations = 300 (e.g., Manager A: 100, Manager B: 200).

  • Total user deposits = 700 deToken.

depositRAACFromPool(1000) is called by the liquidity pool. The entire 1000 RAAC remains in the StabilityPool contract.

  • Managers should receive 300 RAAC (proportional to their allocations).

  • Users should receive the remaining 700 RAAC.

what happens:

All 1000 RAAC is treated as user rewards. Managers get 0

A user with 350 deToken (50% of the total 700 deToken) calls withdraw.

calculateRaacRewards computes and the user receives 500 RAAC (50% of the total pool). However User should receive 350 RAAC (50% of the user-specific 700 RAAC pool).

The remaining 300 RAAC should have gone to managers. User claims 500 RAAC (50% of the entire 1000 RAAC), over-rewarding them by 150 RAAC and Managers receive nothing.

The depositRAACFromPool function has a TODO but no code to split RAAC between managers and users. All RAAC is treated as user rewards. calculateRaacRewards uses the total RAAC balance (including the portion meant for managers) to calculate user rewards:

uint256 totalRewards = raacToken.balanceOf(address(this)); // Includes managers' share

Impact

Managers lose rewards

Tools Used

Foundry

Recommendations

function depositRAACFromPool(uint256 amount) external ... {
// Transfer RAAC to the pool
raacToken.safeTransferFrom(msg.sender, address(this), amount);
// Distribute RAAC to managers based on their allocations
for (uint256 i = 0; i < managerList.length; i++) {
address manager = managerList[i];
uint256 managerShare = (amount * managerAllocation[manager]) / totalAllocation;
raacToken.safeTransfer(manager, managerShare);
}
}
Updates

Lead Judging Commences

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

StabilityPool::calculateRaacRewards uses contract balance for reward calculation, incorrectly including tokens meant for manager allocation - Manager allocation not implemented

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

StabilityPool::calculateRaacRewards uses contract balance for reward calculation, incorrectly including tokens meant for manager allocation - Manager allocation not implemented

Support

FAQs

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

Give us feedback!