@somnia-chain/markets-sdk / index / perpLiquidationPrice
Function: perpLiquidationPrice()
perpLiquidationPrice(
p):bigint|null
Defined in: packages/sdk/src/perp/margin.ts:437
Solve for the mark price at which one market's position trips maintenance margin —
the shared kernel behind client.getLiquidationPrice and
client.previewPerpLiquidationPrice, which is why a current and a projected price
cannot disagree on identical inputs.
Pure: no client, no block, no I/O. Feed it a consistent snapshot and it is exact arithmetic.
Both sides of the inequality move with the price. Liquidation begins where
equity == mmReq — MarginBank._classify returns PartialLiquidation the moment
equity < mmReq. Equity moves with the mark through unrealized PnL, at
size / oneBase per unit of price. But mmReq moves too, because
_marketHealthFromSnapshot recomputes it as
ceil(|size| × mark × mmBps / (oneBase × 10000)) against the CURRENT mark. Solving
equity(p) == mmReq(p) therefore carries a factor a fixed-mmReq estimate drops:
long p = mark − (equity − mmReq) × oneBase × 10000 / (|size| × (10000 − mmBps))
short p = mark + (equity − mmReq) × oneBase × 10000 / (|size| × (10000 + mmBps))
Dropping that factor errs conservative on a long and optimistic on a short — reporting the liquidation further away than it is, on the side whose loss is unbounded. At a 250 bps maintenance threshold it misplaces a short's liquidation by ~2.5% of the distance to it.
A single-market solve, deliberately. Only this market's mark is varied; every
other market's contribution stays at the value baked into equity and mmReq. So
the answer is "the price at which THIS market's move alone trips maintenance",
which is what a per-position liquidation price means under cross margin. A
correlated move across several markets liquidates sooner, and nothing here claims
otherwise.
Also held constant: pending funding (already netted into equity), the mark's own
EMA lag, and any fill landing between the read and the move.
Details
- Returns: The liquidation price in raw quote units per whole base, floored at 0 (a price cannot go negative) — or
nullwhen the position is flat, or whenmmBpsis exactly 10000 on a long, where price cancels out of the inequality entirely and no price triggers liquidation. That last case is unreachable on a real pool:PerpPool._validatePerpPoolParametersenforcesinitialMarginBps ≤ 10000andmaintenanceMarginBps < initialMarginBps, sommBps < 10000on every market.
Parameters
p
Returns
bigint | null