# marginX / CLOB-DEX — Long-Term Roadmap

> Living document. Captures strategic initiatives beyond the current feature set so they
> are not lost between sessions. Each initiative lists the goal, what already exists to
> build on, the design sketch, open questions, and a phased plan.
> Last updated: 2026-05-31.

---

## Initiative 0 (IMMEDIATE) — Protocol Analytics Dashboard

**Goal.** A stats dashboard (frontend + backend + indexer) showing protocol-wide health
and activity as **charts/graphs**, modeled on the **Extended.exchange** dashboard
(reference link to be provided). Required metrics:
- **Total trading volume** (cumulative, all markets, USD).
- **Daily volume** (time series, charted).
- **Total number of trades** (cumulative + per-interval).
- **Liquidations** (count + notional liquidated, over time).
- **Bad debt** (socialized debt over time / current outstanding).
- (natural additions: open interest, insurance-fund + backstop-vault balances over time,
  per-market volume breakdown, active traders.)

**What already exists (most data is already indexed):**
- **Candles / buckets** — `hour_buckets`, `daily_buckets`, etc. already carry `volume`,
  `quote_volume`, `volume_usd`, `count` per market (perp candles keyed on the market-token
  address). → total + daily volume and trade counts are a straight aggregation across
  markets. (We just fixed the backend to read perp `volume_usd` from these.)
- **`trades` table** — one row per match (spot + perp), with addresses, side, price, qty,
  fees. → total number of trades = count; volume = Σ price·qty.
- **Liquidations** — `PositionLiquidated` events (PositionHandler) carry `liquidationFee`,
  `liquidationPrice`, collateral, account; `position_history` rows mark decreases. The
  indexer must persist these into a queryable `liquidations` table.
- **Bad debt** — `BackstopVault.totalSocializedDebt` + `DebtSocialized(amount, ts)` events;
  `InsuranceFund` balance + its events. (Verified live: a contrived run produced
  `totalSocializedDebt = 27 USDC`, backstop + insurance drained — so the on-chain signals
  exist and are correct.)

**Gap / what to build (full stack):**
1. **Indexer** — add handlers + tables for `PositionLiquidated` (→ `liquidations`) and
   `DebtSocialized` / insurance-fund + backstop-vault balance snapshots (→ a
   `protocol_stats` time series). Roll up daily aggregates (volume, trade count,
   liquidation count/notional, bad debt) into a `daily_stats` table for cheap charting, or
   expose GraphQL aggregations over the existing buckets.
2. **Backend** — analytics endpoints, e.g. `GET /stats/overview` (cumulative totals),
   `GET /stats/volume?interval=1d&range=90d` (daily volume series),
   `GET /stats/trades`, `GET /stats/liquidations`, `GET /stats/bad-debt`. Cache (30–60s).
   These read the indexer buckets/new tables and sum across markets.
3. **Frontend** — a `Dashboard` / `Analytics` page with chart components (the FE already
   vendors **lightweight-charts** + TradingView and uses SWR): daily-volume bars,
   cumulative-volume line, trades line, liquidations bars, bad-debt area, plus headline
   stat cards (total volume, total trades, OI, insurance/backstop balances). Match the
   Extended.exchange layout once the reference link is in hand.

**Open questions (resolve when the Extended.exchange reference link arrives):** exact chart
set + layout; time ranges (24h/7d/30d/all); per-market vs protocol-wide toggle; whether to
precompute `daily_stats` (recommended for performance) vs live-aggregate.

**Phasing:**
- **P1** — Backend `/stats/overview` + `/stats/volume` over existing candle buckets +
  `trades` (total volume, daily volume, total trades) → FE stat cards + daily-volume chart.
  Ships fast since the data is already indexed.
- **P2** — Indexer `liquidations` + `protocol_stats` (bad-debt / insurance / backstop) tables
  + handlers; backend `/stats/liquidations` + `/stats/bad-debt`; FE liquidations + bad-debt
  charts.
- **P3** — `daily_stats` rollup for performance; per-market breakdowns; polish to match the
  Extended.exchange reference.

---

## Initiative 1 — Fully Gasless Trading (Session Keys + Relayer Network)

