BuildWeb3
Chainlink Oracles
Convert agent budgets across currencies with Chainlink and Pyth prices, then record the validated oracle reading in each settlement receipt.
Why Oracles in the Kernel
A seller-controlled exchange rate can defeat a capability budget. A kernel that authorizes a "$10 of API time" capability must use an independent price source. Oracles provide a public price and time, allowing third parties to verify the oracle reading in a settlement receipt.
The integration is policy-level, not runtime-level: Chio never executes a swap. It reads prices, applies a configurable margin, and records which oracle reading it used in the receipt. If an oracle is stale or a sequencer is down, the kernel rejects the evaluation.
Supported Oracle Stacks
| Oracle | Chains | Typical cadence |
|---|---|---|
| Chainlink Data Feeds | Base Mainnet (default) · Arbitrum One (standby) | Per-feed heartbeat plus deviation trigger |
| Pyth Network (Hermes) | Base Mainnet (default) · Arbitrum One (standby) | Pull-based; sub-second publish cadence |
Base Mainnet is enabled by default and monitored through the official Chainlink sequencer-uptime feed. Arbitrum One ships as standby operator inventory, disabled by default until later web3-runtime milestones consume it. There is no Ethereum Mainnet, Optimism, or Solana entry in the oracle chain inventory today.
Chainlink is the primary source; where a pair also carries a Pyth id, Pyth acts as a corroborating fallback. When the two sources diverge beyond the configured threshold (500 bps by default), Chio trips the circuit breaker for that pair. The failure surfaces as PriceOracleError::CircuitBreakerTripped, carrying the pair, the observed divergence, and the threshold.
How a Price Gets Consumed
Pair Inventory and Freshness
The shipped inventory is four Base pairs under one uniform policy: a max_age_seconds of 600 for staleness and a divergence_threshold_bps of 500 (5%) for cross-source agreement. A reading is rejected if it is stale, and the pair trips its breaker if the sources diverge past the threshold. TWAP smoothing is applied per pair.
| Pair | Sources | TWAP |
|---|---|---|
| ETH/USD | Chainlink + Pyth | Enabled (600 s window) |
| BTC/USD | Chainlink + Pyth | Enabled (600 s window) |
| USDC/USD | Chainlink + Pyth | Disabled — spot only |
| LINK/USD | Chainlink only | Enabled (600 s window) |
Two nuances matter. USDC/USD is spot-only: TWAP is deliberately off because peg deviation is itself the signal, and smoothing it away would hide the thing you want to catch. LINK/USD runs Chainlink-only, with no Pyth fallback, so its breaker never trips on cross-source divergence. Per-pair overrides (enable/disable, forced backend, custom divergence threshold, degraded mode) are loaded from the operator config and enforced for every subsequent call.
FX Conversion with Margin
Once a price passes its checks, Chio applies an operator-configured FX margin before quoting the converted amount. The margin protects both sides against the short window between price read and on-chain execution. The shipped default is a uniform exchange_rate_margin_bps of 200 (2%) across every pair; operators tune it per pair as needed.
{
"primary": "chainlink",
"fallback": "pyth",
"pairs": [
{
"base": "ETH", "quote": "USD", "chain_id": 8453,
"chainlink": { "address": "0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70", "decimals": 8, "heartbeat_seconds": 300 },
"pyth": { "id": "0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace" },
"policy": {
"max_age_seconds": 600,
"divergence_threshold_bps": 500,
"exchange_rate_margin_bps": 200,
"twap_enabled": true
}
},
{
"base": "USDC", "quote": "USD", "chain_id": 8453,
"chainlink": { "address": "0x7e860098F58bBFC8648a4311b374B1D669a2bc6B", "decimals": 8, "heartbeat_seconds": 68400 },
"pyth": { "id": "0xeaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a" },
"policy": {
"max_age_seconds": 600,
"divergence_threshold_bps": 500,
"exchange_rate_margin_bps": 200,
"twap_enabled": false,
"stable_pair": true
}
}
],
"operator": {
"global_pause": false,
"chains": [
{
"chain_id": 8453,
"label": "base-mainnet",
"caip2": "eip155:8453",
"enabled": true,
"sequencer_uptime_feed": "0xBCF85224fc0756B9Fa45aA7892530B47e10b6433",
"sequencer_grace_period_seconds": 300
}
]
}
}Circuit Breakers and Sequencer Health
Two operational conditions trigger an automatic circuit break on oracle-backed conversions:
- Feed outage · N consecutive reads return stale timestamps or revert. After the threshold, the feed is marked unhealthy and conversions against it deny until it recovers.
- L2 sequencer downtime · On optimistic L2s a frozen sequencer can keep a feed's on-chain timestamp advancing while the underlying price has not actually updated. Chio reads the chain's official sequencer-uptime feed and fails with
SequencerDownwhile the sequencer is offline. After it recovers, conversions stay blocked withSequencerRecoveringuntil thesequencer_grace_period_secondswindow (300 s by default) elapses, so a just-restarted sequencer does not immediately price against stale state.
Fail closed on oracle uncertainty
Oracle Evidence in Receipts
When a conversion succeeds, chio attaches an OracleConversionEvidence block to the resulting receipt. The block records the consulted readings, applied margin, and final rate. A verifier can recompute the conversion from those recorded inputs.
{
"oracle_evidence": {
"pair": "USDC/USD",
"readings": [
{
"source": "chainlink",
"chain": "eip155:8453",
"feed_address": "0x7e86...bc6b",
"round_id": "18446744073709562042",
"answer": "99980000",
"decimals": 8,
"updated_at": 1760923400
},
{
"source": "pyth",
"price_id": "0xeaa0...9c94a",
"price": 0.99982,
"conf": 0.00014,
"publish_time": 1760923399
}
],
"applied_margin_bps": 200,
"final_rate": 0.97980,
"direction": "USD_to_USDC"
}
}Next Steps
- Settlement · on-chain execution that uses oracle-backed quotes
- Budgets & Metering · how cross-currency budgets are authored and enforced
- x402 Payments · agent-level payments where oracle quotes feed per-request pricing