web3.path

PHASE 14 Interop · ~3 hours

Cross-chain & Oracles

A blockchain can only see itself. To know "what's ETH/USD" or "did something happen on Solana", you need bridges (move value) or oracles (import data). Both are trust-minimized, not trust-free.

Goal — understand oracle design (Chainlink, UMA), messaging protocols (LayerZero, CCIP, Wormhole, Axelar), and integrate a price feed into a contract.

1. Oracles — why they're hard

A smart contract has no HTTP client. You can't fetch("https://coinbase.com/btc"). Instead, off-chain nodes ("oracles") push signed data on-chain. The contract trusts them.

Analogy — a contract is a server with no egress firewall rule. Oracles are a proxy that reads the outside world and posts signed messages through the one inbound port.

2. Chainlink price feeds — 80% of what you need

import "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";

contract PriceConsumer {
    AggregatorV3Interface feed;
    constructor(address _feed) { feed = AggregatorV3Interface(_feed); }
    function priceUSD() external view returns (int256) {
        (, int256 answer, , uint256 updatedAt,) = feed.latestRoundData();
        require(block.timestamp - updatedAt < 1 hours, "stale");
        return answer;   // 8 decimals
    }
}

3. Oracle design taxonomy

TypeHow it worksExample
PushOperators proactively update on-chainChainlink data feeds
PullUser fetches signed data off-chain, submits with txPyth, Redstone
OptimisticAnyone posts; anyone can challenge with bondUMA
VRFVerifiable randomnessChainlink VRF

Pull oracles are often cheaper (users pay gas only when they need fresh data) but more UX complexity.

4. Cross-chain messaging — the shape of the problem

Chain A: Sender contract → ? ? ? → Chain B: Receiver contract Between: "who relays, who attests, who's liable if they lie?"

All bridges boil down to: a set of validators attests to "this message happened on chain A", and chain B trusts them up to some threshold.

5. Messaging protocol cheat sheet

ProtocolTrust modelLatency
CCIP (Chainlink)DON + anti-fraud monitoringMinutes
LayerZero v2 (OApp)Configurable DVN + Executor; EndpointV2Minutes
AxelarOwn PoS validator set~1 min
Wormhole19 guardians~15 min
HyperlaneISM (modular, app-picks)Varies
Canonical rollup bridgeL1 inherits via proof7d optimistic / hours zk

6. LayerZero v2 (OApp) — use v2 for new work

LayerZero v1 is legacy. New integrations use EndpointV2 and OApp with configurable DVNs (decentralized verifiers) and executors. Pin version per toolchain matrix.

// OApp v2 receive path — validate endpoint + peer
function _lzReceive(
    Origin calldata origin, bytes32, bytes calldata payload, address, bytes calldata
) internal override {
    require(peers[origin.srcEid] == origin.sender, "untrusted peer");
    _handleMessage(origin.srcEid, payload);
}
Rule — always validate endpoint caller and source peer. Lab: labs/phase-23-bridge/ models message state without claiming production bridge security.

6b. Light-client vs multisig bridges

ModelTrustWhen
Multisig / oracle relayN-of-M attestersFaster; bridge hacks historically here
Light client on-chainConsensus header verificationStronger; higher gas/complexity
Rollup canonical bridgeL1 proof + challenge windowPreferred for same-ecosystem L2

7. The bridge trilemma (Vitalik, 2022)

You can't have all three: (a) trust-minimized, (b) generalized (arbitrary messages), (c) works across independent chains. Pick two. This is why every bridge design is a different compromise.

8. VRF — on-chain randomness

block.timestamp, blockhash and block.prevrandao are manipulable. For fair NFT reveals, lotteries, matchmaking — use Chainlink VRF.

function requestRandom() external {
    uint256 reqId = vrf.requestRandomWords(...);
    pending[reqId] = msg.sender;
}
function fulfillRandomWords(uint256 reqId, uint256[] memory words) internal override {
    // use words[0] deterministically
}

9. Patterns that actually ship

10. Project

Deliverable — use two contracts to model a message lifecycle: on Sepolia, lock an ERC-20; on Base Sepolia, mint a wrapped version through a test endpoint. Prove authentication of the transport and remote peer, source-chain binding, message ID/nonce consumption, duplicate/out-of-order handling, rate limits, supply caps, emergency pause, and sent→delivered→executed monitoring. Use Phase 23’s simulated receiver before relying on any production bridge protocol.

Quiz

Q. Your contract reads feed.latestRoundData() but doesn't check updatedAt. In a sequencer outage, the price was stale for 3 hours at $100 while the real price dropped to $50. A user borrowed against an asset at the stale price. What just happened?
Stale-price checks are mandatory. On L2s also check the L2 sequencer uptime feed — there's a dedicated Chainlink feed for "is the sequencer up".
← Phase 13Phase 15: Production Engineering →