Core Contracts

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

[H] Incorrect Scaling in `mint` Functions in `DebtToken` and `RToken`

Summary

The mint functions in the DebtToken and RToken contracts incorrectly scale the balance increase, leading to incorrect calculations. The balanceOf function already returns the scaled balance of the user, so scaling it again is incorrect.

Vulnerability Details

The current mint function in the DebtToken contract is:

function mint(
address user,
address onBehalfOf,
uint256 amount,
uint256 index
) external override onlyReservePool returns (bool, uint256, uint256) {
...
uint256 scaledBalance = balanceOf(onBehalfOf);
...
uint256 balanceIncrease = 0;
if (
_userState[onBehalfOf].index != 0 &&
_userState[onBehalfOf].index < index
) {
balanceIncrease =
scaledBalance.rayMul(index) -
scaledBalance.rayMul(_userState[onBehalfOf].index);
}
...
return (scaledBalance == 0, amountToMint, totalSupply());
}

The balanceIncrease is incorrectly scaled because balanceOf already returns the scaled balance.

The balanceOf function in 2 contracts is same i.e

function balanceOf(
address account
) public view override(ERC20, IERC20) returns (uint256) {
uint256 scaledBalance = super.balanceOf(account);
return
scaledBalance.rayMul(
ILendingPool(_reservePool).getNormalizedDebt()
);
}

The same issue is present in the RToken contract's mint functions:

function mint(
address caller,
address onBehalfOf,
uint256 amountToMint,
uint256 index
) external override onlyReservePool returns (bool, uint256, uint256, uint256) {
...
uint256 scaledBalance = balanceOf(onBehalfOf);
...
uint256 balanceIncrease = 0;
if (_userState[onBehalfOf].index != 0 && _userState[onBehalfOf].index < index) {
balanceIncrease = scaledBalance.rayMul(index) - scaledBalance.rayMul(_userState[onBehalfOf].index);
}
...
return (isFirstMint, amountToMint, totalSupply(), amountScaled);
}

The balanceIncrease is incorrectly scaled because balanceOf already returns the scaled balance.

Links to the issues:

  1. https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/tokens/RToken.sol#L126

  2. https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/tokens/DebtToken.sol#L150

  3. https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/tokens/DebtToken.sol#L224

  4. https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/tokens/RToken.sol#L195

Impact

This issue can lead to incorrect calculations of the balance increase, potentially causing issues with token accounting and user balances within the protocol.

Tools Used

Manual code review.

Recommendations

Use the scaledBalanceOf function to get the non-scaled balance and avoid incorrect scaling. The corrected functions should be:

Corrected mint Function in DebtToken

function mint(
address user,
address onBehalfOf,
uint256 amount,
uint256 index
) external override onlyReservePool returns (bool, uint256, uint256) {
...
uint256 scaledBalance = scaledBalanceOf(onBehalfOf);
...
uint256 balanceIncrease = 0;
if (
_userState[onBehalfOf].index != 0 &&
_userState[onBehalfOf].index < index
) {
balanceIncrease =
scaledBalance.rayMul(index) -
scaledBalance.rayMul(_userState[onBehalfOf].index);
}
...
return (scaledBalance == 0, amountToMint, totalSupply());
}

Corrected mint Function in RToken

function mint(
address caller,
address onBehalfOf,
uint256 amountToMint,
uint256 index
) external override onlyReservePool returns (bool, uint256, uint256, uint256) {
...
uint256 scaledBalance = scaledBalanceOf(onBehalfOf);
...
uint256 balanceIncrease = 0;
if (_userState[onBehalfOf].index != 0 && _userState[onBehalfOf].index < index) {
balanceIncrease = scaledBalance.rayMul(index) - scaledBalance.rayMul(_userState[onBehalfOf].index);
}
...
return (isFirstMint, amountToMint, totalSupply(), amountScaled);
}

This ensures that the correct balance is used in the calculations, leading to accurate token accounting and user balances.


Updates

Lead Judging Commences

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

DebtToken::mint miscalculates debt by applying interest twice, inflating borrow amounts and risking premature liquidations

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

DebtToken::mint miscalculates debt by applying interest twice, inflating borrow amounts and risking premature liquidations

Support

FAQs

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

Give us feedback!