Market account in the mint-redeem program. Read that account; you don’t need an off-chain feed.
Despite its name,
user_twap_price is a spot price, not a time-weighted average. The keeper writes it with mint-redeem’s update_risk_state_v2, already adjusted for corporate actions, and the same call stamps twap_updated_at.
On devnet the keeper prices markets from a free public quote source, because Pyth’s public Hermes endpoint now needs an API key. A GJR-GARCH volatility model sets the confidence band. The keeper checks every print against Hyperliquid and skips the push when the two disagree, so Hyperliquid can veto a price but never sets one. Mainnet will use Pyth (Pyth Pro). See Oracle.
NAV and worst-case quotes
oracle_confidence × the confidence multiplier for the current risk state:
The multipliers live in
worst_case_config: 1× in Normal, 1.5× in ProxyMode and 3× in Stress. In Recovery the multiplier falls from 3× to 1× over one hour. Every devnet market runs in ProxyMode. When worst_case_config.enabled is false, c is 0 and both legs trade at NAV; as of 10 Oct 2026 that is true for QQQ only. Fees are separate and use risk_fee_config (see Mint and redeem example).
Sample
s_gamma_index was still 0 (never written), so γ read as 1.0. Its first write, on 11 Oct 2026, set it to 0.99954.
Freshness
Mint and redeem revert withTwapNotAvailable when P is 0 or twap_updated_at is more than 300 s old. There is no fallback price. The keeper withholds a push whenever its source price is stale. That happens every time the underlying market closes, so outside trading hours mint and redeem stop working 300 s after the last push.
Committed orders (enabled on every live market since 11 Oct 2026) settle only at a push newer than the commit, and expire 180 s after it. The bin books are the reverse: they trade only once the price is more than 300 s old outside Normal, against a demand-sized free-float book that the keeper posts.
Apply the same rule in your UI: mark prices older than 300 s as stale and disable mint and redeem.
OracleConfig is not the live price
The oracle program’s OracleConfig accounts are not updated on devnet; the keeper writes prices only to Market. As of 10 Oct 2026, QQQ’s OracleConfig still holds a last_price of 562330000000, written on 4 Apr 2026. OracleConfig prices are scaled to 1e9, not 1e6, so that is $562.33. Don’t read OracleConfig for live prices.
Book centre (Pool account)
Each side of a market has a bin book: a Pool account in the CLP program at [b"pool", market, [side]]. Its base_price_1e6 is the centre the keeper last posted. The keeper shifts that centre for the protocol’s inventory, so it can sit away from NAV. With a CLP client loaded from clp.json the same way:
Subscribe or poll
- Subscribe with
connection.onAccountChange(marketPda, ...)to see each push as it lands. - Poll every 15 to 30 s for dashboards, and batch markets into one
fetchMultiplecall.
Decimals
Token amounts andMarket prices use 6 decimals. γ and OracleConfig prices use 9. Keep raw values in BN or bigint math and convert once, for display:
BN has arbitrary precision, so prefer it over toNumber() for anything you multiply.
See also
Reading state
Full state-fetch patterns (markets, vaults, positions).
Risk states
What
Stress, ProxyMode and Recovery mean and how to surface them.
