Diffusal
Protocol

Liquidation

Proactive liquidation mechanics to ensure protocol solvency

Liquidation ensures protocol solvency by allowing third-party keepers (or anyone) to intervene when a user's equity falls below the maintenance margin. This prevents bad debt from cascading during market volatility.


Liquidation Trigger

A user becomes liquidatable when:

Portfolio Equity<Maintenance Margin\text{Portfolio Equity} < \text{Maintenance Margin}

This can happen to any user regardless of position type:

Position TypeHow Liquidation Can Trigger
Long holdersOption values drop significantly
Short holdersOption values rise significantly (obligation increases)
Mixed portfoliosNet losses exceed collateral buffer

The Liquidation Process

  1. Trigger: Keeper detects Equity < MM
  2. Calculate: Determine debt and positions to close
  3. Close Positions at penalized mark price: Long (size > 0) liquidator buys at mark × (1 - penalty%); Short (size < 0) liquidator buys back at mark × (1 + penalty%)
  4. Settle: Proceeds applied to user's collateral, liquidator receives bounty, and if shortfall, insurance fund covers

Debt Calculation

Debt=Initial MarginPortfolio Equity\text{Debt} = \text{Initial Margin} - \text{Portfolio Equity}

If Debt > 0 and Equity < MM, the user is underwater and liquidation is triggered.


Mark Price Liquidation

Liquidations use the mark price (Black-Scholes theoretical) directly. They do not go through the orderbook or RFQ system.

The liquidator buys positions directly from the liquidated user at a penalized mark price:

Position TypeLiquidation PriceEffect
Long (size > 0)mark × (1 - penalty%)Liquidator buys at discount
Short (size < 0)mark × (1 + penalty%)Liquidator buys back at premium

The liquidator immediately earns the penalty as profit. They can then sell the acquired positions via orderbook or RFQ.


Volatility-Adjusted Penalty

The liquidation penalty scales with implied volatility to properly incentivize liquidators during market stress:

Penalty Rate=Base (1%)+Current IV50%100\text{Penalty Rate} = \text{Base (1\%)} + \frac{\text{Current IV} - 50\%}{100}

Examples

IVPenalty CalculationRate
50%1% + (50-50)/1001.0%
75%1% + (75-50)/1001.25%
100%1% + (100-50)/1001.5%
150%1% + (150-50)/1002.0%

Why Volatility Adjustment Matters

In high volatility environments:

  • Positions move faster - A barely underwater position can become deeply underwater within blocks
  • Liquidators take more risk - Prices may move against them before they can hedge
  • Higher penalties compensate - Ensures liquidators remain incentivized during stress

Without vol-adjustment, liquidators might delay during market stress (when liquidations are most critical), leading to bad debt accumulation.


Partial vs Full Liquidation

The protocol supports partial liquidation to give users a chance to recover.

Key Insight

Margin requirements use stressed scenarios (±30% spot, +50% IV), but liquidation executes at current mark prices. This means:

  • Selling positions at current mark barely reduces equity (just the penalty)
  • But it dramatically reduces the margin requirement (which was stress-based)
  • So partial liquidation often restores health without destroying the user

Proportional Liquidation

Partial liquidation uses a proportional approach based on the user's debt-to-margin ratio:

Positions to Close=Total Positions×DebtInitial Margin\text{Positions to Close} = \text{Total Positions} \times \frac{\text{Debt}}{\text{Initial Margin}}

This ensures just enough positions are closed to cover the debt proportionally.

Liquidation Process

  1. Trigger: Equity < MM
  2. First Attempt: Close debt/IM fraction of positions — Liquidator acquires proportional amount at penalized mark price
  3. Re-check: Is user now healthy? (Equity ≥ MM)?
    • If yes, stop and user retains remaining positions
    • If no, automatically escalate to full liquidation (close remaining positions)

Why Proportional?

  • Closing a fraction proportional to debt targets the exact amount needed
  • Equity only decreases by the penalty (~1-2% of closed position value)
  • Automatic escalation ensures health is always restored
  • More efficient than fixed 50% - avoids over-liquidating healthy-ish users

After liquidation, the user retains any remaining equity and positions (if partial was sufficient).


