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

# MaxIL — the cap and the unit of risk

> Why MaxIL is both the load-bearing payout cap and the unit that makes positions fungible to an underwriter — and why the premium is quoted as a percentage of it.

MaxIL is the single most important number in Inflexion. It is the maximum in-range impermanent loss of a specific Uniswap v3 position — **pure geometry, computable at creation, frozen for the life of the swap, and identical across all three durations.** Everything the protocol does — collateralizing the trade, pricing it, and making positions interchangeable to an underwriter — is built on top of it.

MaxIL is **three things at once**:

<CardGroup cols={3}>
  <Card title="(a) The load-bearing cap" icon="shield">
    Payout is `min(realized_IL, MaxIL)`. Locking collateral `= MaxIL` makes `payout ≤ collateral` true *by construction* — the structural core of [no-bad-debt](/concepts/no-bad-debt).
  </Card>

  <Card title="(b) The unit of risk" icon="cubes">
    MaxIL is L-independent (in the fair-rate sense) and frozen at creation, so positions become **fungible** to an underwriter — which is why MM quotes are [per-market, never per-NFT](/concepts/two-rails).
  </Card>

  <Card title="(c) The pricing denominator" icon="percent">
    The premium is quoted as a *percentage of MaxIL*, not of position value. This is what makes the underwriter indifferent to range width and gives the market full depth.
  </Card>
</CardGroup>

<Note>
  The one-line mental model from the math: **MaxIL is pure geometry (the *how much capital*); [`fairRate`](/concepts/fair-value) is pure stochastics (the *how risky*); the load stack is pure inventory state (the *how scarce*). They multiply:**

  $$
  \text{premium} = \text{fairRate} \cdot \text{MaxIL} \cdot (1 + \text{load})
  $$

  MaxIL carries **none** of the vol/time dependence — that all lives in `fairRate`.
</Note>

## What MaxIL is

Let price $P$ be the price of token0 in token1 (e.g. ETH measured in USDC). A position is liquidity $L$ over a tick range $[P_a, P_b]$, opened at $P_0$ with the **in-range requirement $P_a \le P_0 \le P_b$ enforced at creation** (out-of-range entries revert `PositionOutOfRange`). In-range impermanent loss is the gap between just holding the entry basket and what the LP position is actually worth:

$$
\mathrm{IL}(P) = V_{\text{hold}}(P) - V_{\text{lp}}(P)
$$

MaxIL is the **maximum value that gap takes while price stays in range**:

$$
\boxed{\;\text{MaxIL} = \max\big(\mathrm{IL}(P_a),\; \mathrm{IL}(P_b)\big)\;}
$$

`ILMath.computeMaxIL` computes it on-chain. It is **pure geometry** — a function of $(P_a, P_b, L, P_0)$ only, with no vol and no time. See the full IL setup in [the IL formula](/math/il-formula) and the boundary proof in [the MaxIL derivation](/math/maxil-derivation).

### Why the maximum is at a boundary

$\mathrm{IL}(P)$ is **convex on $[P_a, P_b]$**, so it attains its maximum at an endpoint:

* $V_{\text{hold}}(P) = \texttt{amount0\_entry}\cdot P + \texttt{amount1\_entry}$ is **affine** in $P$.
* In range, $V_{\text{lp}}(P) = L\big(2\sqrt{P} - \sqrt{P_a} - P/\sqrt{P_b}\big)$, so $\dfrac{d^2 V_{\text{lp}}}{dP^2} = -\tfrac14 L\, P^{-3/2} < 0$ ⇒ $V_{\text{lp}}$ is **strictly concave**.
* $\mathrm{IL} = \text{affine} - \text{concave} = \text{convex}$, and $\max(0, \mathrm{IL})$ (a pointwise max of convex functions) is convex too.
* A convex function on a compact interval attains its max at an endpoint. ∎

This holds for **any** entry $P_0$ — centered or not. The asymmetry is real and predictable: even for a *ratio*-symmetric range, the convex curve is larger toward the upper boundary, so typically $\text{MaxIL} = \mathrm{IL}(P_b)$. In the canonical fixture $[80, 100, 125]$, $\text{MaxIL} = \mathrm{IL}(P_b{=}125) > \mathrm{IL}(P_a{=}80)$.

***

## (a) MaxIL as the load-bearing cap

The protocol does **not** cover unbounded IL. Above $P_b$ the LP has fully rotated into token1, so $V_{\text{lp}}$ is *constant* while $V_{\text{hold}}$ keeps growing linearly with price — absolute IL is **unbounded beyond the range**. Anything promising to cover that could not be fully collateralized, so it could not be trustless. The protocol therefore covers the **capped** payoff:

$$
\text{covered\_payoff} = \min(\text{realized\_IL},\; \text{MaxIL})
$$

