Core Contracts

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

Incorrect Return Order in `RToken.mint()` Causes Misinterpretation in `ReserveLibrary.deposit()` and `LendingPool.deposit()`

Summary

The RToken.mint() function returns values in an incorrect order, causing ReserveLibrary.deposit() to misinterpret the minted amount. This results in incorrect token distribution and liquidity tracking.

Vulnerability Details

The mint() function in RToken has a return statement:

return (isFirstMint, amountToMint, totalSupply(), amountScaled);

However, the function comment specifies that the expected return order is:

/**
* @return A tuple containing:
* - bool: True if this is the first mint for the recipient, false otherwise
* - uint256: The amount of scaled tokens minted
* - uint256: The new total supply after minting
* - uint256: The amount of underlying tokens minted
*/

In ReserveLibrary.deposit(), the return values of mint() are destructured as follows:

(bool isFirstMint, uint256 amountScaled, uint256 newTotalSupply, uint256 amountUnderlying) = IRToken(reserve.reserveRTokenAddress).mint(
address(this),
depositor,
amount,
reserve.liquidityIndex
);

Since mint() returns amountToMint instead of amountScaled as the second value, amountScaled and amountToMint get swapped. This leads to ReserveLibrary.deposit() incorrectly assigning:

amountMinted = amountScaled;

Since amountScaled is actually amountToMint, the function operates on unscaled values, leading to incorrect supply calculations.

Impact

  • The protocol’s offchain accounting may be incorrect, leading to liquidity and interest rate miscalculations.

  • Provide wrong information to user about the minted tokens in LendingPool.deposit()

Tools Used

Manual Review

Recommendations

Modify the return statement in RToken.mint() to align with the function documentation:

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);
+ return (isFirstMint, amountScaled, totalSupply(), amountToMint);
}
Updates

Lead Judging Commences

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

RToken::mint doesn't return data in the right order, making the protocol emit wrong events

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

RToken::mint doesn't return data in the right order, making the protocol emit wrong events

Support

FAQs

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