Summary
In RToken#mint(), the calculation of scaledBalance is incorrect, leading to an incorrect computation of balanceIncrease. As a result, the Mint() event emits incorrect values.
Vulnerability Details
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);
}
Incorrect scaledBalance Calculation
balanceOf(onBehalfOf) already scales the balance by liquidityIndex.
However, scaledBalance is expected to store the raw amount without scaling.
Since balanceOf() already includes index, balanceIncrease is miscomputed.
Incorrect Mint() Event Emission: emit Mint(caller, onBehalfOf, amountToMint, index);
Impact
Events display wrong data: Misleading accounting for integrations.
Tools Used
manual
Recommendations
Modify scaledBalance to store the actual balance before scaling and add accrued interest to amountToMint in Mint() event.
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);
+ uint256 scaledBalance = scaledBalanceOf(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);
+ emit Mint(caller, onBehalfOf, amountToMint + balanceIncrease, index);
return (isFirstMint, amountToMint, totalSupply(), amountScaled);
}