Order Routing System Development Across Multiple DEXes

The 1inch aggregator demonstrated a simple idea: if you're looking for the best price on only one DEX, you're leaving money on the table. Since then, order routing systems have evolved into complex solutions with split routing, multi-hop, and specialized algorithms. We design and implement such syst

Blockchain Development Services

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1450
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1308
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    1003
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1269
  • image_logo-advance_0.webp
    B2B Advance company logo design
    719
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    1009

The 1inch aggregator demonstrated a simple idea: if you're looking for the best price on only one DEX, you're leaving money on the table. Since then, order routing systems have evolved into complex solutions with split routing, multi-hop, and specialized algorithms. We design and implement such systems turnkey—from scratch or as an extension of existing infrastructure.

A custom order routing system is needed when standard aggregators (1inch, ParaSwap, 0x) don't support the required chain; integration of custom protocols is needed; control over liquidity sources is required; or existing APIs are too slow for a trading bot. Our track record: 5+ years in blockchain development and 30+ DeFi projects.

How Does an Order Routing System Across Multiple DEXes Work?

Routing is a pathfinding problem in a weighted directed graph. Vertices are tokens. Edges are pools—each pool creates two directed edges: A→B and B→A with the price in that direction.

To find the best path for a fixed amountIn, the task is to find the path with the maximum product of exchange rates (or equivalently, the minimum sum of negative logarithms). This is a modification of the Bellman-Ford or Dijkstra algorithm.

But there is a nuance that makes the problem harder: the price in a pool depends on volume. For amountIn = 100 USDC, the best route might be a Uniswap V3 0.05% pool. For amountIn = 1,000,000 USDC, the same pool gives 3% slippage, while splitting across multiple pools yields 0.3%. This transforms the problem from pathfinding in a fixed-weight graph into an optimization problem with volume-dependent weights.

How Does Split Routing Reduce Slippage on Large Orders?

For large orders, the optimal solution is not a single route but distributing volume across multiple paths. The approach using binary search for optimal split for two routes:

function findOptimalSplit( routeA: Route, routeB: Route, totalAmount: bigint, steps: number = 20 ): { splitA: bigint; splitB: bigint; totalOut: bigint } { let bestSplit = { splitA: 0n, splitB: totalAmount, totalOut: 0n } for (let i = 0; i <= steps; i++) { const fraction = i / steps const amountA = BigInt(Math.floor(Number(totalAmount) * fraction)) const amountB = totalAmount - amountA const outA = amountA > 0n ? simulateRoute(routeA, amountA) : 0n const outB = amountB > 0n ? simulateRoute(routeB, amountB) : 0n const totalOut = outA + outB if (totalOut > bestSplit.totalOut) { bestSplit = { splitA: amountA, splitB: amountB, totalOut } } } return bestSplit } 

For N routes, the problem becomes N-dimensional optimization—we apply gradient descent or Nelder-Mead with constraints (sum of shares = 1, all shares ≥ 0).

Pool Simulation: Accuracy vs Speed

Uniswap V2: Exact Formula

function getAmountOutV2(amountIn: bigint, reserveIn: bigint, reserveOut: bigint): bigint { const amountInWithFee = amountIn * 997n const numerator = amountInWithFee * reserveOut const denominator = reserveIn * 1000n + amountInWithFee return numerator / denominator } 

Uniswap V2 Whitepaper

Uniswap V3: Tick Traversal

V3 requires iterating over the tick bitmap to find the nearest active ticks. Full simulation is accurate but slow—several milliseconds for a large swap with traversal through many ticks.

For quick estimation (during route screening), we use an approximation via current sqrtPriceX96 and liquidity without tick traversal—accurate for small volumes, with error for large ones. Exact simulation is run only for final candidates.

Curve StableSwap: Iterative Formula