Liquidator Incentives

Liquidators are compensated through two mechanisms:

1. Penalty Profit (1-2%+)

Liquidators acquire positions at a discount/premium from mark price. For example, when liquidating a long position with mark price 100andpenalty1.5100 and penalty 1.5%, the liquidation price is 100 × 0.985 = 98.50.Theliquidatorbuysat98.50. The liquidator buys at 98.50 for a position worth 100,yieldingimmediateprofitof100, yielding immediate profit of 1.50 per contract.

2. Bounty (5% of debt)

Bounty=min(Debt×5%,Proceeds)\text{Bounty} = \min(\text{Debt} \times 5\%, \text{Proceeds})

The bounty is always paid first from liquidation proceeds to incentivize liquidators, even in shortfall cases. The bounty is capped at total proceeds to ensure we don't pay more than available.

Total Liquidator Profit

Total Profit=Penalty Profit+Bounty\text{Total Profit} = \text{Penalty Profit} + \text{Bounty}

This incentivizes keepers to monitor positions and liquidate promptly, especially during high volatility when the penalty (and thus profit) is higher.


Post-Liquidation

After acquiring positions, the liquidator can:

ActionDescription
Sell via limit ordersPlace orders on the orderbook
Sell via RFQRequest quote from Main Market Maker
Hold positionsKeep exposure if desired
Hedge externallyOffset risk on other venues

Insurance Fund

When liquidation proceeds are insufficient to cover debt (bad debt scenario):

Shortfall=DebtProceeds\text{Shortfall} = \text{Debt} - \text{Proceeds}

The Insurance Fund covers the shortfall.

DiffusalInsuranceFund Contract

The insurance fund is a separate contract (DiffusalInsuranceFund) that:

  • Receives all protocol trading fees (set as feeRecipient on OrderBook and RFQ)
  • Holds funds in a deposit on the CollateralVault
  • Provides cover() function callable by LiquidationEngine or SettlementEngine

Insurance Fund Sources

SourceDescription
Protocol feesAll trading fees routed via feeRecipient
Initial seed capitalBootstrap funding via deposits

Flow Diagram

At settlement, funds flow from short holders (obligations) to the settlement pool, then to long holders (payouts). If there's a shortfall, the insurance fund provides coverage.


Worked Example

Initial State

Portfolio (ETH spot = $3,000, IV = 50%):

PositionStrikeMarkEntrySize
Long ETH Call$3,200$98.76$150+10
Short ETH Put$2,800$80.63$120-5
  • Deposited: $2,000
  • Unrealized PnL: -$315.58
  • Equity: $1,684.42
  • IM: $4,416.53
  • MM: $3,533.22

Trigger: Equity (1,684.42)<MM(1,684.42) < MM (3,533.22) - LIQUIDATE

Calculation

Step 1: Debt

Debt=$4,416.53$1,684.42=$2,732.11\text{Debt} = \$4,416.53 - \$1,684.42 = \$2,732.11

Step 2: Penalized Prices (1% penalty)

PositionMarkPenalty DirectionLiq Price
Long Call$98.76-1%$97.77
Short Put$80.63+1%$81.44

Step 3: Proceeds

PositionSizeLiq PriceProceeds
Long10$97.77$977.70
Short5$81.44$407.20
Total$1,384.90

Step 4: Bounty

Bounty=$2,732.11×5%=$136.61\text{Bounty} = \$2,732.11 \times 5\% = \$136.61

Step 5: Settlement

1. Pay bounty first: $136.61 to liquidator
2. Remaining proceeds: $1,384.90 - $136.61 = $1,248.29
3. Apply to debt: $1,248.29 < $2,732.11 (shortfall)
4. Shortfall: $2,732.11 - $1,248.29 = $1,483.82
5. Insurance covers: $1,483.82

User retains $0 after liquidation (insufficient proceeds to cover debt after bounty). Positions are closed.

Extreme Case

If spot crashed to $2,000:

  • Proceeds drop to ~$800
  • Bounty: min(136.61,136.61, 800) = $136.61
  • Remaining: 800800 - 136.61 = $663.39
  • Shortfall: 2,732.112,732.11 - 663.39 = $2,068.72
  • Insurance fund covers $2,068.72
  • Liquidator still receives bounty (paid first to incentivize action even in stress)

