Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.trails.build/llms.txt

Use this file to discover all available pages before exploring further.

Highlights

  • Trails v1.5 intent protocol is now live in production with many improvements to the intent protocol from gas savings, flexibility, 1-click gasless flows, and expanding chain routes.
  • The Trails API supports both v1 (original) and v1.5 (new) intent protocols out-of-the-box and apps using older Trails SDK versions will default to using the v1 intent protocol as before.
  • We recommend apps to upgrade to the latest [email protected] sdk to take advantage of many upgrades and the new v1.5 intent protocol.
  • Please review the upgrade / migration notes below in detail.

Upgrade / Migration Notes

This guide covers the breaking changes in SDK 0.15.0 and intent protocol v1.5, and how to update your integration.
useQuote amount units changed. from.amount and to.amount are now human-readable decimal strings (e.g. "1.5"), not raw smallest-unit values. Internally they are scaled via parseUnits using the token’s decimals. Passing a wei-style string like "1500000000000000000" will quote a vastly larger trade than intended — audit every useQuote call site before upgrading.To pass raw values, use from.amountRaw or to.amountRaw instead.

Summary checklist

1

Migrate useQuote to structured inputs

Replace flat props (fromTokenAddress, fromChainId, etc.) with from: { token, chain, amount } and to: { token, chain, recipient, ... }.
2

Update amount units

Change from.amount / to.amount in useQuote and tokenAmount / fromAmount in useTrailsSendTransaction from raw wei to human-readable decimal strings or use the raw value amount props.
3

Remove paymasterUrls if used

Delete the paymasterUrls prop from any TrailsWidget usage.
4

Rename lifecycle callbacks

Rename all onCheckout* callbacks to the new names (see table above).
5

Migrate to.calldata (if used)

Replace to.calldata on useQuote with actions (for supported protocols) or to.calls (for custom contracts).

Breaking changes

useQuote amount units changed

NOTE: useQuote hook is an optional low-level integration some developers use. If you’re using Trails with just the widget, this secton does not apply to you. If you are using useQuote please please the notes and upgrade. from.amount and to.amount are now human-readable decimal strings (e.g. "1.5"), not raw smallest-unit integers. They are scaled internally using parseUnits with the token’s decimals. Use from.amountRaw or to.amountRaw for passing raw values.
// Before — raw wei
from: { token: 'USDC', chain: 'arbitrum', amount: '1000000' } // 1 USDC

// After — human-readable
from: { token: 'USDC', chain: 'arbitrum', amount: '1' }       // 1 USDC
If you need to pass a raw value (bigint or string), use from.amountRaw or to.amountRaw instead of from.amount / to.amount. The same applies to useTrailsSendTransaction: tokenAmount and fromAmount are now human-readable decimal strings. Native value remains raw wei bigint (wagmi-compatible). Use tokenAmountRaw or fromAmountRaw to pass raw values. You can also pass tokenDecimals / fromDecimals overrides to skip the registry or on-chain decimal lookup.

useQuote restructured inputs

useQuote now takes structured from and to objects instead of flat props. The flat fields — fromTokenAddress, fromChainId, toTokenAddress, toChainId, toAddress, toApprove, toCalldata, swapAmount, tradeType — are all gone. Trade type is now inferred: set from.amount for exact-input, to.amount for exact-output.
// Before
const { quote, send } = useQuote({
  fromTokenAddress: '0xA0b8...', // USDC
  fromChainId: 42161,
  toTokenAddress: '0x8335...',  // USDC on Base
  toChainId: 8453,
  toAddress: address,
  swapAmount: '1000000',         // raw wei
  tradeType: 'EXACT_INPUT',
})

// After
const { quote, send } = useQuote({
  from: { token: 'USDC', chain: 'arbitrum', amountRaw: '1000000' }, // or use "from.amount" which accepts human readable amount string ("1" = 1 USDC)
  to:   { token: 'USDC', chain: 'base', recipient: address },
})

useQuote to.calldata deprecated

Passing to.calldata on useQuote now logs a runtime deprecation warning and is mutually exclusive with actions and to.calls. Migrate to one of:
  • actions — composable DeFi primitives (lend, deposit, swap, etc.)
  • to.calls — raw ABI-encoded Call[] for custom contracts
// Deprecated
const { send } = useQuote({
  from: { ... },
  to: { ..., calldata: encodedCalldata },
})

// Preferred — composable actions
const { send } = useQuote({
  from: { ... },
  to: { ... },
  actions: [lend({ marketId: 'base-usdc-aave-v3-lending', amount: '100' })],
})

paymasterUrls removed from TrailsWidget

The paymasterUrls prop has been removed from TrailsWidget. Remove it from your configuration — it has no replacement.
// Before
<TrailsWidget paymasterUrls={{ 137: 'https://...' }} />

