Market account with mint_redeem::update_risk_state_v2. Mint, redeem, committed-order settlement and book repositioning all read that stored price, user_twap_price. Despite its name it is a spot price, scaled to 1e6, and the program has already applied any corporate-action adjustment.
Sources
Pyth’s public Hermes service has required an API key since 26 Aug 2026, so the devnet keeper prices markets from a keyless public quote source. That source publishes no confidence interval, so the keeper derives one from a GJR-GARCH volatility model kept per market.
A move of more than 10% from the last accepted price is held until it is confirmed or an operator releases it (see CNBC price holds).
The keeper checks every fresh price against Hyperliquid before pushing it. It compares the price with Hyperliquid’s oracle price for the same market (SPY and QQQ go through a learned index ratio), and a disagreement beyond a per-market band blocks the push. Hyperliquid can veto a price but never sets one. If Hyperliquid is unreachable, the push goes ahead.
The oracle program is not in the devnet price path. The keeper skips
update_price_observation on devnet, so OracleConfig there is stale. Don’t read it for live prices; read the Market account.
ProxyMode means the program prices off the keeper-pushed user_twap_price. In Normal, the mainnet steady state, mint and redeem read the market’s Pyth account inside the transaction instead. That read enforces its own limits: it rejects a print older than 60 s (MAX_PYTH_AGE_SECS) or one whose confidence is wider than 2% of the price (MAX_PYTH_CONF_BPS), with OraclePriceUnavailable. Devnet never uses this path.
What one push contains
user_twap_priceis the source price, 1e6-scaled. The program multiplies it by the market’s corporate-action ratio before storing it. This isL_NAV.oracle_confidenceis the absolute half-width of the confidence band, in the same units and with the same adjustment. It drives worst-case quotes, and the keeper’s spread never quotes inside it.new_risk_stateis the keeper’s risk regime for the market. See Risk states.source_publish_timeis when the source published the price. The program rejects a push whose publish time is in the future or more than 300 s old (OraclePriceUnavailable), and stores it astwap_updated_at. When the keeper can’t verify the publish time it sends 0, and the program stores the current on-chain time instead.
- On-chain, the program rejects any price move over 25% from the stored price in one push (
MAX_TWAP_MOVE_BPS), so a compromised keeper key can’t teleport NAV. The first push to a market is exempt. - On mainnet only, the keeper refuses to push a price more than 10% away from the oracle program’s last TWAP (
MAX_HERMES_DEVIATION_BPS). On devnet this envelope is off on purpose: the stored price is the keeper’s own last write, so comparing against it would be circular and would deadlock after any pause.
The staleness chain: what happens when the market closes
Quote sources keep serving the last price after the underlying stops trading, at night and over weekends for equities. Re-pushing that frozen price would keep mint and redeem open at a stale NAV all weekend. A chain of gates stops that:ProxyMode the freeze exists only because the keeper withholds pushes. Nothing on chain knows the market is closed, and any accepted push resets the clock.
While frozen:
- Mint and redeem revert with
TwapNotAvailable, so nothing prices off a dead feed. - The bin books open.
pool_swapfills only now, while the price is stale outsideNormal, against a free-float book: one per side, anchored at the last price, with each side in one bin within 1% of it, sized to measured demand ($500 a side until flow is measured) and limited by a risk cap on that market’s share of the treasury. A guard can pull bins on the side that other venues (extended-hours sessions, futures, Hyperliquid, tokenized gold and euro) show is stale. It never moves the centre or adds depth. - Committed orders can’t settle, because settlement needs a push newer than the commit. About 5 s after the 180 s TTL, the keeper refunds the order with
cancel_swap, which anyone may send. - At reopen, the first accepted push re-anchors NAV, committed orders settle again, the books stop filling, and the keeper re-posts the live books.
Confidence intervals
The confidence band feeds two mechanisms:- Mint and redeem price each leg off
P + corP − c, whichever is worse for the user, wherec = oracle_confidence× the risk state’s confidence multiplier. See worst-case quoting. - The keeper’s spread engine includes
oracle_conf + fixedin its max-of-floors stack, so the books never quote inside the band.
Reading prices from a client
Read theMarket account. It holds the price the program will use, and reading it needs no oracle CPI.
twap_updated_at before you assume a mint or redeem will go through. The protocol prices off the stored value, whatever your client computes.
Read more
Risk states
What
Normal / ProxyMode / Stress / Recovery mean for your operations.mint-redeem reference
update_risk_state_v2, staleness gates, error catalog.
