Routing
Routing
The three-layer design implemented across the @arc-route packages.
Arc Route is organized into three cooperating layers, each implemented in its own package. The routing layer receives a TransferIntent and discovers candidate paths through the routing graph (@arc-route/graph). The solver layer estimates per-hop economics, simulates each candidate, and scores them so one route can be selected (@arc-route/scoring). The execution and settlement layer runs the committed route atomically — submitting each hop through a pluggable bridge adapter, assembling a settlement proof, and gating on validator quorum (@arc-route/execution).
Each layer has a narrow responsibility and a defined handoff to the next. Nothing in the pipeline re-enters a prior layer: once a path is committed it is not re-scored, and once execution begins the committed route is not replaced. This keeps failure modes localized — a routing defect does not corrupt settlement, and a settlement delay does not rewrite the selected route.
The orchestration lives in @arc-route/routing-engine. The RoutingEngine class is the single entry point of the protocol: given a TransferIntent it discovers paths, converts them into Routes, simulates and scores them, then commits and executes the best one. Its dependencies — the RoutingGraph, Simulator, RouteScorer, and Executor — are injected, so the engine is agnostic to their concrete implementations.
A transfer flows through the system in one direction. Intent enters the routing layer, which evaluates candidate paths against the graph. Each candidate is converted into a Route through per-hop cost, latency, and reliability estimates, then simulated for feasibility, output amount, and slippage. The feasible routes are scored and ranked; the highest-ranked Route is selected and committed. Execution submits each hop to its bridge adapter, collects transaction hashes, and assembles a settlement proof once every hop succeeds. Finality is reached when a supermajority of validator stake confirms the settled state.
This unidirectional flow is what makes the outcome deterministic from the user's perspective: the path quoted up front is the path that settles.
The layering is reflected directly in the package boundaries. @arc-route/graph knows only about topology and liquidity; it has no concept of cost or scoring. @arc-route/scoring knows how to rank Routes but never touches a bridge. @arc-route/execution knows how to run a committed Route but never chooses one. Keeping these concerns in separate packages means each can be reasoned about, audited, tested, and improved in isolation, and that accountability is unambiguous when a transfer behaves unexpectedly.
Cross-cutting concerns — logging, structured errors, protocol constants, timeout handling — are centralized in @arc-route/shared so no package duplicates them or reaches across the layering.