The issue stems from an incorrect calculation of scaledUserDebt
in StabilityPool.liquidateBorrower()
, which may lead to unnecessary reverts at a late stage in Lending.finalizeLiquidation()
.
(Note: There's also a double scaling issue on userDebt
in the code logic that I have reported separately.)
Incorrect Calculation of scaledUserDebt
in StabilityPool.liquidateBorrower()
As noted in the code logic below, getNormalizedDebt()
is being referenced without updating the reserve state first, highly likely leading to an outdated or lower scaledUserDebt
value.
If scaledUserDebt
is underestimated, it falsely passes the following check:
The thing is crvUSDToken.balanceOf(address(this))
is technically the exact amount sent into the contract by the manager or the owner after querying the user's debt by incorporating the outdated reserve's normalized debt too via lendingPool.getNormalizedDebt()
:
This means the Stability Pool may unnecessarily proceed with finalizing a liquidation attempt that's bound to fail unless lendingPool.updateState()
has atomically been called/utilized first both by the function logic as well as the caller.
Late Revert in lendingPool.finalizeLiquidation()
Later, in lendingPool.finalizeLiquidation()
, the correctly scaled up debt amount is recalculated after having the state updated:
This userDebt
(equal to amountScaled
) is used in:
If scaledUserDebt
was underestimated earlier, the actual required amountScaled
might be greater than crvUSDToken.balanceOf()
associated with StabilityPool.sol.
The transfer from the Stability Pool may revert and fail late in the execution flow, causing an unnecessary revert after multiple state updates have already occurred.
Additionally, if some liquidations fail due to outdated state, it may leave the system with unclaimed bad debt. This is especially true and exacerbated by the very fact that user.scaledDebtBalance
is increasingly growing with exponential interests entailed. The longer the wait and delay, the more crvUSDToken
will be needed.
Manual
Consider implementing the following refactoring. Simply update lending pool state BEFORE fetching user debt. No need to update state again before liquidation since finalizeLiquidation
will do so:
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.