Summary
In the flow LendingPool::withdraw
the function calls RToken::burn
. This function contains two issues in handling withdraw of the reserve assets:
The users will withdraw the wrong reserve asset amount without the correct accrued interest.
Vulnerability Details
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);
@> @audit: missing interest accouting
_userState[from].index = index.toUint128();
if(amount > userBalance){
amount = userBalance;
}
uint256 amountScaled = amount.rayMul(index);
_userState[from].index = index.toUint128();
@> _burn(from, amount.toUint128());
if (receiverOfUnderlying != address(this)) {
IERC20(_assetAddress).safeTransfer(receiverOfUnderlying, amount);
}
emit Burn(from, receiverOfUnderlying, amount, index);
return (amount, totalSupply(), amount);
}
Impact
The burn
function omits to calculate the accrued interest and to add them toamount
, causing accrued interest to be ignored. Additionally, it uses amount
instead ofamountScaled
causing incorrect token burning.
Users will withdraw the wrong reserve assets amount without the accrued interest.
Tools Used
Manual review.
Recommendations
Add interest accrual calculation and useScaled
amount for burning.
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);
+ uint256 balanceIncrease = 0;
+ if (_userState[from].index != 0 && _userState[from].index < index) {
+ uint256 depositIndex = ILendingPool(_reservePool).getNormalizedIncome();
+ balanceIncrease = userBalance.rayMul(depositIndex) - userBalance.rayMul(_userState[from].index);
+ amount = amount + balanceIncrease;
+ }
_userState[from].index = index.toUint128();
if(amount > userBalance){
amount = userBalance;
}
uint256 amountScaled = amount.rayMul(index);
- _userState[from].index = index.toUint128();
- _burn(from, amount.toUint128());
+ _burn(from, amountScaled.toUint128());
if (receiverOfUnderlying != address(this)) {
IERC20(_assetAddress).safeTransfer(receiverOfUnderlying, amount);
}
emit Burn(from, receiverOfUnderlying, amount, index);
- return (amount, totalSupply(), amount);
+ return (amountScaled, totalSupply(), amount);
}