> ## Documentation Index
> Fetch the complete documentation index at: https://inflexion.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Access-layer architecture

> The three-layer routing rule — SDK for live reads/writes, subgraph-via-API for history, API for cached public reads — the end-to-end MM → engine → chain → API flow, and why the two off-chain services are deliberately thin.

<Info>
  **Inflexion's access layer is governed by one routing rule and one authority principle.** The rule decides *which surface answers which question*; the authority principle decides *who is allowed to compute the answer*. The chain is the authority for pricing and settlement; the two off-chain services — the **engine** (a Path-B quote relayer) and the **API** (a read-only REST facade) — are deliberately thin convenience and data surfaces that **never settle, match, or hold a wallet**.
</Info>

There are exactly three ways a consumer reaches Inflexion's state, and choosing the wrong one is the most common integration mistake. This page gives you the routing rule, the end-to-end flow that produces the data each layer serves, and the architectural reason each off-chain piece is kept thin.

***

## The three-layer routing rule

The rule is stated verbatim as:

> **Needs to write, or needs the exact price right now → SDK.**
> **Needs history or an aggregate → Subgraph (consumed via the API).**
> **Needs frictionless public access with no wallet and no RPC key → API.**

<CardGroup cols={3}>
  <Card title="SDK" icon="bolt" href="/sdk/overview">
    **Live on-chain reads + all writes.** The only layer that holds a signer and the only one that can answer *"what dollar premium will I be charged on **this** position if I sign in the next block?"* Needs an RPC key; can hold a wallet.
  </Card>

  <Card title="Subgraph (via API)" icon="layer-group" href="/integrate/subgraph">
    **History and aggregates.** Internal infrastructure — nobody queries it directly in production except the API. Indexes the on-chain moat events into the entities the five behavioral signals aggregate over.
  </Card>

  <Card title="API" icon="globe" href="/integrate/api-endpoints">
    **Cached, public, read-only.** No wallet, no RPC key, no signer for the consumer. A thin `node:http` facade composing the subgraph, a small set of live RPC reads (routed *through the SDK*), and the engine's telemetry sinks.
  </Card>
</CardGroup>

### Why three layers and not one

Each layer exists because the other two cannot do its job without giving something up:

| Question | Why the SDK | Why the subgraph-via-API | Why the public API |
| - | - | - | - |
| *Write a transaction* | Only the SDK holds a signer | Read-only | Read-only |
| *Exact dollar premium for **this** position, right now* | Needs a fresh `FairValueOracle` read **+** the position geometry; position-specific | Indexes the past, not the next block | Forwards the SDK's row; cannot derive it |
| *Time series / cross-fill aggregate* | A single client cannot scan history cheaply | Purpose-built indexer | Caches the subgraph result |
| *Public read, no wallet, no RPC key* | Needs an RPC endpoint | Internal infra, GraphQL, unstable to expose | Exactly this — CORS-open, cached, typed-degrading |

<Note>
  **The pricing implementation exists in exactly one place per concern.** The fair rate (the [Φ-sum](/math/fair-value-phi-sum)) is computed only on-chain by the Stylus `FairValueOracle` and read through the SDK. The deterministic [load stack](/math/load-stack) is computed on-chain in pricing and re-evaluated client-side only via the SDK's **parity-locked** [`CvammPricing` TS port](/sdk/cvamm-port) (the deployed library is delegatecall-only, so a direct `eth_call` reverts). **The API never re-derives the fair rate or the load stack** — it forwards the SDK's row. One implementation per concern is what keeps the access layer honest.
</Note>

***

## The two off-chain services

The access layer wraps the on-chain core — `InflexionCore`, the Stylus `FairValueOracle`, the cvAMM `ConvexityVault` — with two small Node/TS services. Both are framework-free (`node:http`), offline-test-friendly, and intentionally thin.

<CardGroup cols={2}>
  <Card title="@inflexion/engine — the Path-B relayer" icon="tower-broadcast" href="/integrate/engine">
    A thin off-chain relayer for the **optional** market-maker rail. Accepts EIP-712 signed quotes over WebSocket, verifies signature + light freshness, serves the cheapest live quote, and captures the two day-one telemetry signals. **Does not match or settle — the chain does.**
  </Card>

  <Card title="@inflexion/api — the public REST facade" icon="server" href="/integrate/api-overview">
    A public, **read-only, cached** facade — no wallet, no signer, no RPC key for consumers. Composes three independently-degrading backings: the subgraph, live RPC reads via the SDK, and the engine's telemetry sinks.
  </Card>
