Core Contracts

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

Incorrect Interest Accrual in RToken Mint Function Leading to Overestimated Balance Increase

Summary

In the calculation of RToken::mint function accrued interest for existing users. By using the scaled balance (already adjusted by the current liquidity index) instead of the raw stored balance, the function overestimates the balance increase. This results in users receiving excess tokens during minting, leading to incorrect token supply inflation and potential protocol insolvency.

Vulnerability Details

The RToken contract tracks user balances scaled by a liquidity index to account for accrued interest. When minting new tokens, the contract calculates any existing balance increase due to interest accrual since the user's last interaction.

function mint(
address caller,
address onBehalfOf,
uint256 amountToMint,
uint256 index
) external override onlyReservePool returns (bool, uint256, uint256, uint256) {
if (amountToMint == 0) {
return (false, 0, 0, 0);
}
uint256 amountScaled = amountToMint.rayDiv(index);
if (amountScaled == 0) revert InvalidAmount();
@>> uint256 scaledBalance = balanceOf(onBehalfOf);
bool isFirstMint = scaledBalance == 0;
uint256 balanceIncrease = 0;
if (_userState[onBehalfOf].index != 0 && _userState[onBehalfOf].index < index) {
balanceIncrease = scaledBalance.rayMul(index) - scaledBalance.rayMul(_userState[onBehalfOf].index);
}
_userState[onBehalfOf].index = index.toUint128();
_mint(onBehalfOf, amountToMint.toUint128());
emit Mint(caller, onBehalfOf, amountToMint, index);
return (isFirstMint, amountToMint, totalSupply(), amountScaled);
}
function balanceOf(address account) public view override(ERC20, IERC20) returns (uint256) {
uint256 scaledBalance = super.balanceOf(account);
@>> return scaledBalance.rayMul(ILendingPool(_reservePool).getNormalizedIncome());
}

The vulnerability arises in the mint function where the balance increase is computed using the scaled balance (post-index adjustment) instead of the raw stored balance. Specifically, the code uses balanceOf(onBehalfOf) which returns the user's balance adjusted by the current index. This value is then multiplied again by the current and previous indices, leading to a double application of the index and an overestimated balance increase.

Impact

This issue allows users to mint new tokens while receiving an incorrectly calculated balance increase, resulting in:

  • Users gain more tokens than entitled, diluting the value for all holders.

  • The underlying assets may not cover the inflated token supply, leading to potential inability to honor withdrawals.

Proof of Concept (POC)

  1. Initial State:

    • RToken liquidity index (index) = 1.0e27 (RAY)

    • User's stored scaled balance (S) = 100e18 (raw units)

    • balanceOf(user) = 100e18 * 1.0e27 / 1e27 = 100e18 (actual balance)

  2. Index Increase:

    • New index = 1.1e27 (10% increase)

    • User's _userState.index remains at 1.0e27 (not updated yet)

  3. User Mints Additional Tokens:

    • balanceOf(user) now returns 100e18 * 1.1e27 / 1e27 = 110e18 (current balance)

    • The code calculates balanceIncrease as:

      balanceIncrease = 110e18.rayMul(1.1e27) - 110e18.rayMul(1.0e27)
      = (110e18 * 1.1e27 / 1e27) - (110e18 * 1.0e27 / 1e27)
      = 121e18 - 110e18 = 11e18
    • Expected Balance Increase:

      100e18 * (1.1e27 - 1.0e27) / 1e27 = 10e18
    • Actual Balance Increase: 11e18 (10% over expected)

Result:

The user receives an extra 1e18 tokens due to the double application of the index, leading to incorrect token minting and supply inflation.

Tools Used

Manual review

Recommendation

Use the raw stored scaled balance scaledBalanceOf instead of the adjusted balanceOf value when calculating the balance increase.

Corrected Code:

uint256 storedScaledBalance = scaledBalanceOf(onBehalfOf);
// ...
balanceIncrease = storedScaledBalance.rayMul(index) - storedScaledBalance.rayMul(_userState[onBehalfOf].index);

This adjustment ensures the calculation uses the base scaled amount without double-counting the current index, accurately reflecting the interest accrued.

Updates

Lead Judging Commences

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

RToken::mint should mint the amountScaled not the amountToMint

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

RToken::mint should mint the amountScaled not the amountToMint

Support

FAQs

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

Give us feedback!