Summary
Incorrect debt calculation in StabilityPool.sol#liquidateBorrower() will cause excessive liquidation costs for the protocol as the user debt is being scaled up twice unnecessarily.
Root Cause
In StabilityPool.sol the userDebt is being incorrectly scaled up with lendingPool.getNormalizedDebt() even though it's already scaled in LendingPool.sol#getUserDebt().
function liquidateBorrower(address userAddress) external onlyManagerOrOwner nonReentrant whenNotPaused {
-> uint256 userDebt = lendingPool.getUserDebt(userAddress);
-> uint256 scaledUserDebt = WadRayMath.rayMul(userDebt, lendingPool.getNormalizedDebt());
if (userDebt == 0) revert InvalidAmount();
.........................
emit BorrowerLiquidated(userAddress, scaledUserDebt);
}
The debt is already scaled in LendingPool:
File: LendingPool.sol
function getUserDebt(address userAddress) public view returns (uint256) {
UserData storage user = userData[userAddress];
-> return user.scaledDebtBalance.rayMul(reserve.usageIndex);
}
Impact
The protocol will suffer from larger liquidation costs than necessary due to the double scaling of debt amounts. This means more funds will be used than required during liquidations.
Mitigation
Remove the additional scaling in StabilityPool.sol#liquidateBorrower():
function liquidateBorrower(address userAddress) external onlyManagerOrOwner nonReentrant whenNotPaused {
uint256 userDebt = lendingPool.getUserDebt(userAddress);
- uint256 scaledUserDebt = WadRayMath.rayMul(userDebt, lendingPool.getNormalizedDebt());
if (userDebt == 0) revert InvalidAmount();
uint256 crvUSDBalance = crvUSDToken.balanceOf(address(this));
- if (crvUSDBalance < scaledUserDebt) revert InsufficientBalance();
+ if (crvUSDBalance < userDebt) revert InsufficientBalance();
- bool approveSuccess = crvUSDToken.approve(address(lendingPool), scaledUserDebt);
+ bool approveSuccess = crvUSDToken.approve(address(lendingPool), userDebt);
if (!approveSuccess) revert ApprovalFailed();
lendingPool.finalizeLiquidation(userAddress);
- emit BorrowerLiquidated(userAddress, scaledUserDebt);
+ emit BorrowerLiquidated(userAddress, userDebt);
}