@somnia-chain/markets-sdk


@somnia-chain/markets-sdk / index / LiquidationEvent

Type Alias: LiquidationEvent

LiquidationEvent = object

Defined in: packages/sdk/src/perp/history.ts:146

A liquidation event (mirror of the indexer LiquidationEvent entity). All numeric fields are raw units; any may be null when the source event didn't carry it.

Properties

id

id: string

Defined in: packages/sdk/src/perp/history.ts:148

Event id (${txHash}_${logIndex}).


account

account: string

Defined in: packages/sdk/src/perp/history.ts:150

Liquidated account (lowercased).


pool

pool: string | null

Defined in: packages/sdk/src/perp/history.ts:152

Perp pool (lowercased); null on account-scoped rows.


kind

kind: string

Defined in: packages/sdk/src/perp/history.ts:183

WHICH stage of the liquidation/deleveraging waterfall this row is. Read this first — the rows are stages of one mechanism, not repetitions of one event, and without it an ADL leg is indistinguishable from a liquidation:

AccountLiquidated account-level summary (positionsProcessed, stageReached) PositionLiquidated per-position liquidation (size, price) PositionSkipped below min quantity, left in place (size) PositionTakenOver stage-4 backstop takeover (counterparty = bidder, price) AutoDeleveraged ADL leg (counterparty absorbed it; price = bankruptcy price) Throttled DEFERRED by the pool's per-block volume cap KeeperReward paid to the keeper that ran it (counterparty = keeper) OrderPanicked the liquidation IOC reverted with a Solidity PANIC PositionTransferred stage-4 transfer (counterparty, size) CloseOutMarginSettled stage-4 close-out margin flow (counterparty) BadDebtAbsorbed the fund was ASKED to cover (insuranceCovered, deficit, counterparty = fund). It fires on the request, not on the payment: insuranceCovered may be 0. Read that field before you conclude the fund paid. ResidualBadDebt uncovered, INSOLVENT hole after the waterfall (badDebt) AdlPriceCapacityExhausted terminal: hole exceeds aggregate position capacity (badDebt) ResidualBackedByOpenPnl hole fully backed by the account's OWN open PnL (deficit, equity) CoverageDeclined coverage the equity cap DEFERRED (coverageDeclined) AdlSessionDiscarded ADL session abandoned; amount is on the same-tx BadDebtAbsorbed row AdlCapacityShortfall ADL could not source enough capacity (size)

A string, not LiquidationKind: the row carries what the DEPLOYED indexer wrote, which can outrun a pinned SDK. isLiquidationKind narrows it for an exhaustive switch or to pass back into the filter.


size

size: string | null

Defined in: packages/sdk/src/perp/history.ts:190

Signed size for the leg, where the event carries one (raw base units).

Signed, not absolute: PositionLiquidated emits a signed sizeDelta, and the sign is the side being closed.


price

price: string | null

Defined in: packages/sdk/src/perp/history.ts:195

Price for the leg (raw quote per whole base) — mark price, takeover price, or ADL bankruptcy price depending on kind.


counterparty

counterparty: string | null

Defined in: packages/sdk/src/perp/history.ts:205

The other side of the leg: the ADL counterparty who absorbed it, the takeover bidder, the transfer/close-out peer, or — on BadDebtAbsorbed — the Insurance Fund the engine ASKED to cover. Null on rows with no counterparty.

On BadDebtAbsorbed this names the fund that was asked, not one that paid. The address is recorded even when insuranceCovered is 0, so read that field to see whether any value moved.


penalty

penalty: string | null

Defined in: packages/sdk/src/perp/history.ts:207

Penalty charged (raw collateral; reserved — not carried by current events).


badDebt

badDebt: string | null

Defined in: packages/sdk/src/perp/history.ts:228

The LEVEL of the account's uncovered, genuinely insolvent realized hole after this liquidate() call — ResidualBadDebt, or AdlPriceCapacityExhausted for the terminal price-capacity case (raw collateral).

A level, not a flow — never SUM this across rows. The underlying residual is a post-call state sample, so a later call on the same account re-reports the same (possibly changed) hole, and a stage-5 residual can co-fire with a terminal ADL one in a single call: two samples of one hole at two stages.

Sound aggregates: the latest row per account is that account's currently known uncovered hole (an upper bound — a deposit can repay it with no row here, see MarginEvent), and the sum of those latest rows across accounts is point-in-time system bad debt.

Deliberately narrow: what the fund actually paid is LiquidationEvent.insuranceCovered, a gross pre-coverage hole is LiquidationEvent.deficit, and a deferred coverage decision is LiquidationEvent.coverageDeclined. Collateral that merely MOVED between accounts is in collateralAmount.


