Documentation

How to read and use the router.

Everything needed to verify the contract, integrate against it, or decide not to. The limitations section is not a footnote — read it first if you are considering size.

Whose contract this is. The router below was deployed and is owned by the Vunix project. Keel is a front end that reads and calls it; it does not control the registry, the owner key, or the upgrade path. Point ADDRESSES.router at your own deployment before presenting the best-execution guarantee as Keel’s own.

Deployment

Addresses

Chain
Robinhood Chain · id 4663
RPC
https://rpc.mainnet.chain.robinhood.com
Registry
71 venues · 27 pairs · block 53,253,320

Chain contracts

Uniswap v4 PoolManager
0x8366a39CC670B4001A1121B8F6A443A643e40951
Uniswap v3 Factory
0x1f7d7550B1b028f7571E69A784071F0205FD2EfA
Multicall3
0xcA11bde05977b3631167028862bE2a173976CA11 · canonical
USDG
0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168 · 6 decimals
WETH
0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73 · 18 decimals

Identify contracts on this chain by ABI, never by name. The canonical Ethereum mainnet Uniswap router and quoter addresses both exist here and hold the same unrelated 2,109-byte contract. Ten contracts are named UniswapV3Factory.

Integration

Placing an order: approve the router for tokenIn, then call swapExactIn. Legs must sum exactly to amountIn; the contract rejects anything else.

function swapExactIn(
    SwapRequest calldata request, // tokenIn, tokenOut, amountIn,
                                  // minAmountOut, recipient, deadline
    Leg[] calldata legs           // { venueIndex, amountIn }[]
) external returns (uint256 amountOut);

Compute the legs off-chain with the engine, or read the book yourself. Two view functions expose everything the contract knows:

// what one venue would return for this size
function quoteVenue(address tokenIn, address tokenOut,
                    uint256 index, uint256 amountIn)
    external view returns (uint256 amountOut);

// the benchmark your order must beat
function bestSingleVenue(address tokenIn, address tokenOut,
                         uint256 amountIn)
    external view returns (uint256 bestOut, uint256 bestIndex);

Venue indices come from venueCount and venueAt. They are not stable: removeVenue swaps the last entry into the gap, so re-read them after any registry change rather than caching.

The guarantee

What is actually proven: before any leg executes, the router quotes every registered venue for the pair at the full order size. After executing, it compares the fill against that benchmark.

if (amountOut < bestSingleVenueOut)
    revert CannotProveBestExecution(amountOut, alternative, venueIndex);

Quoting happens before execution on purpose. Quoting afterwards would let someone move an unrelated pool inside the same block to manufacture a better-looking alternative and force your order to revert — cheap griefing.

There is no tolerance. A split settles only when it strictly beats the best single venue, which is the intended reading: a split that cannot beat single-venue routing has no reason to execute.

Curation

How a venue gets admitted. Every filter is deny-by-default — a venue is admitted only by passing all of them:

Asset identity
answers uiMultiplier() — clones revert
Quote asset
USDG or WETH, pinned addresses
Hooks
must be address(0)
Fee
≤ 1% — v4 permits up to 100%
Depth to route
≥ $2,500 to move price 1%
Depth to appear
none — a venue that has drained to nothing still shows
On-chain check
v3 must match factory.getPool; v4 key must be initialised

One floor, not two, because reading a venue and routing to it are different jobs. Depth decides only what may receive an order, and that set is exactly what the router holds. Nothing is hidden from the book for being thin — a pool that has drained to nothing and still advertises a price is the clearest example of the problem this exists to solve.

Depth is the quote notional required to move a venue’s price by 1%, derived from active liquidity. Not from balanceOf — v4 is a singleton, so its balance is the total across every pool it holds and describes none of them. Not from liquidity() either: a fake pool holding a few dollars of real value has reported a liquidity scalar of 4.19e23.

Read this part

Limitations

Unaudited
Written and tested over a single session. 22 tests pass against live chain state, including a real order settling at a price matching its own on-chain quote. That is evidence, not an audit.
Proof scoped to registry
Best execution is proven against registered venues only. A pool outside the registry is not considered, so the guarantee is exactly as good as the curation.
The owner curates
The owner can add and remove venues. Entries are validated against the canonical factory and the PoolManager, so a compromised owner cannot route your order into their own contract — but they can still decide which real pools are eligible.
Assertion gas scales
Every registered venue is re-quoted on every order. A normal venue costs roughly 29k gas to quote; a thin one with tight tick spacing can walk to the crossing cap and cost ~790k on its own. That is why the depth floor exists.
Splitting rarely helps
On most assets between $1,000 and $100,000 the solver finds no improvement at all, because the cheapest venue is normally also the deepest, so it picks one venue. It is not uniformly zero: on the more fragmented names at the larger end of that range it finds low single-digit basis points. The quote reports the gain it measured rather than a headline number.