Core Contracts

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

Incorrect Scaling of Token Amounts in `_update` Function Leading to Loss of Value for Users

Summary

The _update function in the RToken contract incorrectly scales token amounts during minting, burning, and transferring operations. This issue arises because the liquidityIndex is always increasing, causing users to receive fewer tokens than expected when minting and withdrawing. Additionally, the scaling logic is duplicated in the transfer and transferFrom functions, leading to double scaling and further loss of value for users.

Vulnerability Details

In the _update function, where token amounts are scaled by the liquidityIndex:

function _update(address from, address to, uint256 amount) internal override {
// Scale amount by normalized income for all operations (mint, burn, transfer)
uint256 scaledAmount = amount.rayDiv(ILendingPool(_reservePool).getNormalizedIncome());
super._update(from, to, scaledAmount);
}

The liquidityIndex is always increasing, which means that the scaling factor (rayDiv) reduces the amount of tokens users receive during minting and increases the amount of tokens they burn during withdrawals. This results in users receiving fewer tokens than they should when minting and withdrawing.

Additionally, the transfer and transferFrom functions already scale the amounts before calling _update, leading to double scaling:

function transfer(address recipient, uint256 amount) public override(ERC20, IERC20) returns (bool) {
uint256 scaledAmount = amount.rayDiv(ILendingPool(_reservePool).getNormalizedIncome());
return super.transfer(recipient, scaledAmount);
}
function transferFrom(address sender, address recipient, uint256 amount) public override(ERC20, IERC20) returns (bool) {
uint256 scaledAmount = amount.rayDiv(_liquidityIndex);
return super.transferFrom(sender, recipient, scaledAmount);
}

This double scaling further exacerbates the loss of value for users, as the amounts are scaled twice, leading to even fewer tokens being transferred.

Consider the following scenario:

  1. The liquidityIndex is 1.1e27 (10% interest accrued).

  2. A user deposits 110e18 units of the underlying asset.

  3. The mint function calculates the scaled amount as:

    uint256 scaledAmount = 110e18.rayDiv(1.1e27); // 100e18

    The user receives 100e18 RTokens instead of 110e18.

  4. When the user withdraws, the burn function calculates the scaled amount as:

    uint256 scaledAmount = 100e18.rayMul(1.1e27); // 110e18

    The user receives 110e18 units of the underlying asset, but due to the double scaling in transfer and transferFrom, the actual amount received is less.

  5. If the user transfers tokens, the amount is scaled twice:

    uint256 scaledAmount = amount.rayDiv(ILendingPool(_reservePool).getNormalizedIncome()); // First scaling
    super.transfer(recipient, scaledAmount); // Calls _update, which scales again

    This results in the user transferring fewer tokens than intended.

Impact

  1. Loss of Value for Users: Users receive fewer tokens than expected when minting and withdrawing, leading to a loss of value.

  2. Double Scaling: The transfer and transferFrom functions scale amounts twice, further reducing the number of tokens transferred.

Tools Used

Manual review

Recommendations

The _update function should not scale the amounts, as the scaling is already handled in the mint, burn, transfer, and transferFrom functions. The corrected _update function should look like this:

function _update(address from, address to, uint256 amount) internal override {
// Do not scale the amount here, as it is already scaled in the calling functions
super._update(from, to, amount);
}
Updates

Lead Judging Commences

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

RToken::transfer and transferFrom double-scale amounts by dividing in both external functions and _update, causing users to transfer significantly less than intended

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

RToken::transfer and transferFrom double-scale amounts by dividing in both external functions and _update, causing users to transfer significantly less than intended

Support

FAQs

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

Give us feedback!