Skip to content

fix(pegs): per-feed oracle↔market divergence threshold (fix cbBTC false positive)#310

Merged
spalen0 merged 1 commit into
mainfrom
fix/peg-oracle-divergence-per-feed
Jul 1, 2026
Merged

fix(pegs): per-feed oracle↔market divergence threshold (fix cbBTC false positive)#310
spalen0 merged 1 commit into
mainfrom
fix/peg-oracle-divergence-per-feed

Conversation

@spalen0

@spalen0 spalen0 commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Problem

Production fired a false HIGH alert — and it escalated to the emergency forced_cap: 0 dispatch on Coinbase-collateral markets:

cbBTC oracle ↔ market divergence — Oracle: $59211.55, Market (DeFiLlama): $58544.51, Divergence: +1.14% (threshold 1.00%)

check_market_divergence used a flat 1% threshold. But a Chainlink feed only pushes a new answer when the price moves past its on-chain deviation parameter, so the oracle legitimately lags the live market by up to that band. cbBTC/USD's band is 2%, so a ~1.14% lag is normal update behaviour, not an anomaly — the flat 1% was tighter than the feed's own band.

Fix

Divergence now triggers at feed deviation band + buffer, both per-feed.

ChainlinkFeed.deviation_threshold — each feed's real band, verified against Chainlink's reference data directory:

Feed band Feed band
USDC/USD 0.25% USDe/USD 0.5%
USDT/USD 0.25% WBTC/BTC 0.5%
USDS/USD 0.3% LBTC/BTC 0.5%
cbBTC/USD 2%

divergence_buffer — slack for overshoot / cross-source noise. Default 0.25% (tight — right for stable/ratio answers). cbBTC overrides to 0.5%, because it's the one feed whose answer tracks the full volatile BTC price and can overshoot its band on a fast move (WBTC/BTC and LBTC/BTC are ~1.0 ratios, so they keep the tight default).

Effective triggers: stables 0.5–0.75%, cbBTC 2.5%. The 1.14% that fired now sits comfortably under cbBTC's 2.5%, while the stables get tighter than the old flat 1% (a real stable depeg trips sooner). Genuine depegs are still caught independently by check_peg_deviation (oracle vs peg), so loosening divergence creates no blind spot.

The PEG_ORACLE_DIVERGENCE_THRESHOLD env var is replaced by PEG_ORACLE_DIVERGENCE_BUFFER (global buffer override; per-feed values otherwise).

Tests

Regression tests added: the exact ~1.14%-within-band scenario stays quiet; cbBTC's wider 0.5% buffer and USDC's tight 0.25% default are both locked in. Full suite green, ruff clean.

Known follow-ups (not in this PR)

  • Heartbeats are hardcoded to 24h, but USDC/USDS/USDe are actually 23h — the staleness check is slightly lax for those three.
  • There's no cbBTC/BTC price feed (only cbBTC/USD 2% and a cbBTC Reserves PoR feed), which is why cbBTC can't get the clean ratio treatment WBTC/LBTC get. A fundamental backing check via the PoR feed could be added later.

🤖 Generated with Claude Code

…se positive)

The L2 divergence check used a flat 1% threshold, tighter than some feeds' own
on-chain deviation band. A Chainlink feed only re-pushes when price moves past
that band, so the oracle legitimately lags the live market by up to the band —
cbBTC/USD (2% band) lagging ~1.14% tripped a HIGH alert and the emergency
dispatch hook (forced_cap: 0 on coinbase markets). A false positive by design.

- Add per-feed ChainlinkFeed.deviation_threshold, verified against Chainlink's
  reference data directory: USDC/USDT 0.25%, USDS 0.3%, USDe/WBTC-BTC/LBTC-BTC
  0.5%, cbBTC 2%.
- Divergence now fires at deviation_threshold + buffer. Buffer defaults to 0.25%
  (tight, for stable/ratio answers) and is per-feed overridable: cbBTC widens to
  0.5% since its answer tracks the volatile BTC price and can overshoot the band.
- Real depegs remain covered independently by check_peg_deviation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@spalen0 spalen0 merged commit 639c26d into main Jul 1, 2026
3 checks passed
@spalen0 spalen0 deleted the fix/peg-oracle-divergence-per-feed branch July 1, 2026 12:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant