In the StabilityPool contract, during the liquidation process, the user's debt is mistakenly scaled a second time. The LendingPool's getUserDebt function already returns the debt value after applying the necessary scaling (via ray multiplication with the reserve's usage index). However, in the liquidateBorrower function, this value is scaled again using the normalized debt, leading to an inflated debt value. This double scaling error results in incorrect debt calculations, potentially blocking legitimate liquidations.
The issue arises in the liquidateBorrower function within the StabilityPool contract:
Here, lendingPool.getUserDebt(userAddress) returns a value already scaled by the reserve's usage index:
Since the returned value is fully scaled, applying WadRayMath.rayMul with the normalized debt again results in double scaling. This inflated debt value (scaledUserDebt) is then used for subsequent checks and operations in the liquidation process, such as verifying if the StabilityPool has enough crvUSD tokens to cover the debt and approve the lendingPool for using the crvUSD.
getUserDebt() returns debt already scaled by reserve.usageIndex (RAY-multiplied)
Debt becomes (scaledDebt × usageIndex²) instead of correct (scaledDebt × usageIndex)
Initial State:
Actual user debt: 100 crvUSD
reserve.usageIndex: 1.1e27 (10% interest)
getUserDebt() returns 110 crvUSD (100 × 1.1)
Liquidation Call:
Legitimate liquidation attempts may revert because the approve value is wrong, causing the following call to revert in the LendingPool::finalizeLiquidation() function
Manual Review
Remove the unnecessary second scaling in the liquidateBorrower function. The debt fetched from getUserDebt() is already properly scaled – no need to multiply it again.
Before:
After:
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.