How composable actions work
Composable Actions let you chain any number of sequential DeFi steps into a single cross-chain transaction. A user can stake a token, receive the staked derivative, and deposit it into a lending protocol on a different chain, all in one intent, with no manual bridging or intermediate steps. This gives developers a straightforward way to build powerful primitives on top of onchain infrastructure. Complex multi-protocol flows that would otherwise require multiple transactions, manual coordination, and careful UX handling are reduced to a list of steps. Users get a single confirmation with a predictable outcome. Composable Actions describe what happens on the destination chain after Trails bridges and swaps funds. Instead of encoding calldata by hand, you build a list of high-level steps and pass them touseQuote or useTrailsSendTransaction. Trails handles quoting, bridging, and executing.
useTrailsSendTransaction: trigger the Trails modal, let the user choose their origin token and chainuseQuote: preview the quote in your own UI before sending
Supply into a lending protocol
Uselend to supply into any Aave, Compound, or Fluid-style money market. Pass a marketId from useEarnMarkets:
supply() on the Aave pool.
Deposit into a vault
Usedeposit for ERC-4626 and vault-style markets (Morpho, Yearn, SummerFi, Sky):
receiverAddress to redirect them.
Chain multiple DeFi steps
Usedynamic() to consume whatever the previous step produced without predicting bridge fees or slippage. This example delivers 0.2 USDT on Polygon, splits it across four destination steps:
dynamic() on amountIn and amount means “use whatever the intent wallet holds at that point”. A concrete value like "0.1" splits off a fixed slice. Actions run sequentially and any failed assertCondition reverts the whole batch, so partial state is never left behind.
Preview a quote before sending
UseuseQuote when you want to show the user a breakdown before they commit. Pass the same actions array alongside from and to fields:
Discover market IDs at runtime
Hard-coding market IDs is fine for known protocols. For a dynamic UI, useuseEarnMarkets to fetch available markets and grab the id from the result:
Use a protocol not covered by the builders
Usecustom as an escape hatch for any protocol. Pair it with erc20Utils and buildCall to keep calldata ergonomic:
SDK reference
- Overview - How composable actions fit into the Trails intent model
- Building Actions - Full API for
swap,lend,deposit,assertCondition,custom - Dynamic Values - How
dynamic()andself()resolve at runtime - Markets and Providers - Discover market IDs with
useEarnMarkets - ERC-20 Helpers - Token registry,
buildCall,buildApproveAndCall, slippage helper