For educational purposes only; not investment advice. Investing may result in loss.
Direct answer
An oracle value is stale for a specific consumer action when age = consumerClock - sourceTimestamp exceeds that action’s configured maxAge. A price that has not changed can still be fresh, and a recently published value can still be economically wrong. The consumer must first reject missing or future timestamps and invalid answers, then apply a feed-, asset-, chain-, market-hours-, and action-specific acceptance policy.
Heartbeat and deviation thresholds are publication triggers, not freshness guarantees or service-level agreements. A report can be delayed after a trigger, and a market can move below the deviation threshold while an action requires a tighter maximum age. Pull oracles introduce another boundary: a caller may need to submit an authenticated update before reading, and the contract must reject updates older than its stated limit.
On an L2, sequencer status and recovery grace form a separate gate. Passing that gate does not prove the asset price is fresh, the L2 is final, or all users had equal access. Fallback and last-good prices are controlled degradation modes, not truth; every source and recovery path needs units, timestamps, independence, permissions, allowed actions, and reconciliation rules.
How it works
- Pin the chain, block and clock, consumer contract and action, feed proxy and aggregator, asset pair and decimals, interface version, fallback configuration, and upgrade state.
- Read the exact response through the deployed interface and handle revert or no-data states. Validate answer, status or confidence where applicable,
sourceTimestamp != 0, andsourceTimestamp <= consumerClockbefore subtracting. - Record heartbeat, deviation, market-hours and publication configuration, then set an independent
maxAgefor each action. Define the boundary explicitly, such as acceptage <= maxAgeand rejectage > maxAge. - On supported L2 deployments, validate sequencer-feed initialization and status, compute time since recovery from the documented field, and enforce the configured grace period before separately checking price freshness.
- Trace every required leg of composite, ratio and fallback prices. Normalize direction and units, and constrain effective freshness by the oldest necessary dependency rather than the newest timestamp.
- Define normal, degraded and paused states per action. New borrowing, minting or leverage may fail closed while repayment or collateral addition remains available; test stale, fallback and resumed prices against exposure, liquidity and keeper capacity.
- Monitor source and proxy changes, update latency, rejection rates, sequencer state, cross-source divergence and market hours; rehearse outage, fallback failure, jump recovery, concentrated liquidation, MEV, bad-debt accounting and return to normal mode.
For Chainlink-style interfaces, latestRoundData() can expose a round identifier, signed answer, start time, update time and a legacy round field. The current API documents answeredInRound as deprecated, so a historical inequality check must not be presented as a universal current rule; inspect the exact proxy, aggregator and implementation. A timestamp says when the documented feed state was updated, not that the value is executable at arbitrary size. Solidity block.timestamp is the current block timestamp under consensus bounds, not an external wall-clock oracle.
Worked examples
- Maximum-age boundary. Let
consumerClock = 1,800,000,000andsourceTimestamp = 1,799,999,100, soage = 900 seconds = 15 minutes. AmaxAge = 600 secondspolicy rejects it by300 seconds; amaxAge = 1,200 secondspolicy accepts it with300 secondsof headroom. The same feed value can therefore be acceptable for one action and stale for another. - Trigger is not freshness. The last published price is
100.00, the deviation trigger is1%, and heartbeat is3,600 seconds. After2,700 seconds, an observed market price of100.80is only0.8%away, so neither teaching trigger has fired. At101.20, the deviation is1.2%and may initiate publication, but the consumer still reads100.00until a valid new report is included. - L2 double gate. A sequencer feed reports up with
startedAt = 1,799,996,400,consumerClock = 1,800,000,000, andgrace = 3,600 seconds, so elapsed time is exactly3,600 seconds. Under a policy that blocks whileelapsed <= grace, the action remains blocked and becomes eligible at3,601 seconds. Eligibility still depends on the separate price timestamp, answer and every other consumer check. - Recovery cliff. With
10 ETHcollateral,12,000 USDdebt and a75%liquidation threshold, a stale2,000 USD/ETHvalue giveshealthFactor = 10 * 2,000 * 0.75 / 12,000 = 1.25. A resumed1,400 USD/ETHvalue gives0.875. The account becomes eligible for liquidation under these teaching inputs, but execution still depends on protocol rules, liquidity, keepers, gas, ordering and chain availability.
Risks
- Wrong chain, feed, proxy, aggregator, asset pair, or interface version.
- A consumer reads an answer without a timestamp or documented status.
- Missing timestamp zero, future timestamp, or subtraction underflow is not rejected.
- The maximum age is too loose for the asset, action, market hours, or volatility.
- The maximum age is too tight and creates denial of service or blocks risk reduction.
- Heartbeat is treated as a guaranteed publication deadline or service-level agreement.
- Sub-threshold drift or basis accumulates while no deviation trigger fires.
- A triggered report is delayed by source, signer, network, gas, relay, or chain failure.
- A deprecated or implementation-specific round check is applied universally.
- Feed, proxy, aggregator, heartbeat, deviation, or interface configuration changes unnoticed.
- Closed-market, holiday, paused-market, or carried-forward data semantics are ignored.
- A composite or ratio price appears fresh while one required leg is stale.
- L2 sequencer status is ignored, uninitialized, delayed, or read from the wrong network.
- Recovery grace is missing, misconfigured, or has an off-by-one boundary.
- Sequencer status passes while the asset price remains stale or unavailable.
- L1 time, L2 block time, source observation time, publication time, and wall time are conflated.
- A pull update is absent, too old, selectively chosen, malformed, or underfunded.
- A fallback or last-good value is stale, correlated, differently scaled, or circular.
- Fail-open permits unsafe actions, while blanket fail-closed blocks repayment, collateral addition, or orderly recovery.
- Recovery jump, liquidation clustering, MEV, thin liquidity, pause races, or bad-debt reconciliation causes secondary loss.
Common misconceptions
- “Heartbeat guarantees a fresh update every interval.” It is an update trigger configuration, and source or chain failures can still delay publication.
- “A recent timestamp proves a correct executable price.” It proves only the documented update time; source quality, units, confidence, market depth and consumer logic remain separate.
- “One maximum age works for every feed and action.” Assets, market hours, chains and borrowing, liquidation, trading and settlement actions have different latency and liveness needs.
- “Sequencer up means every action can resume immediately.” Recovery grace and price freshness are independent gates, and protocol or chain safety policies may add more.
- “Fallback or making every function revert is always safest.” A weak fallback misprices risk, while indiscriminate failure can prevent users from repaying or improving collateralization.
Related topics
Sources
- Chainlink Data Feeds - Chainlink Documentation (accessed: 2026-08-13)
- Data Feeds API Reference - Chainlink Documentation (accessed: 2026-08-13)
- Developer Responsibilities - Chainlink Documentation (accessed: 2026-08-13)
- L2 Sequencer Uptime Feeds - Chainlink Documentation (accessed: 2026-08-13)
- How to Use Real-Time Data in EVM Contracts - Pyth Developer Hub (accessed: 2026-08-13)
- Best Practices - Pyth Developer Hub (accessed: 2026-08-13)
- Units and Globally Available Variables - Solidity Documentation (accessed: 2026-08-13)
- SC03:2026 Price Oracle Manipulation - OWASP Smart Contract Security (accessed: 2026-08-13)