Summary
The incorrect debt calculation in _repay() function will cause wrong logging of repayment amounts, impacting frontend applications that rely on these events.
Root Cause
In LendingPool.sol the actualRepayAmount is incorrectly calculated using scaled debt values which leads to incorrect event emissions.
function _repay(uint256 amount, address onBehalfOf) internal {
if (amount == 0) revert InvalidAmount();
if (onBehalfOf == address(0)) revert AddressCannotBeZero();
UserData storage user = userData[onBehalfOf];
ReserveLibrary.updateReserveState(reserve, rateData);
408 uint256 userDebt = IDebtToken(reserve.reserveDebtTokenAddress).balanceOf(onBehalfOf);
409 uint256 userScaledDebt = userDebt.rayDiv(reserve.usageIndex);
412 uint256 actualRepayAmount = amount > userScaledDebt ? userScaledDebt : amount;
uint256 scaledAmount = actualRepayAmount.rayDiv(reserve.usageIndex);
418 (uint256 amountScaled, uint256 newTotalSupply, uint256 amountBurned, uint256 balanceIncrease) =
419 IDebtToken(reserve.reserveDebtTokenAddress).burn(onBehalfOf, amount, reserve.usageIndex);
422 IERC20(reserve.reserveAssetAddress).safeTransferFrom(msg.sender, reserve.reserveRTokenAddress, amountScaled);
reserve.totalUsage = newTotalSupply;
user.scaledDebtBalance -= amountBurned;
ReserveLibrary.updateInterestRatesAndLiquidity(reserve, rateData, amountScaled, 0);
emit Repay(msg.sender, onBehalfOf, actualRepayAmount);
}
Impact
The frontend applications will receive incorrect repayment amounts in events, leading to display of wrong information to users. This may cause confusion and trust issues with the protocol.
Mitigation
The actualRepayAmount should be calculated using the unscaled debt value:
function _repay(uint256 amount, address onBehalfOf) internal {
if (amount == 0) revert InvalidAmount();
if (onBehalfOf == address(0)) revert AddressCannotBeZero();
UserData storage user = userData[onBehalfOf];
ReserveLibrary.updateReserveState(reserve, rateData);
uint256 userDebt = IDebtToken(reserve.reserveDebtTokenAddress).balanceOf(onBehalfOf);
- uint256 userScaledDebt = userDebt.rayDiv(reserve.usageIndex);
- uint256 actualRepayAmount = amount > userScaledDebt ? userScaledDebt : amount;
+ uint256 actualRepayAmount = amount > userDebt ? userDebt : amount;
- uint256 scaledAmount = actualRepayAmount.rayDiv(reserve.usageIndex);
(uint256 amountScaled, uint256 newTotalSupply, uint256 amountBurned, uint256 balanceIncrease) =
- IDebtToken(reserve.reserveDebtTokenAddress).burn(onBehalfOf, amount, reserve.usageIndex);
+ IDebtToken(reserve.reserveDebtTokenAddress).burn(onBehalfOf, actualRepayAmount, reserve.usageIndex);
IERC20(reserve.reserveAssetAddress).safeTransferFrom(msg.sender, reserve.reserveRTokenAddress, amountScaled);
reserve.totalUsage = newTotalSupply;
user.scaledDebtBalance -= amountBurned;
ReserveLibrary.updateInterestRatesAndLiquidity(reserve, rateData, amountScaled, 0);
emit Repay(msg.sender, onBehalfOf, actualRepayAmount);
}