Core Contracts

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

Incorrect stability pool formula leading to loss of funds

Summary

calculateRcrvUSDAmount is implemented incorrectly when the 2 tokens have different decimals. Depending which has more, there are 2 outcomes - users lose funds and receive nothing or user withdrawals are DoS'd

Vulnerability Details

When depositing in a stability pool, a decimal correction is performed to account for differences between rToken and deToken

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

There is the reverse conversion when initiating a withdrawal via calculateRcrvUSDAmount.

function calculateRcrvUSDAmount(uint256 deCRVUSDAmount) public view returns (uint256) {
uint256 scalingFactor = 10**(18 + rTokenDecimals - deTokenDecimals);
return (deCRVUSDAmount * getExchangeRate()) / scalingFactor;
}

However the latter formula is implemented incorrectly.

Let's observe a case where rToken has 18 decimals and deToken has 6. Depositing 1e18 rToken would yield 1e6 deToken. If we attempt a withdrawal the conversion in calculateRcrvUSDAmount will round down to 0 since scalingFactor = 10**(18 + 18 - 6) = 1e30 whereas deCRVUSDAmount * exchangeRate = 1e24. Execution will continue, user's deToken will be burnt and they will receive nothing in return.

Let's check the reverse case - rToken has 6 decimals and deToken has 18. Depositing 1e6 rToken would yield 1e18 deToken. If we attempt to withdraw our 1e6 deToken calculateRcrvUSDAmount will return 1e18 * 1e18 / 1e6 = 1e30 rTokens to be received. This withdraw will not go through and will end up reverting due to this check

uint256 rcrvUSDAmount = calculateRcrvUSDAmount(deCRVUSDAmount); // returns 1e30
uint256 raacRewards = calculateRaacRewards(msg.sender);
if (userDeposits[msg.sender] < rcrvUSDAmount) revert InsufficientBalance(); // our deposit was 1e6, this will never pass
userDeposits[msg.sender] -= rcrvUSDAmount;

Impact

Permanent loss of funds, DoS

Recommendations

Rewrite the scaling factor calculation in calculateRcrvUSDAmount.

Updates

Lead Judging Commences

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

Incorrect scaling factor formula in StabilityPool::calculateRcrvUSDAmount function

Both tokens have 18 decimals. Info

Support

FAQs

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

Give us feedback!