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);
}