Check eligibility and permissions
The account must have health factor below1e18; use
is_liquidatable(account_id) or get_health_factor(account_id) to check.
Every collateral and debt asset needed for valuation must have a valid price.
An unavailable, stale, or disagreeing price reverts the transaction.
debt_payments gives a maximum token-native budget for each debt market.
The liquidator holds and authorizes those tokens. The planner can use less.
A final full-close plan pulls the entire merged offer and the pool refunds
excess; other plans pull only accepted amounts.
Global protocol pause permits liquidation. Collateral seizure ignores listing
paused and frozen flags. It checks no_seize only on generated seizure legs,
after dropping rounded-zero legs (#318 SpokeAssetSeizureHalted). A paused debt
listing blocks repayment; a frozen listing permits it. Missing listings permit
repayment and seizure of existing positions.
Choose a seize mode
One mode applies to all collateral, seized pro rata by USD value:Credit(0) creates an account owned by the liquidator on the target’s spoke.
For a nonzero receiving id, the liquidator must be its current NFT owner or an
active registered manager delegated by that owner.
The receiving account must use that spoke and PositionMode::Normal.
Creating a receiver supply position requires a current listing. An existing
receiver position retains its stamped risk parameters. Execution also checks
receiver position limits and isolation rules.
Credit(account_id) cannot name the account being liquidated
(#133 SelfLiquidationNotAllowed). This restriction concerns the receiving
account; the owner may still liquidate its own account.
Estimate the result
Callget_liquidation_estimate(account_id, debt_payments, seize_mode) using the
same budgets and mode intended for execution. The result includes gross
seizure, protocol fees, unused budgets, maximum payment, and bonus rate.
get_liquidation_collateral(account_id) returns liquidation-threshold-weighted
collateral in USD-WAD. It is the health-factor numerator, not the maximum
seizure amount.
The estimate does not check receiver authorization, receiver capacity, or pool
cash. Simulate the full call to check execution feasibility.
Seizure and fee tuples contain token addresses without hub ids. Match them to
the target’s ordered (hub_id, asset) supply keys, allowing omitted legs. A
unique ordered match identifies the markets. Repeated token addresses can make
the match ambiguous. Use the lowest proceeds across compatible mappings, or stop
if you cannot establish a bound. An address-only lookup can select the wrong index.
Enforce a profitability bound
Estimates reflect the state at the time of the read. Another liquidation or price change can alter the executable bonus and amounts. Enforce the required net proceeds in the liquidator contract and revert if they are insufficient. A full-debt ideal permits smaller offers. The final plan still depends on rounding, collateral backing, and available debt legs. Low-decimal partial seizures release repayment that rounded-away collateral no longer backs. See repayment limits.Build and authorize the call
liquidator source-account identity in these direct
signer examples. A contract liquidator must supply its own invocation authorization.
Only the liquidator authorizes the call and repayment transfers to the pool.
The target owner’s signature is not required. The pool authorizes Transfer
payouts; Credit seizure moves supply shares without transferring collateral
tokens.
Verify the liquidation
ConfirmgetTransaction(original_hash) returns SUCCESS on the intended
network before applying events. Preserve the signed envelope and original hash
before submission. Follow unknown transaction recovery
if submission or polling leaves the outcome unknown.
The events describe several parts of settlement:
LiqSeize is gross of fees; LiqCredit is net. Their event amount values use
token units with different rounding. Subtracting them cannot measure an exact
Credit fee, and summing them double-counts collateral. Each child event’s scaled
amount is the resulting position balance.
For an identified Credit invocation, calculate each market’s exact fee in shares:
30 - 27 = 3 shares. Transaction-start balances would give the wrong result.
Read the target’s health factor, collateral, and debt balances after execution.
For Credit mode, also read the receiving account’s scaled positions. Check
actual token balances for repayment and Transfer payouts. A valid Credit call
with no net seizure has no receiver position batch.
Clean bad debt
Any caller can invokeclean_bad_debt(caller, account_id) when debt exceeds
collateral and remaining collateral is at most $5 in USD-WAD. Liquidation
also performs this cleanup when it leaves an eligible residue.
Cleanup removes the remaining positions and account, burns the NFT, and
reduces supply indexes in markets with debt losses. Other markets’ indexes are
unaffected. See bad-debt accounting.
Above the $5 collateral limit, governance can call
force_socialize_bad_debt(account_id) when debt exceeds collateral.
Permissionless cleanup rejects ineligible accounts with #114 CannotCleanBadDebt.
Both paths emit CleanBadDebtEvent with account_id, total_borrow_usd_wad,
and total_collateral_usd_wad. This event contains no position deltas and
follows any position batch.
Common errors
Use Events for event field definitions and
Errors for the full error reference.
Match an error code and emitting contract from the same raw diagnostic event.
A handled nested failure can precede the final propagated error. Preserve raw
diagnostics; decoded display helpers can omit metadata and success flags.

