Core Contracts

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

`RToken::calculateDustAmount` Incorrectly Scales `RToken` Values Drasticly Lowering Dust Amount

Summary

RToken::calculateDustAmount double scales rToken values by applying liquidityIndex twice, leading to incorrect dust calculations.

Vulnerability Details

[](https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/tokens/RToken.sol#L203-L205)

Inside of RToken::calculateDustAmount grab the current total supply of RTokens via RTokens::totalSupply which inside scales the return value:

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

Then calculateDustAmount scales it again with rayMul(getNormalizedIncome()), effectively squaring the index.

[](https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/tokens/RToken.sol#L321C1-L325C112)

uint256 totalRealBalance = currentTotalSupply.rayMul(ILendingPool(_reservePool).getNormalizedIncome());

Impact

  • Incorrect accounting/tracking of actual dust amounts

  • Potential issues for integrators relying on dust calculations

  • Higher gas costs from multiple dust transfers

Tools Used

Foundry

Recommendations

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;
+ return contractBalance <= currentTotalSupply ? 0 : contractBalance - currentTotalSupply;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 month 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.