Lock exactly `MaxIL` of collateral at creation, and the no-bad-debt argument becomes a three-line construction:

```text theme={null}
collateral_FULL = MaxIL                            (locked at creation)
covered_payoff  = min(realized_IL, MaxIL) ≤ MaxIL  (by construction of the cap)
∴ payout ≤ collateral = MaxIL                       (no bad debt — invariants I1, I2)
```

This is **orthogonal to the premium and oracle-independent**: it holds for any price path and any (even wrong) $\sigma$. The relevant settle-path invariants are `I1` (`payout ≤ collateral == MaxIL`), `I2` (`payout == min(realized_IL, MaxIL)`), and `I3` (the guarded, never-underflowing subtraction). See [the invariants](/security/invariants) and [the no-bad-debt math](/math/no-bad-debt-math).

<Tip>
  The cap is **the product, not a defect.** At the range boundary the LP has fully rotated into one asset; IL *beyond* that point is *directional* loss (foregone spot upside), not the *impermanent* loss the LP set out to hedge. Capping at MaxIL keeps the product fully collateralized and trustless. This is exactly why Inflexion is an [in-range convexity hedge](/concepts/in-range-convexity-hedge), **NOT "IL insurance."**
</Tip>

The cap is also verified empirically. The heavy calibration run measured the payout fraction `min(IL,MaxIL)/MaxIL` over a ±99% (and widened −6…+6 log-move) grid on every simulated path: `max_payout_frac = 1.000000`, zero exceptions — structurally, independent of any oracle.

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

***

## (b) MaxIL as the unit of risk → positions are fungible

MaxIL is **frozen at creation**, **identical across the three durations (7/30/90d)** for a given position, and **`L`-independent in the fair-rate sense** — `fairRate` depends only on $a = P_a/P_0$, $b = P_b/P_0$, $\sigma$, $T$, not on $L$. Those properties together are what make positions **fungible to an underwriter within a market.**

Because every position in a market reduces, for pricing purposes, to a normalized geometry plus a MaxIL, an underwriter does not need to quote each NFT individually. They express a single view over the whole market — and any position that fits fills against it.

<Warning>
  **MaxIL is a collateral / normalization unit, NOT a risk metric.**

  Two positions with identical MaxIL can carry very different risk — different distance-to-edge, different delta profile, different probability of touching the cap. Both the pool and MMs price $E_Q[\min(\mathrm{IL}, \text{MaxIL})]/\text{MaxIL}$ for the **specific geometry**, not for MaxIL alone. `MaxIL/V0` is a useful monotone *proxy for width* when displaying or filtering positions, but it is **never** the pricing input — the pricing input is the full on-chain geometry, which is public via `positions(tokenId)`. That public geometry dissolves the old adverse-selection story entirely.
</Warning>

### Why this means MM quotes are per-market, never per-NFT

This is the direct mechanical consequence of fungibility. The `SignedQuote` struct carries a `marketId` — `keccak256(token0, token1, fee, durationSeconds)` — and **has no `tokenId` field at all**:

```solidity theme={null}
struct SignedQuote {
    address mm;                 // signer; collateral in UnderwriterVault (or EIP-1271)
    bytes32 marketId;           // keccak(token0, token1, fee, durationSeconds) — PER-MARKET
    uint16  loadBps;            // load over on-chain FairPremium
    uint16  minMaxILRatioBps;   // per-market MaxIL/V0 band lower bound
    uint16  maxMaxILRatioBps;   // per-market MaxIL/V0 band upper bound
    // ... quotePrice, priceBandBps, model, maxNotionalV0, validUntil, quoteId, nonce
    // NOTE: there is NO tokenId.
}
```

An MM streams a single quote — `(load, MaxIL-ratio band, capacity)` — for an entire `marketId`, and **any** LP position in that market fills against it. At fill, the contract computes the LP's own ratio $\texttt{ratioBps} = \text{MaxIL}\cdot 10^4 / V_0$ and requires it lie in `[minMaxILRatioBps, maxMaxILRatioBps]`, else reverts `RatioOutOfBand`. So an MM expresses "I write positions whose MaxIL is 2%–7% of V0" once, and the contract enforces it per-fill — positions within the band are interchangeable.

<Note>
  Post-pivot, the MaxIL-ratio band is a **convenience filter**, not an asymmetry fix. The old "the LP knows the range and the MM does not, so the MM quotes a band to avoid adverse selection" framing is **void and deleted** — v3 position parameters are public on-chain, so both rails read the exact geometry. See [two rails](/concepts/two-rails).
</Note>

***

## (c) Why the premium is quoted as a percentage of MaxIL

