Docs Hub Paper Chapter Call Graphs Yellow Paper
Liquidation Reference

Liquidation and ADL

This page is the dedicated execution reference for perp liquidation, portfolio margin liquidation, auto-deleveraging, and BOLE lending liquidation. It is meant to sit between the broad paper and the raw RE notes: concrete enough to implement from, honest about what is still inferred, and explicit about where spot and outcomes diverge from the perp liquidation family.

Perps / PM confirmed family
BOLE begin_block lane implemented on main
Outcomes settlement path, not liquidation
Spot dust conversion, not perp-style liquidation

1. Product Surface Split

Surface Trigger family Execution lane LtHash / state effect
Perp cross account_value < maintenance_margin Liquidate action, then ADL on residual shortfall LiquidatedCross
Perp isolated allocated_margin + uPnL < maintenance_margin Liquidate action, then ADL on residual shortfall LiquidatedIsolated
Portfolio margin Unified account ratio breach across eligible assets Same liquidation family as cross margin, but with PM account summary and mixed asset exposure Same perp liquidation family; exact mixed-leg order still open
BOLE lending health_factor < 0.8 begin_block lending liquidation pass BoleMarketLiquidation, BoleBackstopLiquidation, BolePartialLiquidation
Spot No normal perp-style liquidation path Separate spot clearinghouse / dust conversion behavior SpotDustConversion is the relevant state-hash lane
Outcomes Settlement / cancellation, not liquidation outcomeSettledCanceled, outcomeSettledRejected, merge / settlement logic Outcome state transitions, not perp liquidation categories

2. End-to-End Liquidation Flow

The high-level split is simple: ordinary liquidation first, ADL only if bad debt remains, and BOLE handled in an earlier lending pass during begin_block.

flowchart TD BB["begin_block"] --> DF["distribute_funding"] DF --> BL["apply_bole_liquidations"] BL --> UF["update_funding_rates"] UF --> CP["cancel_aggressive_at_oi_cap"] CP --> PR["prune / tracker / stale-mark maintenance"] PR --> DA["drain action delayer"] DA --> ACT["process signed actions"] ACT --> LIQ{"Liquidate action?"} LIQ -->|no| NEXT["continue execution"] LIQ -->|yes| CHECK["maintenance / margin checks"] CHECK --> KIND{"cross or isolated?"} KIND -->|cross| LC["cross liquidation execution"] KIND -->|isolated| LI["isolated liquidation execution"] LC --> SF{"shortfall remains?"} LI --> SF SF -->|no| HASH["update LtHash"] SF -->|yes| ADL["ADL on opposing profitable side"] ADL --> HASH BL --> BOLE{"BOLE health factor < 0.8?"} BOLE -->|yes| MODE["market / partial / backstop"] MODE --> BHASH["update BOLE LtHash lane"]

3. Trigger Formulas

Perp Cross

confirmed structure

margin_available
= balance
+ cross_uPnL
- maintenance_margin_used

liquidatable if margin_available < 0

Perp Isolated

confirmed structure

isolated_margin_available
= allocated_margin
+ unrealized_pnl
- isolated_maintenance_margin

liquidatable if isolated_margin_available < 0

Margin Tiers

tiered table

initial_margin
= sum(notional_in_tier / max_leverage)

maintenance_margin
= sum(notional_in_tier / max_leverage
     - maintenance_deduction)

BOLE Health

implemented on main

ltv = borrowed_value / supplied_value

health_factor
= supplied_value * reserve.liquidation_threshold
/ borrowed_value

liquidatable if health_factor < 0.8
Formula / rule Current best state Confidence
Perp liquidation trigger account_value < maintenance_margin Confirmed structure
ADL ranking Opposing profitable side, ordered by ROE descending Confirmed surface
BOLE threshold health_factor < 0.8 Confirmed / implemented locally
BOLE partial cooldown 30s default cooldown guard Observed in docs + local implementation
PM mixed-leg liquidation order Depends on live account exposure and oracle ordering Open implementation detail

4. Auto-Deleveraging

ADL is the bad-debt cleanup lane, not the first response. The exchange only flips into ADL when ordinary liquidation leaves residual shortfall. Current engine state exposes the same core fields the binary notes point at: perform_auto_deleveraging, adl_shortfall_remaining, and per-bucket requirements keyed by asset plus side.

flowchart LR A["liquidation shortfall > 0"] --> B["set perform_auto_deleveraging"] B --> C["set adl_shortfall_remaining"] C --> D["bucket by (asset, opposing side)"] D --> E["collect profitable counterparties"] E --> F["rank by ROE descending"] F --> G["delever until shortfall is exhausted"]
roe = unrealized_pnl / margin_allocated

ADL bucket key = (asset, opposing_side)
eligible side  = opposite side of the liquidated position
priority       = higher ROE first, then larger notional

What is still not fully closed: exact shortfall sizing and the final residual handling when the ranked profitable side cannot absorb all remaining debt.

5. BOLE begin_block Lane

On current main, BOLE liquidation is a top-of-block lending pass. It runs immediately after funding distribution and before the aggressive OI-cap cancel lane. That keeps lending insolvency handling ahead of later cleanup and trading-prep effects.

flowchart TD A["begin_block"] --> B["distribute_funding"] B --> C["apply_bole_liquidations"] C --> D{"candidate kind?"} D -->|market| E["seize collateral + repay borrow"] D -->|partial| F["reduce borrow + set cooldown"] D -->|backstop| G["transfer position to default liquidator"] E --> H["record BOLE liquidation LtHash"] F --> H G --> H H --> I["continue begin_block pipeline"]
Mode Meaning Key guardrail
Market Normal BOLE liquidation path Only after health-factor breach and absent higher-priority backstop route
Partial Risk reduction without full account transfer partial_liquidation_cooldown
Backstop Default liquidator takes the borrow position Requires configured liquidator and reserve routing

6. Portfolio Margin and Non-Perp Surfaces

Portfolio margin is not modeled here as its own liquidation engine. It is a mode overlay on the same liquidation family, with a different account summary and broader asset set. The current protocol claim in the repo is: keep PM as an account mode, not a separate universe.

  • Perps and PM share the liquidation family.
  • Spot is not handled like a normal perp liquidation path; dust conversion is the visible state-hash lane.
  • Outcomes settle and cancel through their own execution stack instead of the perp liquidation engine.
  • BOLE is a lending liquidation system with separate begin-block execution and separate LtHash categories.

7. Call Graph and Code Map

Surface Primary local code path Reference artifact
begin_block ordering crates/hl-engine/src/exchange.rs (private repo path) exchange_block_pipeline.dot (omitted from public export)
ADL planning crates/hl-engine/src/liquidation.rs (private repo path) Liquidation Engine note
BOLE state and reserves crates/hl-engine/src/services.rs (private repo path) clearinghouse_liquidation.dot (omitted from public export)
Paper overview paper chapter 9 rendered call-graphs page

8. What Is Still Open

Gap Why it matters Status
Exact ADL execution sizing Needed for end-to-end parity, not just ranking parity open
Residual shortfall handling after ADL capacity is exhausted Solvency and parity risk surface open
Portfolio margin mixed-leg order Needed to replay PM liquidation exactly across perps and spot borrows open
Final BOLE penalty / sizing details Current local execution is directionally correct but not yet final-protocol exact work in progress
Outcome solvency lane Outcome settlement and merge logic is a separate safety review, not a liquidation path active research