Composable Actions with Trails
Composable Actions allow developers to easily specify multiple actions to take on a destination chain that can compose with multiple protocols. For example, staking in a liquid staking token and then depositing that token into a vault. This means a user can sign a single transaction and multiple onchain interactions can take place from virtually any chain as the starting point. Instead of encoding calldata by hand, you build a list of high-level steps —swap, lend, deposit, assertCondition, custom — and pass them to useQuote or useTrailsSendTransaction. Trails handles quoting, bridging, and executing.
Use Cases
Ideal for a variety of multi-step DeFi scenarios:- Stake a token and deposit the staked derivative into a lending protocol in one transaction
- Swap to a vault asset and deposit, starting from any token on any chain
- Split funds across multiple protocols atomically — if any step fails, the whole batch reverts
- Chain yield strategies across chains without requiring the user to touch intermediate steps
"100" for 100 USDC, not "100000000".
Supply into a lending protocol
Uselend to supply into supported lending markets such as Aave. 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.
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