โกYul Router
The gas-optimized router used for Ekubo swaps on EVM chains, and the TypeScript SDK that encodes routes for it
The Yul Router is a gas-focused router written in Yul that executes Ekubo swaps on EVM chains. It is how swaps are executed in production today: the interface encodes routes from Quoter API results and sends them to the router.
The router is deployed deterministically at the same address on every supported network (currently Ethereum, Base, Arbitrum, and Robinhood Chain, plus their testnets):
0x00000000D542a1Afa7A01ECB16254F7A0F8ceB61The address is also exported by the SDK as YUL_ROUTER_ADDRESS.
Design
The router deliberately carries everything it needs โ token addresses, pool configs, extension forwardee addresses, and token wrapper addresses โ in calldata. There are no token or extension jump tables and no stored routes. There is also no public ABI selector: any call that does not come from Ekubo Core is interpreted directly as packed route data. Calls from Core are reserved for the lock callback (selector 0x00000000); the forward callback (selector 0x00000001) always reverts.
A single transaction can contain many multi-hop routes. The router executes all of them under one Core lock, aggregates the specified and calculated amounts, applies one slippage check against the aggregate, and settles token transfers once.
Supported hop types:
core
A direct Core.swap against the pool key
forwarded
Core.forward(forwardee, ...) for forward-only swap extensions such as MEVCapture and Ve33
signedExclusiveSwap
A controller-signed swap on a SignedExclusiveSwap pool (pool key, params, signed meta, minimum balance update, and signature)
wrapper
Wrapping or unwrapping through an Ekubo token wrapper
Excluded by design, as a security posture:
No delegatecall routing (the router checks an immutable self address and rejects delegatecall execution)
No routing through
Core.forward(router, ...)โ the forward callback revertsNo protocol or integration fee collection and no fee claiming
The router has been audited, and CI continuously verifies it against production: live mainnet quotes from the Quoter API are converted to calldata with the SDK and executed against canonical Core on a mainnet fork, covering ETHโERC20, ERC20โERC20, and exact-output swaps.
The SDK: @ekubo/yul-router-sdk
Routes are encoded with @ekubo/yul-router-sdk (published with npm provenance from the repository's release workflow):
Encoding a swap
encodeRoutes(...) is the primary surface. Each entry in multiHops is an independent path from specifiedToken to calculatedToken with its own specifiedAmount; the router aggregates them all under one lock and one slippage check. Splitting a trade across multiple multi-hops is how split routes execute atomically.
Notes:
Native ETH is
address(0)(alwaystoken0); attachvalueto the transaction when the input is native ETH.All multi-hops in one call must agree on direction โ mixing exact-in and exact-out throws.
encodeRoute(...)is a convenience wrapper for a single path;generateCalldata(...)is an alias ofencodeRoutes(...).Limits: up to 256 multi-hops per call and 256 hops per multi-hop.
Signed exclusive swaps
For signedExclusiveSwap hops, encodeSignedSwapMeta({ deadline, fee, nonce, authorizedLocker }) packs the signed metadata word. deadline and fee are uint32 numbers; nonce must be a bigint (a JavaScript number is rejected so uint64 nonces cannot lose precision). encodePoolBalanceUpdate(delta0, delta1) packs the signed minimum balance update.
Other exports
YUL_ROUTER_ADDRESSโ the deterministic router addressMIN_SQRT_RATIO/MAX_SQRT_RATIOโ bounds forsqrtRatioLimiton hops (see Price representation)PoolKey,Hop,MultiHop, and parameter types for TypeScript consumerscalldataSize(data)โ helper for estimating calldata cost
Typical flow
Fetch a quote from the Quoter API โ it returns block-pinned split routes in exactly the shape the SDK consumes.
Convert each split and hop into
multiHopsentries and callencodeRoutes(...)with your slippage threshold.Send the calldata to
YUL_ROUTER_ADDRESSpromptly (quotes are pinned to a block).
To deploy the router to a new chain, use the repository's Foundry deploy script โ it deploys through the canonical deterministic deployer against the canonical Core address, so the router lands at the same address everywhere.
Last updated
Was this helpful?

