Liquidations
SportsPerp uses a three-layer liquidation cascade designed around a single invariant: the protocol never accrues bad debt. Every position that becomes insolvent is unwound through one of three mechanisms before the global liquidity pool is exposed.
This page is the high-level overview. The detailed layer-by-layer mechanics live in Three-Layer Cascade and Auto-Deleveraging.
The three layers
βββββββββββββββββββββββββββββββββββββββ
β margin_ratio = equity / size β
ββββββββββββββββ¬βββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββ
β β β
ratio > 20% 20% β₯ ratio > 13.33% ratio β€ 13.33%
[healthy] [LAYER 1: Partial] β
ββββββββββββ΄βββββββββββ
β β
insurance can absorb? no insurance left
β β
[LAYER 2: Backstop] [LAYER 3: ADL]| Layer | Trigger | Action | Liquidator reward |
|---|---|---|---|
| 1. Partial | margin β€ 20%, > 13.33% | Close 20% of the position at mark price; 30s cooldown | 5% of closed collateral |
| 2. Backstop | margin β€ 13.33%, insurance healthy | Insurance fund absorbs the full position at mark; fund unwinds 10% per call | 3% per unwind chunk |
| 3. ADL | margin β€ 13.33%, insurance depleted | Force-close opposing profitable positions, ranked by PnL Γ leverage | (none β protocol-driven) |
Why three layers
A single-shot liquidation (the dominant crypto-perp model) is fragile:
- Insufficient fill. If the book is thin, the liquidator canβt close the full position and the protocol eats the residual loss.
- Liquidation cascades. One liquidationβs price impact triggers the next; socialized losses follow.
- Bad-debt socialization. When things fail, everyone on the winning side gets haircut.
SportsPerpβs cascade avoids all three:
- Layer 1 repairs gently. Closing 20% at a time lets a recovering market bring the position back above the maintenance threshold without a full wipeout. The 30-second cooldown prevents stacked partials on the same position.
- Layer 2 socializes to a dedicated pool, not to other traders. The insurance fund exists to absorb these losses; it is funded by 50% of every Layer 1 liquidationβs proceeds, so the system is self-capitalizing in normal operation.
- Layer 3 is the nuclear option. Only when insurance is depleted does ADL fire. By that point, the protocolβs losses are being absorbed by opposing profitable positions β the participants best able to afford it, because theyβve already captured the gain.
Anti-manipulation protection
A critical subtlety: profitable positions cannot be liquidated unless they have materially lost value vs their most recent margin transfer.
The check, enforced in partial_liquidate.rs:
liquidation allowed only if:
pnl_vs_entry < 0 // position currently losing vs entry
OR
(last_margin_transfer_collateral - effective_collateral) / last_margin_transfer_collateral
β₯ 18.3% // lost β₯ 18.3% since last margin opsIn plain English: a trader who is ahead on the trade and has not topped up collateral cannot be liquidated. Only when theyβre down on the trade or down β₯ 18.3% from their last margin baseline does the cascade become eligible to fire.
This protects against a specific attack: an adversary could grief a healthy position by briefly manipulating the oracle to trigger a margin-ratio check failure. The 18.3% floor makes that economically pointless β the attacker would need to sustain a major dislocation, not a one-block flash.
Margin baseline resets on every add_collateral and withdraw_collateral call (collateral.rs:30,96). So if a trader actively manages their position, their anti-manipulation baseline stays fresh.
Mark price is the liquidation reference
Liquidations execute against the EMA-smoothed composite mark price, not the raw oracle. This means:
- A single oracle push cannot trigger mass liquidations on its own β the 150-second EMA dampens the impact.
- A single vAMM squeeze cannot trigger liquidations either β the composite weighting pulls toward the oracle.
- Liquidations are well-defined. Every participant and keeper observes the same on-chain
mark_price_emafield and computes identical eligibility.
See Mark Price for the full composite calculation.
Permissionless execution
All three layers are permissionless: any Solana account can invoke partial_liquidate, backstop_liquidate, unwind_backstop, or auto_deleverage. This means:
- Liquidator incentives align without centralized operators. A 5% reward on Layer 1 and 3% on Layer 2 is enough to fund at least one competitive keeper. In practice, multiple keepers compete for the reward.
- No SPoF in liquidation. If SportsPerpβs liquidator bot (keeper/liquidator.mjs) goes down, third parties can still clear underwater positions.
- The math is on-chain. A liquidator doesnβt need to trust any off-chain data feed; the program itself determines eligibility.
Zero-bad-debt guarantee
Across the three layers, the protocol maintains the following invariant:
No close of any single position can result in negative collateral settlement against the global liquidity pool.
Layer 1 enforces this by closing only 20% at a time β if the partial close would leave remaining collateral negative, the position is escalated to Layer 2. Layer 2 lets the insurance fund absorb the negative slice. Layer 3 engages when insurance canβt cover β at which point opposing profitable positions absorb the loss via ADL.
There is no configuration under which the pool can hold a negative balance. The 50%-of-effective_oi single-position cap (tier 5), the 20% maintenance margin, the 18.3% anti-manipulation floor, and the 50K max backstop exposure collectively ensure that the liquidation math always closes. The full pool-solvency invariant pool_token.amount β₯ Ξ£ obligations is monitored continuously off-chain by scripts/probe-solvency.ts.
Further reading
- Three-Layer Cascade β detailed mechanics for each layer.
- Auto-Deleveraging β Layer 3 specifics and ranking.
- Insurance Fund β Layer 2βs absorbing pool.
- Margin β the maintenance-margin check that starts the cascade.