Skip to content

Replace reserve-and-cap with haircut risk model in perpetual futures#83

Open
mikemaccana wants to merge 1 commit into
mainfrom
claude/perpetual-futures-risk-model-fuayxj
Open

Replace reserve-and-cap with haircut risk model in perpetual futures#83
mikemaccana wants to merge 1 commit into
mainfrom
claude/perpetual-futures-risk-model-fuayxj

Conversation

@mikemaccana

Copy link
Copy Markdown
Collaborator

Summary

This PR replaces the reserve-and-cap risk model with the haircut model adapted from Percolator in both the Anchor and Quasar perpetual futures implementations. The key insight: trader profit is a junior claim backed by liquidity-provider capital and an insurance fund, not a capped reserve.

Key Changes

Risk Model Overhaul:

  • Removed reserved_liquidity field and all up-front reserve accounting
  • Eliminated the open-interest cap that prevented positions from opening when reserved + size > liquidity
  • Positions now open freely regardless of pool backing; solvency is enforced at exit instead

Haircut Mechanism:

  • Added haircut_ratio() function that computes h = min(1, backing / liability) where:
    • backing = liquidity + insurance_fund
    • liability = max(0, traders' aggregate unrealized profit)
  • When h < 1, every closing winner is paid the same fraction of their profit, preventing selective defaults
  • As losses settle back in, h rises automatically without governance intervention

Profit Maturation Gate:

  • Added profit_warmup_slots parameter to prevent oracle-spike arbitrage
  • Profit cannot be realized until current_slot >= entry_slot + profit_warmup_slots
  • Losses can be closed immediately (no manipulation incentive to lock down losses)
  • Applied in close_position before haircut is computed

Insurance Fund:

  • Replaced reserve concept with explicit insurance_fund field
  • Added insurance_fee_bps parameter: fraction of every open/close fee routed to insurance
  • Insurance fund absorbs bankruptcy deficits (losses exceeding collateral) before socializing to LPs
  • Counts as backing for profit alongside liquidity in haircut calculation

Fee Splitting:

  • Added split_fee() helper to divide fees between insurance fund and protocol fees
  • Ensures no base units are lost between the two cuts

State Changes:

  • Pool: removed reserved_liquidity, added insurance_fund and profit_warmup_slots
  • Position: added entry_slot to track when profit maturation window began
  • PoolParameters: added insurance_fee_bps and profit_warmup_slots fields

Implementation Details

  • Haircut is computed before the closing position leaves the accumulators, so the closer is one of the winners being scaled rather than scaling only those left behind
  • Haircut division floors, ensuring payouts never exceed backing
  • Provider withdrawals are capped at tracked liquidity (not AUM), preventing over-withdrawal when marked gains haven't settled
  • Liquidation now draws deficits from insurance fund first, then socializes remainder to LPs
  • Comprehensive test coverage added for haircut scaling, maturation gates, insurance fund mechanics, and bankruptcy absorption

Testing

Added 8 new tests covering:

  • Positions opening without full backing
  • Profit running uncapped when fully backed
  • Haircut scaling profit when pool is stressed
  • Profit blocked before maturation, realized after
  • Losses not gated by maturation
  • Insurance fund accumulation and bankruptcy absorption
  • Provider withdrawal limits under marked gains

https://claude.ai/code/session_012D5CfmXC1Ztae1NMrD7Yrm

Replace the reserve-and-cap risk model in both the Anchor and Quasar
implementations with the haircut model from Percolator
(github.com/aeyakovenko/percolator):

- Profit is a junior claim. Positions open with no up-front reserve and
  no open-interest cap; profit runs uncapped. Solvency is held at exit by
  a global haircut ratio h that scales every winner's profit to the
  backing the pool can cover, the same fraction for all. Removes
  Pool.reserved_liquidity and the per-position profit cap; provider
  withdrawals are gated by the profit traders are currently owed.
- Profit maturation: positions carry entry_slot and cannot be closed in
  profit until profit_warmup_slots elapse (oracle-manipulation defense).
  Loss is never gated.
- Insurance fund: funded by an insurance_fee_bps cut of each fee, absorbs
  bankruptcy deficits before liquidity providers, and counts as backing
  in the haircut.

Both implementations build to SBF and pass their LiteSVM tests (29 Anchor,
20 Quasar), including new haircut, maturation, withdrawal-guard, and
insurance-fund cases. READMEs, TERMINOLOGY, and CHANGELOG document the
model and why Percolator's peer-to-peer A/K overhang indices do not map
onto a single-counterparty pool.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants