Get early access

Best Pool Swap

Quote every venue inside the transaction. Branch at inclusion against live pool state. Route through the winner.

RoutingAggregationAtomic
How it runsBase mainnet · 8453
Inputs
poolA=0xd0b...c84bpoolB=0xb4cb...8a2ftokenIn=WETHtokenOut=USDCamountIn=0.05amountOutMin=120.4
In-transaction
01Quote pool A124.823 USDC
02Quote pool B123.041 USDC
03Decide: outA > outB
true → pool = poolAfalse → pool = poolB
04Require: out ≥ amountOutMinPASSED
05Execute swap on chosen pool0x3f9a...e84c
Result
Swap receipt · 1 tx · atomic
best-pool.sauce.ts
Base · 8453READ-ONLY
1import { IERC20 } from "@openzeppelin/contracts/build/contracts/IERC20.json";2import { IV3SwapRouter } from "@uniswap/swap-router-contracts/artifacts/contracts/interfaces/IV3SwapRouter.sol/IV3SwapRouter.json";3import { IQuoterV2 } from "@uniswap/v3-periphery/artifacts/contracts/interfaces/IQuoterV2.sol/IQuoterV2.json";4import { IUniswapV3Pool } from "@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol/IUniswapV3Pool.json";56// Quote two Uniswap V3 pools on-chain and swap through whichever gives the7// better output, via SwapRouter02 — all decided inside one transaction.8// Router and Quoter are fixed (Base mainnet); the tokens, amount, caller and9// the two pools are parameters.1011function main(12 tokenIn: Address, tokenOut: Address, amountIn: Uint256, caller: Address,13 pool1Addr: Address, pool2Addr: Address,14): Uint256 {15 const router: Address = 0x2626664c2603336E57B271c5C0b26F421741e481;16 const quoter: Address = 0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a;1718 // Pull the input tokens in and let the router spend them.19 const token = IERC20.at(tokenIn);20 token.transferFrom(caller, address.self, amountIn);21 token.approve(router, amountIn);2223 // Read each pool's fee tier on-chain.24 const feeA: Uint256 = IUniswapV3Pool.at(pool1Addr).fee();25 const feeB: Uint256 = IUniswapV3Pool.at(pool2Addr).fee();2627 // Quote both pools. Keys a-e sort alphabetically onto QuoteExactInputSingleParams:28 // a=tokenIn, b=tokenOut, c=amountIn, d=fee, e=sqrtPriceLimitX9629 const q = IQuoterV2.at(quoter);30 const outA: Uint256 = q.quoteExactInputSingle({ a: tokenIn, b: tokenOut, c: amountIn, d: feeA, e: 0 })[0];31 const outB: Uint256 = q.quoteExactInputSingle({ a: tokenIn, b: tokenOut, c: amountIn, d: feeB, e: 0 })[0];3233 // Swap through the better pool. Keys a-g sort onto ExactInputSingleParams:34 // a=tokenIn, b=tokenOut, c=fee, d=recipient, e=amountIn, f=amountOutMinimum, g=sqrtPriceLimitX9635 const r = IV3SwapRouter.at(router);36 if (outA >= outB) {37 r.exactInputSingle({ a: tokenIn, b: tokenOut, c: feeA, d: caller, e: amountIn, f: 0, g: 0 });38 } else {39 r.exactInputSingle({ a: tokenIn, b: tokenOut, c: feeB, d: caller, e: amountIn, f: 0, g: 0 });40 }4142 // Output tokens were sent straight to the caller by the router.43 return IERC20.at(tokenOut).balanceOf(caller);44}
Try it liveLive on Base mainnet
01Connect wallet
Loading…
02Configure inputs
Connect wallet to continue
03Compile
Compile to continue
04Execute
Compile first

About

Best-pool swap quotes every listed venue inside the same transaction that will execute. The script reads live pool state, picks the better venue, and routes through it. The branch is evaluated at inclusion, so the decision sees the same block the swap will land in.

When to use this

  • DEX aggregator integrations needing in-tx route selection
  • Wallet swap routes priced against live state
  • Payment apps that must clear a minimum or revert