Core Contracts

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

Incorrect Collateral Gain Calculation After Collateral Sunset

Summary

When collateral is sunset (disabled) and later reintroduced, the contract fails to reset error-tracking variables related to collateral gain calculations.

  • This can lead to over-distribution of rewards, potentially draining the collateral pool unfairly.

  • The last user to claim rewards may receive nothing, as prior claims could deplete the available balance.

The function _update() is executed in deposit() and withdraw(), but it does not handle resetting error offsets, leading to reward misallocations:

function _update() internal {
_mintRAACRewards();
}

Vulnerability Details

In the RAAC StabilityPool, when a collateral type is disabled (sunset) and later re-enabled, the lastCollateralError_Offset is not reset. This results in:

  1. Early withdrawers getting more rewards than they should.

  2. Later withdrawers losing rewards because the pool is prematurely drained.

** Setup for the Attack in RAAC Codebase**

Let's assume we have three users (Alice, Bob, and Charlie) interacting with StabilityPool.sol. The following functions are involved:

Step 1: Users Deposit Collateral

Alice, Bob, and Charlie deposit rToken into the pool, expecting proportional rewards.

StabilityPool.deposit(1000); // Alice deposits 1000 rToken
StabilityPool.deposit(2000); // Bob deposits 2000 rToken
StabilityPool.deposit(500); // Charlie deposits 500 rToken

Each user expects rewards based on deposit share.

Step 2: Governance Disables Collateral

At some point, governance sunsets collateral, preventing new deposits/withdrawals.

StabilityPool.removeMarket(address(rToken)); // Disabling collateral

This locks existing collateral and stops reward accumulation.
But it does NOT reset lastCollateralError_Offset.

** Step 3: Governance Re-Enables Collateral**

After some time, governance re-enables collateral.

StabilityPool.addMarket(address(rToken), 5000); // Re-enabling collateral

Bug: lastCollateralError_Offset is NOT reset.
This causes incorrect reward calculations.

Step 4: Users Withdraw (Exploit)

  • Alice withdraws first:

    StabilityPool.withdraw(1000);

    She receives excessive rewards because error offset was not reset.

  • Bob withdraws next:

    StabilityPool.withdraw(2000);

    Bob also gets more than he should.

  • Charlie withdraws last:

    StabilityPool.withdraw(500);

    Pool is drained, and Charlie gets nothing.
    Loss of fairness – later withdrawers are impacted.

Impact

Users may claim more rewards than available, creating a shortfall in the reward pool.

  • The last user attempting to claim may receive nothing, causing fund loss for them.

  • This can lead to unexpected behavior in the stability mechanism, disrupting fair reward allocation.

Tools Used

Manual Review

Recommendations

Reset Offsets When Re-Enabling Collateral

Modify addMarket() to reset tracking variables using some mechanism.

function addMarket(address market, uint256 allocation) external onlyOwner validAmount(allocation) {
if (supportedMarkets[market]) revert MarketAlreadyExists();
supportedMarkets[market] = true;
marketAllocations[market] = allocation;
totalAllocation += allocation;
// ✅ Reset error offsets to prevent reward misallocation
lastCollateralError_Offset[market] = 0;
emit MarketAdded(market, allocation);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Too generic

Support

FAQs

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