Risk Parameters

ParameterDefaultDescription
LIQUIDATION_PENALTY_BASE1%Base price penalty
LIQUIDATION_PENALTY_IV_BASELINE50%IV threshold for penalty scaling
LIQUIDATOR_BOUNTY5%% of debt paid to liquidator

Note: Partial liquidation uses proportional position closure (debt/IM fraction) rather than a fixed percentage.


Main Market Maker Exception

The Main Market Maker (MMM) is a privileged, non-liquidatable entity. The liquidation function rejects any attempt to liquidate the MMM address by first checking if the user is an MMM (returning false if so) before checking equity vs maintenance margin.

Why MMM Is Exempt

The MMM's solvency is managed operationally, not by protocol rules:

ConcernMitigation
MMM goes underwaterMMM operator monitors and rebalances externally
MMM accumulates too much riskMMM offloads shorts via limit orders or OTC
MMM runs out of capitalMMM operator injects capital before insolvency
MMM becomes maliciousGovernance can replace MMM address

This is a deliberate trust tradeoff: by trusting one well-managed entity, the protocol guarantees that RFQ always functions and liquidations can always execute against MMM inventory.


Security Considerations

Keeper Monitoring

  • Permissionless: Anyone can call liquidate() - no special access required
  • Multiple keepers: Protocol can run backup keepers alongside third-party services (Gelato, Chainlink)
  • Incentive alignment: Penalty + bounty ensures keepers are motivated

Front-Running Protection

  • Liquidation price is determined by mark price at execution time
  • No advantage to front-running the liquidation call
  • MEV protection via fast block finality on supported chains

Manipulation Resistance

  • Mark price uses oracle (Pyth/Chainlink), not order book
  • Cannot avoid liquidation by placing fake orders
  • TWAP smoothing prevents flash loan attacks on oracle

Smart Contract API

The DiffusalLiquidationEngine contract implements the liquidation mechanics. It is permissionless - anyone can call liquidation functions.

Liquidation Functions

  • liquidate(user) — Full liquidation that closes all positions. Returns a LiquidationResult containing: user address, liquidator, debt (USDC 6 decimals), totalProceeds, bounty, insuranceUsed, newEquity, positionsLiquidated, and isPartial (false for full liquidation).
  • liquidatePartial(user) — Partial liquidation that closes a proportional fraction (debt/IM) of positions. If partial liquidation doesn't restore health, automatically escalates to full liquidation. Returns same result struct with isPartial = true.

View Functions

  • getLiquidationInfo(user) — Returns comprehensive info: isLiquidatable, debt (USDC 6 decimals), estimatedProceeds, estimatedBounty, positionCount
  • calculateDebt(user) — Returns debt = max(0, Initial Margin - Equity)
  • calculatePenaltyRate(pairId) — Returns penalty rate in WAD (e.g., 0.015e18 = 1.5%). Penalty = Base (1%) + (IV - 50%) / 100
  • getInsuranceFundBalance() — Returns current insurance fund balance

External Insurance Fund

The insurance fund is a separate contract (DiffusalInsuranceFund) with these functions:

  • getBalance() — Current fund balance (USDC, 6 decimals)
  • collateralVault() — CollateralVault reference
  • liquidationEngine() — LiquidationEngine reference
  • cover(shortfallAmount) — Draw funds for shortfalls (callable by LiquidationEngine or SettlementEngine)
  • withdraw(amount) — Withdraw excess funds (owner only)

The insurance fund receives all protocol trading fees by being set as feeRecipient on OrderBook and RFQ contracts.

Deployment Integration

The liquidation engine must be registered as an operator on DiffusalOptionsPositionManager (for updatePosition()) and DiffusalCollateralVault (for creditCollateral() and debitCollateral()). Additionally, the insurance fund must be connected to the liquidation engine, and fees should be routed to the insurance fund.


Contract Implementation

ContractRole
DiffusalLiquidationEngineCore liquidation logic
DiffusalInsuranceFundShortfall coverage
DiffusalCollateralVaultCollateral settlement

On this page