Skip to main content
This page is a task cookbook. Each recipe is a short, runnable snippet pulled from the per-surface worked examples. Nothing here re-implements protocol math: the fair-value Φ-sum is always read on-chain from the Stylus FairValueOracle, and only the deterministic load stack is mirrored client-side via the parity-locked cvamm TS port. Every recipe degrades gracefully — reads return a typed envelope rather than throwing, and writes degrade rather than crash at construction.
All recipes assume a single sdk built once with createInflexionSdk. No contract address is ever passed in — every address loads from the on-chain address registry. For the live addresses, see the deployments reference. Network: Arbitrum Sepolia · chainId 421614 · deploy block 274081134 (subgraph startBlock) · deployed 2026-06-05

Core protocol

Stylus & libraries

Oracles

Uniswap

Demo tokens / pool / LP

Lifecycle swaps

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.
Units are load-bearing. dUSDC is the numéraire at 6 decimals — every premium, collateral, V0, and maxIL figure is a 6-dec raw bigint (1 dUSDC = 1_000_000n). dWETH is 18 decimals, Chainlink feeds are 8, and ratios (aWad, bWad, σ_ref, load components) are WAD = 1e18. See decimals & units.

Recipe 1 — Read the live load surface

The price-to-beat: the current pool clearing load across a set of markets. This is the one DataClient method that hits live RPC — it fans the same read set MM pricing uses (one shared loadParams + inventory, a per-market markets multicall, then a per-market fairPremium multicall) and finishes the load stack with the TS port. It works now, with no subgraph.
The load % is geometry-independent — only the dollar fairPremium/poolPremium scale with a/b/maxIL, so passing geometry is optional and a neutral reference geometry is used when omitted. To read the same surface with no wallet and no RPC key, hit the public API instead: GET /pool/load-surface?marketIds=….
This is the live half of Signal 1. The Path-A load is the mechanical baseline, never sold as a behavioral signal — see circular vs behavioral.

Recipe 2 — Preview, then buy protection (routed best-of)

The two-step LP flow: price it with previewPremium (Path-A pool + the best engine MM quote, both capped at MaxIL), then commit with buyProtection. With no quote/signature, buyProtection fires createSwapRouted, which gives the LP the cheaper of pool vs MM on-chain and falls back to the pool on a bad MM quote — it never reverts on a bad quote.
1

Price it

previewPremium reads FairValueOracle.fairPremium (never re-implemented), finishes the load stack via the TS port, and best-effort fetches the cheapest live MM quote from the engine. An unreachable engine simply leaves premiumB undefined and routes Path A.
2

Set the slippage guard

maxPremium is the LP’s slippage guard (numéraire raw, 6-dec). The on-chain create reverts if the routed premium would exceed it. Round up.
3

Buy (routed)

Default approvals send two txs before the create call — NPM approve(core, tokenId) and dUSDC approve(core, maxPremium) — the spender is InflexionCore.
4

Settle after expiry

settle recovers the expiry from the swap, walks Chainlink rounds to find the bracketing round (or accepts a hintRoundId), and calls Core.settle. The protocol pays the LP min(realized_IL, MaxIL) from the chosen underwriter’s collateral.
Omit quote/signature. A missing quote uses the EMPTY_QUOTE sentinel (mm == address(0)) so the router falls back to the pool.
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.
Entry requires Pa ≤ P0 ≤ Pb — out-of-range positions are rejected at creation by the inRange gate in resolveGeometry. This is an in-range convexity hedge, not “IL insurance”.

Recipe 3 — Deposit to a tranche

Underwrite the always-on cvAMM pool (Path A) by depositing dUSDC into the junior (first-loss) or senior tranche. The deposit spender is the ConvexityVault, not Core.
Withdraws are cooldown-gated and the junior tranche cannot drain below the locked amount.
  • Limit: withdraw can return status:'error' with a JuniorBelowLocked revert.
  • Why: the on-chain totalLocked ≤ juniorAssets junior-first waterfall must hold so senior protection is never broken.
  • Mitigation: the SDK surfaces the revert as a typed error WriteResult, not a thrown exception — wait for active swaps to settle (freeing locked collateral) and retry, or withdraw a smaller amount.
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.
The junior tranche is first-loss and captures most of the premium; the senior tranche is structurally protected from underwriting loss only — not from a systemic tail. See the tranche waterfall.

Recipe 4 — Stream, sign, and publish an MM quote

The Path-B market-maker loop. A quote is per-market (a load + a MaxIL-ratio band + capacity), never per-NFT — the SignedQuote carries no tokenId. The MM streams the geometry-free pool load to beat, builds a quote that undercuts it, signs it (EIP-712), and publishes it to the engine.
1