This is the key pricing innovation, and it follows directly from MaxIL being the unit of risk. The premium is denominated as $X\%$ **of MaxIL** — equivalently, of the underwriter's posted collateral — never as a percentage of position value $V_0$.

Consider the counterfactual. If premium were $X\%$ **of $V_0$**:

<Tabs>
  <Tab title="Premium = X% of V0 (broken)">
    Collateral posted is `MaxIL`, but income is tied to `V0`.

    * A **narrow** range has a tiny MaxIL relative to V0 → the underwriter posts little collateral but earns a fat fee → **enormous return on collateral (ROC)**.
    * A **wide** range has a large MaxIL relative to V0 → the underwriter posts a lot of collateral for the same fee → **insufficient ROC**.

    Result: underwriters **adversely select against wide ranges**. Wide-range LPs cannot find a counterparty at a fair price. **Liquidity fragments.**
  </Tab>

  <Tab title="Premium = X% of MaxIL (correct)">
    Collateral posted is `MaxIL`, and income is `X% · MaxIL`.

    * The underwriter posts collateral `= MaxIL` and earns `X%` ROC **regardless of range width**.
    * Narrow and wide positions become **equally attractive** to write.

    Result: underwriter **indifference to range width** → no adverse selection → **full depth across all widths.**
  </Tab>
</Tabs>

Denominating in MaxIL also makes the two factors of price cleanly separable: $\text{fairRate} = E_Q[\min(\mathrm{IL}, \text{MaxIL})]/\text{MaxIL}$ is a dimensionless **fraction of MaxIL** — an S-curve in $\sigma^2 T$ bounded in $[0, 1]$ — and $\text{FairPremium} = \text{fairRate} \cdot \text{MaxIL}$. Read more on the [pricing stack](/protocol/pricing-stack) and [the load stack](/math/load-stack).

***

## Reference magnitudes — MaxIL as a fraction of V0 by width

These are pure geometry (no vol, no time), for a **geometric-symmetric** range $[\,P_0/(1+w),\; P_0\cdot(1+w)\,]$. They are the verified outputs of `compute_max_il`, and `ILMath` computes them correctly on-chain:

| Range width | MaxIL / V0 (geometric centering) |
| - | - |
| ±5% | **1.27%** |
| ±10% | **2.56%** |
| ±20% | **5.23%** |
| ±50% | **13.76%** (arithmetic centering ±50% → \~18.0%) |

<Warning>
  **Use the table above — older docs carry a stale, \~4.2× too-low set.**

  * **Limit:** older centered-range ballparks list `±5% → 0.3%`, `±10% → 1.2%`, `±20% → 4.8%`, `±50% → 25%`.
  * **Why:** that was a documentation transcription bug — the `ILMath` contract **always** computed the correct (higher) values; no code ever shipped the low numbers.
  * **Mitigation:** the table above is the corrected set straight from `compute_max_il`. (The *fixture* table for `[80,100,125]` — `MaxIL = 0.13932023`, ≈6.6% of V0 — is correct and verified.)
</Warning>

### Worked fixture `[80, 100, 125]`, `L = 1e18` (verified to the wei)

Asserted by the `amounts_fixture_matches_python` / `maxil_fixture_matches_python` tests and mirrored in the Solidity test suite:

| Quantity | Value (token1 wei, integer) | ≈ (× 1e18) |
| - | - | - |
| `amount0_entry` | `10_557_280_900_008_417` | 0.01055728 |
| `amount1_entry` | `1_055_728_090_000_841_200` | 1.05572809 |
| `V_hold(P0)` | `2_111_456_180_001_682_900` | 2.11145618 |
| `IL(Pa = 80)` | `≈ 1.11456e17` | 0.111456 |
| `IL(Pb = 125)` | `139_320_225_002_101_320` | 0.13932023 |
| **MaxIL** | `139_320_225_002_101_320` | 0.13932023 |

$\text{MaxIL} = \mathrm{IL}(P_b) > \mathrm{IL}(P_a)$ confirms the upper-boundary asymmetry, and $\text{MaxIL}/V_{\text{hold}}(P_0) \approx 6.6\%$. The on-node integer-floor MaxIL sits 1,691 wei from the Python float anchor — inside the 10,000-wei float-vs-integer tolerance; Stylus ≡ Solidity is exact to the wei.

***

## One position, three prices — same MaxIL

This is the property that proves MaxIL carries none of the vol/time dependence. Take a **50,000 USDC** position, ±10% geometric range, $\sigma_{\text{ref}} = 60\%$, `baseLoad = +15%`, skews = 0. MaxIL is **identical for all three durations**; only `fairRate` moves:

| Duration | MaxIL (constant) | fairRate | FairPremium | cvAMM publishes (@ +15%) |
| - | - | - | - | - |
| 7d | 1,280 USDC (2.56% of V0) | 44.9% | 574 USDC | 661 USDC (1.32% of V0) |
| 30d | 1,280 USDC (2.56% of V0) | 70.8% | 906 USDC | 1,042 USDC (2.08% of V0) |
| 90d | 1,280 USDC (2.56% of V0) | 82.9% | 1,061 USDC | 1,221 USDC (2.44% of V0) |

Collateral (MaxIL) is constant at 1,280 USDC for all three; the S-curve does all the work. Over 90d the ±10% band is touched \~75% of the time vs \~24% over 7d — so the product carries the **most** convexity value for wide/short positions (cheapest fraction of MaxIL) and the **least** for tight/long (e.g. ±5%/90d: fairRate ≈ 91%, effectively pre-paying a near-certain loss). See [`fairRate` and the S-curve](/concepts/fair-value) and [the full worked example](/math/worked-example).

### Live on-chain confirmation

The 2026-06-05 create→settle lifecycle on the Arbitrum Sepolia stack used a real MaxIL on both rails:

* **Path A (cvAMM):** V0 = \$270,531.28, **MaxIL = \$1,669.24**, premium = \$9.70 (0.58% of MaxIL — a wide/short position, low fairRate), realized IL at settle = \$148.64, payout = \$148.64 ≤ MaxIL, paid from the `ConvexityVault`.
* **Path B (MM won the route):** **MaxIL = \$3,215.65**, the MM's own collateral locked = MaxIL, realized IL = \$245.66, payout = \$245.66 ≤ MaxIL, paid from `UnderwriterVault`.

On both rails `payout ≤ MaxIL = collateral` held end to end — `I1` and `I2` in production. See live addresses on [the deployments page](/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.

***

## FAQ

<AccordionGroup>
  <Accordion title="Does MaxIL change if the LP adds liquidity after creation?">
    No. MaxIL is computed from the liquidity `L` **stored at creation** in the `SwapRecord`, and settlement re-reads that stored `L`, never the live NFT (invariant `I6`). Anyone can `increaseLiquidity` on a custodied v3 NFT, but the extra liquidity is simply returned with the NFT at settlement and **cannot inflate payout above MaxIL.** See [the invariants](/security/invariants).
  </Accordion>

  <Accordion title="Is MaxIL the worst case an LP can suffer?">
    No — it is the worst case *while price stays in range*. Beyond the range the LP's absolute IL is unbounded (fully rotated into one asset while a hold position keeps tracking price). That uncovered region is **directional** loss, not impermanent loss, and is deliberately out of scope — covering it would break full collateralization. LPs who want beyond-range protection re-cover after re-ranging.
  </Accordion>

  <Accordion title="If two positions have the same MaxIL, are they the same risk?">
    No. MaxIL is a **collateral / normalization unit, not a risk metric.** Two positions with identical MaxIL can sit at very different distances from the current price and carry very different probabilities of touching the cap. Both the pool and MMs price the specific on-chain geometry — `E_Q[min(IL,MaxIL)]/MaxIL` — not MaxIL in isolation.
  </Accordion>

  <Accordion title="Why does the same position get three different premiums?">
    Because `fairRate` is an S-curve in $\sigma^2 T$ and the three durations (7/30/90d) sit at different points on it, while MaxIL — pure geometry — is frozen and identical across all three. Longer duration ⇒ higher probability the band is touched ⇒ higher fairRate ⇒ higher premium, all backed by the **same** collateral. See [fair value](/concepts/fair-value).
  </Accordion>

  <Accordion title="Why quote in MaxIL instead of dollars or % of position value?">
    Quoting `X% of MaxIL` makes the underwriter's return-on-collateral independent of range width, so they are indifferent to writing narrow vs wide positions — no adverse selection, full depth. Quoting `% of V0` would hand narrow ranges an enormous ROC and starve wide ranges, fragmenting liquidity.
  </Accordion>
</AccordionGroup>

***

## Where to go next

<CardGroup cols={2}>
  <Card title="The MaxIL derivation" icon="square-root-variable" href="/math/maxil-derivation">
    The full boundary proof, the asymmetric-entry case, and the verified fixtures.
  </Card>

  <Card title="The IL formula" icon="function" href="/math/il-formula">
    `V_hold` vs `V_lp`, the three regimes, and the guarded realized-IL subtraction.
  </Card>

  <Card title="Fair value & fairRate" icon="chart-line" href="/concepts/fair-value">
    The exact closed-form Φ-sum that turns geometry + σ + T into a price.
  </Card>

  <Card title="No-bad-debt" icon="shield-check" href="/concepts/no-bad-debt">
    How `payout ≤ collateral = MaxIL` becomes a construction, qualified correctly.
  </Card>
</CardGroup>


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