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.
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.
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
}
}
- Aggregator = many independent node operators signing the same value; on-chain median.
- Always check
updatedAt(staleness) and thatanswer > 0. - Different feeds update at different cadences (heartbeat + deviation threshold).
3. Oracle design taxonomy
| Type | How it works | Example |
|---|---|---|
| Push | Operators proactively update on-chain | Chainlink data feeds |
| Pull | User fetches signed data off-chain, submits with tx | Pyth, Redstone |
| Optimistic | Anyone posts; anyone can challenge with bond | UMA |
| VRF | Verifiable randomness | Chainlink 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
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
| Protocol | Trust model | Latency |
|---|---|---|
| CCIP (Chainlink) | DON + anti-fraud monitoring | Minutes |
| LayerZero v2 (OApp) | Configurable DVN + Executor; EndpointV2 | Minutes |
| Axelar | Own PoS validator set | ~1 min |
| Wormhole | 19 guardians | ~15 min |
| Hyperlane | ISM (modular, app-picks) | Varies |
| Canonical rollup bridge | L1 inherits via proof | 7d 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);
}
labs/phase-23-bridge/ models message state without claiming production bridge security.6b. Light-client vs multisig bridges
| Model | Trust | When |
|---|---|---|
| Multisig / oracle relay | N-of-M attesters | Faster; bridge hacks historically here |
| Light client on-chain | Consensus header verification | Stronger; higher gas/complexity |
| Rollup canonical bridge | L1 proof + challenge window | Preferred 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
- Burn-and-mint bridged tokens (supply conserved).
- Lock-and-mint (L1 lock, L2 mint; most rollups).
- Atomic swaps via hashed-timelock contracts (mostly historical).
- Liquidity-based bridges (Stargate, Hop, Across) — instant UX, uses LP pools on each chain.
10. Project
Quiz
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?- Nothing; Chainlink is always live
- Stale oracle → under-collateralized loan → bad debt for the protocol
- Reentrancy
- Front-running