Read the pool load to beat

getPoolLoadToBeat is geometry-free — it needs no position. It returns the pure pool floor an MM must undercut, with the baseLoad/util/disp decomposition.
2

Build the per-market quote

The 13 fields must match InflexionCore.SIGNED_QUOTE_TYPEHASH exactly or createSwap/createSwapRouted rejects the signature. quotePrice, maxNotionalV0, validUntil, nonce are bigint; the *Bps/model fields are plain number.
3

Sign (enforces I10 + below-pool) and publish

mm.signQuote delegates to the engine signer (never re-implemented) and enforces two guards before returning: I10 (loadBps ≤ loadParams.maxLoadBps) and below-pool (loadBps < live pool load) — else it throws MmQuoteError.
Publish over WebSocket — { type: 'quote', quote: <QuoteWire>, signature } — or via the browser-friendly POST /quote. The engine verifies the signature + a light freshness gate, stores the cheapest-per-market candidate, and logs winners and losers to COMPETITION_LOG.
MM collateral is a separate flow — not part of signQuote.
  • Limit: signing a quote does not post collateral; an unfunded MM’s quote cannot be filled.
  • Why: collateral lives in the UnderwriterVault, locked at MaxIL on a Path-B fill to pay the LP at settlement.
  • Mitigation: approve + deposit dUSDC to the UnderwriterVault before quoting, and read it with mm.getMmCollateral(mm) → { deposited, locked, available }.
This is the no-last-look design: firm GTD quotes with a tiny TTL + an oracle-anchored band. See the Path-B market-maker rail and quote signing.

Recipe 5 — Read pool NAV

Pool NAV is a DataClient surface split into a live composite (current vault state) and a history series. The live composite reuses the depositor getVaultState and works now; the per-tranche NAV time series is subgraph-backed and served live from the subgraph via the hosted API.
NAV history is live. Both getNavHistory and the API GET /pool/nav-history return data, served live from the deployed subgraph via the hosted API — the subgraph indexes on-chain history from the redeploy block. The live composite (getVaultState / GET /pool) returns current NAV alongside it. If SUBGRAPH_URL were unset, the history surface would degrade to a typed pending body (embedding the route + query) rather than erroring.
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.

Recipe 6 — Consume a moat signal

The data moat exposes five non-circular behavioral signals. One — Signal 4 (demand skew) — is intrinsically split: its latent half (LPs who priced but did not buy) is off-chain engine telemetry that is LIVE now, while its realized half (on-chain fills) is subgraph-backed and also live (served from the deployed subgraph via the API). Putting unfilled interest on-chain would break invariant I7, so the latent half can only live in telemetry.
The five signals — clearing-load surface, pool-vs-MM spread + win-rate, convexity term structure, demand skew, and net gamma — are all behavioral, measured against the transparent mechanical baseline, never derived from it. Inverting fairRate to recover an “implied vol” is deliberately dropped as circular — it would recover nothing but our own published σ_ref and load stack. See circular vs behavioral for the rigor.
Two halves of the moat are unreconstructable retroactively — capture them from day one.
  • Limit: the latent half of Signal 4 and the dynamic half of Signal 2 never reach the chain.
  • Why: invariant I7 guarantees an unchosen quote touches no nonce/capacity, so a previewed-but-unbought LP interest and a losing/withdrawn MM quote leave no on-chain trace — and the data is gone forever if not logged at the time.
  • Mitigation: set DEMAND_LOG and COMPETITION_LOG on the engine from the first deploy; the SDK previewPremium ping (PII-free, coarse buckets only) and every GET /quote feed them now.
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.

Degradation cheat-sheet

Every recipe above returns one of these typed envelopes rather than throwing:
Live today, no subgraph needed: premium preview, current load surface, σ_ref, market pricing, vault state, protection status, position geometry, on-chain book scan, coarse fill watching, and the off-chain telemetry halves (Signals 2 & 4 dynamic/latent). Subgraph-backed and now live (served from the deployed subgraph via the hosted API): all DataClient history, precise QuoteFilled fill attribution, full fee accounting, and NAV history. If SUBGRAPH_URL were unset, these would degrade to a typed pending body — render the state, never an error.

SDK overview

The five surfaces, the factory, and the degradation contract in full.

API endpoints

The cached, public, read-only REST facade — every route, query, and backing.

Quote signing

The definitive EIP-712 SignedQuote reference and the on-chain bounds.

The five signals

Each behavioral signal with its exact non-circularity verdict.