The liquidateBorrower() function in the StabilityPool contract incorrectly scales the user's debt when attempting to liquidate a borrower. The function retrieves the user's debt using getUserDebt(), which already normalizes the debt based on the current usageIndex. However, the liquidateBorrower() function then applies an additional scaling operation, resulting in a double scaling of the debt amount.
This unnecessary operation leads to inaccuracies in the approval amount for token transfers.
Here is how liquidateBorrower() works:
This function retrieves userDebt by lendingPool.getUserDebt():
Notice that this function already normalizes the scaledDebtBalance by rayMul(reserve.usageIndex) meaning that the value returned here is already in underlying asset units.
However, the liquidateBorrower() proceeds to rescale this into scaledUserDebt: WadRayMath.rayMul(userDebt, lendingPool.getNormalizedDebt()) which does the same thing already done by getUserDebt() to an already normalized value.
Then, it proceeds to set approval using this final value.
However, lets see what value is actually pulled in finalizeLiquidation():
Now lets see how DebtToken.burn() handles all this and the values it returns:
Notice that in finalizeLiquidation(), the first return value (amountScaled) is what the contract pulls from stability pool. And as we have seen, this is actually the same userDebt that was passed to burn().
Therefore, there is really a big mismatch between what was approved and what is being pulled.
The incorrect scaling of userDebt can result in the approval amount being set inaccurately, which may not reflect the actual amount needed to repay the user's debt. Due to this double scaling, the scaledUserDebt may be very large and if crvUSDBalance < scaledUserDebt, the function will revert with InsufficientBalance() error when in reality there may be enough tokens in the contract to cover the repay.
Manual Review
Remove the double scaling done in liquidateBorrower() and use the normalized value directly.
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.