</CardGroup>

### Where the chain stays the authority

Pushing matching or settlement off-chain would reintroduce trust — and would break the no-bad-debt guarantee. So the relayer is structurally incapable of doing either:

* It **cannot compute a dollar premium.** The final premium is *position-specific* and derived **on-chain** at `createSwapRouted` as $\text{FairPremium} \cdot (1 + \text{loadBps})$. The relayer returns the *signed quote + its `loadBps`*, not a dollar figure — it would need the LP's exact geometry and an RPC read of `FairPremium` to do otherwise.
* It applies only a **light, non-authoritative** freshness gate. Its skew window (`maxValiditySkewS = 60s`) is deliberately *looser* than the on-chain validity window of `[5, 15] s`. The chain re-checks everything; the relayer just drops obvious junk so the store stays clean.
* It **holds no wallet and never signs.** It verifies an MM's EIP-712 signature; it never produces one.

<Warning>
  **Limit — the engine is the only place latent demand and lost quotes are ever recorded; if the sinks are not configured from the first deploy, that data is gone forever.**

  * **Why.** Invariant **I7** guarantees an *unchosen* quote touches no nonce and no capacity, so an LP who priced but did not buy, and an MM quote that lost or was withdrawn, leave **no on-chain trace by design**. Putting unfilled interest on-chain would both cost gas and break I7.
  * **Mitigation.** The engine writes two **append-only JSONL** telemetry sinks — `DEMAND_LOG` (Signal 4 latent half) and `COMPETITION_LOG` (Signal 2 dynamic half) — from the very first interaction. The writer is best-effort and **never throws**: a full disk or missing sink never breaks a quote ack, a preview, or a `/quote` request. Set `DEMAND_LOG` and `COMPETITION_LOG` on the engine from deploy day. See [the engine](/integrate/engine) and [telemetry](/moat/telemetry).
</Warning>

### Why Path A needs no engine at all

The engine exists **only** so a sophisticated MM can compete on price against the pool. Path A — the cvAMM pool — is *always-on and signature-free*; a pooled vault underwrites with no relayer in the loop. `createSwapRouted` then hands the LP the cheaper of `{pool, MM quote}`. The engine is **pure upside**: if no MM is connected, [Path A](/protocol/path-a-cvamm) still clears every position, and an expired, over-band, or under-collateralized MM quote causes routing to fall back to the pool, **never revert**. See [routing](/protocol/routing).

***

## End-to-end: MM → engine → chain → API

This is the flow that produces the state each layer serves. It is the canonical sequence followed end to end.

