Core Contracts

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

Hardcoded Exchange Rate Calculation Will Cause Undercollateralization, Blocking Withdrawals

Summary

The StabilityPool contract’s getExchangeRate() function is hardcoded to return 1e18, resulting in deTokens being minted and redeemed at a fixed 1:1 ratio regardless of the pool’s actual collateral. This flaw will cause undercollateralization and ultimately block user withdrawals.

Vulnerability Details

In the StabilityPool contract, the getExchangeRate() function is implemented as follows:

function getExchangeRate() public view returns (uint256) {
// uint256 totalDeCRVUSD = deToken.totalSupply();
// uint256 totalRcrvUSD = rToken.balanceOf(address(this));
// if (totalDeCRVUSD == 0 || totalRcrvUSD == 0) return 1e18;
// uint256 scalingFactor = 10**(18 + deTokenDecimals - rTokenDecimals);
// return (totalRcrvUSD * scalingFactor) / totalDeCRVUSD;
return 1e18;
}

causing this function to always returns 1e18:

Scenerio Flow

  • Deposit Flow: When a user deposits rTokens via the deposit() function, calculateDeCRVUSDAmount() uses getExchangeRate() to mint deTokens at a fixed 1:1 ratio. For example, when Bob deposits rTokens, he receives an equivalent amount of deTokens regardless of the actual pool collateral.

  • Liquidation Event: Later, if a liquidation event occurs—such as when Shelia is liquidated via the liquidateBorrower() function—the pool’s rToken balance is reduced significantly.

  • Withdrawal Flow: When Bob subsequently attempts to withdraw his rTokens using the withdraw() function, calculateRcrvUSDAmount() again uses the fixed exchange rate (1e18). Since the pool’s collateral has been depleted by Shelia’s liquidation, the calculated redeemable rToken amount exceeds the available collateral, causing Bob’s withdrawal to fail.

Impact

In this example the fixed exchange rate causes the StabilityPool to become undercollateralized once rToken reserves drop due to Shelia’s liquidation.

As a result, Bob will be unable to withdraw his funds because the contract’s calculations assume full collateralization, leading to failed transactions and locked assets.

Ultimately, users are directly affected by this flaw. The inability to redeem deTokens for the correct amount of rTokens compromises the integrity of the protocol and puts user funds at risk.

Tools Used

Manual Review

Recommendations

Modify the getExchangeRate() function to calculate the exchange rate dynamically based on the actual rToken reserves and the deToken total supply. For example:

function getExchangeRate() public view returns (uint256) {
uint256 totalDeCRVUSD = deToken.totalSupply();
uint256 totalRcrvUSD = rToken.balanceOf(address(this));
if (totalDeCRVUSD == 0 || totalRcrvUSD == 0) return 1e18;
uint256 scalingFactor = 10**(18 + deTokenDecimals - rTokenDecimals);
return (totalRcrvUSD * scalingFactor) / totalDeCRVUSD;
}

This update ensures that:

  • Deposits mint deTokens in proportion to the actual collateral in the pool.

  • Withdrawals correctly redeem rTokens based on current pool conditions.

  • Under adverse scenarios such as Shelia’s liquidation, Bob’s deTokens accurately reflect the diminished collateral, preventing blocked withdrawals and safeguarding user funds.

Updates

Lead Judging Commences

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

StabilityPool::getExchangeRate hardcodes 1:1 ratio instead of calculating real rate, enabling unlimited deToken minting against limited reserves

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

StabilityPool::getExchangeRate hardcodes 1:1 ratio instead of calculating real rate, enabling unlimited deToken minting against limited reserves

Support

FAQs

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

Give us feedback!