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 contracts
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:
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