> ## Documentation Index
> Fetch the complete documentation index at: https://docs.eco.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Best-pool swap

> A complete SauceScript program that quotes two Uniswap V3 pools onchain and swaps through whichever gives the better output, decided inside one transaction on Base. Adapted from the compiler's example set with a minimum-output parameter.

Quote two Uniswap V3 pools onchain and swap through whichever gives the better output, via SwapRouter02, all decided inside one transaction. The router and quoter are fixed (Base mainnet); the tokens, amount, caller, two pools and minimum output are `main` parameters supplied at run time. The program imports its contract ABIs as JSON artifacts placed beside the source.

## Prerequisites

* Complete [Sauce setup](/programmable-transactions/sauce/getting-started), including access, a Pot and the current Kitchen fee.
* Use Base mainnet (chain ID `8453`) and two Uniswap V3 pools for the same token pair.
* The caller must hold the input tokens and approve the Pot to spend `amountIn`.
* Save these four ABI files beside the program: [IERC20](/cookbook/sauce/abis/IERC20.json), [IV3SwapRouter](/cookbook/sauce/abis/IV3SwapRouter.json), [IUniswapV3Pool](/cookbook/sauce/abis/IUniswapV3Pool.json), and [IQuoterV2](/cookbook/sauce/abis/IQuoterV2.json).
* Supply a minimum acceptable output in the output token's smallest unit. Review the [compiler compatibility limitation](/programmable-transactions/sauce/architecture-and-deployments#compiler-and-engine-compatibility) before execution.

## Program

```typescript best-pool-swap.sauce.ts theme={null}
import { IERC20 } from "./IERC20.json";
import { IV3SwapRouter } from "./IV3SwapRouter.json";
import { IQuoterV2 } from "./IQuoterV2.json";
import { IUniswapV3Pool } from "./IUniswapV3Pool.json";

// Quote two Uniswap V3 pools on-chain and swap through whichever gives the
// better output, via SwapRouter02 — all decided inside one transaction.
// Router and Quoter are fixed (Base mainnet); the tokens, amount, caller and
// the two pools and minimum output are parameters.

function main(
  tokenIn: Address, tokenOut: Address, amountIn: Uint256, caller: Address,
  pool1Addr: Address, pool2Addr: Address, minOut: Uint256,
): Uint256 {
  const router: Address = 0x2626664c2603336E57B271c5C0b26F421741e481;
  const quoter: Address = 0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a;

  // Pull the input tokens in and let the router spend them.
  const token = IERC20.at(tokenIn);
  token.transferFrom(caller, ctx.self(), amountIn);
  token.approve(router, amountIn);

  // Read each pool's fee tier on-chain.
  const feeA: Uint256 = IUniswapV3Pool.at(pool1Addr).fee();
  const feeB: Uint256 = IUniswapV3Pool.at(pool2Addr).fee();

  // Quote both pools. Keys a-e map positionally onto QuoteExactInputSingleParams:
  //   a=tokenIn, b=tokenOut, c=amountIn, d=fee, e=sqrtPriceLimitX96
  const q = IQuoterV2.at(quoter);
  const outA: Uint256 = q.quoteExactInputSingle({ a: tokenIn, b: tokenOut, c: amountIn, d: feeA, e: 0 })[0];
  const outB: Uint256 = q.quoteExactInputSingle({ a: tokenIn, b: tokenOut, c: amountIn, d: feeB, e: 0 })[0];

  // Swap through the better pool. Keys a-g map positionally onto ExactInputSingleParams:
  //   a=tokenIn, b=tokenOut, c=fee, d=recipient, e=amountIn, f=amountOutMinimum, g=sqrtPriceLimitX96
  const r = IV3SwapRouter.at(router);
  if (outA >= outB) {
    r.exactInputSingle({ a: tokenIn, b: tokenOut, c: feeA, d: caller, e: amountIn, f: minOut, g: 0 });
  } else {
    r.exactInputSingle({ a: tokenIn, b: tokenOut, c: feeB, d: caller, e: amountIn, f: minOut, g: 0 });
  }

  // Output tokens were sent straight to the caller by the router.
  return IERC20.at(tokenOut).balanceOf(caller);
}
```

## What to notice

* The two quotes and the swap happen in the same transaction, so the decision is made against the state the swap executes in.
* Under a Pot delegatecall, `ctx.self()` is the Pot, so the input tokens are pulled to the Pot and the router is approved from there.
* The struct arguments use positional keys (`a` to `g`). The [SauceScript reference](/programmable-transactions/sauce/saucescript#contract-interop) explains the naming rules for struct fields.

## Run it

Compile with `@eco-incorp/sauce-compiler` (`target: "evm"`) with the four ABI JSON files next to the source, append the seven `main` arguments as 32-byte words, and execute through your Pot with the Kitchen fee. See [Getting started with Sauce](/programmable-transactions/sauce/getting-started).

## Troubleshooting

If execution reverts, check the input balance, allowance to the Pot, pool pair, fee tiers and minimum output. Simulate the complete call and estimate gas before submission. A quote or swap failure reverts the transaction.

## Next steps

Review [SauceScript contract calls](/programmable-transactions/sauce/saucescript#contract-interop) or [package the program as an intent](/programmable-transactions/sauce/programs-as-intents).
