Core Contracts

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

Incorrect calculateDustAmount in RToken.sol

Summary

the calculateDustAmount is supposed to calculate the amount of _assetAddresstokens that is simply lying in the contract (not intended for any user). But this calculation is wrong.

Vulnerability Details

Going through the burn function in the RToken.sol ,it can be seen that the balanceof(user) is the amount of _assetAddressthat the user deserves. => amount can be a maximum of balanceOf(from), and this amount is transferred to the receiverofUnderlying. Thus the above point should be clear.

function burn(
address from,
address receiverOfUnderlying,
uint256 amount,
uint256 index
) external override onlyReservePool returns (uint256, uint256, uint256) {
if (amount == 0) {
return (0, totalSupply(), 0);
}
uint256 userBalance = balanceOf(from);
_userState[from].index = index.toUint128();
if(amount > userBalance){
amount = userBalance;
}
uint256 amountScaled = amount.rayMul(index);
_userState[from].index = index.toUint128();
_burn(from, amount.toUint128());
if (receiverOfUnderlying != address(this)) {
IERC20(_assetAddress).safeTransfer(receiverOfUnderlying, amount);
}


But the calculateDustAmount(), makes many mistakes:

  1. contractBalance: should have been just IERC20(_assetAddress).balanceOf(address(this)),

  2. totalRealBalance: should have been just the totalSupply (which is just the addition of balanceOf(users) of all the users)

  3. Thus the entire calculation makes no sense and actually reduces the amount of dust calculated than the actual. This makes the contract alway have some extra balance.

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;
}


Impact

Incorrect dust removal functionality

Tools Used

manual review

Recommendations

update the dust calculations as follows:

dust = IERC20(_assetAddress).balanceOf(address(this)) - totalSupply()

Updates

Lead Judging Commences

inallhonesty Lead Judge 4 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.