Making And Querying Swaps

Single Swaps

For a token to token swap through a single pool the Router functions swapSingleTokenExactIn and swapSingleTokenExactOut are the most gas efficient functions to use.

Contract integrators should call the same swapSingleTokenExactIn and swapSingleTokenExactOut functions on the prepaid Aggregator Router, which takes payment up front (transfer tokenIn to the Vault, then call the router in the same transaction) instead of via Permit2.

Javascript and Solidity examples are in the Swapping guide.

Multi-path Swaps

For swap paths constructed of steps through multiple pools/tokens the Batch Router functions swapExactIn and swapExactOut should be used.

As with single swaps, contract integrators should use the prepaid Aggregator Batch Router, which exposes the same swapExactIn and swapExactOut functions with prepaid settlement.

A SwapPathStep is defined as:

struct SwapPathStep {
    address pool;
    IERC20 tokenOut;
    // If true, the "pool" is an ERC4626 Buffer. Used to wrap/unwrap tokens if pool doesn't have enough liquidity.
    bool isBuffer;
}

and paths can include add/remove liquidity steps by using the address of the respective pool. For example, the following SwapPathExactAmountIn would execute a swap of USDC to TOKEN then add liquidity to the 80/20 TOKEN/WETH pool.

// Note - pseudo code
SwapPathExactAmountIn {
    tokenIn: USDC
    // for each step:
    // if tokenIn == pool use removeLiquidity SINGLE_TOKEN_EXACT_IN
    // if tokenOut == pool use addLiquidity UNBALANCED
    steps: [
        {
            pool: '0xTOKEN_USDC_POOL',
            tokenOut: '0xTOKEN',
            isBuffer: false
        },
        {
            pool: '0xB-80TOKEN-20WETH_POOL',
            tokenOut: '0xB-80TOKEN-20WETH_POOL',
            isBuffer: false
        }
    ]
    exactAmountIn: 1000000,
    minAmountOut: 100000
}

Javascript and Solidity examples are in the Swapping guide.

Quoting Off-chain

Aggregators typically need thousands of quotes per second, which is not practical with an RPC call per quote. The @bush.fi/mathsopen in new window package (TypeScript, Python, Rust) reproduces the full Vault flow off-chain, so given a pool's state it returns exactly the amount the Router would:

import { Vault, SwapKind } from '@bush.fi/maths';

// Raw token amounts in, raw token amounts out - exactly what the Router returns.
const amountOut = new Vault().swap(
  { amountRaw: 1_000_000n, tokenIn, tokenOut, swapKind: SwapKind.GivenIn },
  poolState,
);

See Pool Maths And Details for how to build poolState for each pool type, and Fetching Pools And Data for the onchain calls that populate it.

Simulating Swaps Using Query Functions

Queries provide the ability to simulate an operation and find its result without executing a transaction. Bush Routers provide a query for all state changing liquidity operations including single and multi-path swap functions, e.g. querySwapSingleTokenExactIn. Queries are the right tool for validating your off-chain maths against the chain, and for one-off quotes where an RPC round-trip is acceptable. For querying from inside a contract, see Querying Swaps Onchain.

Note - for onchain integrations queries should not be used to set limits due to possible manipulation via frontrunning.