DEV Community

DE LIGHT
DE LIGHT

Posted on

I stress-tested Pyth Oracle's confidence intervals and built a provably fair game seeded by live oracle attestations

Every Pyth price feed comes with a published confidence interval (CI) — the oracle's way of saying "I'm 68% confident the true price is within ±X of my reported price." But does that 68% claim hold up against real historical data? I built Pyth Insight to find out.
Testing Pyth's CI empirically
The methodology:

Fetch price snapshots at 60-minute intervals over 3 days (72+ snapshots) using the Hermes historical API: https://hermes.pyth.network/v2/updates/price/{timestamp}
For each consecutive pair, check whether the actual price move landed inside the CI band, scaled by sqrt(actualInterval / horizon) to adjust for measurement period
Compute coverage at multiple sigma levels (0.5σ–3σ) and compare against theoretical normal distribution coverage
Score the feed: 80–100 = Well-Calibrated, 60–79 = Acceptable, 40–59 = Poor, 0–39 = Unreliable

What the live data shows for BTC/USD:

At ±1σ, the CI should capture 68.3% of moves — it actually captures ~45%
At ±2σ, should capture 95.4% — actually captures ~70%
Verdict: systematically over-confident — the CI is consistently too tight

This has real implications for DeFi lending protocols using Pyth CIs as liquidation thresholds.
Building a provably fair game with Pyth oracle entropy
The Oracle Challenge game needed a verifiable, unpredictable seed to select which price feed players bet on each round. I wanted to use Pyth Entropy's commit-reveal scheme — specifically the RevealedWithCallback event from the Fortuna provider on Base — because that output is the strongest form of provable randomness Pyth offers.
Pyth Entropy's commit-reveal scheme:

Requester generates a secret, submits keccak256(secret) as commitment
Fortuna provider does the same
After both commit, both reveal — final randomness = keccak256(userRandom XOR providerRandom)
This is emitted as a RevealedWithCallback event on the Entropy contract

The RevealedWithCallback event on Base (0x98046Bd286715D3B0BC227Dd7a956b83D8978603) has this ABI structure:
RevealedWithCallback(
Request request, // 8 fields × 32 bytes = 256 bytes
bytes32 userRandom, // + 32 bytes
bytes32 providerRandom, // + 32 bytes
bytes32 randomNumber // + 32 bytes = last 32 bytes of event.data
)
// Total event.data = 352 bytes (all static types, no dynamic offsets)
I implemented the full pipeline — Fortuna REST API → BaseScan event index → eth_getLogs. All three confirmed the same thing: the Base mainnet Entropy contract has no fulfilled RevealedWithCallback sequences yet. You can verify this directly on Basescan. The contract exists and accepts requests, but no one has fulfilled a sequence on Base mainnet.
Falling back to Pyth Hermes attestations as the entropy source
Rather than fall back to a block hash, I pivoted to the Pyth Hermes oracle itself. The BTC/USD price attestation from Hermes:

Changes every ~400ms (Pythnet heartbeat)
Is signed by Pyth validators — cannot be predicted before publication
Is independently verifiable at https://hermes.pyth.network/v2/updates/price/latest

The implementation packs the attestation fields into a deterministic 32-byte game seed:
typescript// Feed ID: BTC/USD
const HERMES_BTC_FEED = "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43";

const res = await fetch(
https://hermes.pyth.network/v2/updates/price/latest?ids[]=${HERMES_BTC_FEED}&parsed=true
);
const { parsed } = await res.json();
const { price, conf, expo, publish_time } = parsed[0].price;
const { price: ema } = parsed[0].ema_price;

// Pack into 32 bytes: price(8B) | conf(4B) | ema(8B) | publishTime(4B) | padding(8B)
const toBEHex = (val: bigint, bytes: number): string =>
val.toString(16).padStart(bytes * 2, "0").slice(-(bytes * 2));

const seed =
toBEHex(BigInt(price), 8) +
toBEHex(BigInt(conf), 4) +
toBEHex(BigInt(ema), 8) +
toBEHex(BigInt(publish_time), 4) +
"0000000000000000"; // padding

// → 64 hex chars = 32 bytes, signed by Pyth validators, verifiable by anyone
publish_time is used as the sequence identifier. Anyone can verify the seed by querying Hermes with that timestamp and confirming the packed bytes match.
The game shows a green "✓ Real Entropy" badge when a live Pyth oracle value powers the round, with the source and pack formula displayed.
Live

App: https://pyth-insight.vercel.app
Code: https://github.com/DE-LIGHTPRO/pyth-insight

Top comments (0)