Summary
The RToken.burn() function burns an amount using amount instead of a scaled amount. Here, amount represents the quantity of reserve tokens being withdrawn, and burning RToken at this value implies an exchange rate of 1:1. This is incorrect.
Vulnerability Details
The RToken.burn() function burns an amount using amount.
Since amount represents the amount of reserve tokens being withdrawn, burning RToken at this value means that the exchange rate is 1:1, which is incorrect.
Instead, the burn amount should be a scaled value according to the exchange rate index.
As a result, the withdrawer burns more RTokens than they should.
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);
_userState[from].index = index.toUint128();
176 _burn(from, amount.toUint128());
if (receiverOfUnderlying != address(this)) {
IERC20(_assetAddress).safeTransfer(receiverOfUnderlying, amount);
}
emit Burn(from, receiverOfUnderlying, amount, index);
return (amount, totalSupply(), amount);
}
Impact
Withdrawers burn more RTokens than they should.
Tools Used
Manual review
Recommendations
The burn amount should be scaled.
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);
_userState[from].index = index.toUint128();
- _burn(from, amount.toUint128());
+ _burn(from, amount.rayDiv(index).toUint128());
if (receiverOfUnderlying != address(this)) {
IERC20(_assetAddress).safeTransfer(receiverOfUnderlying, amount);
}
emit Burn(from, receiverOfUnderlying, amount, index);
- return (amount, totalSupply(), amount);
+ return (amount.rayDiv(index), totalSupply(), amount);
}