A chain-agnostic transaction router is a smart contract system that enables users to submit a single, standardized transaction intent. The router then handles the complexities of selecting the optimal destination chain, managing gas fees, and executing the transaction. This abstraction is fundamental for building seamless cross-chain applications, moving beyond simple asset bridges to enable complex interactions like cross-chain lending, governance, and NFT minting. The core challenge is designing a system that can validate intents, estimate costs across networks, and ensure atomic execution or safe rollback.
How to Implement a Chain-Agnostic Transaction Router
How to Implement a Chain-Agnostic Transaction Router
Learn to build a transaction router that can execute operations across any EVM-compatible blockchain, abstracting away chain-specific complexities.
The architecture typically involves three key components: an Intent Listener, a Chain Selector, and an Executor. The Intent Listener receives structured user requests (e.g., "swap X tokens for Y on the chain with the best price"). The Chain Selector, which may query off-chain oracles or on-chain liquidity data, determines the most efficient target chain based on parameters like gas costs, latency, and liquidity depth. The Executor is responsible for holding funds in escrow, initiating the transaction on the selected chain via a generalized message passing protocol like Chainlink CCIP or Axelar, and handling the callback for success or failure.
Implementing the router requires careful state management to track pending cross-chain transactions. You must assign a unique, incrementing crossChainId to each user intent and store it in a mapping with its status. When using a cross-chain messaging service, you will receive a message ID from the protocol; your contract must map this external ID back to your internal crossChainId. This dual-ID system is critical for correctly routing execution confirmations and failures back to the original user request. Always implement a timeout mechanism to release escrowed funds if a transaction is not finalized within a specified period.
Security is paramount. Your router must validate all incoming intents to prevent malformed data from clogging the system. When integrating with a cross-chain protocol, you are placing trust in its security model. Therefore, implement pausable functions and guardian multisig controls for critical operations like updating the Executor address or the supported chain ID list. Use OpenZeppelin's ReentrancyGuard for functions handling asset escrow. Thoroughly test failure scenarios, such as a destination chain transaction reverting, to ensure assets are always returned to the user or the operation is retried transparently.
Start development by setting up a Foundry or Hardhat project and importing the necessary SDKs, such as the Axelar Gateway SDK or Chainlink CCIP SDK. Write and deploy a mock TargetContract on two testnets (e.g., Sepolia and Mumbai) that your router will call. Your main router contract should implement a function like routeTransaction(uint256 targetChainId, bytes calldata payload, address target) that encodes the logic for sending a cross-chain message. Use the protocol's SDK to estimate the gas fee required on the destination chain and require the user to supply this as part of their transaction value.
The future of chain-agnostic routing lies in intent-based architectures and shared sequencer networks. Instead of prescribing exact transaction paths, users will declare desired outcomes ("I want to buy 1 ETH with USDC"), and a network of solvers will compete to fulfill it across chains. Projects like Across Protocol and SocketDL are pioneering this approach. As a developer, designing your router with modular adapters for different cross-chain protocols and solver networks will ensure it remains adaptable as the interoperability landscape evolves beyond simple message passing.
Prerequisites
Before building a chain-agnostic transaction router, you need a solid grasp of core Web3 concepts and development tools. This section outlines the essential knowledge and setup required.
A chain-agnostic transaction router is a system that intelligently routes user transactions across multiple blockchains to achieve the best outcome, such as lowest cost or fastest execution. To build one, you must first understand the fundamental components of the multi-chain ecosystem. This includes knowledge of EVM-compatible chains (like Ethereum, Arbitrum, Polygon), their unique fee markets, and the concept of gas tokens. You should also be familiar with cross-chain messaging protocols like LayerZero, Axelar, and Wormhole, which enable communication between these isolated networks.
Your development environment must be configured for multi-chain interaction. This requires setting up a Node.js or Python project and installing essential libraries. For EVM chains, you'll need the ethers.js v6 or viem library for interacting with smart contracts and providers. A multi-RPC provider service like Alchemy, Infura, or QuickNode is crucial for reliable access to various networks. You will also need testnet tokens (e.g., Sepolia ETH, Mumbai MATIC) for deployment and testing. Managing private keys securely using environment variables (via dotenv) is a non-negotiable best practice.
A deep understanding of smart contract interactions is required. Your router will need to call functions on decentralized exchanges (DEXs) like Uniswap, bridges, and liquidity pools. You must know how to encode transaction calldata, estimate gas, and handle reverts. Familiarity with common token standards—especially ERC-20 for fungible tokens and the permit function for gasless approvals—is essential. You should also understand how to read and interact with contract ABIs to dynamically construct transactions for various protocols.
Finally, you need a strategy for discovering and evaluating routes. This involves querying on-chain and off-chain data sources for real-time information. You'll need to fetch token prices from oracles like Chainlink, check liquidity pool reserves on DEXs, and pull current gas prices from network providers. Implementing an efficient algorithm to compare these data points—balancing gas costs, swap rates, and bridge delays—is the core challenge. Start by prototyping a simple comparator that evaluates two possible paths for a swap.
How to Implement a Chain-Agnostic Transaction Router
A chain-agnostic transaction router is a middleware system that intelligently routes user transactions across multiple blockchains, abstracting away network complexity. This guide outlines its core architectural components and implementation logic.
A chain-agnostic transaction router functions as a decentralized application's execution layer. Its primary goal is to select the optimal blockchain network for a given transaction based on real-time conditions like gas fees, latency, and liquidity depth. The architecture is built on three core pillars: a quote engine for simulating costs, a liquidity aggregator to source assets, and a relayer network for final execution. Unlike a simple bridge, a router does not lock assets but instead facilitates a direct swap or action on the destination chain, often using protocols like Socket, Li.Fi, or a custom solver network.
The implementation begins with the quote engine. This component must connect to RPC providers for each supported chain (e.g., Ethereum, Arbitrum, Polygon) to fetch live gas prices and simulate transaction outcomes. For a swap, it would call the quote functions on multiple DEX aggregators like 1inch, 0x, and CowSwap. The engine evaluates all returned quotes using a scoring algorithm that weighs cost (gas + fees), speed (estimated block time), and success probability. The result is a ranked list of possible routes.
Next, the liquidity aggregator resolves the chosen route. If the best quote involves a cross-chain swap from ETH on Ethereum to USDC on Arbitrum, the aggregator must ensure liquidity is available on both ends. It interacts with bridge protocols (e.g., Hop, Across) and liquidity pools. A critical implementation detail is managing approvals and allowances in a non-custodial way, typically using ERC-20 permit signatures or a pre-approved smart contract wallet like Safe to batch operations.
Finally, the relayer network executes the transaction. For a truly chain-agnostic user experience, the router should sponsor gas fees on the destination chain—a concept known as gas abstraction. This can be implemented via ERC-4337 account abstraction, using a paymaster contract, or by leveraging relayer services like Biconomy or Gelato. The relayer submits the signed user transaction, monitors its status across chains, and provides a unified transaction hash for tracking.
Security is paramount. The router's smart contracts must be audited and designed with modularity, allowing components to be upgraded. Use a circuit breaker pattern to pause operations if anomalous conditions are detected. Furthermore, implement slippage protection and deadline parameters on every transaction to shield users from unfavorable market moves during the multi-step process. Always source price data from multiple oracles like Chainlink to avoid manipulation.
In practice, developers can integrate existing SDKs like Socket's Fusion or Li.Fi's SDK to bootstrap functionality. For a custom build, the stack typically involves Node.js/TypeScript for the backend routing logic, ethers.js or viem for chain interaction, and a Redis cache for storing temporary quote data. The end system provides a single routeTransaction function that accepts a user's intent and returns a seamless, optimized cross-chain execution.
Core System Components
A transaction router is the core engine for cross-chain execution. This section breaks down the essential components you need to build one.
Fallback & State Management
Handle transaction failures and maintain consistency. Key components:
- State Machine: Track each cross-chain transaction through states (Created, Sent, Confirmed, Executed, Failed).
- Fallback Handlers: If a swap on the destination chain fails, logic should return funds or retry with different parameters.
- Nonce Management: Ensure transactions are executed in the correct order across chains to prevent race conditions and double-spends.
Step 1: Query Bridge and Messaging Protocols
The first step in building a chain-agnostic router is to gather real-time data on available cross-chain paths, their costs, and security guarantees.
A transaction router must first understand the cross-chain liquidity landscape. This involves programmatically querying multiple bridge and messaging protocols—like Axelar, Wormhole, LayerZero, and Hyperlane—to collect live data on supported routes, asset availability, transfer fees, and estimated completion times. Each protocol exposes this data differently, often through a combination of REST APIs, GraphQL endpoints, and on-chain contract calls. Your router's initial job is to normalize this heterogeneous data into a consistent internal model for comparison.
Key data points to query for each potential route include the source and destination chain IDs, the specific token contract addresses (as they differ per chain), the current estimated gas fee on both sides, the protocol's bridge fee structure, and the security model (e.g., optimistic, zk-proof, or external validator set). For messaging protocols, you also need the message fee and gas airdrop requirements for the destination chain. This data forms the raw input for the routing algorithm in the next step.
Implementing these queries requires robust error handling and fallback logic. Bridge APIs can be rate-limited or temporarily unreachable. A production router should cache responses with short TTLs (e.g., 30 seconds) to reduce latency and load, while implementing retry logic with exponential backoff for failed requests. It's also critical to verify the returned data, such as checking that the destination token address is a legitimate, non-zero contract.
Here is a simplified TypeScript example using the Axelar SDK to query a transfer fee:
typescriptimport { AxelarQueryAPI, Environment } from "@axelar-network/axelarjs-sdk"; const axelarQuery = new AxelarQueryAPI({ environment: Environment.TESTNET }); async function getAxelarFee(sourceChain, destChain, symbol, amount) { try { const fee = await axelarQuery.estimateGasFee( sourceChain, destChain, symbol, BigInt(amount) ); return fee; } catch (error) { console.error("Axelar fee query failed:", error); return null; } }
This function fetches the estimated gas fee for moving an asset, which is a core component of the total transfer cost.
After aggregating data from all target protocols, your system should have a list of viable routes for a given user request (e.g., "Send 1 ETH from Ethereum to Arbitrum"). The next step is to apply a routing algorithm to this dataset to select the optimal path based on predefined criteria like cost, speed, or security.
Step 2: Integrate DEX Aggregator APIs
Learn how to query multiple DEX aggregators to find the best cross-chain swap routes and execute them through a unified interface.
A chain-agnostic transaction router needs to source liquidity from multiple venues. Instead of integrating directly with dozens of individual DEXes, you can use DEX aggregator APIs like 1inch, 0x, ParaSwap, and CowSwap. These services aggregate liquidity across their integrated protocols, find optimal swap routes, and provide a simple API endpoint to fetch a ready-to-sign transaction. Your router's core function is to query these aggregators across different chains, compare the returned quotes, and select the best one for the user based on output amount, gas costs, and security assumptions.
Start by setting up API clients for your chosen aggregators. Most provide a RESTful API with a standard request pattern: you specify the chainId, sellToken, buyToken, and sellAmount. The response includes the buyAmount, estimated gas, and a transaction object. For example, a request to the 1inch API for a swap on Ethereum might look like GET https://api.1inch.io/v5.0/1/swap?fromTokenAddress=0xEee...&toTokenAddress=0xaaa...&amount=1000000000000000000. You must handle chain-specific RPC endpoints and native token addresses (like 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for ETH).
To implement a true multi-aggregator comparison, you need to parallelize API calls. Use Promise.all() or similar concurrency patterns to fetch quotes from 1inch, 0x, and ParaSwap simultaneously for the same swap parameters. Once all quotes are received, your logic must normalize the data—comparing net received amount after deducting aggregator fees and estimating network gas costs in the token you're selling. This final comparison yields the effective exchange rate. Remember to implement robust error handling; if one aggregator fails or times out, your router should fall back to the results from the others.
After selecting the best quote, you must prepare the transaction for the user's wallet. The transaction object from the aggregator typically requires a from address (the user) and a gasPrice or maxFeePerGas. For maximum compatibility, especially for meta-transactions or smart contract wallets, you should use the eth_sendTransaction or eth_sendRawTransaction RPC methods. Libraries like ethers.js or viem simplify this. Critical security step: always validate that the transaction's to address matches the aggregator's official router contract for that chain, which you should hardcode or fetch from a verified source to prevent phishing.
For advanced routing, consider cross-chain aggregators like LI.FI or Socket. Their APIs accept a source chain, asset, and destination chain, returning a complex route that may involve a bridge and a destination-chain swap. Integrating these adds another dimension, requiring you to compare single-chain swap routes against cross-chain bundle routes. Your comparison logic must account for bridge security, time-to-completion, and any intermediate wrapping steps. The core principle remains: your router is a meta-aggregator, querying multiple services to find the single best path for the user's intent.
Step 3: Implement the Pathfinding Algorithm
The pathfinding algorithm is the engine of your transaction router. It evaluates available liquidity across chains and protocols to find the optimal route for a user's swap.
At its core, pathfinding is a graph search problem. Each blockchain is a node, and each bridge or cross-chain liquidity pool is an edge connecting them. Your algorithm must traverse this graph to find a sequence of hops that fulfills the swap request—maximizing output amount, minimizing cost, or optimizing for speed. For simple two-chain swaps, you might check a few direct bridges. For complex multi-hop routes across 3+ chains, you need a more sophisticated approach like a modified Dijkstra's algorithm or A* that can handle the state (e.g., current token, chain) and constraints like gas fees on each leg.
You'll need real-time data to power the search. This includes: token prices from oracles like Chainlink, available liquidity in pools (e.g., on Uniswap, Curve), bridge fees, estimated gas costs on destination chains, and bridge security ratings. Fetch this data from RPC providers, subgraphs, and bridge APIs, caching aggressively to avoid latency. Structure your data model so the algorithm can quickly query all possible "next hops" from any given (chainId, tokenAddress) state. Many routers use a priority queue to explore the most promising routes first.
Here's a simplified TypeScript skeleton for a basic pathfinder. It assumes you have functions to fetch possible bridges and liquidity pools for a given asset.
typescriptinterface RouteStep { fromChainId: number; toChainId: number; bridgeProtocol: string; inputToken: string; outputToken: string; estimatedOutput: bigint; // Account for fees & slippage gasCost: bigint; } async function findBestRoute( startChainId: number, startToken: string, endChainId: number, endToken: string, amountIn: bigint ): Promise<RouteStep[]> { // Priority queue: routes with highest estimated output are explored first const queue = new PriorityQueue<{path: RouteStep[], outputEstimate: bigint}>((a, b) => b.outputEstimate - a.outputEstimate); queue.push({path: [], outputEstimate: amountIn}); while (!queue.isEmpty()) { const {path, outputEstimate} = queue.pop(); const currentState = getCurrentStateFromPath(path, startChainId, startToken); // Goal check if (currentState.chainId === endChainId && currentState.token === endToken) { return path; } // Get all possible next hops (bridges & destination DEX pools) const nextHops = await fetchPossibleHops(currentState, outputEstimate); for (const hop of nextHops) { const newPath = [...path, hop]; // Prevent cycles & apply heuristics (e.g., max hops) if (!hasCycle(newPath) && newPath.length <= MAX_HOPS) { queue.push({path: newPath, outputEstimate: hop.estimatedOutput}); } } } throw new Error('No route found'); }
For production, this basic search must be heavily optimized. You'll need to implement pruning to discard suboptimal routes early, use memoization to avoid recalculating states, and integrate slippage models from DEXes like 1inch or 0x. Consider security in your scoring function; a route using a newer, less-audited bridge might offer a slightly better rate but carry higher risk. Many projects use a weighted scoring system that balances output amount (weight=0.7), total cost (weight=0.2), and security score (weight=0.1).
Finally, validate the theoretical route. Before returning it to the user, perform simulation calls using eth_call or similar methods on each step to verify the expected output amounts and that the route is still valid (liquidity hasn't moved). Tools like Tenderly or OpenZeppelin Defender can help simulate cross-chain transactions. The output of this step is a complete, executable route object that your next component—the transaction assembler—will use to construct the actual cross-chain transaction bundle.
Cross-Chain Protocol Comparison for Integration
Key technical and economic factors for selecting a cross-chain messaging protocol to power a transaction router.
| Protocol Feature / Metric | LayerZero | Wormhole | Axelar |
|---|---|---|---|
Consensus Mechanism | Decentralized Oracle Network | Guardian Network (19 Nodes) | Proof-of-Stake Validator Set |
Gas Abstraction | |||
General Message Passing | |||
Avg. Finality Time | 3-5 min | ~15 sec | ~6 min |
Relayer Cost per Tx | $2-5 | $0.25-1 | $0.10-0.50 |
Supported Chains | 50+ | 30+ | 55+ |
Native Token for Fees | |||
Pre-Crime / Security Stack |
Step 4: Build the Execution Engine
This step details the core logic for routing and executing transactions across different blockchains, focusing on gas optimization and failure handling.
The execution engine is the core component that receives a validated cross-chain intent—like "swap 1 ETH on Arbitrum for USDC on Polygon"—and orchestrates its fulfillment. Its primary responsibilities are transaction routing and gas management. It must determine the optimal sequence of on-chain calls across potentially multiple networks, handle the funding and execution of these calls, and manage the entire lifecycle from initiation to final settlement or rollback. A robust engine abstracts the complexities of individual chain RPCs, gas price estimation, and nonce management from the user.
Start by defining a Route data structure. This should encapsulate the entire execution path, including the source and destination chains, the sequence of Action objects (e.g., BridgeAction, SwapAction), and the required asset flow between them. Each Action must specify its target chain, target contract address, calldata, and value. The engine's router uses this to calculate the optimal path, often querying decentralized aggregators like 1inch Fusion or SocketDL for quotes, balancing speed, cost, and success probability.
Gas management is critical. The engine must hold or have access to native gas tokens on every chain it operates on. Implement a GasEstimator module that polls multiple sources (e.g., chain RPCs, services like Blocknative or Gas Station Network) for current base fees and priority fees. For sponsored transactions or gas abstraction, integrate with paymaster contracts like those from Biconomy or Pimlico. The engine should estimate total gas costs for the entire route upfront and ensure sufficient funds are available, potentially using a gas tank model on a hub chain.
Execution follows a state machine pattern, often with statuses like Pending, Executing, Completed, or Failed. Use a transaction manager to submit each step, monitor its inclusion via receipts, and handle retries with adjusted gas prices if necessary. For atomicity, consider conditional logic: if a swap on the destination chain fails, the engine should execute a fallback, such as bridging the received assets back to the source chain. Libraries like Viem or Ethers.js are essential for consistent multi-chain interaction.
Finally, implement comprehensive logging and monitoring. Every route attempt, gas estimate, transaction hash, and state transition should be logged. Integrate with alerting systems to flag stuck transactions or repeated failures. The engine's API should expose endpoints for users to query the status of their cross-chain intents, providing transparency into each step of the execution process. This completes the functional core, enabling reliable, chain-agnostic transaction routing.
Frequently Asked Questions
Common questions and technical clarifications for developers implementing a chain-agnostic transaction router.
A chain-agnostic transaction router is a smart contract system that dynamically selects and executes the optimal path for a cross-chain transaction. It abstracts away the complexity of interacting with individual bridges and DEXs by evaluating multiple factors in real-time.
Key components include:
- Quote Aggregator: Fetches prices, fees, and estimated times from multiple liquidity sources (e.g., Stargate, Axelar, Wormhole) and DEXs.
- Pathfinder Algorithm: Computes the best route based on parameters like total cost, speed, and security.
- Execution Engine: Handles the multi-step transaction, managing approvals, bridging, and swaps atomically where possible.
The goal is to provide users with the best possible outcome (highest output, lowest cost, fastest time) without requiring them to manually compare dozens of protocols.
Essential Resources and Tools
These resources cover the core components required to build a chain-agnostic transaction router, from cross-chain messaging layers to execution, quoting, and safety tooling. Each card focuses on a concrete tool or concept that developers can integrate directly.
Conclusion and Next Steps
This guide has outlined the core architecture for building a chain-agnostic transaction router. Here's a recap of key learnings and resources for further development.
A successful chain-agnostic router requires a modular architecture. The core components are a quote engine (e.g., using 1inch Fusion, 0x API, or a custom solver network), a gas estimator that accounts for different base and priority fees across chains, and a unified interface (like EIP-5792) for managing bundled transactions. The router's primary function is to abstract chain-specific complexities—such as differing RPC calls, native tokens, and block times—behind a single, consistent API for the end-user application.
For implementation, start by integrating with a multi-chain RPC provider like Chainstack, Alchemy's Supernode, or a decentralized network. Use viem or ethers.js with custom chain configurations to handle interactions. A critical pattern is the Intent Listener: your backend should listen for user intents (e.g., "swap X for Y with max slippage Z"), source the optimal route across supported chains via your quote engine, and then construct a UserOperation for an account abstraction wallet or a bundled transaction for an EOA using a relayer service like Biconomy or Gelato.
Security and testing are paramount. Key considerations include validating all quote data on-chain, implementing robust slippage protection that factors in cross-chain latency, and conducting thorough audits of your routing logic. Use forked mainnet environments (via Foundry Anvil or Hardhat) to simulate transactions across multiple chains. Monitor for bridge risks when routing involves cross-chain asset transfers; prefer native fast bridges with attestation security or validated canonical bridges.
To extend your router, explore advanced features. Integrate MEV protection by routing through private RPC endpoints or using services like Flashbots Protect. Implement dynamic fee optimization that adjusts for real-time network congestion. Consider adding support for intent-based architectures, where users sign declarative statements of desired outcomes rather than specific transactions, which can be settled by a decentralized solver network.
For further learning, review the documentation for leading routing APIs (1inch, 0x, LI.FI), account abstraction standards (ERC-4337, EIP-5792), and cross-chain messaging layers (LayerZero, Axelar, Wormhole). The codebase for the Uniswap Universal Router and CowSwap's solver infrastructure provides valuable real-world references. Building a chain-agnostic router is an iterative process—start with support for two EVM chains, rigorously test the transaction lifecycle, and gradually expand to more ecosystems based on user demand and liquidity depth.