**Goal.** A user signs once to authorize a **session key**; thereafter the front-end/API
hands signed intents to a **relayer**, which submits the on-chain transactions on the
user's behalf and pays gas. The user never holds the gas token and never signs a wallet
popup per action. Support **multiple allowed relayer addresses (~10)** for redundancy,
load-balancing, and censorship-resistance.

**What already exists (build on this, do not re-invent):**
- **EIP-712 signed orders** are already implemented across all three markets:
  `placeOrderBySignature` / `cancelOrderBySignature` on `CLOBRouter`,
  `CLOBPerpetualRouter`, `UnifiedMarginRouter` (and the Monad `CLOBEngine`/`PerpEngine`).
  Per-user monotonic **nonces** + **deadline** for replay protection; domain separator
  includes chain id.
- **BuilderRegistry** (Hyperliquid-style builder codes) — partner/relayer fee plumbing,
  per-builder approval + fee caps, fees deducted at the router level.
- A standalone **relayer service** already runs in production (`marginx-relayer`) and
  submits signed orders.

**Gap / what to build:**
1. **Session-key delegation.** Today a signature must come from the order's `maker`
   (`msg.sender == _user` style checks, Security Rule #1). Add a delegation layer so a
   user can authorize a *session key* (a fresh keypair held by the front-end) to sign on
   their behalf, scoped by:
   - expiry (e.g. 24h / 7d),
   - allowed actions (place / cancel / modify; spot / perp / lending),
   - allowed markets,
   - optional notional / spend caps,
   - revocable on-chain at any time.
   Implementation options: (a) an on-chain `SessionKeyRegistry` the routers consult when
   verifying a signature whose signer ≠ maker; (b) ERC-4337 account abstraction with
   session-key validation modules; (c) ERC-7710/7715 delegation. Lean toward (a) first —
   it composes with the existing EIP-712 path with the least surface area.
2. **Relayer allowlist (multi-relayer).** An on-chain `RelayerRegistry` (owner-managed)
   holding up to N (~10) authorized relayer addresses. Routers accept a relayed submission
   only from an allowlisted relayer. Off-chain: a relayer pool with health checks,
   round-robin / least-loaded dispatch, nonce coordination per user, and gas funding.
3. **Gas accounting.** Decide who ultimately pays: protocol-subsidized, deducted from the
   user's collateral balance at settlement (BalanceManager debit), or paid by a builder in
   exchange for builder fees. The BuilderRegistry fee rails can fund relayer gas.

**Open questions:** session-key UX on first login (one signature to register the key);
key storage (the front-end already creates a signing key — extend that); how revocation
propagates to in-flight relayed txs; rate-limiting per session key to bound abuse.

**Phasing:**
- **P1** — `SessionKeyRegistry` + router signature path accepts session-key signatures
  (signer ≠ maker, validated against registry scope). Reuse existing nonces/deadline.
- **P2** — `RelayerRegistry` (≤10 allowlisted relayers) + relayer-pool service (dispatch,
  nonce mgmt, gas funding, failover).
- **P3** — Gas-cost settlement (BalanceManager debit or builder-funded) + spend caps.
- **P4** — Optional migration to ERC-4337 smart accounts if broader AA is desired.

---

## Initiative 2 — HLP-Style Protocol Liquidity Vault

**Goal.** A community-funded vault (à la **Hyperliquid HLP** / **Extended.exchange** vaults)
that provides protocol-owned liquidity, **takes the other side of trades**, and is a
**first-class participant in the liquidation market** (absorbs liquidated positions, runs
ADL-style takeovers), distributing the resulting PnL + fees to depositors.

**Study targets (do the research before designing):**
- **Hyperliquid HLP** — single vault that market-makes, backstops liquidations, and earns
  fees + liquidation PnL; depositors share PnL pro-rata; transparent on-chain accounting.
  Note its liquidation flow: positions that can't be closed on-book are taken over by HLP.
- **Extended.exchange** vault mechanics — deposit/withdraw, profit share, risk controls,
  liquidation participation.
- Compare to GMX GLP and dYdX MegaVault for contrast.

**What already exists (consolidate, don't fragment):**
- **`MarketMakingVault`** — an ERC-4626 vault for automated market making (+ `VaultGauge`
  rewards).
- **`BackstopVault`** — already absorbs liquidation residual / socializes bad debt
  (`updateVaultPnL`, `totalSocializedDebt`, ADL trigger ratio).
- **`InsuranceFund`** — captures liquidation penalties + a fee pool; covers funding
  shortfalls.
- **ADL engine** in `PositionHandler` (`_triggerADL`, `ADLExecuted`) — force-reduces
  profitable counterparties when insurance/backstop are exhausted.

**Gap / what to build:** an **HLP vault** that *unifies* the MM + backstop + liquidation-
counterparty roles into one depositor-owned vault:
- ERC-4626 deposits; share price = NAV (collateral + unrealized PnL of vault positions).
- Vault is registered as an authorized perp adapter / liquidation counterparty so the
  liquidation flow can hand it bankrupt positions at the bankruptcy price (instead of, or
  ahead of, socializing via BackstopVault).
- Vault runs (or co-runs) market making across markets (extend `MarketMakingVault`).
- Risk controls: max utilization vs vault size (BackstopVault already has `MAX_UTILIZATION`
  = 80%), per-market exposure caps, withdrawal queue / lockup, performance fee
  (BackstopVault has a 10% perf fee precedent).

**Open questions:** one global vault vs per-market vaults (Hyperliquid = one HLP +
permissionless user vaults); how HLP interacts with the existing BackstopVault/InsuranceFund
waterfall (likely HLP sits *above* socialization: HLP absorbs first, backstop/insurance only
on HLP insolvency); depositor liquidity risk during mass-liquidation events.

**Phasing:**
- **P1** — Research memo: HLP vs Extended vs GLP, mapped to our existing
  BackstopVault/InsuranceFund/MarketMakingVault. Decide unify-vs-extend.
- **P2** — `HLPVault` (ERC-4626) as a registered liquidation counterparty; route
  liquidation takeovers to it before socialization. Measure with the liquidation E2E suite.
- **P3** — HLP as active market maker (absorb `MarketMakingVault`), gauge/rewards, perf fee.
- **P4** — Permissionless user-created vaults (leader/follower), à la Hyperliquid.

---

## Initiative 3 — Auto-Borrow on Insufficient Collateral (Just-In-Time Margin)

**Goal.** When a user attempts an action (open perp, place spot order, withdraw) but lacks
sufficient USDC/collateral, the system **automatically borrows** the shortfall from the
lending market so the action succeeds, rather than reverting. The borrow is opened against
the user's portfolio margin and unwound when they repay or deposit.

**What already exists (build on this):**
- Full **lending system**: `LendingOrderBook` (price = interest rate), `LoanManager`
  (fixed-rate/fixed-term loans), `AutoLender` (keeper auto-lends idle balances),
  `LendingLooper` (leveraged lend-borrow loops with leverage-cap pre-checks).
- **Unified Margin**: `UnifiedMarginAccount` already unifies spot + lending + perp PnL into
  one portfolio-margin calc with shock pricing (Quantum Risk Engine), per-account leverage
  caps, per-borrower concentration caps, real-time interest accrual.
- `LiquidationEngine` already force-repays borrower positions during portfolio liquidation.

**Gap / what to build:**
1. **JIT-borrow hook in the action path.** In `UnifiedMarginRouter` (and perp open flow),
   when the collateral check fails by `shortfall`, attempt `borrow(shortfall)` against the
   account's available margin *before* reverting. Respect the QRE post-borrow health check
   (the action + the new loan must leave the account solvent) and the existing concentration
   / utilization / leverage caps.
2. **Borrow source & pricing.** Borrow at the best available `LendingOrderBook` ask rate (or
   an `AutoLender`-backed pool for guaranteed liquidity). Decide max auto-borrow APR the user
   tolerates (a slippage-style cap), and what happens if no lending liquidity exists (revert
   with a clear reason, or partial fill).
3. **Unwind policy.** Auto-repay from incoming deposits / realized PnL; surface the
   outstanding auto-borrow + its accruing interest in the account API so the user sees it.

**Open questions:** opt-in vs default-on (probably opt-in per account with a max-borrow
cap); interaction with the 8-hour minimum interest (avoid dust-loan spam from tiny
shortfalls — batch or set a minimum auto-borrow size); ordering vs the JIT collateral
top-up that market-maker bots already do (wrap native → deposit).

**Phasing:**
- **P1** — `borrow()` integrated into `UnifiedMarginRouter` deposit/open path behind an
  account flag + max-borrow cap, gated by post-action QRE health.
- **P2** — Best-rate routing across `LendingOrderBook` + `AutoLender` liquidity; APR cap.
- **P3** — Auto-repay-on-deposit/PnL + full API surfacing of outstanding JIT borrows.

---

## Initiative 4 — Unified Market-Making Engine in the SDK

**Goal.** Collapse the fragmented market-making code into **one config-driven engine that
handles both spot and perp**, shipped as part of the SDK. Today it is split across **two
repos and two languages**, which makes operations error-prone:
- Perp MM = TypeScript (`perp-market-maker/index.ts`)
- Spot MM = Rust (`clobdex-rust-sdk/examples/market_maker`)
- plus a stray TS spot bot (`perp-market-maker/spot-trader-bot.ts`) and Rust perp paths.

Each re-implements the same concerns: deployment-manifest loading, inventory/funding
(perp wraps native→collateral; spot mints base + wraps quote + deposits to BM), gas-reserve
management, and the quoting loop (oracle mid → N levels → place/cancel). Per-market launcher
shell scripts (`run-mm-*.sh`) multiply the surface.

**Design sketch.** A single engine, parameterized by `market_type: spot|perp`, `symbol`,
`sizePerLevel`, `spread`, `levels`, `leverage`/`marginMode` (perp), `cycleSecs`. It reuses
the SDK's typed contract clients + deployment loader, with pluggable modules:
- **Funding/inventory** — one module that knows: perp → wrap native→collateral→BM; spot →
  mint/acquire base + wrap quote→BM; both keep a gas reserve. (Mint authority: the deployer
  is the mock minter on Arc; quote USDC=WNATIVE is wrap-only.)
- **Quoting** — shared oracle-mid → ladder → place/cancel, with market-type-specific order
  params (perp openPosition vs spot router order).
- **Run model** — one binary, N processes via env (`MARKET=BTC-PERP` / `BTC-USDC` / …);
  drop the per-bot launcher scripts in favor of a single entrypoint + env.

**Recommendation: build it in Rust in `clobdex-rust-sdk`** as a first-class example/binary
(or a small `market-maker` crate). Rationale: Rust is faster (repo memory: Rust view calls
~2× TS), the spot MM is already Rust, the TS perp quoting logic ports cleanly, and shipping
it in the SDK means integrators get a reference MM too. Retire `perp-market-maker/` (TS bots)
and the stray spot bot once parity is verified. Keep a thin TS wrapper in `clobdex-ts-sdk`
only if integrators specifically need a JS MM.

**Open questions:** whether to keep ANY TS MM for integrator ergonomics; how to express the
markets×params fleet (a single `markets.json` the engine iterates vs one process per market);
shared inventory/risk caps across a fleet of co-located MM processes.

**Phasing:**
- **P1** — Extract the shared funding + quoting modules in `clobdex-rust-sdk`; make the
  existing Rust spot `market_maker` drive perp too via `MARKET_TYPE`.
- **P2** — Port the TS perp MM's logic/params, verify spot+perp parity on Arc, cut the live
  bots over to the unified binary, retire `perp-market-maker/`.
- **P3** — Fleet config (`markets.json`) + a single supervisor; optional thin TS wrapper.

## Cross-cutting notes
- All three lean on infrastructure that already exists (EIP-712 gasless, BuilderRegistry,
  BackstopVault/InsuranceFund/ADL, the full lending + unified-margin stack) — the work is
  primarily **integration + a few new registries/vaults**, not green-field.
- Any contract change follows the **Mandatory Post-Change Workflow** in `CLAUDE.md`
  (sizes < 24KB / 128KB Monad, full tests, fuzz, Pashov + Nemesis audits, Monad/non-Monad
  parity) before shipping.
- Sequencing suggestion: **Initiative 0 (analytics dashboard)** is the IMMEDIATE near-term
  deliverable (data is mostly already indexed) → **Initiative 1 (gasless)** (best UX
  leverage, lowest contract risk, infra mostly present) → **Initiative 3 (auto-borrow)**
  (high user value, lending stack already built) → **Initiative 2 (HLP)** (largest design +
  capital + risk surface; needs the research memo first).
