Oracles, L2s & EVM Chains
Contracts cannot access off-chain data (prices, weather, randomness, API results) by themselves.
39.1 The oracle problem
Contracts cannot access off-chain data (prices, weather, randomness, API results) by themselves. Oracles bring data on-chain; their security becomes your security.
Chainlink Data Feeds decentralized node networks push aggregated prices on deviation/heartbeat
Chainlink Data Streams, Pyth, RedStone pull-based: users submit signed price updates with their transaction Chainlink VRF Chainlink Automation scheduled/conditional execution Chainlink Functions / CCIP off-chain computation; cross-chain messaging and token transfers Uniswap v3/v4 TWAP on-chain time-weighted average price optimistic oracle (assertions with dispute period)
39.2 Safe Chainlink price consumer
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function latestRoundData()
external view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}
contract PriceConsumer {
AggregatorV3Interface public immutable feed; // e.g., ETH/USD feed address from docs.chain.link
AggregatorV3Interface public immutable sequencerFeed; // L2 sequencer uptime feed (zero on L1)
uint256 public immutable heartbeat; // e.g., 3600 s — check the feed's documented heartbeat
uint256 private constant GRACE_PERIOD = 1 hours;
error StalePrice();
error InvalidPrice();
error SequencerDown();
error GracePeriodNotOver();
constructor(address _feed, address _sequencerFeed, uint256 _heartbeat) {
feed = AggregatorV3Interface(_feed);
sequencerFeed = AggregatorV3Interface(_sequencerFeed);
heartbeat = _heartbeat;
}
/// @return price scaled to 18 decimals
function getPrice() public view returns (uint256) {
if (address(sequencerFeed) != address(0)) {
…39.3 Randomness with Chainlink VRF
On-chain values (block.prevrandao, blockhash, timestamps) are predictable or biasable by validators. VRF returns a random number with a cryptographic proof via a callback (fulfillRandomWords) in a later transaction. Design consequences: two-step flows (request → fulfill), never allow users to cancel/re-roll after seeing the request, and handle callback gas limits.
39.4 Layer 2s and EVM chains
Withdrawal to L1 Arbitrum One, OP Mainnet, Base (OP Stack), Blast post tx data to L1; assume valid unless a fraud proof challenges within ~7 days ~7 days (fast via bridges/liquidity) zkSync Era, Starknet (Cairo), Scroll, Linea, Polygon zkEVM, Taiko validity proofs verified on L1 after proof (hours) Sidechains / alt-L1 EVMs
Polygon PoS, BNB Chain, Avalanche C-Chain, Gnosis App-chains / L3s
Arbitrum Orbit, OP Superchain chains, ZK Stack chains custom rollups settling to an L2 or L1
Since EIP-4844 (Dencun, March 2024), rollups post data as blobs, making L2 fees cents or less.
39.5 Differences to watch when deploying cross-chain
some chains lack PUSH0, MCOPY, transient storage — set evmVersion on Arbitrum, returns an approximate L1 block number; use ArbSys(100).arbBlockNumber() for L2 blocks block.timestamp, block times vary (e.g., 2 s on OP Stack, ~0.25 s on Arbitrum) — don't assume 12 s
L2 fee = L2 execution + L1 data cost; gas tricks that save L1 execution may not matter different bytecode (zksolc compiler), different CREATE/CREATE2 address derivation, native account abstraction Precompiles / opcodes
PREVRANDAO, COINBASE, SELFDESTRUCT semantics differ on some chains centralized sequencers can go down — use uptime feeds for liquidations same deployer + nonce or CREATE2 gives same address across chains; tokens at same address may differ replay protection by chain ID; use audited messaging (CCIP, native bridges, LayerZero, Hyperlane, Wormhole)