> ## 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.

# Before you start

> Wallet, network, demo tokens, and an eligible in-range v3 position — plus the optional backends and the one mental model that makes the app honest: pending is not error.

The Inflexion dApp is **live on Arbitrum Sepolia (chainId 421614)** against the fresh full redeploy of **2026-06-05**. This page is everything you need before you open a door: a wallet on the right network, the demo tokens, a v3 position that is actually eligible to hedge, and — most importantly — the one piece of mental model that explains why so much of the UI says "pending" without being broken.

If you only read one thing, read [Pending is not error](#pending-is-not-error). It is the trust signal the whole product is built around.

<Note>
  Three of the six dApp pages **write** to the chain — [Protect](/app/protect) (LP), [Earn](/app/earn) (depositor), and [Underwrite](/app/underwrite) (MM) — and need a connected wallet. Two are **read-only** and need no wallet at all: the [markets browser](/app/markets) and the [data-moat showcase](/app/data). The [dashboard](/app/dashboard) reads for everyone and writes only when you act.
</Note>

## What you need

<CardGroup cols={2}>
  <Card title="A wallet on Arbitrum Sepolia" icon="wallet">
    chainId `421614`. RainbowKit + wagmi + viem. Reads work immediately; writes are gated behind a `ConnectGate`.
  </Card>

  <Card title="Demo dUSDC + dWETH" icon="coins">
    `dUSDC` (6-dec numéraire — premiums and collateral) and `dWETH` (18-dec demo volatile token). Protocol-owned mocks, not Circle's testnet tokens.
  </Card>

  <Card title="(To protect) an in-range v3 NFT" icon="shield-halved">
    A Uniswap v3 position on the seeded dWETH/dUSDC pool (fee 500) that is currently **in range** ($P_a \le P_0 \le P_b$). Out-of-range is rejected at creation.
  </Card>

  <Card title="The backends" icon="plug">
    The Path-B engine and the REST API power the MM rail and history — both hosted at `inflexion-backend.onrender.com`. If a backing is absent the app degrades honestly — it never crashes.
  </Card>
</CardGroup>

## Step 1 — wallet and network

Connect any EVM wallet on **Arbitrum Sepolia (chainId 421614)**. The frontend stack is RainbowKit + wagmi + viem.

Every dApp page gates its **write** actions behind a `ConnectGate`; **reads run immediately**, with or without a wallet. Concretely, on `/protect` the gate copy is *"Connect a wallet on Arbitrum Sepolia to view your positions and buy protection"* — but the markets browser, the data showcase, and the premium preview math will already be running before you click connect.

<Steps>
  <Step title="Switch your wallet to Arbitrum Sepolia">
    chainId `421614`. If your wallet doesn't have it, add it with RPC `https://sepolia-rollup.arbitrum.io/rpc` and chainId `421614`.
  </Step>

  <Step title="Get a little Sepolia ETH for gas">
    Bridge or faucet a small amount of Arbitrum Sepolia ETH. Gas on the L2 testnet is negligible, but every write (approve, deposit, buy, settle) is a transaction.
  </Step>

  <Step title="Connect">
    Click connect. From here, writes are unlocked; reads were live the whole time.
  </Step>
</Steps>

<Warning>
  **Limit:** if `NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID` is unset, WalletConnect itself is non-functional.

  **Why:** WalletConnect needs a project id to broker the relay; the app ships a placeholder so it still **builds** without one.

  **Mitigation:** use an injected wallet (e.g. a browser extension) which needs no WalletConnect id, or set `NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID` to a real id. See [env vars](/reference/env-vars).
</Warning>

## Step 2 — get demo tokens

Inflexion runs on its own **demo mocks**, not Circle's testnet stablecoin. You need two:

| Token | Decimals | Role | Notes |
| - | - | - | - |
| **dUSDC** | 6 | The numéraire — pays premiums, posts collateral | `1 dUSDC = 1_000_000n` raw. Every premium, collateral amount, `V0`, and MaxIL is 6-dec raw. |
| **dWETH** | 18 | The demo volatile token | Oracle-priced via Chainlink ETH/USD. Chainlink feeds are **8 decimals**. |

These are a deliberately **numéraire-correct pair**: the mocks are chosen so `dWETH < dUSDC` by address, which forces `token1 = dUSDC = numéraire` in the seeded pool. That is why they are distinct from Circle's testnet USDC/WETH — the canonical Circle pair would order the wrong way.

<Tip>
  **Where the units bite you.** `dUSDC` is 6-dec, `dWETH` is 18-dec, Chainlink feeds are 8-dec, and ratios (`σ_ref`, loads, regime bands) use WAD = `1e18`. The SDK's `fmtUsd` divides by `1e6`; the oracle price card renders `Number(price) / 1e8`. If a number looks a million-x off, it's almost always a decimals mismatch. See [decimals & units](/reference/decimals-units).
</Tip>

Mint or claim demo `dUSDC` and `dWETH` to the address you'll connect with. The exact mock addresses live in [the deployments registry](/reference/deployments) — never hardcode them. The seeded amounts in the live deployment were sized for the demo lifecycle (a market maker, for instance, deposited 5,000 dUSDC of collateral).

## Step 3 — what makes a v3 position eligible

This step is **only for protecting** ([the LP door](/app/protect)). Depositors and market makers do not need a position; they supply capital.

To have something to hedge, you need a **Uniswap v3 NFT on the seeded dWETH/dUSDC pool** (`0xfE1Eb4D5796a350B13852F822B3E6a9fDbb858a5`, fee 500) that is **currently in range**. Eligibility is not a soft filter — it is enforced at creation.

<AccordionGroup>
  <Accordion title="The in-range gate — Pa ≤ P0 ≤ Pb" icon="ruler-horizontal">
    Inflexion is an [in-range convexity hedge](/concepts/in-range-convexity-hedge), **not** "IL insurance." Entry requires that the current price sit inside the position's range:

    $P_a \le P_0 \le P_b$

    Out-of-range positions are **rejected at creation** — the `/protect` empty-state says exactly this: *"Out-of-range positions are not protectable — entry requires Pa ≤ P0 ≤ Pb"*. The in-range requirement is what makes the payoff a clean convexity hedge with a [load-bearing cap](/concepts/maxil); see [why this matters](/concepts/in-range-convexity-hedge).
  </Accordion>

  <Accordion title="What the position list actually checks" icon="list-check">
    The Protect page calls `lp.listEligiblePositions(owner, { durations: [selectedDuration] })`. It enumerates the owner's NonfungiblePositionManager NFTs and computes geometry and MaxIL per position. Each row shows:

    * the **tokenId** (e.g. `#3218`);
    * an **in-range badge** — teal "in range", amber "out of range", or "oracle degraded" when `inRange` is `undefined`;
    * **V0** (notional), **MaxIL** (the cap, in amber), and **L** (the stored liquidity) when priceable; otherwise a degraded reason.

    If you have no eligible positions, the empty-state explains the in-range gate rather than showing nothing.
  </Accordion>

  <Accordion title="The seeded demo LP — tokenId 3218" icon="seedling">
    The deploy seeded a **\~\$100k unprotected demo LP, `tokenId 3218`**, on the fee-500 dWETH/dUSDC pool. It powers the premium previews and the *illustrative* pricing on [Underwrite](/app/underwrite). You don't own it — mint your own in-range position to actually buy protection — but it's the reference geometry the docs and the app quote against.
  </Accordion>
</AccordionGroup>

<Note>
  **MaxIL travels with the position, not with the protection price.** MaxIL is pure geometry, frozen at creation, and L-independent in the fair-rate sense — which is exactly what makes positions **fungible** to an underwriter. That is why an MM quote is [per-market, never per-NFT](/protocol/path-b-mm). You'll see MaxIL on every position row before you ever pick a market.
</Note>

## Step 4 — the backends

The protocol's core flows run on **RPC alone**. Two further services extend it — both **hosted as one combined backend at `https://inflexion-backend.onrender.com`** (REST API at `/`, engine at `/engine`). If a backing is absent the app degrades to exactly what RPC can serve — it does not error.

| Service | Env var | What it adds | If unset |
| - | - | - | - |
| **Path-B engine** (MM quote relay) | `NEXT_PUBLIC_ENGINE_URL` | The MM rail — firm signed quotes that can beat the pool | Path B unavailable → `/protect` previews **Path A only**, `premiumB` undefined; `/underwrite` signs but **cannot publish** |
| **Public REST API** (history) | `NEXT_PUBLIC_API_URL` | Historical and aggregate surfaces, served live from the subgraph | DataClient history surfaces return `{ available: false }` and render a typed pending state |
| **RPC** | `NEXT_PUBLIC_RPC_URL` | Everything — the transport for all reads/writes | No RPC; all reads fail at the transport layer |

RPC is **not** optional — it is the floor the whole app stands on. The engine and the API are the extensions. On the free hosting tier the combined backend sleeps after \~15 min idle, so the first request after a lull may cold-start.

<Warning>
  **Limit:** without `NEXT_PUBLIC_ENGINE_URL`, the Path-B market-maker rail is dark — LPs see no competing MM quote and MMs can sign but not publish.

  **Why:** Path B is an off-chain quote relay by design. The engine matches firm EIP-712 quotes to LP demand; without it there is simply nowhere for a signed quote to go.

  **Mitigation:** the app falls back to **Path A, the always-on signature-free pool** — [`createSwapRouted`](/protocol/routing) routes to the cheaper rail and **never reverts on a missing or bad MM quote**, it silently uses the pool. And on `/underwrite`, when the engine URL is unset the page renders the **exact wire envelope** the MM would have published, so the signing flow is still fully demonstrable.
</Warning>

## What is live today

Here is the split between what runs **right now over RPC** and what is served live from the subgraph via the hosted API.

<Tabs>
  <Tab title="Live now (RPC)">
    * Premium preview and the payoff-with-cap chart
    * Buy and settle on **Path A** (the cvAMM pool)
    * Vault deposit / withdraw (depositor)
    * Market pricing and the current **clearing-load surface**
    * σ\_ref (the reference vol) and the regime badge
    * The book (on-chain swap scan) and **coarse** fills
  </Tab>

  <Tab title="Live via the subgraph">
    * Per-market history and volume
    * NAV history
    * The time-series [data-moat signals](/concepts/data-moat) (Signals 2–5)
    * Precise MM fill attribution (the `QuoteFilled` join)

    The subgraph is deployed and indexing, so these structures are live now — served through the hosted API. The dataset itself is still young, so the *dynamics* mature with MM competition and volume.
  </Tab>
</Tabs>

## Pending is not error

This is the most important thing to internalize before you use the app — and the design principle the whole UI is built around.

**The subgraph is deployed and indexing.** The rich on-chain events (`SwapPriced`, `QuoteFilled`, and the lifecycle events) have been emitted on-chain since deploy block `274081134`, and the indexer has backfilled them — so historical, aggregate, and time-series surfaces are now served live through the hosted API. The graceful-degradation property remains a *design property*: if a backing (subgraph URL, RPC, or a telemetry sink) is absent, the affected surface returns a typed pending body rather than throwing.

What it does **not** do is throw, freeze, or fake a number. Every such surface degrades into a typed, honest state:

<Steps>
  <Step title="Reads return a typed envelope, never a throw">
    Any read needing a reverting oracle, an absent rich event, or an unconfigured subgraph backing returns a typed `{ available: false }` / `{ priceable: false }` envelope and renders a calm *pending* / *degraded* state — **never an error**.
  </Step>

  <Step title="The pending note names its route">
    A `PendingNote` prints the reason and, where applicable, the **exact API route + query** the surface is served from. It is a promise, not a placeholder.
  </Step>

  <Step title="Writes degrade at click-time, not at construction">
    With no `walletClient`, LP/MM writes throw a clear error only **when you click** (not when the SDK is built); the `DepositorClient` returns `WriteResult { status: 'deferred-no-wallet' }` so an external signer can take the unsigned tx.
  </Step>

  <Step title="Live-but-degraded oracle states are honest too">
    If the live oracle reverts (stale feed / sequencer down), a position is shown as *not priceable now* — the protection still exists and becomes quotable when the oracle recovers, and Buy is disabled rather than producing a wrong number.
  </Step>
</Steps>

<Info>
  **Why it's built this way.** Showing fabricated history looks polished and is dishonest. Crashing on a missing backend looks broken. Inflexion does neither: a missing data source becomes a *typed, self-describing pending state* that tells you precisely what is missing and where it will come from. Treating "pending" as a first-class, honest state — not a bug and not a fake number — is itself the trust signal.
</Info>

<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>

## A few cross-cutting things to expect

These show up on every write page, so it's worth knowing them up front.

<AccordionGroup>
  <Accordion title="Three different approval spenders (the recurring gotcha)" icon="key">
    Approvals do **not** all go to the same contract:

    * **LP premium** → spender is **InflexionCore**
    * **Depositor deposit** → spender is the **ConvexityVault** (not Core)
    * **MM collateral** → spender is the **UnderwriterVault**

    These are three distinct spenders. The Protect and Earn flows auto-approve for you; the MM collateral flow is a direct two-tx approve+deposit.
  </Accordion>

  <Accordion title="Transaction states" icon="spinner">
    Every write drives its button through `signing → pending → success / error` via `useTx`, waits for the receipt, and trims viem's verbose revert dumps to the first line so errors are readable.
  </Accordion>

  <Accordion title="Addresses always come from the registry" icon="address-book">
    The app never hardcodes contract addresses — they load from the on-chain address registry via `@inflexion/sdk`. The canonical table:

    **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.
  </Accordion>
</AccordionGroup>

## The two separate guarantees — keep them apart

Before you put any capital in, internalize that Inflexion makes **two distinct claims** that are never merged.

<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>

If you are an **LP** buying protection, Claim A is yours. If you are a **depositor or market maker** supplying capital, Claim B is yours — your capital is at risk; the no-bad-debt guarantee is for the LP you underwrite, not for you.

## Where to go next

You're set up. Pick your door.

<CardGroup cols={2}>
  <Card title="Protect an LP position" icon="shield-halved" href="/app/protect">
    Buy in-range IL protection on your v3 NFT. LP / claim A.
  </Card>

  <Card title="Earn in the cvAMM" icon="piggy-bank" href="/app/earn">
    Deposit into the pooled vault — senior or junior tranche. Depositor / claim B.
  </Card>

  <Card title="Underwrite as a market maker" icon="gavel" href="/app/underwrite">
    Post collateral and stream firm per-market signed quotes. MM / claim B.
  </Card>

  <Card title="Browse markets (no wallet)" icon="table-cells" href="/app/markets">
    The 9 markets with live clearing load — fully live over RPC.
  </Card>

  <Card title="The data moat (no wallet)" icon="chart-line" href="/app/data">
    The first public view into the LP volatility-risk premium.
  </Card>

  <Card title="Status & caveats" icon="clipboard-list" href="/reference/status-caveats">
    The full honest ledger of what's live, pending, and why.
  </Card>
</CardGroup>


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