<Steps>
  <Step title="MM streams a firm quote to the engine (WebSocket)">
    The market maker streams `{ type: 'quote', quote, signature }` over WS. The relayer verifies the EIP-712 signature + the light freshness gate, stores it as the cheapest-per-market candidate, and logs it to `COMPETITION_LOG` (a *winner* if accepted, a *loser* if rejected — **both are logged**). The quote is **per-market**, never per-NFT: it carries a `loadBps`, a `[minMaxILRatioBps, maxMaxILRatioBps]` band, and a capacity ceiling, but **no `tokenId`**. This is load-bearing — [MaxIL](/concepts/maxil) makes positions fungible to an underwriter within a market.
  </Step>

  <Step title="LP previews via the SDK">
    `LpClient.previewPremium` reads the *live* pool-load surface (RPC, or the API's `/pool/load-surface`) and the cheapest MM load from the engine's `GET /quote`, then best-effort POSTs `/telemetry/preview` (logged to `DEMAND_LOG`, `filled: false`). The preview ping carries **only bucketed geometry + marketId** (no PII, no `tokenId`, no addresses).
  </Step>

  <Step title="LP buys on-chain — the chain re-derives everything">
    The LP calls `createSwapRouted` on `InflexionCore`. The chain re-derives `FairPremium` (the [Φ-sum](/math/fair-value-phi-sum) from the Stylus `FairValueOracle`), re-checks the quote's `[5, 15] s` validity window, the [price band](/security/price-pinning) (invariant **I9** / Fork 2), and the bitmap nonce (**I7**), then routes to the cheaper of `{cvAMM pool, MM quote}`. An invalid quote falls back to Path A, **never reverts**. **Only the executed rail mutates nonce, capacity, and the collateral lock.**
  </Step>

  <Step title="Settlement pays the LP from the chosen underwriter">
    `settle()` pays the LP $\min(\text{realized\_IL}, \text{MaxIL})$ trustlessly from the chosen underwriter's collateral. The 2026-06-05 lifecycle demonstrated both rails: Path A (cvAMM, swap #1, premium \$9.70 = 0.58% of MaxIL, payout \$148.64) and Path B (MM beat the pool, swap #2, MM load 1000 bps, payout \$245.66 from MM collateral).
  </Step>

  <Step title="The API exposes the microstructure">
    Live surfaces are served now via RPC (through the SDK); the off-chain telemetry halves are served now from the JSONL sinks; history and aggregate surfaces are served live from the subgraph via the API. The subgraph has indexed the on-chain `SwapPriced` / `QuoteFilled` events from the redeploy block, joining the structural moat halves to the dynamic halves already captured. See [the five signals](/moat/five-signals).
  </Step>
</Steps>

The two on-chain events that the subgraph indexes for the moat both shipped in the 2026-06-05 redeploy and are **live on-chain now**, and the subgraph indexes them live:

```solidity theme={null}
// the mechanical baseline, all three create paths
event SwapPriced(
    uint256 indexed swapId,
    uint8   path,            // 0 = cvAMM pool (A), 1 = MM (B)
    uint256 fairPremium,     // the WAD baseline the load multiplies
    uint256 baseLoadWad, uint256 utilSkewWad, uint256 dispSkewWad,  // pool load decomposition (Path A)
    uint256 totalLoadWad,    // Path A: clamped pool load; Path B: MM loadBps in WAD
    uint256 sigmaRefWad,     // the σ_ref the swap was priced against
    bool    cappedAtMaxIL    // true ⇒ premium hit the cap ⇒ ZERO load info
);

// THE single non-circular load datum (behavioral)
event QuoteFilled(uint256 indexed swapId, address indexed mm, bytes32 indexed quoteId, uint256 nonce, uint16 loadBps);
```

***

## What is intentionally thin — and why

Thinness is a design constraint, not an unfinished state. Each service is kept small so the chain stays the only authority and so both degrade gracefully under absence.

<AccordionGroup>
  <Accordion title="The engine does not match or settle">
    The relayer's entire job is three things: verify + store the latest signed quote per `(market, MM)`, serve the cheapest live quote over `GET /quote`, and capture the two day-one telemetry signals. Matching and settlement are the chain's — pushing them off-chain would reintroduce trust and break the no-bad-debt guarantee. The relayer returns a *load*, not a dollar premium, because the premium is position-specific and computed on-chain.
  </Accordion>

  <Accordion title="The API never re-derives pricing — it forwards the SDK">
    Live RPC reads in the API reuse `@inflexion/sdk` `DataClient.getCurrentLoadSurface` and `DepositorClient.getVaultState`. The Φ-sum fair rate is computed in exactly one place (the Stylus `FairValueOracle`, surfaced through the SDK); the API only forwards it. This is a hard rule — duplicating the pricing math in the API would create a second source of truth.
  </Accordion>

  <Accordion title="The API has no wallet, no signer, and is GET-only">
    Consumers need no RPC key and no signer. Non-GET requests return `405 { available:false, reason:'method-not-allowed', detail:'read-only API; GET only' }`. The whole stack is fully testable offline — mock subgraph, injected fetch, injected telemetry reader, pre-built SDK clients.
  </Accordion>

  <Accordion title="Engine scope: no auth, no rate-limit, no persistence beyond JSONL">
    The store is in-memory (`marketId → mm → latest quote`) with an optional append-only JSONL log; multi-MM works because the store keys per MM, but there is no auth, no rate-limit, and no persistence beyond the JSONL log. The definitive Stylus ≡ Solidity ≡ off-chain digest cross-check is an integration test added with the SDK. Production hardening (auth, rate-limit, durable store) is a bounded follow-up — the architecture does not change, only the operational envelope.
  </Accordion>
</AccordionGroup>

### Everything degrades to a typed value, never an exception

Both services treat absence as a first-class, typed state — not an error path. This is what lets a UI render a "pending" or "degraded" panel instead of catching an exception.

* **The API response envelope is a discriminated union** that **never throws**:

```jsonc theme={null}
// Available
{ "available": true, /* ...payload */ }

// Pending (typed degraded) — returned only if a backing is absent (e.g. SUBGRAPH_URL unset)
{ "available": false,
  "reason": "subgraph-not-deployed",
  "detail": "no subgraph url configured",
  "query":  "query Markets($first: Int = 100) { markets(...) { id token0 token1 fee ... } }" }
```

* **`PendingReason` is a closed enum**: `subgraph-not-deployed`, `subgraph-unreachable`, `rich-events-pre-redeploy`, `telemetry-sink-absent`, `rpc-unavailable`. Each one names precisely what unblocks the surface.
* **Subgraph-backed routes embed the exact query** so the surface is self-documenting; if a backing is ever absent, the pending body still names precisely what data the route serves. A consumer can read exactly what data appears.
* **A last-resort 500 guard** wraps every handler: a stray bug returns `500 { available:false, reason:'internal' }` rather than crashing the process.

<Note>
  **Live — the subgraph is deployed and indexing, so every history/aggregate (`[SG]`) surface serves real data now via the API.**

  The subgraph is deployed on The Graph Studio (slug `inflexion-arb-sepolia`) and has indexed the on-chain moat events (`SwapPriced` / `QuoteFilled`, both live on-chain) from the redeploy block `274081134` — the subgraph `startBlock`, where the on-chain moat dataset begins. The hosted API composes it alongside the live RPC surfaces (current load surface, vault state, pricing preview) and the telemetry halves (`DEMAND_LOG`, `COMPETITION_LOG`). Each `[SG]` route runs its embedded GraphQL against the subgraph; if `SUBGRAPH_URL` were ever unset, the same route degrades to a typed `{ available:false, reason:'subgraph-not-deployed', query:… }` body rather than erroring. See [status & caveats](/reference/status-caveats) and the [moat state](/moat/state-and-limits).
</Note>

***

## Which layer serves which surface (live status)

A quick map of what is reachable today, by layer. Backing key: **\[RPC]** live via the SDK, **\[SG]** subgraph (deployed and indexing), **\[TEL]** engine telemetry sink.

| Surface | Layer | Backing | Live now? |
| - | - | - | - |
| Premium preview for a position | SDK / API `/pricing/preview` | \[RPC] | **Yes** |
| Current pool-load surface ("price-to-beat") | SDK `getCurrentLoadSurface` / API `/pool/load-surface` | \[RPC] | **Yes** |
| Vault / NAV state (Claim B) | SDK `getVaultState` / API `/pool` | \[RPC] | **Yes** |
| Cheapest live MM quote | Engine `GET /quote` | (engine store) | **Yes** |
| Latent demand (Signal 4 latent half) | API `/data/demand-requests` | \[TEL] | **Yes** (latent half) |
| Quote competition (Signal 2 dynamic half) | API `/data/quote-competition` | \[TEL] | **Yes** |
| Load-surface history, term structure, NAV history | API `/data/*`, `/pool/nav-history` | \[SG] | **Yes** |
| Swaps, MM fills, σ\_ref history | API `/swaps`, `/mm/:addr/fills`, `/sigma/:token/history` | \[SG] | **Yes** |
| Net gamma / supply depth (Signal 5) | API `/data/net-gamma`, `/data/supply-depth` | \[SG] | **Yes** |

<Note>
  **Structures ship from day one; the full DYNAMICS (pool-vs-MM spread as a forward-vol signal) mature with multiple competing MMs and volume. The dataset begins at the single redeploy; the off-chain telemetry halves begin at the first interaction logged.**

  What Inflexion offers today is the **architecture and the first public view** into the microstructure of the DeFi LP volatility-risk premium — not yet a mature dataset:

  * **Structures are present day-one.** All five non-circular behavioral signals are defined and queryable from launch.
  * **Dynamics mature with volume.** The richer signal — the pool-vs-MM spread read as a forward-vol indicator — only sharpens once multiple market makers compete and real flow accumulates.
  * **The dataset begins at the single redeploy**, and the off-chain telemetry halves begin at the first interaction logged. History is served live from the subgraph via the API; if a backing (subgraph URL / RPC / telemetry) is absent, surfaces degrade to a typed `pending` state — never an error.
</Note>

***

## The claims, stated correctly

The access layer carries two **separate, never-merged** standing disclosures. The API attaches Claim A to every payout/swap/MM surface and Claim B to every NAV/yield/pool surface; they are never combined into one statement. LP no-bad-debt (Claim A) and depositor/MM capital risk (Claim B) are distinct claims.

<Warning>
  **LPs are always paid with no bad debt in FULL mode — qualified: capped payoff + solvent USDC + oracle/settlement liveness.**

  The no-bad-debt guarantee is **exact only** under the full clause:

  * **FULL collateralization** — the underwriter has posted exactly `MaxIL` per swap, locked for the life of the position.
  * **Capped payoff** — the payout is `min(realized_IL, MaxIL)`. The cap is load-bearing: it is what makes `payout ≤ collateral` hold by construction.
  * **Solvent USDC** — the collateral numeraire (`dUSDC`) holds its peg and remains redeemable.
  * **Oracle / settlement liveness** — the price oracle stays live and `settle()` runs within the protocol's settlement window.
  * **No rehypothecation breach** — locked collateral stays instantly liquid; it is never routed to utilization-gated venues.

  Stated without these qualifiers, the guarantee is **not** correct.
</Warning>

<Warning>
  **Depositor capital is NOT guaranteed: the junior tranche is first-loss; the senior tranche is structurally protected from underwriting loss only, not systemic tail.**

  Underwriting capital — whether supplied to the pooled cvAMM vault (Path A) or posted directly by a market maker (Path B) — is **at risk**:

  * **Junior tranche — first-loss.** Junior depositors absorb underwriting losses first and buffer the senior tranche.
  * **Senior tranche — protected from underwriting loss, exposed to the systemic tail.** The senior tranche is structurally shielded from ordinary underwriting loss while junior capital buffers, but it still takes the systemic tail once the junior buffer is exhausted.

  No-bad-debt is a guarantee to the **LP being paid** (see the FULL-mode payout clause), **not** a guarantee that depositor or MM capital is preserved.
</Warning>

***

## Where to go next

<CardGroup cols={2}>
  <Card title="The engine" icon="tower-broadcast" href="/integrate/engine">
    The Path-B relayer in depth: the `SignedQuote`, the WS protocol, the freshness gate, and the day-one telemetry sinks.
  </Card>

  <Card title="API overview" icon="server" href="/integrate/api-overview">
    The response envelope, the closed `PendingReason` enum, caching, and graceful degradation.
  </Card>

  <Card title="API endpoints" icon="list" href="/integrate/api-endpoints">
    The full path · query · backing · returns reference for every route.
  </Card>

  <Card title="The subgraph" icon="layer-group" href="/integrate/subgraph">
    The internal indexer: the moat entities, the embedded queries, and the marketId-parity note.
  </Card>

  <Card title="SDK overview" icon="bolt" href="/sdk/overview">
    The typed access layer — the only signer-holding surface, its five clients, and degradation model.
  </Card>

  <Card title="The data moat" icon="chart-line" href="/moat/thesis">
    The five non-circular behavioral signals and how the access layer reaches each one.
  </Card>
</CardGroup>

For the live contract addresses, see the [deployments reference](/reference/deployments).

**Network:** Arbitrum Sepolia · **chainId** `421614` · **deploy block** `274081134` (subgraph startBlock) · **deployed** 2026-06-05

## Core protocol

| Contract | Address | Role |
| - | - | - |
| InflexionCore | `0xC19865cF8403F59B8Eca835833aFEe3Aa8DA4848` | Main entry point — quotes, createSwap, settlement |
| ILVault | `0x9f7615Aca943832977CEf3ac1862fD48B87b7664` | Holds LP premiums and protocol IL accounting |
| UnderwriterVault | `0x4Fb459F3393D206c2b7faD7f0fC9C35a78348D64` | Market-maker (Path B) collateral deposits |
| ConvexityVault | `0xDE2fFeBA2E6A18f3A53D43EC0fCCD299158eC30d` | Pooled cvAMM (Path A) underwriter collateral |
| Treasury | `0x96455C9b00D530BD0629b71B674298440328b1Dd` | Protocol fee recipient (also deployer) |

## Stylus & libraries

| Contract | Address | Role |
| - | - | - |
| FairValueOracle (Stylus) | `0x98a6aa75108b70fc0794bc3b87efe0ae99d5d52c` | Rust/WASM fair-premium pricing (set-once init to live VolOracle) |
| ILMath | `0x7e90362bc6Df9cb5faA13952e07853ab16c77bd2` | Core impermanent-loss math |
| TickMath (library) | `0xbf02bbc82e0fb1a4b9828bb90fc9dd9e97578965` | Tick ↔ sqrtPrice conversions (delegatecall) |
| CvammPricing (library) | `0x4a053d29a55a64172140f9ebbc27c321c0ba2b53` | Path-A pool pricing components (delegatecall) |
| SwapMath (library) | `0xf7be9745b6768d06a18c386c6db5c8cb065ba314` | Swap math helpers (delegatecall) |
| QuoteVerification (library) | `0x74819eed322f3e1a2dc10bb0d3cae50078d90807` | EIP-712 quote signature verification (delegatecall) |

## Oracles

| Contract | Address | Role |
| - | - | - |
| OracleManager | `0x2c18147B6ec75dcb330d9A48B6B96a4d1a8b529b` | Chainlink feed router, staleness & sequencer checks |
| VolOracle | `0xfdEafBB381192FC5337499d041eaead04d565Ed9` | Realized-volatility reference (sigma\_ref) |

## Uniswap

| Contract | Address | Role |
| - | - | - |
| UniswapV3Factory | `0x248AB79Bbb9bC29bB72f7Cd42F17e054Fc40188e` | v3 pool factory |
| NonfungiblePositionManager | `0x6b2937Bde17889EDCf8fbD8dE31C3C2a70Bc4d65` | LP position NFTs |
| SwapRouter02 | `0x101F443B4d1b059569D643917553c771E1b9663E` | Swap routing |
| QuoterV2 | `0x2779a0CC1c3e0E44D2542EC3e79e3864Ae93Ef0B` | Off-chain swap quoting |

## Chainlink feeds

| Contract | Address | Role |
| - | - | - |
| ETH / USD | `0xd30e2101a97dcbAeBCBC04F14C3f624E67A35165` | Price feed (8 dec, \~120s heartbeat) |
| BTC / USD | `0x56a43EB56Da12C0dc1D972ACb089c06a5dEF8e69` | Price feed (8 dec, \~120s heartbeat) |
| ARB / USD | `0xD1092a65338d049DB68D7Be6bD89d17a0929945e` | Price feed (8 dec, 86400s heartbeat) |
| USDC / USD | `0x0153002d20B96532C639313c2d54c3dA09109309` | Price feed (8 dec, 86400s heartbeat) |

## Demo tokens / pool / LP

| Contract | Address | Role |
| - | - | - |
| WETH9 | `0x980B62Da83eFf3D4576C647993b0c1D7faf17c73` | Canonical Arbitrum Sepolia WETH (18 dec) |
| USDC (Circle) | `0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d` | Circle native testnet USDC (6 dec) |
| dWETH (demo) | `0xA8C07E1B245B346c5D1910c5055Efe67bF9E7D1D` | Mock WETH, oracle-priced via Chainlink ETH/USD (18 dec) |
| dUSDC (demo) | `0xB89630Dc6e020ae2A84aE72b7d9EEDBDfb2C544d` | Mock USDC numeraire (6 dec) |
| Demo pool (dWETH/dUSDC, fee 500) | `0xfE1Eb4D5796a350B13852F822B3E6a9fDbb858a5` | Seeded v3 pool, tokenId 3218 \~\$100k unprotected LP |

## Lifecycle swaps

| Contract | Address | Role |
| - | - | - |
| Market maker (demo signer) | `0xe632B215120dD43A719458487bA3e03638fec953` | Path-B underwriter; deposited 5,000 dUSDC, own collateral paid settlement |

Live create→settle lifecycle (2026-06-05, short 300s fee-500 market `0xb8bbd684f213d5833886ade7b531a6949d85522249881a2b5d46a5cc76e439c2`):

* **Path A (cvAMM convexity)** — swapId 1, LP tokenId 3220 · V0 \$270,531.28 · MaxIL \$1,669.24 · premium \$9.70 (0.58% of MaxIL) · settled payout \$148.64 from ConvexityVault.
* **Path B (MM routing)** — swapId 2, LP tokenId 3221 · MM beat cvAMM (\$8.93 vs \$13.80) · MaxIL \$3,215.65 · MM collateral locked \$3,215.65 · settled payout \$245.66 from MM collateral.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.