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

# Oracle

> How Continuum sources prices, what the keeper pushes on-chain, and the staleness chain that freezes mint/redeem when the underlying market closes.

Continuum's price layer is simple by design: the keeper fetches **Pyth Hermes** price + confidence per market (\~15 s cadence) and writes both onto the `Market` account via `mint_redeem::update_risk_state`. Everything that prices against NAV - mint, redeem, committed-order settlement, book repositioning - reads that one on-chain TWAP.

## Sources

| Network               | Source             | How it reaches the chain                                          |
| --------------------- | ------------------ | ----------------------------------------------------------------- |
| **Devnet**            | Pyth Hermes (HTTP) | Keeper pushes via `update_risk_state`; markets run in `ProxyMode` |
| **Mainnet (planned)** | Pyth on-chain      | Read directly; the keeper-push path remains as fallback           |

On devnet, Hermes is **the** oracle - not a fallback. Pyth's on-chain devnet accounts for RWA feeds are unreliable (stale, sometimes empty), so they are not consulted at all. That is exactly what `ProxyMode` means: the program prices off the keeper-relayed `user_twap_price` instead of an on-chain Pyth account. All devnet markets run in `ProxyMode` permanently.

<Warning>
  Mainnet prerequisite: committed-order settlement (`settle_swap`) currently prices off the keeper-relayed TWAP. Mainnet requires reading Pyth directly with `publish_time > order.created_at`.
</Warning>

## What one push contains

```
update_risk_state(new_risk_state, user_twap_price, oracle_confidence)
```

* **`user_twap_price`** - the Hermes price, 6 decimals. This is `L_NAV`.
* **`oracle_confidence`** - the Hermes confidence interval. Used for worst-case quote markups, and the spread engine never quotes inside it.
* **`new_risk_state`** - the keeper-derived risk regime. See [Risk states](/concepts/risk-states).

Two safety rails bound each write:

* **On-chain move cap**: the program rejects any TWAP move over 25% per call (`MAX_TWAP_MOVE_BPS`), so a compromised keeper key cannot teleport NAV.
* **Keeper-side envelope (mainnet only)**: the keeper refuses to push a Hermes price that deviates more than 10% from the prior on-chain TWAP. On devnet this check is deliberately disabled - the on-chain TWAP *is* the keeper's own last Hermes write, so comparing against it would be self-referential and would deadlock after any pause.

## The staleness chain: what happens when the market closes

Hermes keeps serving the **last** price after the underlying stops trading (nights, weekends for equities). Re-pushing that frozen price would keep mint/redeem open at a stale NAV all weekend. Instead, a chain of gates takes over:

```
underlying closes
  → Hermes publish_time ages past 120 s        (HERMES_STALE_SECS)
  → keeper WITHHOLDS the push entirely
  → on-chain TWAP ages past 300 s              (MAX_TWAP_AGE_SECS)
  → mint/redeem self-freezes (program-side gate, no keeper action needed)
  → books stop repositioning (no fresh NAV → no drift signal)
  → books FLOAT at their standing band
```

While frozen:

* **Mint and redeem reject** (`OraclePriceUnavailable`) - nothing prices off a dead oracle.
* **The CLMM books keep trading** inside their standing band - off-hours price discovery within the last posted spread.
* **Committed orders cannot settle** (settlement requires an oracle print strictly after the commit); after the 180 s TTL, `cancel_swap` refunds unconditionally.
* At reopen, the first fresh print re-anchors NAV and the keeper re-pins the books.

## Confidence intervals

Every Hermes response includes a confidence interval. It feeds two mechanisms:

1. **Worst-case quote markup** on mint: `mint_price = NAV × (1 + state_mult × confidence_bps / 10_000)`, with `state_mult` per risk state (configurable via `configure_worst_case_quoting`). Wider uncertainty → worse mint quote, paid into the collateral vault.
2. **Spread floor**: the keeper's [spread engine](/concepts/keeper#the-spread-engine-model-free) includes `oracle_conf + fixed` in its max-of-floors stack - the books never quote inside oracle uncertainty.

## Reading prices from a client

### 1. Read from the Market account (recommended)

```typescript theme={null}
const market = await mintRedeem.account.market.fetch(marketPDA);
const lNav = market.userTwapPrice.gtn(0)
  ? market.userTwapPrice
  : market.initialLPrice;
const sNav = market.initialLPrice.mul(market.initialSPrice).div(lNav);

// Freshness gate - mirrors the program's own MAX_TWAP_AGE_SECS check
const fresh = Date.now() / 1000 - market.twapUpdatedAt.toNumber() <= 300;
```

`user_twap_price` is a plain field on the Market account - no oracle CPI needed at read time. Always check `twap_updated_at` before assuming mint/redeem will accept a transaction.

### 2. Read from Hermes directly (off-chain)

```typescript theme={null}
const res = await fetch(
  "https://hermes.pyth.network/v2/updates/price/latest" +
  "?ids[]=0x9695e2b96ea7b3859da9ed25b7a46a920a776e2fdae19a7bcfdf2b219230452d",
);
const data = await res.json();
console.log(data.parsed[0].price);
```

The on-chain TWAP and Hermes agree to within one keeper tick (\~15 s) during open hours. Use Hermes for a raw spot reference; use the on-chain TWAP for anything that affects user-facing pricing - the protocol prices off the on-chain value regardless of what your client computes.

## Integration pattern

```typescript theme={null}
const market = await mintRedeem.account.market.fetch(marketPDA);
const ageSecs = Date.now() / 1000 - market.twapUpdatedAt.toNumber();

if (ageSecs > 300) {
  // Underlying market is closed (or keeper outage).
  // Mint/redeem will reject; books float; committed orders won't settle.
  console.warn("TWAP stale - mint/redeem frozen until next oracle print.");
}
```

## Read more

<CardGroup cols={2}>
  <Card title="Risk states" icon="shield-check" href="/concepts/risk-states">
    What `Normal` / `ProxyMode` / `Stress` / `Recovery` mean for your operations.
  </Card>

  <Card title="mint-redeem reference" icon="square-terminal" href="/programs/mint-redeem">
    `update_risk_state`, staleness gates, error catalog.
  </Card>
</CardGroup>
