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

# NAV math

> How long and short NAVs are derived, why the constant-product invariant matters, and how to compute paired position value.

NAV (Net Asset Value) is what each long and short token is worth in cUSDC, **at the protocol layer**. It is what you pay to mint, what you receive to redeem, and what the keeper anchors pool prices to.

## The two formulas

```
L_NAV = market.user_twap_price                                (or initial_l_price if TWAP == 0)
S_NAV = (initial_l_price × initial_s_price) / L_NAV × γ        (γ = s_gamma_index / 1e9, default 1.0)
```

`user_twap_price` is the on-chain TWAP from the [oracle program](/programs/oracle), updated by the keeper roughly every 15 seconds. `initial_l_price` and `initial_s_price` are set at market initialization and never change. `γ` is the volatility-decay scalar (`s_gamma_index / 1e9`), `1.0` unless the keeper has marked the short leg down — see [Volatility decay](#volatility-decay). While `γ = 1.0` the trailing factor is a no-op and these are the plain constant-product NAVs.

For QQQ at launch: `initial_l_price = 480, initial_s_price = 1`. So if `L_NAV = 528` (QQQ moved +10%), then `S_NAV = 480 × 1 / 528 = 0.909`.

## Why constant-product

The relationship `L_NAV × S_NAV = initial_l × initial_s` is invariant by construction. This produces several useful properties:

1. **Pair value is bounded.** `L_NAV + S_NAV` is minimized at `L_NAV = S_NAV = √(initial_l × initial_s)` (the geometric mean) and grows as either side moves away. There is no scenario where the pair value collapses to zero.
2. **No funding rate needed.** In a perp DEX, funding redistributes from longs to shorts (or vice versa) when one side is over-popular. Continuum doesn't need this - the constant-product NAV does the redistribution **automatically** through reciprocal NAV movement. If everyone holds L, S becomes cheap, and any new mint on the popular side is dilutive in NAV terms.
3. **Short side can never go negative.** As `L_NAV → ∞`, `S_NAV → 0`. A holder of S can lose 100% of their position but never owe more.
4. **Long side has unbounded upside.** No cliff, no liquidation; if the underlying 100xs, the L side 100xs.

## Computing paired position value

For a position holding `n_L` long tokens and `n_S` short tokens:

```
position_value_cUSDC = n_L × L_NAV + n_S × S_NAV
```

For a position minted from `mint_amount` cUSDC at the time of minting:

```
mint_value_per_side = (mint_amount × (1 - mint_fee_bps / 10_000)) / 2
n_L                 = mint_value_per_side / L_NAV_at_mint
n_S                 = mint_value_per_side / S_NAV_at_mint
```

So at mint time, the position value equals `mint_amount × (1 - mint_fee_bps / 10_000)` - i.e., your deposit minus fees. Trivially.

## How position value moves with the underlying

Take a 100 cUSDC mint at QQQ = 480 (initial\_l = 480, initial\_s = 1, mint fee = 10 bps):

```
mint_value_per_side = (100 × 0.999) / 2 = 49.95 cUSDC
n_L = 49.95 / 480     = 0.10406 QQQL
n_S = 49.95 / 1       = 49.95   QQQS
```

Now QQQ moves to some new price `P`. New NAVs:

```
L_NAV = P
S_NAV = (480 × 1) / P = 480 / P
```

Position value:

```
value = 0.10406 × P + 49.95 × (480 / P)
      = 0.10406 × P + 23976 / P
```

Some sample values:

| QQQ price      | Position value   | Note                         |
| -------------- | ---------------- | ---------------------------- |
| 240 (-50%)     | 124.85 cUSDC     | gain on short side dominates |
| 384 (-20%)     | 102.39 cUSDC     | small gain - convexity       |
| 432 (-10%)     | 100.43 cUSDC     | small gain                   |
| **480** (mint) | **100.00 cUSDC** | break-even (modulo fee)      |
| 528 (+10%)     | 100.30 cUSDC     | small gain                   |
| 576 (+20%)     | 101.55 cUSDC     | small gain                   |
| 720 (+50%)     | 108.20 cUSDC     | gain on long side dominates  |
| 1440 (+200%)   | 166.50 cUSDC     | long appreciation            |

Note: a paired position has **near-zero delta** locally - it's a curved zero-coupon. The pair becomes valuable only at large moves in either direction. To take a directional view, sell one leg.

## Volatility decay

The short-leg **γ-index**. All of the pair's convexity lives in the **short** leg: `L_NAV = P` is linear (`d²L/dP² = 0`), while `S_NAV = K/P` is convex (`d²S/dP² = 2K/P³ > 0`). The protocol is the counterparty to that convexity, so it is structurally **short volatility** on the short side.

To charge for that, the keeper can post a decay scalar `γ = s_gamma_index / 1e9` that marks the short NAV down:

```
S_NAV = (initial_l_price × initial_s_price) / L_NAV × γ
```

* **Ratchet-down only.** The on-chain `set_s_gamma_index` instruction rejects any value above the current γ, and clamps to a floor of `0.5` (at most 50% cumulative decay). γ can never be raised to retroactively restore short claims.
* **It charges realized variance, not direction.** The keeper decays γ by the realized per-cycle variance (`Δγ/γ ≈ σ²`), so a *choppy* path costs the decay while a *smooth directional* move barely does — the directional payoff lives in the untouchable long leg. This banks the choppiness-convexity the protocol is short as collateral surplus.
* **It is not a funding rate.** There is no periodic cash transfer between holders. γ is a structural mark on the short token's value; an instant mint→redeem round-trip is unaffected at a fixed γ, and **long positions never pay it**. The frontend surfaces it on the short side as "volatility decay," deliberately not "funding."
* **Default 1.0 (off).** Until the keeper posts a value (`CLMM_GAMMA_DECAY_ENABLED`, off by default), `s_gamma_index` reads as `1e9` and every formula above reduces to the plain constant-product NAV.

See [Solvency](/concepts/solvency) for why this only covers the variance regime and not a directional run.

## NAV in the on-chain Market account

The relevant fields on the [`Market` PDA](/programs/mint-redeem#market-account):

```rust theme={null}
pub struct Market {
    pub initial_l_price: u64,    // 6 decimals (lamports of cUSDC per L token)
    pub initial_s_price: u64,    // 6 decimals
    pub user_twap_price: u64,    // 6 decimals - the on-chain TWAP source for L_NAV
    pub twap_updated_at: i64,    // unix seconds
    // ... fees, mints, oracle, yield (deployed_to_yield), buffer_target_bps ...
    pub s_gamma_index: u64,      // 1e9 fixed; 0/unset → 1.0 (no decay). Short-leg vol decay.
}
```

To read NAV from a client:

```typescript theme={null}
import { BN } from "@coral-xyz/anchor";

const market = await mintRedeem.account.market.fetch(marketPDA);
const lNav = market.userTwapPrice.gt(new BN(0))
  ? market.userTwapPrice
  : market.initialLPrice;
// Short NAV includes the γ decay scalar (1e9 = 1.0). 0/unset → no decay.
const GAMMA_ONE = new BN(1_000_000_000);
const gamma = market.sGammaIndex && market.sGammaIndex.gt(new BN(0))
  ? market.sGammaIndex
  : GAMMA_ONE;
const sNav = market.initialLPrice.mul(market.initialSPrice).div(lNav).mul(gamma).div(GAMMA_ONE);
```

The 6-decimal scaling means `lNav.toNumber() / 1e6` gives a human-readable price.

## TWAP and risk-state effects on NAV

The TWAP is what the user-facing flow uses. There's also a **keeper TWAP** (shorter window) used internally for arb decisions. They derive from the same observation buffer in the oracle program but with different windows.

When the oracle's risk state is **not** `Normal`, the mint-redeem program applies a **worst-case quoting markup** to mint pricing. This is bounded by `oracle_confidence` (also stored on the market) and a state-specific multiplier:

| Risk state  | Multiplier (default) | Effect on mint price                        |
| ----------- | -------------------- | ------------------------------------------- |
| `Normal`    | 1×                   | NAV directly                                |
| `ProxyMode` | 2×                   | NAV + 2 × confidence\_bps markup            |
| `Stress`    | (mint blocked)       | mint rejected with `MintNotAllowedInStress` |
| `Recovery`  | 1×                   | NAV directly (post-stress recovery)         |

Redeem prices are not marked up - only mint. (Otherwise users would be stranded when the oracle goes shaky.)

→ [Risk states explained](/concepts/risk-states)

## When TWAP is zero

On a freshly initialized market, `user_twap_price = 0` until the keeper has pushed enough observations to populate the TWAP window (default 5 observations / \~75 seconds). During this window:

```
L_NAV = initial_l_price   (fallback)
S_NAV = initial_s_price   (since L_NAV × S_NAV = initial_l × initial_s holds at boot)
```

Mints during the boot window use the initial prices. Once TWAP populates, NAV becomes price-responsive.

## Edge: oracle stale or paused

If `last_oracle_update` is past the staleness threshold, the oracle's `OracleHealth` flips to `Passive`, and the mint-redeem program rejects new mints (`OraclePriceUnavailable`). Existing redeems still work, but at the last-fresh NAV - see [Risk states](/concepts/risk-states).

## NAV vs pool price

NAV is what the protocol mints/redeems at. **Book price** is what the native per-side CLMM book trades at between repositions - the two are kept close by structure, not by arbitrage. The keeper re-pins each book's base to NAV whenever drift exceeds the per-market gate (20-40bps), and the standing half-spread means the book never quotes inside NAV ± spread anyway.

In steady state, `book_price ≈ NAV ± half_spread`. During closed market hours the oracle withholds pushes and the books float - the gap can widen, and the first fresh print re-anchors everything. A user choosing a venue picks by size and urgency:

* **Small size, urgent**: hit the book (`pool_swap`) - instant, pays the bin ladder's real spread.
* **Large size**: commit an order - fills at the *next* oracle print at NAV ± 10bps, any size.
* **Want the pair, not a direction**: mint or redeem at NAV (pays the mint/redeem fee, no spread).

→ [Trading venues](/flows/trade)

## NAV in TradingView and analytics

Continuum's frontend overlays NAV on a TradingView chart. The long-side book price is shown directly; the short-side is **derived from the long side via the constant-product invariant** for visual coherence (otherwise two charts that should be inverse appear unrelated). When you read the S book programmatically, you get its actual base price.
