Routing
Routing
How the RoutingEngine discovers candidate paths and selects a route.
The RoutingEngine class in @arc-route/routing-engine is the single entry point of the protocol. Given a TransferIntent, it runs a fixed sequence: discover candidate paths through the RoutingGraph, convert each path into a Route via per-hop cost and latency estimates, simulate each Route for feasibility and slippage, score and rank the feasible set with the RouteScorer, then commit and execute the best Route through the Executor. Every collaborator is injected, so the same engine drives live routing, simulation, and tests with different wiring.
An intermediate HopEstimator turns each GraphEdge into the economics a hop contributes — estimated gas cost, bridge fee, latency, and a reliability score. The default estimator derives these heuristically from the bridge id and the edge's reported liquidity, with no network calls; a production deployment supplies an estimator that calls each bridge's quote endpoint.
Path discovery is the responsibility of the RoutingGraph class in @arc-route/graph. When the engine receives an intent, it asks the graph for every simple path between the source and destination nodes. Discovery is a hop-limited depth-first search: the findPaths(source, destination, maxHops) method walks the adjacency list, tracks visited node keys to reject cycles within a single path, and returns each matching path in DFS pre-order. The hop count is capped — both by the requested maxHops and by a hard ceiling (HARD_MAX_HOPS, currently six) — so the search space stays finite. The default configuration uses three hops.
Because the graph is a multigraph, multiple bridges can connect the same pair of nodes and each is explored as a distinct edge. The engine hands the full candidate set to the scorer rather than relying on discovery order, so ranking is governed by the scoring function, not by traversal order.
Critically, the graph reflects liquidity as it exists at the moment of routing. A GraphBuilder assembles the graph from bridge lanes and liquidity snapshots, and only edges with available liquidity are traversable by default — so the engine reasons about what can move now, not what could move in principle.
Candidate paths are ranked by the RouteScorer (covered in its own section), which combines cost, speed, reliability, and liquidity into a single comparable score. The highest-ranked feasible Route is selected and committed before execution begins, and once committed it is fixed for the lifetime of the transfer. There is no re-routing mid-transfer. This is a deliberate trade-off: it sacrifices the ability to chase marginal improvements during execution in exchange for a deterministic, quotable outcome that the rest of the pipeline can rely on.