Summary
The amount scaled calculated in the rtoken.sol contract is wrong during burning.
Vulnerability Details
Amount scaled should be obtained with rayDiv and not rayMul
function burn(
address from,
address receiverOfUnderlying,
uint256 amount,
uint256 index
) external override onlyReservePool returns (uint256, uint256, uint256) {
if (amount == 0) {
return (0, totalSupply(), 0);
}
uint256 userBalance = balanceOf(from);
_userState[from].index = index.toUint128();
if(amount > userBalance){
amount = userBalance;
}
uint256 amountScaled = amount.rayMul(index);
Raymul is used to convert scaled balance to actual balance
* @notice Returns the scaled balance of the user
* @param account The address of the user
* @return The user's balance (scaled by the liquidity index)
*/
function balanceOf(address account) public view override(ERC20, IERC20) returns (uint256) {
uint256 scaledBalance = super.balanceOf(account);
@audit>> return scaledBalance.rayMul(ILendingPool(_reservePool).getNormalizedIncome());
}
hence when converting actual to sacled balance ray div should be used
See aave implementation and debt token .sol also
Aave =>
function _burnScaled(address user, address target, uint256 amount, uint256 index) internal {
@audit>> uint256 amountScaled = amount.rayDiv(index);
require(amountScaled != 0, Errors.INVALID_BURN_AMOUNT);
uint256 scaledBalance = super.balanceOf(user);
uint256 balanceIncrease = scaledBalance.rayMul(index) -
scaledBalance.rayMul(_userState[user].additionalData);
_userState[user].additionalData = index.toUint128();
_burn(user, amountScaled.toUint128());
Debt token .sol
function burn(
address from,
uint256 amount,
uint256 index
) external override onlyReservePool returns (uint256, uint256, uint256, uint256) {
if (from == address(0)) revert InvalidAddress();
if (amount == 0) {
return (0, totalSupply(), 0, 0);
}
uint256 userBalance = balanceOf(from);
uint256 balanceIncrease = 0;
if (_userState[from].index != 0 && _userState[from].index < index) {
uint256 borrowIndex = ILendingPool(_reservePool).getNormalizedDebt();
balanceIncrease = userBalance.rayMul(borrowIndex) - userBalance.rayMul(_userState[from].index);
amount = amount;
}
_userState[from].index = index.toUint128();
if(amount > userBalance){
amount = userBalance;
}
@audit>> uint256 amountScaled = amount.rayDiv(index);
if (amountScaled == 0) revert InvalidAmount();
_burn(from, amount.toUint128());
emit Burn(from, amountScaled, index);
return (amount, totalSupply(), amountScaled, balanceIncrease);
}
Impact
Wrong amount scaled calculation.
Tools Used
Manual Review
Recommendations
Calculate amountScaled properly
++ uint256 amountScaled = amount.rayDiv(index);