Core Contracts

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

Wrong dust amount calculation leads to fund freezing

Summary

An incorrect calculation in RToken.sol will cause frozen funds in RToken as the dust amount calculation incorrectly handles liquidity index scaling.

Root Cause

In RToken.sol, the calculateDustAmount() function contains two critical scaling errors:

  1. On L322, totalSupply() returns a value already scaled by liquidityIndex, but L325 multiplies by liquidityIndex again

  2. On L319, contractBalance is incorrectly scaled down by liquidityIndex before comparison

function calculateDustAmount() public view returns (uint256) {
// Calculate the actual balance of the underlying asset held by this contract
319 uint256 contractBalance = IERC20(_assetAddress).balanceOf(address(this)).rayDiv(ILendingPool(_reservePool).getNormalizedIncome());
// Calculate the total real obligations to the token holders
322 uint256 currentTotalSupply = totalSupply();
// Calculate the total real balance equivalent to the total supply
325 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;
}

Impact

The protocol will calculate incorrect dust amounts, leading to funds being frozen in the RToken contract. This affects all users who interact with the RToken system.

Mitigation

The scaling issues should be fixed by removing the unnecessary liquidity index operations:

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