Example: LP on Aave from another chain
Bridge and supply in one signature. WETH on Base in, aUSDC on Arbitrum out, and the solver does the staking.
One argument selects LayerZero, Axelar or same-chain execution. What the Router does with it, what it refuses, and which routes are coming.
Hub and Spoke do not know how to cross a chain. They hand a Message to a Router and say which bridge to use. That single enum argument is the whole bridge decision an integrator makes, and it can be changed per order without touching code. Dapps can pick a provider or let the user pick.
enum Bridge { NULL, LAYERZERO, AXELAR, CCIP, ACROSS, EVERCLEAR, WORMHOLE }
struct Message {
Bridge bridge; // which bridge to use
uint32 chainId; // destination chain id
bytes32 destination; // receiver on the destination chain
bytes payload; // arbitrary data to deliver
bytes extra; // bridge-specific extra data
bytes32 sender;
}The BaseRouter is an interface for a generic cross-chain message router: callers pass a Message, pay any required fee, and if the chosen bridge is supported on this chain the router emits MessageBroadcasted. Otherwise it reverts with UnsupportedBridgingRoute().
Only whitelisted contracts may call it (NotWhitelisted otherwise). That protects the privileged messaging infrastructure from attackers and keeps the event log free of noise. On each chain a Router supporting one or both of the current bridges is deployed.
The LzRouter extends LayerZero’s OApp. It maps standard chain ids to LayerZero EIDs, sends messages, estimates the native fee for a call, and on arrival dispatches the payload to the target’s onMessageReceived hook. If no EID is configured for a chain it reverts with UnsupportedLzChain(). Use it on any chain LayerZero supports.
The AxRouter maps chain ids to Axelar chain names, keeps a peer router address per remote chain, and dispatches incoming messages to the right contract. It refuses unknown chains with UnsupportedAxChain() and refuses messages that do not come from the configured peer with InvalidPeer(). Use it on any chain Axelar supports.
An AxLzRouter exists too: one contract that supports both, for chains where both bridges are live.
The NullRouter does not bridge. If message.chainId equals block.chainid it delivers the payload immediately to the target; otherwise it reverts. Every router supports the null route, so an integrator gets same-chain order flow, the same RFQ, the same custody model, with the same code path. Set source and destination chain id to the same value and pick NULL.
The enum already reserves CCIP, ACROSS, EVERCLEAR and WORMHOLE. Chainlink CCIP and Across are next on the roadmap. Because the choice is an argument, adding a route means deploying a router, not migrating integrators.
Next: a complete order that turns WETH on Base into an Aave position on Arbitrum.
Bridge and supply in one signature. WETH on Base in, aUSDC on Arbitrum out, and the solver does the staking.