Core Contracts

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

Wrong Scaled amount calculation in Rtoken.sol contract

Summary

The amount scaled calculated in the rtoken.sol contract is wrong during burning.

Vulnerability Details

Amount scaled should be obtained with rayDiv and not rayMul

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); // BUG burn should first get the balance increase and not just allow user to loses interest
_userState[from].index = index.toUint128();
if(amount > userBalance){
amount = userBalance;
}
uint256 amountScaled = amount.rayMul(index); // Low Wrong not used in another place Divray not raymul

Raymul is used to convert scaled balance to actual balance

/**
* @notice Returns the scaled balance of the user
* @param account The address of the user
* @return The user's balance (scaled by the liquidity index)
*/
function balanceOf(address account) public view override(ERC20, IERC20) returns (uint256) {
uint256 scaledBalance = super.balanceOf(account);
@audit>> return scaledBalance.rayMul(ILendingPool(_reservePool).getNormalizedIncome());
}

hence when converting actual to sacled balance ray div should be used

See aave implementation and debt token .sol also

Aave =>

function _burnScaled(address user, address target, uint256 amount, uint256 index) internal {
@audit>> uint256 amountScaled = amount.rayDiv(index);
require(amountScaled != 0, Errors.INVALID_BURN_AMOUNT);
uint256 scaledBalance = super.balanceOf(user);
uint256 balanceIncrease = scaledBalance.rayMul(index) -
scaledBalance.rayMul(_userState[user].additionalData);
_userState[user].additionalData = index.toUint128();
_burn(user, amountScaled.toUint128());

Debt token .sol

function burn(
address from,
uint256 amount,
uint256 index
) external override onlyReservePool returns (uint256, uint256, uint256, uint256) {
if (from == address(0)) revert InvalidAddress();
if (amount == 0) {
return (0, totalSupply(), 0, 0);
}
uint256 userBalance = balanceOf(from);
uint256 balanceIncrease = 0;
if (_userState[from].index != 0 && _userState[from].index < index) {
uint256 borrowIndex = ILendingPool(_reservePool).getNormalizedDebt();
balanceIncrease = userBalance.rayMul(borrowIndex) - userBalance.rayMul(_userState[from].index); // bug we no use this one oo God
amount = amount;
}
_userState[from].index = index.toUint128();
if(amount > userBalance){
amount = userBalance;
}
@audit>> uint256 amountScaled = amount.rayDiv(index);
if (amountScaled == 0) revert InvalidAmount();
_burn(from, amount.toUint128()); //bug Will revert we never mint new balance to user medium
emit Burn(from, amountScaled, index);
return (amount, totalSupply(), amountScaled, balanceIncrease);
}

Impact

Wrong amount scaled calculation.

Tools Used

Manual Review

Recommendations

Calculate amountScaled properly

++ uint256 amountScaled = amount.rayDiv(index);
Updates

Lead Judging Commences

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

RToken::burn incorrectly calculates amountScaled using rayMul instead of rayDiv, causing incorrect token burn amounts and breaking the interest accrual mechanism

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

RToken::burn incorrectly calculates amountScaled using rayMul instead of rayDiv, causing incorrect token burn amounts and breaking the interest accrual mechanism

Support

FAQs

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