// After
<TrailsWidget />

Widget lifecycle callback renames

All TrailsWidget checkout lifecycle callbacks were renamed. The onCheckout prefix is gone.
Before (0.13.x)After (0.15.0)
onCheckoutStartonStart
onCheckoutQuoteonQuote
onCheckoutSignatureRequestonSignRequest
onCheckoutSignatureConfirmedonSign
onCheckoutSignatureRejectedonSignReject
onCheckoutCompleteonSuccess
onCheckoutErroronError
onCheckoutStatusUpdateonStatus
onCheckoutApprovalRequestonApproveRequest
onCheckoutApprovalConfirmedonApprove
onCheckoutApprovalRejectedonApproveReject
// Before
<TrailsWidget
  onCheckoutStart={...}
  onCheckoutComplete={...}
  onCheckoutError={...}
/>

// After
<TrailsWidget
  onStart={...}
  onSuccess={...}
  onError={...}
/>

New features

Composable actions

useQuote gains an actions array for composing destination-side DeFi flows: All amount props for actions are in human-readable form only.
import { useQuote, swap, lend, deposit, dynamic, assertCondition } from '0xtrails'

const { send } = useQuote({
  from: { chain: 'arbitrum', token: 'USDC' },
  to:   { chain: 'polygon', token: 'USDT', amount: '0.2' },
  actions: [
    deposit({
      marketId: 'polygon-usdt-bbqusdt0-0xb7c9988d...-4626-vault',
      amount: '0.1',
    }),
    swap({
      tokenIn: 'USDT',
      tokenOut: 'USDC',
      amountIn: dynamic(), // resolved at runtime from wallet balance
      fee: '0.3',
    }),
    assertCondition({
      erc20Balance: { token: 'USDC', gte: '0.08' },
    }),
    lend({
      marketId: 'polygon-usdc-aave-v3-lending',
      amount: dynamic(),
    }),
  ],
})
Action factories: swap, lend, deposit, custom, assertCondition
  • Use lend for lending markets (Aave), deposit for ERC-4626 vaults (Morpho, Yearn).
  • Discover marketId values with useEarnMarkets filtered by type: "lending" or type: "vault".
Runtime sentinels:
  • dynamic() — resolves to the intent wallet’s ERC-20 balance at execution time
  • self() — resolves to address(this) (the intent wallet under DELEGATECALL)
Low-level escape hatch: useQuote({ to: { calls } }) accepts raw Call[] (or Call[][]) for hand-rolled ABI-encoded transactions. Calls support dynamicAmountToken, hydrateEntries, and sweepTokens for runtime hydration and dust recovery.

New hooks

HookPurpose
useEarnMarketsDiscover lending and vault markets usable with lend / deposit
useEarnBalancesRead a user’s balances across earn markets
useEarnProvidersList supported earn protocols
useResolveActionsResolve ActionItem[] into encoded destination Call[]

Mode-specific widget components

New typed wrappers exported from 0xtrails/widget, each with a tighter prop shape than the generic TrailsWidget:
import { Pay, Fund, Swap, Earn, Withdraw } from '0xtrails/widget'
ComponentUse case
PayPayments to a recipient — structured to/from, paymentMethod discriminator
FundFund a wallet from any source
SwapSwap-only flows
EarnDeposit and withdraw from earn markets
WithdrawWithdrawal flows
TrailsWidget with mode="pay" | "fund" | "swap" | "earn" | "withdraw" continues to work. These wrappers are additive.

Other additions

  • intentProtocolVersion prop on TrailsWidget — pin the intent protocol version per-instance.
  • fromAmount prop on TrailsWidget — pre-populate source amount in human-readable units (e.g. "1.5").
  • fundOptions additions on TrailsWidget — new paymentMethodType field (Meld payment method pre-selection, e.g. "CREDIT_DEBIT_CARD") and meshExchangeKey field (Mesh exchange pre-selection, e.g. "coinbase").
  • Wallet-less quote preview — pass walletAddress to useQuote before a wallet is connected.
  • Auto-refresh expired quotes (widget only) — The Trails Widget now schedule a refetch when a quote’s expiresAt passes (waking on the next user interaction), so the “Intent quote has expired” pre-signing error no longer appears in the built-in UI.
  • New utilities: erc20Utils, buildCall, buildApproveAndCall, buildErc20Approve, getAmountWithSlippage, resolveChainId, resolveChainName.
  • API helpers: getEarnMarkets, getEarnBalances, getEarnProviders.
  • New error codes: CHAIN_MISMATCH, CALL_RESOLUTION_FAILED.
  • 0xtrails/hydrate subpath — Hydrate builders, selectors, and calldata helpers for v1.5 execution flows.