agentleFS
iktok90-designiktok90-design/ai-smart-contract-auditor/skills/oracle-redundancy/SKILL.md

oracle-redundancy

Skill36 starsChanged 5 months agoMITView on GitHub

Detect oracle fallback and redundancy failure modes (distinct from price manipulation) — single point of failure, missing staleness/heartbeat/deviation checks, an "all oracles down" path that reverts or silently returns stale/zero, missing L2 sequencer-uptime feed, and absent circuit breakers. Activate whenever code reads a price/rate feed, especially Chainlink latestRoundData, with fallbacks or on an L2.

The file

We split this skill into the rules it gives an agent

1 rule. About 0 are common, 1 is distinctive, and 0 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Fail closed: when all sources are stale/invalid, pause the affected operations rather than returning 0, last price, or reverting …

    line 69

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Oracle redundancy detection

When this applies

Trigger on any of:

  • latestRoundData() / latestAnswer() reads from Chainlink or any push feed
  • Custom oracle aggregators with primary + fallback sources
  • L2 deployments reading any price feed (Arbitrum, Optimism, Base, etc.)
  • Rate/price reads that gate borrowing, liquidation, minting, or redemption
  • Any "if primary fails, use secondary" branching

Detection patterns

Missing staleness / heartbeat check (HIGH)

(, int256 price,,,) = feed.latestRoundData();   // ignores updatedAt & answeredInRound
require(price > 0);
return uint256(price);

Signal: no updatedAt freshness gate. A frozen feed (feed deprecated, node outage, or a market-wide halt) returns the last value forever; protocol prices off stale data. Require block.timestamp - updatedAt <= heartbeat and answeredInRound >= roundId.

Single point of failure (HIGH)

One feed, no fallback, no degradation plan. If that feed is deprecated or returns garbage, the protocol is bricked or mispriced. Signal: a hard dependency on exactly one external address with no alternative path.

Fallback that silently returns 0 or last price (HIGH)

try feed.latestRoundData() returns (...) { ... }
catch { return lastGoodPrice; }   // ← stale, or worse:
catch { return 0; }               // ← 0 collateral value = mass liquidation, or free mint

Signal: the catch path masks failure. Returning 0 can make collateral worthless (mass liquidation) or debt free; returning a stale cached price keeps trading on bad data. Failures must surface, not be swallowed.

Missing L2 sequencer-uptime feed (HIGH on L2)

// Arbitrum/Optimism: no check of the sequencer uptime feed
(, int256 answer, uint256 startedAt,,) = sequencerUptime.latestRoundData();
require(answer == 0 && block.timestamp - startedAt > GRACE_PERIOD);

Signal: on an L2, if the sequencer was down, Chainlink prices are stale on resume. Without the uptime feed + grace period, the first post-downtime block liquidates everyone at stale prices. Chainlink documents this exact guard.

"All oracles down" path undefined (MEDIUM)

The aggregator handles primary-down but has no defined behavior when every source is stale/reverting — it either reverts (DoS) or falls through to an uninitialized default. Define an explicit safe-halt (pause) rather than trade on uncertainty.

No deviation / circuit breaker (MEDIUM)

Accepting any reported price without comparing primary vs secondary deviation, so a single compromised/erroneous feed is trusted outright.

Severity rubric

PatternSeverityNotes
Fallback returns 0 on failureHighMass liquidation / free mint
Missing staleness/heartbeat gateHighTrades on frozen price
Single feed, no fallbackHighBrick / misprice on outage
Missing L2 sequencer-uptime checkHighStale-price liquidation on resume
"All down" path reverts (DoS) vs safe-haltMediumAvailability vs safety tradeoff
No primary/secondary deviation checkMediumSingle bad feed trusted

Remediation patterns

  1. Validate every read: updatedAt freshness vs a per-feed heartbeat, answeredInRound >= roundId, price > 0, and a sane min/max bound.
  2. L2 sequencer-uptime feed + GRACE_PERIOD before trusting prices post-downtime (Chainlink reference pattern).
  3. Real redundancy: primary + independent secondary (e.g. Chainlink + Uniswap V3 TWAP / Pyth) with a deviation threshold; disagreement → pause, not pick-one.
  4. Fail closed: when all sources are stale/invalid, pause the affected operations rather than returning 0, last price, or reverting unboundedly.
  5. Circuit breaker on max per-block deviation to absorb wicks.

False-positive notes

  • A feed read that already checks updatedAt, answeredInRound, and bounds is fine — don't re-flag for "no fallback" if it correctly pauses on staleness.
  • Mainnet-only contracts don't need the sequencer feed — don't flag its absence off-L2.
  • A deliberate revert-on-stale (fail-closed) is acceptable when paired with a pause path; distinguish from an unbounded DoS.

Related

  • [[oracle-manipulation]] — manipulation is the price-correctness sibling to redundancy
  • [[liquidation-cascade]] — stale/zero prices trigger mass liquidation
  • [[dos-vectors]] — revert-on-all-down can become a denial of service

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.