Core Contracts

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

Incorrect Scaling of Contract Balance in `RToken::calculateDustAmount` Function

Summary

The calculateDustAmount function in the RToken contract incorrectly scales the contract's balance of the underlying asset by dividing it by the normalized income from the lending pool. This scaling is unnecessary and incorrect because the contract balance represents the actual amount of the underlying asset held by the contract, not a scaled value. This issue could lead to incorrect calculations of dust amounts, potentially affecting the protocol's accounting and the ability to rescue dust tokens.

Vulnerability Details

In the calculateDustAmount function, where the contract balance of the underlying asset is scaled by dividing it by the normalized income from the lending pool:

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());
// All balance, that is not tied to rToken are dust (can be donated or is the rest of exponential vs linear)
return contractBalance <= totalRealBalance ? 0 : contractBalance - totalRealBalance;
}

The contractBalance represents the actual amount of the underlying asset held by the contract, not a scaled value. The normalized income is used to scale token balances to account for interest accrual, but it should not be applied to the contract's actual balance of the underlying asset. This incorrect scaling can lead to an underestimation of the dust amount, which is the difference between the contract's actual balance and the total obligations to token holders.

  1. The lending pool has a normalized income of 1.1e27 (10% interest accrued).

  2. The contract holds 100e18 units of the underlying asset.

  3. The total supply of RTokens is 90e18, which corresponds to 99e18 units of the underlying asset when scaled by the normalized income (90e18 * 1.1e27 / 1e27 = 99e18).

In this case, the dust amount should be 1e18 (100e18 - 99e18). However, due to the incorrect scaling, the contractBalance is calculated as:

uint256 contractBalance = 100e18.rayDiv(1.1e27) ≈ 90.909e18

The dust amount is then calculated as:

uint256 dustAmount = 90.909e18 - 99e18 = 0

This results in an incorrect dust amount of 0, when it should be 1e18.

NOTE: There is an underflow revert happens, but this is only an example to explain the issue better.

Impact

The dust amount may be underestimated, leading to incorrect accounting of the contract's balance.

Tools Used

Manual review

Recommendations

The calculateDustAmount function should not scale the contract balance by the normalized income.

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());
+ uint256 contractBalance = IERC20(_assetAddress).balanceOf(address(this));
// 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());
// All balance, that is not tied to rToken are dust (can be donated or is the rest of exponential vs linear)
return contractBalance <= totalRealBalance ? 0 : contractBalance - totalRealBalance;
}
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!