Skip to content

scanner: per-feed Chainlink max_age — stable feeds (USDC/USDT) regularly stale beyond 600s #331

@obchain

Description

@obchain

Problem

crates/charon-scanner/src/oracle.rs:27 defines a single DEFAULT_MAX_AGE = 600s for every Chainlink feed. On BSC mainnet:

  • BNB / USD heartbeat ~60s — comfortable
  • ETH / USD heartbeat ~120-300s — comfortable
  • USDT / USD heartbeat ~24h, deviation-triggered (often updates every 15-30 min)
  • USDC / USD heartbeat ~24h, deviation-triggered (often updates every 30-60 min)

Both stable feeds regularly trip the global gate:

WARN charon_scanner::oracle: chainlink refresh failed
  symbol=USDC  err=feed 'USDC' is stale (updated 1006 s ago, max_age 600 s)
WARN charon_scanner::oracle: chainlink refresh failed
  symbol=USDT  err=feed 'USDT' is stale (updated 932 s ago, max_age 600 s)

When the BNB feed's gate fires (rare but possible during quiet periods), charon listen exits at startup:

Error: chainlink feed for 'BNB' missing or stale on chain 'bnb' — gas cost cannot be priced

Impact

P1. Stables are always treated as stale → debt and collateral pricing on USDC/USDT-denominated positions falls back to whatever the profit gate does with None. In the best case the position is dropped from consideration; in the worst it's evaluated with a stale cached value.

A single global threshold cannot fit feeds with heartbeats spanning two orders of magnitude.

Proposed fix

  1. Add per-symbol max_age_secs overrides in [chainlink.bnb]:
    [chainlink.bnb.max_age_secs]
    USDT = 86400
    USDC = 86400
    FDUSD = 86400
  2. Read overrides in PriceCache::new. Default remains 600s for unspecified feeds.
  3. Honor CHARON_PRICE_MAX_AGE_SECS as the per-process default, but make it advisory not authoritative — per-feed overrides win.

Acceptance

  • charon listen against a fresh fork keeps USDT and USDC inside the freshness window indefinitely.
  • BNB / ETH still gated tightly at 600s.
  • Operator can adjust without rebuilding.

Found during the local mainnet validation walk on 2026-04-25.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinglayer:rustRust crates (core / scanner / protocols / executor / cli)priority:p1-coreCore MVP scopestatus:readyScoped and ready to pick up

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions