Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: high
Valid

Protocol will suffer from bigger liquidation expense due to incorrect debt scaling

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 {
// Get the user's debt from the LendingPool.
-> 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 {
// Get the user's debt from the LendingPool.
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();
// Approve the LendingPool to transfer the debt amount
- bool approveSuccess = crvUSDToken.approve(address(lendingPool), scaledUserDebt);
+ bool approveSuccess = crvUSDToken.approve(address(lendingPool), userDebt);
if (!approveSuccess) revert ApprovalFailed();
// Call finalizeLiquidation on LendingPool
lendingPool.finalizeLiquidation(userAddress);
- emit BorrowerLiquidated(userAddress, scaledUserDebt);
+ emit BorrowerLiquidated(userAddress, userDebt);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

StabilityPool::liquidateBorrower double-scales debt by multiplying already-scaled userDebt with usage index again, causing liquidations to fail

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!