Curve uses the invariant A * n^n * sum(x_i) + D = A * D * n^n + D^(n+1) / (n^n * prod(x_i)). Computing amountOut is iterative (Newton's method). For JavaScript/TypeScript—BigInt arithmetic with 18-decimal precision.

Balancer WeightedPool

Balancer with weighted pools (e.g., 80/20 BAL/ETH) uses a different invariant. getAmountOut depends on token weights in the pool—a more complex formula than V2.

On-Chain vs Off-Chain Routing

Routing can happen entirely on-chain (smart contract finds the route inside the transaction) or off-chain (computation off-chain, result passed to the contract).

On-chain routing: full transparency, no possibility of manipulation by the aggregator. Problem: limited gas, cannot iterate over all routes. Used for simple cases (2–3 pools maximum).

Off-chain routing (approach of 1inch, ParaSwap): computation in the backend, the contract receives a ready-made route. The contract only executes. Gas efficient, route can be more complex. Risk: the backend might return a suboptimal route. Protection via slippage protection: minAmountOut in the transaction guarantees a minimum for the user.

How Is the Router Contract Structured?

The contract must support heterogeneous routes: part through Uniswap V2, part through V3, part through Curve.

struct SwapStep { address pool; address tokenIn; address tokenOut; uint24 fee; // For V3 uint8 dexType; // 0=V2, 1=V3, 2=Curve, 3=Balancer bytes extraData; // Additional parameters per DEX type } function multiSwap( SwapStep[] calldata steps, uint256 amountIn, uint256 minAmountOut, address recipient ) external returns (uint256 amountOut) { IERC20(steps[0].tokenIn).transferFrom(msg.sender, address(this), amountIn); uint256 currentAmount = amountIn; for (uint256 i = 0; i < steps.length; i++) { currentAmount = _executeStep(steps[i], currentAmount); } require(currentAmount >= minAmountOut, "Slippage exceeded"); IERC20(steps[steps.length-1].tokenOut).transfer(recipient, currentAmount); return currentAmount; } 

_executeStep dispatches to the specific DEX implementation based on dexType. Each implementation is a separate library (Solidity library pattern) to save bytecode size.

Why Is Pool Cache Critical for Speed?

For fast routing without RPC calls per request, we need a cache of the current state of pools: WebSocket subscriptions on Sync events (V2 pools) and Swap events (V3 pools) via eth_subscribe("logs"). On each event, we update reserves/sqrtPrice in memory.

For 500–1000 active pools, that's ~50–100 events/block on Ethereum mainnet. Processing via event-driven architecture (Node.js EventEmitter or Rust tokio channel) with ≤1ms update latency.

Cold start: on service startup, we need to load the current state of all pools via multicall. For 1000 pools—5–10 multicall transactions (up to 200 calls each), takes 1–3 seconds.

Architectural Approach Comparison

Approach When It Fits Complexity Latency
Simple multi-hop 3–5 chains, top-5 DEXes Low 200–500ms
Split routing Large orders ($50K+) Medium 500ms–1s
With pool cache Trading bot, < 50ms High 10–50ms
On-chain router Maximum transparency Medium 1 block

Estimated Development Time

Stage Time
Analytics (list of DEXes, latency requirements) 1–2 days
Routing engine development (graph, algorithm, simulation) 5–7 days
Router contract (multi-step, fork tests) 3–5 days
Pool cache (WebSocket + in-memory) 3–5 days
Integration, testing, documentation 2–3 days

Step-by-Step Development Process

  1. Pool and liquidity graph analysis — compile a map of tokens and pools for your chains.
  2. Pathfinding algorithm development — implement a modified Dijkstra accounting for volume dependency.
  3. Simulation integration — write simulators for Uniswap V2/V3, Curve, Balancer.
  4. Mainnet fork testing — run orders of various sizes, compare against baseline.
  5. Deployment and monitoring — launch on testnet and mainnet, configure alerts.

What's Included in the Work

  • Architecture documentation: pool graph description, caching scheme, contract specification.
  • Routing engine: pathfinding and split routing implementation with V2/V3/Curve/Balancer support.
  • Router contract: multi-step execution with slippage protection.
  • Pool cache (optional): WebSocket subscriptions + in-memory store.
  • Testing: Foundry fork tests, Echidna fuzzing.
  • Integration: deployment on testnet and mainnet, monitoring setup.
  • Team training: internal documentation, code review.

Order a consultation—we'll send a technical and commercial proposal within 1 day after the brief. Get a detailed analysis of your current infrastructure and routing optimization recommendations. Contact us to discuss your project.