insuranceCovered

insuranceCovered: string | null

Defined in: packages/sdk/src/perp/history.ts:242

Wei the Insurance Fund ACTUALLY moved — BadDebtAbsorbed only (raw collateral).

A flow, and the only summable amount here: rows are disjoint payments, so a SUM over any slice is exact fund outflow. A insuranceCovered below the same row's deficit does NOT mean the fund was underfunded — part of a hole is unattributable (a pre-existing balance, or funding owed), and that remainder surfaces as a ResidualBadDebt row instead.

AdlSessionDiscarded deliberately leaves this null: its absorption is the same absorbBadDebt call that emits BadDebtAbsorbed in the same transaction, so counting both would double the outflow. Join on txHash.


deficit

deficit: string | null

Defined in: packages/sdk/src/perp/history.ts:255

The GROSS realized hole a stage reported, before coverage (raw collateral) — BadDebtAbsorbed (the full negative balance) and ResidualBackedByOpenPnl (a hole the account's own open profit fully backs, so it is NOT bad debt; read equity alongside it, and note it becomes bad debt if the position reverses).

A level, and overlapping per-stage views of one hole — never SUM, and never add to badDebt. When BadDebtAbsorbed and ResidualBadDebt both fire in one call the balance moved only by what the fund paid, so badDebt == deficit - insuranceCovered for that call: a useful cross-row audit check, and the direct proof that summing the gross figure with the residual double-counts.


coverageDeclined

coverageDeclined: string | null

Defined in: packages/sdk/src/perp/history.ts:266

Attributable coverage the stage-5 equity cap did NOT pay — CoverageDeclined only (raw collateral).

A flow and summable as "total coverage deferred", but NOT a loss: the fund underwrites insolvency and the account was not insolvent by that much at that moment. If the backing later evaporates the hole returns as a pre-existing negative balance, which is unattributable by definition, so it is written off rather than re-declined (accepted policy, OQ-13).


collateralAmount

collateralAmount: string | null

Defined in: packages/sdk/src/perp/history.ts:272

Collateral that MOVED rather than was lost — PositionTransferred (collateral following the position) and CloseOutMarginSettled. Kept separate from badDebt so neither aggregate contaminates the other.


equity

equity: string | null

Defined in: packages/sdk/src/perp/history.ts:274

Account equity where the event reports it (ResidualBackedByOpenPnl; signed).


positionsProcessed

positionsProcessed: string | null

Defined in: packages/sdk/src/perp/history.ts:276

Positions processed (AccountLiquidated only).


stageReached

stageReached: number | null

Defined in: packages/sdk/src/perp/history.ts:309

The deepest waterfall stage that ACTED (AccountLiquidated only).

The protocol enum is 0-indexed and has six members. The published waterfall numbers its stages 1 to 6. The two do not line up, so map them with this table:

0 OrderCancellation before stage 3 — cancelling the account's resting orders alone restored health 1 CLOBPartial stage 3 2 BidderTakeover stage 4 3 InsuranceFund stage 5 4 ADL stage 6 5 Deferred not a stage — stage 3 hit its per-block rate limit, and stages 4 to 6 were not consulted. Ships dormant, so it does not appear yet

Published stages 1 (Healthy) and 2 (Margin Call) are account states, not actions. The engine cannot reach them, so no value maps to them.

Two rules the number does not state on its own:

It names the deepest stage that ACTED, not the deepest stage consulted. A stage that ran and moved nothing does not promote it. So BidderTakeover (2) beside a BadDebtAbsorbed row is consistent, and means the fund was asked and paid nothing. Check insuranceCovered on that row to confirm.

CLOBPartial (1) is a fall-through marker. It means stages 4 to 6 were consulted and none of them acted. It does NOT prove stage 3 filled anything. Against an empty book you get CLOBPartial with a positionsProcessed of 0, which means the account's orders were cancelled and no position was closed. Always read positionsProcessed with this field.


marginStatusBefore

marginStatusBefore: number | null

Defined in: packages/sdk/src/perp/history.ts:311

Margin status before / after (AccountLiquidated only).


marginStatusAfter

marginStatusAfter: number | null

Defined in: packages/sdk/src/perp/history.ts:312


timestamp

timestamp: string

Defined in: packages/sdk/src/perp/history.ts:314

Timestamp (unix seconds) of the row.


blockNumber

blockNumber: string

Defined in: packages/sdk/src/perp/history.ts:315


txHash

txHash: string

Defined in: packages/sdk/src/perp/history.ts:317

Tx hash the row landed in. Stages of one liquidation share it.