Core Contracts

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

Stability Pool DEToken Minting Desynchronization

Summary

StabilityPool's deposit function fails to maintain proper balance synchronization between DEToken minting and actual deposits. When users deposit rTokens, the minted DEToken amount can deviate from the expected 1:1 ratio, potentially leading to incorrect reward distributions and system imbalances.

The issue emerges in the StabilityPool's deposit function. While it correctly handles the rToken transfer and DEToken minting, the calculateDeCRVUSDAmount function uses a complex exchange rate calculation that can lead to precision loss: StabilityPool.sol/#calculateDeCRVUSDAmount

The exchange rate calculation introduces potential rounding errors, especially when dealing with different decimal places between rToken and DEToken.

Impact - This precision loss could accumulate over multiple deposits, creating a growing discrepancy between the total supply of DEToken and the actual rToken deposits in the StabilityPool. This affects:

  1. Reward calculations that depend on user deposit shares

  2. Withdrawal amounts when users redeem their DETokens

  3. Overall system accounting accuracy

Vulnerability Details

The issue emerges in the interaction between StabilityPool and DEToken minting. Notice how the protocol aims to maintain a delicate balance between real estate assets and DeFi liquidity through its stability mechanism.

The Stability Pool serves as the cornerstone of RAAC's risk management, where users deposit rTokens and receive DETokens. These DETokens represent their share in the stability mechanism and their right to earn RAAC rewards through the RAACMinter.

The StabilityPool's deposit function reveals a critical flaw in the balance synchronization: StabilityPool.sol/#deposit

function deposit(uint256 amount) external nonReentrant whenNotPaused validAmount(amount) {
_update(); // → Updates rewards state before deposit
// FLOW 1: Initial rToken Transfer
rToken.safeTransferFrom(msg.sender, address(this), amount);
// FLOW 2: Critical Calculation Point
// → This is where the desynchronization can occur
uint256 deCRVUSDAmount = calculateDeCRVUSDAmount(amount);
// FLOW 3: DEToken Minting
// → No validation that minted amount maintains 1:1 backing
deToken.mint(msg.sender, deCRVUSDAmount);
// FLOW 4: State Updates
userDeposits[msg.sender] += amount; // → Tracks rToken deposits
_mintRAACRewards(); // → Triggers RAACMinter for rewards
}
function calculateDeCRVUSDAmount(uint256 rcrvUSDAmount) public view returns (uint256) {
// CRITICAL POINT: Decimal Handling
// → Potential precision loss in decimal conversion
uint256 scalingFactor = 10**(18 + deTokenDecimals - rTokenDecimals);
// VULNERABILITY: Exchange Rate Division
// → Division after multiplication can lead to rounding errors
// → No check that output maintains expected ratio
return (rcrvUSDAmount * scalingFactor) / getExchangeRate();
}

The mistake is in the calculateDETokenAmount function. This calculation determines how many DETokens users receive for their rToken deposits, but it fails to maintain the crucial 1:1 backing ratio that the protocol depends on.

This means that over time, the total DEToken supply could deviate from the actual rToken reserves in the StabilityPool. For a protocol designed to bring real estate stability on-chain, this misalignment poses a significant risk to the entire system's integrity.

The impact ripples through the dual-gauge system, where both RWA and RAAC gauges rely on accurate stability pool accounting for proper reward distribution. A skewed DEToken:rToken ratio would directly affect:

  1. The protocol's ability to maintain stable real estate asset backing

  2. The accuracy of gauge-weighted rewards

  3. The effectiveness of the ve-token governance mechanism

Impact

RAAC brings real estate on-chain through an innovative system of interconnected contracts. The StabilityPool which acts like a secure vault where users deposit rTokens (representing real estate value) and receive DETokens in return. Think of it as converting your property deed into a more liquid, DeFi-compatible form.

Notice how the stability mechanism connects three key components, the StabilityPool managing deposits, DEToken tracking user shares, and RAACMinter distributing rewards. The core mistake emerges in how these components interact during the deposit process.

When users deposit rTokens, the protocol calculates their DEToken allocation using an exchange rate mechanism. This calculation determines how much of the protocol's real estate backing each user controls.

function calculateDeCRVUSDAmount(uint256 rcrvUSDAmount) public view returns (uint256) {
// CRITICAL POINT: Decimal Handling
// → Potential precision loss in decimal conversion
uint256 scalingFactor = 10**(18 + deTokenDecimals - rTokenDecimals);
// VULNERABILITY: Exchange Rate Division
// → Division after multiplication can lead to rounding errors
// → No check that output maintains expected ratio
return (rcrvUSDAmount * scalingFactor) / getExchangeRate();
}

This means that over time, the total DEToken supply could deviate from the actual rToken reserves. For a protocol designed to tokenize real estate, this misalignment threatens the fundamental premise of stable, asset-backed tokens.

The impact ripples through RAAC's dual-gauge system. The RWA gauge, responsible for real estate yield direction, and the RAAC gauge, managing protocol emissions, both rely on accurate stability pool accounting. A skewed DEToken:rToken ratio directly affects governance voting power and reward distributions.

Recommendations

By implementing precise mathematical operations and adding exchange rate invariant checks, we can ensure RAAC maintains its promise of bringing real estate stability on-chain while preserving the integrity of its governance mechanism.

StabilityPool Contract Flow

function deposit(uint256 amount) external {
_update(); // Sync rewards state
// Money Flow: User -> Pool
rToken.safeTransferFrom(msg.sender, address(this), amount);
// Vulnerability Point
uint256 deCRVUSDAmount = calculateDeCRVUSDAmount(amount);
// Token Minting
deToken.mint(msg.sender, deCRVUSDAmount);
// State Updates
userDeposits[msg.sender] += amount;
_mintRAACRewards(); // Reward Distribution
}

Current Vulnerable Calculation

function calculateDeCRVUSDAmount(uint256 rcrvUSDAmount) public view returns (uint256) {
// Scaling Factor Calculation
uint256 scalingFactor = 10**(18 + deTokenDecimals - rTokenDecimals);
// Precision Loss Point
return (rcrvUSDAmount * scalingFactor) / getExchangeRate();
}

Proposed Fix Using WadRayMath

function calculateDeCRVUSDAmount(uint256 rcrvUSDAmount) public view returns (uint256) {
// Precise Decimal Normalization
uint256 normalizedAmount = WadRayMath.wadMul(rcrvUSDAmount, WadRayMath.WAD);
// Accurate Division
return WadRayMath.wadDiv(normalizedAmount, getExchangeRate());
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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

Give us feedback!