Skip to content

Oracle health

developer

The eight health states, staleness rules, and the uiMultiplier trap.

Address identity

Pricing starts where the asset registry starts: the token address is the identity. A feed is only ever attached to a verified canonical address — never looked up by ticker, because tickers can collide and the docs ticker can even differ from the on-chain symbol (see CUSO/USO).

The eight health states

Every price evaluation resolves to exactly one state. Order matters: pause and sequencer problems mask price data entirely, because a "fresh" price during an outage is still untrustworthy.

StateMeaningPriced?
OKFresh, positive price from a configured feed; sequencer healthy.yes
STALEThe feed's last update is older than the staleness limit (default 90,000s).no
INVALID_PRICEThe feed answered zero/negative, or the round is incomplete (updatedAt ≤ 0).no
MISSING_FEEDNo Chainlink feed proxy exists for this asset — today that means BE (Bloom Energy) only.no
SEQUENCER_DOWNThe L2 sequencer uptime feed reports down; feed values may be frozen.no
GRACE_PERIODThe sequencer just recovered; prices stay untrusted for a grace window (default 3600s).no
ORACLE_PAUSEDThe oracle reports paused — often a corporate action. Price data is masked entirely.no
UNKNOWNA feed is configured but no reading was supplied to the evaluator.no

Staleness: the primary guard

Every Robinhood Chain USD feed publishes on an 86,400-second (24-hour) heartbeat with a 0.5% deviation threshold, so the oracle policy's staleness limit is 90,000 seconds — heartbeat plus a one-hour buffer. A reading is stale when now − updatedAt exceeds that limit (manifests can tighten it via risk.oracleStalenessSeconds). Stock feeds discover prices 24/5, but the heartbeat keeps writing on weekends (verified on a Sunday: observed feed ages stayed at or under 16.7 hours, carrying Friday-close-derived values) — so one threshold covers all days, with no special weekend allowance.

Staleness is the primary guard by policy: the official docs describe the oraclePaused() flag as advisory and not enforced on-chain, so a paused oracle may still return a value. HISS checks the pause flag anyway (strictly more conservative), but never relies on it alone.

Pinned feeds (26 of 27)

Feed proxies were pinned on 2026-07-06 from Chainlink's reference data directory for robinhood-mainnet — the source of truth the official docs point to — and live-verified via eth_call on chain 4663 (spot-checked proxies answered with matching description(), decimals() = 8, positive answers, and fresh timestamps). All pinned feeds: 8 decimals, 86,400s heartbeat, 0.5% deviation, 24/5 market hours. This table renders live from PINNED_FEEDS in @hiss/core:

TickerFeed proxy (chain 4663)DecimalsHeartbeat
WETH0x78F3556b67E17Df817D51Ef5a990cDaF09E8d3A9886,400s
USDG0x61B7e5650328764B076A108EFF5fa7282a1B9aD2886,400s
AAPL0x6B22A786bAa607d76728168703a39Ea9C99f2cD0886,400s
AMD0x943A29E7ae51A4798823ca9eEd2ed533B2A22C72886,400s
AMZN0xD5a1508ceD74c084eBf3cBe853e2C968fB2a651C886,400s
BABA0x62Cc8F9b5f56a33c9C8A60c8B92779f523c4E984886,400s
COIN0xA3a468A452940B7D6b69991207B508c609a98Ef2886,400s
CRCL0x6652eDf64bA3731C4F2D3ce821A0Fb1f1f6b482a886,400s
CRWV0xe1b3aABCAFAd1c94708dc1367dcfF8Aa4407487C886,400s
GOOGL0xF6f373a037c30F0e5010d854385cA89185AE638b886,400s
INTC0x3f390C5C24628Ac7C489515402235FeAD71D1913886,400s
META0x7C38C00C30BEe9378381E7B6135d7283356D71b1886,400s
MSFT0x45C3C877C15E6BA2EBB19eA114Ea508d14C1Af2E886,400s
MU0x425EEFdCf05ed6526C3cE61Af99429A228a6d596886,400s
NVDA0x379EC4f7C378F34a1B47E4F3cbeBCbAC3E8E9F15886,400s
ORCL0x0e6a64a2B58A6693a531E6c555f3A5d042eEA844886,400s
PLTR0x820ABedFF239034956B7A9d2F0a331f9F075eB4c886,400s
SNDK0xfb133Fa4B7b385802B693a293606682Df47109A3886,400s
SPCX0xB265810950ba6c5C0Ff821c9963014a56fD8Bffb886,400s
TSLA0x4A1166a659A55625345e9515b32adECea5547C38886,400s
USAR0xA994d3684e8400A6c8078226925779FdeE682DD9886,400s
QQQ0x80901d846d5D7B030F26B480776EE3b29374C2ae886,400s
SGOV0xa0DF4ee0fFf975306345875E3548Fcc519577A11886,400s
SLV0x209b73908e92Ae021826eD79609845451Ecba2ce886,400s
SPY0x319724394D3A0e3669269846abE664Cd621f9f6A886,400s
CUSO0x75a9c76Ef439e2C7c2E5a34Ab105EcFe3766431c886,400s

Total-return drift

Stock Token feeds carry total-return semantics: dividends are reinvested into the token via the multiplier, so as dividends accrue the feed price drifts above the headline share price. Per the official docs, this is expected — the token tracks price changes plus reinvested dividends, not just the share price. Never treat that drift as an error, and never present the feed price as "the share price" (divide by the multiplier for that display).

uiMultiplier: never double-apply

Robinhood Chain Stock Tokens expose a uiMultiplier() that reflects corporate actions (splits, reinvested dividends). The critical rule: the Chainlink feed price is the token price and already includes the multiplier. The multiplier exists only to display share-equivalent units. Applying it to the feed price double-counts corporate actions.

valuation rules
// USD value of a raw token amount — the ONLY valuation formula:
value = rawTokenAmount * feedPrice;

// Share-equivalent units, for DISPLAY only:
shareEquivalent = rawTokenAmount * uiMultiplier;

// WRONG — double-counts corporate actions:
value = rawTokenAmount * uiMultiplier * feedPrice; // never do this

Corporate actions can change uiMultiplier() at any time, so never cache share-equivalent math.

Why live pricing is still off

Pinned feeds are necessary but not sufficient. The live-mode gate also requires the Chainlink L2 sequencer uptime feed for chain 4663, which is not yet published (no entry in the reference data directory, and Robinhood is absent from Chainlink's L2 sequencer feed list). Until it appears, liveFeedsPinned() returns false and assertLivePricingAllowed() throws on every live-pricing code path — live pricing is structurally impossible to enable by flag alone, and all pricing comes from the deterministic mock oracle.