string— human-readable, e.g."50"or"0.03". Scaled by the token’s decimals.bigint— raw wei, used as-is.dynamic()— “use the intent wallet’s runtime balance at execution time”, accepted only on fields that spend a balance. See Dynamic Values.
swap — on-chain token swap
Trade type is inferred from which amount you pass: amountIn → EXACT_INPUT, amountOut → EXACT_OUTPUT. Setting both (or neither) throws.
dynamic() is allowed on amountIn for exact-input swaps and maxAmountIn for exact-output swaps. amountOut and minAmountOut must be concrete values because they are execution thresholds.
fee:"0.3"(0.3% pool).provider:"UNISWAP_V3". If it isn’t deployed on the destination chain, the error tells you to try SushiSwap.recipient: the intent wallet for the final action; for intermediate actions, output flows back so the next action can consume it. Override only if you want to send output to a third party.
Swap utilities
For anything that isn’t “build calldata foruseQuote” — on-chain quoting, pool discovery, raw Call[] composition, address lookups — 0xtrails exports the underlying chain-scoped helpers behind swap. The same adapter is exported for both Uniswap V3 and SushiSwap V3, with identical method names, parameters, and fee tiers.
Low-level helpers take raw
bigint wei — use viem’s parseUnits to convert from human-readable amounts. Fee tiers take human strings: "0.01" / "0.05" / "0.3" / "1".- Pre-flight quoting — render expected output / price impact in the UI before the user commits, using
simulateSwap. - Pool liquidity check — skip a pair or switch
feetier whengetPoolreturnsnull. - Custom compositions — build
Call[]directly and pass them throughto.calls(useQuote) orcalls(useTrailsSendTransaction) when you need something the typedswapdoesn’t cover (e.g. multi-hop paths, permit2, …).
Chain-scoped adapter
uniswapV3.onChain(chain) (or sushiswapV3.onChain(chain)) returns an adapter bound to a specific chain (name or chain ID):
simulateSwap
Dry-run a swap against the provider’s QuoterV2 — no signing, no broadcast. Use this to render expected output and price impact before the user commits.
type can be "exactInputSingle" or "exactOutputSingle", pass amountIn with the former and amountOut with the latter.
getPool
Find the pool address for a pair and fee tier. Returns null when no pool exists — handy for switching fee tier or skipping the pair.
swapExactInputSingle
Build an approval + swap Call[] for an exact-input swap. Pass the calls through to.calls / calls to embed inside an intent, or send them directly from a wallet.
swapExactOutputSingle
Build an approval + swap Call[] for an exact-output swap.
Address lookups
Top-level helpers return contract addresses per chain:Capability checks
Not every chain has both providers deployed.isSupportedOn returns false instead of throwing — useful for falling back between providers or warning the user.
lend — supply into a money-market
Use for Aave / Compound / Fluid-style lending. Use useEarnMarkets to fetch the marketId.
receiverAddress defaults to the connected user wallet, so aTokens / fTokens / cTokens land on the user’s EOA automatically. Only override when you want the position to belong to a different owner.
deposit — deposit into a vault
Use for vault-shaped markets (ERC-4626, Morpho, Yearn, SummerFi, Sky, …).
receiverAddress— defaults to the connected user wallet so vault shares land on the user’s EOA.
assertCondition — on-chain guard
If the condition is false at execution time the entire batch reverts.
assertCondition is the only builder that does not accept dynamic() — its values must be known at quote time.custom — arbitrary contract call (escape hatch)
Use when nothing above fits. Pair with buildCall and erc20Utils for ergonomic calldata — see ERC-20 Helpers.
dynamic() amount, pass dynamicAmountToken so the encoder knows which ERC-20 balance to hydrate at execution time. The only exception is a bare ERC-20 approve(spender, dynamic()), where the token is inferred from the call target.