Core Contracts

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

Incorrect scaling in dust calculation leads to inaccurate dust amount

Summary

The RToken::calculateDustAmount() function incorrectly uses RToken::totalSupply() (which is not-scaled) instead of the scaled total supply when calculating dust amounts. This leads to a significant overestimation of dust tokens, potentially allowing unauthorized withdrawal of user funds.

Vulnerability Details

The RToken contract maintains two different representations of token amounts:

  1. Scaled amounts - used internally for storage and calculations

  2. Normalized amounts - used externally and scaled by the current interest rate

The RToken::calculateDustAmount() function attempts to compare the contract's actual balance with its obligations to token holders:

function calculateDustAmount() public view returns (uint256) {
// Calculate the actual balance of the underlying asset held by this contract
uint256 contractBalance =
IERC20(_assetAddress).balanceOf(address(this)).rayDiv(ILendingPool(_reservePool).getNormalizedIncome());
// Calculate the total real obligations to the token holders
uint256 currentTotalSupply = totalSupply();
// Calculate the total real balance equivalent to the total supply
@> uint256 totalRealBalance = currentTotalSupply.rayMul(ILendingPool(_reservePool).getNormalizedIncome());
return contractBalance <= totalRealBalance ? 0 : contractBalance - totalRealBalance;
}

The issue is that RToken::totalSupply() already returns a normalized value (scaled by the current interest rate):

function totalSupply() public view override(ERC20, IERC20) returns (uint256) {
return super.totalSupply().rayMul(ILendingPool(_reservePool).getNormalizedIncome());
}

When RToken::calculateDustAmount() multiplies this by getNormalizedIncome() again, it effectively applies the interest rate scaling twice, causing totalRealBalance to be much larger than it should be.

Impact

The double scaling of total supply in dust calculations has severe implications:

  1. The totalRealBalance is artificially inflated by applying the interest rate twice

  2. This causes the dust amount calculation (contractBalance - totalRealBalance) to be much smaller than it should be

  3. In extreme cases, it could even prevent legitimate dust from being detected at all

  4. Since dust can be withdrawn by authorized roles, this could prevent the protocol from recovering actual dust amounts

  5. More critically, if contractBalance is large enough, the function could return a non-zero value even when there is no actual dust, allowing unauthorized withdrawal of user funds

The likelihood is HIGH because the issue will occur every time dust calculations are performed, as it's a fundamental error in the scaling logic.
The impact is HIGH because tt directly affects the protocol's ability to manage user funds correctly and increases as the interest rate grows over time, making the double scaling effect more severe.

Tools Used

Manual review

Recommendations

Update the RToken::calculateDustAmount() function to use the unscaled total supply:

function calculateDustAmount() public view returns (uint256) {
uint256 contractBalance =
IERC20(_assetAddress).balanceOf(address(this)).rayDiv(ILendingPool(_reservePool).getNormalizedIncome());
- // Calculate the total real obligations to the token holders
- uint256 currentTotalSupply = totalSupply();
+ // Use super.totalSupply() to get the unscaled amount
+ uint256 currentTotalSupply = super.totalSupply();
uint256 totalRealBalance = currentTotalSupply.rayMul(ILendingPool(_reservePool).getNormalizedIncome());
return contractBalance <= totalRealBalance ? 0 : contractBalance - totalRealBalance;
}

This ensures that the interest rate scaling is only applied once, leading to accurate dust calculations.

Updates

Lead Judging Commences

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

RToken::calculateDustAmount incorrectly applies liquidity index, severely under-reporting dust amounts and permanently trapping crvUSD in contract

Support

FAQs

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

Give us feedback!