NFTLiquidator forcibly transfers an NFT from the Stability Pool (or user) to its contract, setting up an auction or buyback process:
The code sets tokenData[tokenId].debt = debt, but it never calls or references LendingPool.finalizeLiquidation(...) or otherwise informs the LendingPool that the user’s debt should be wiped out or updated.
LendingPool has its own liquidation flow:
Typically, if an NFT is seized in a liquidation, the LendingPool expects to be told or to handle finalizeLiquidation to remove or reduce the borrower’s debt. But NFTLiquidator never calls that function or triggers any direct synergy.
Hence, after the NFT is forcibly taken from the user or stability pool, the user’s debt in LendingPool remains—the LendingPool is not aware the NFT is gone unless an external actor (like the stability pool, or some manual process) calls finalizeLiquidation(...) separately. This effectively breaks the idea that a single liquidation flow will free the user from their obligations or the system from that user’s risk.
Consequences
Debt Remains Even After Collateral is Seized
The user is left with an active (and possibly accruing) debt in the LendingPool while their NFT is already sold or auctioned by the NFTLiquidator. This mismatch can lead to double accounting (the user no longer has the collateral but is still recorded as a debtor).
Risk of System Inconsistency
The entire protocol’s solvency or user flows rely on the premise that “liquidation of an NFT = clearing or partial repayment of that user’s debt.” Because the NFTLiquidator never updates the LendingPool, the system can remain out of sync, thinking the user still owes money. Meanwhile, the NFT is out of the user’s control.
Manual or Ad Hoc Fix
In practice, an admin or the stability pool might attempt a manual call to LendingPool’s finalizeLiquidation(userAddress) sometime later, but that is not codified. The contract code does not guarantee it, leading to potential confusion or reliant on off-chain procedures.
Proof / Demonstration Scenario
Imagine a user has an NFT locked as collateral in the LendingPool. The user’s loan is undercollateralized, so the stability pool or some external logic calls:
NFT Moved: The NFT is forcibly transferred from stability pool → NFTLiquidator.
No LendingPool Update: The NFTLiquidator sets tokenData[tokenId].debt = userDebt but does not call lendingPool.finalizeLiquidation(userAddress).
User Debt Ongoing: The LendingPool’s state still sees the user as owing userDebt tokens.
User in an Impossible Situation: The user can’t reclaim the NFT from the LendingPool, and they also cannot repay in a normal flow because the system is out of sync with NFTLiquidator’s auction results or buyback logic.
Recommendation
After forcibly seizing the NFT, the NFTLiquidator (or the stability pool acting on its behalf) should call:
or a function that explicitly notifies the LendingPool that the user’s NFT collateral is gone and the debt must be wiped or partially repaid by the stability pool’s funds. This ensures a single integrated liquidation flow.
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.