Intermediate

Oracles & Off-Chain Data — Hands-on lab

Use oracles safely.

Developer Intermediate
4/6 — Oracles & Off-Chain Data — Hands-on lab

Exercise the edge cases Happy paths are trivial; the real work is rejecting stale/invalid data and handling VRF fulfillment securely. Treat circuit breakers as product features—users should understand why an action is paused.

A distributed system is one in which the failure of a computer you didn’t even know existed can render your own computer unusable.
— Leslie Lamport

Make it observable Emit events when guards trip: stale feed, deviation exceeded, VRF fulfillment errors. This helps dashboards and support teams respond.

Fail closed, practice recovery Simulate outages and show how to unpause or switch feeds. Write down the runbook for ops to follow during incidents.

TWAP window (simplified)
twap = Σ(pricei × Δti) ÷ ΣΔti
Use time-weighted averages to dampen manipulation; ensure window length matches your risk tolerance.
function readPrice() public view returns (uint256) {
    (
        uint80 roundId,
        int256 answer,
        ,
        uint256 updatedAt,
        uint80 answeredInRound
    ) = feed.latestRoundData();
    require(answer > 0, "bad answer");
    require(updatedAt >= block.timestamp - 1 hours, "stale");
    require(answeredInRound >= roundId, "incomplete");

    uint256 price = uint256(answer) / 10**feed.decimals();
    uint256 prev = lastGoodPrice;
    uint256 deviation = price > prev ? (price - prev) * 1e18 / prev : (prev - price) * 1e18 / prev;
    require(deviation <= 5e16, "deviation too high"); // 5%
    return price;
}
Steps
  1. Integrate a Chainlink feed:On a testnet; read latestRoundData with freshness, decimals, and min/max bounds. Store the last good price.
  2. Add a deviation guard:If |new-old| / old > threshold, revert or require manual confirmation. Log an event when tripped.
  3. Implement VRF v2:Fund a subscription, request randomness, fulfill, and consume it in a raffle/lottery. Ensure only the coordinator can fulfill.
  4. Add a circuit breaker:That pauses price-dependent actions when the feed is stale/invalid or when the sequencer is down on L2.
  5. Write tests for stale:Rounds, invalid roundId/answeredInRound, decimal mismatch, deviation breaches, VRF fulfill order, and replay attempts.
  6. Optionally add a secondary:Feed or manual override role and test the switchover path.
← Previous section
Next section →