> ## Documentation Index
> Fetch the complete documentation index at: https://docs.polygon.technology/llms.txt
> Use this file to discover all available pages before exploring further.

# Composable actions

> Chain multiple onchain actions into a single intent: bridge, swap, stake, and deposit in one user signature.

Composable actions let you specify a sequence of onchain operations at the destination that execute together after funds arrive. A user signs once on their origin chain; the routing layer bridges and swaps the funds, then executes every action in the sequence from a destination intent wallet.

This is how you build flows like: "fund from a card on any chain, swap to WSTETH, deposit into a yield vault", one signature, no intermediate steps for the user.

## How it works

Every composable action flow is two phases:

1. The user signs a single transaction on their origin chain. Funds bridge and swap to an intent wallet on the destination.
2. The SDK executes the action sequence from that wallet. All actions run top-down in a single atomic batch, if any step fails, the entire batch reverts.

## Quickstart: multi-step DeFi in one intent

This example deposits USDT into Morpho, swaps the remainder to USDC, and lends it into Aave, all in one intent.

```tsx theme={null}
import { useTrailsSendTransaction, deposit, swap, lend, dynamic } from "0xtrails";

function MultiStepButton({ morphoMarketId, aaveMarketId }) {
  const { sendTransaction } = useTrailsSendTransaction({
    to: {
      chain: "polygon",
      actions: [
        // Deposit USDT into Morpho
        deposit({
          marketId: morphoMarketId,
          token: "USDT",
          amount: "100",
        }),
        // Swap remaining funds to USDC
        swap({
          tokenIn: "USDT",
          tokenOut: "USDC",
          amountIn: dynamic(), // consume whatever the previous step left
        }),
        // Lend the USDC output into Aave
        lend({
          marketId: aaveMarketId,
          token: "USDC",
          amount: dynamic(),
        }),
      ],
    },
  });

  return <button onClick={sendTransaction}>Execute</button>;
}
```

`dynamic()` means "use whatever balance the intent wallet holds at execution time." You don't need to predict exact amounts after bridging or swapping. See [Dynamic values](/cross-chain/sdk/composable-actions/dynamic-values) for details.

## Track status across hops

The `onStatusUpdate` callback fires at each step, bridge confirmation, destination execution, and completion. Use it to drive progress UI:

```tsx theme={null}
const { sendTransaction } = useTrailsSendTransaction({
  to: {
    chain: "polygon",
    actions: [...],
  },
  onStatusUpdate: (status) => {
    console.log("Step:", status.step, "State:", status.state);
  },
});
```

## Quote-first pattern

Use `useQuote` if you want to show the user a preview before sending, or if you want to avoid the SDK modal entirely:

```tsx theme={null}
import { useQuote, deposit, dynamic } from "0xtrails";

const { quote, loading } = useQuote({
  from: {
    chainId: 1,
    tokenAddress: "0xdAC17F958D2ee523a2206206994597C13D831ec7", // USDT on Ethereum
    amount: "100",
  },
  to: {
    chainId: 137,
    actions: [
      deposit({
        marketId: "morpho-usdt-vault",
        token: "USDT",
        amount: dynamic(),
      }),
    ],
  },
});

if (quote) {
  console.log("Route preview:", quote.intent.depositAddress);
  await quote.send(); // execute after user confirms
}
```

## Discovering markets

The quickstart example above hard-codes market IDs for clarity. In production, use `useEarnMarkets` to discover available markets for a given chain, token, and provider at runtime:

```tsx theme={null}
import { useEarnMarkets, lend, dynamic, useTrailsSendTransaction } from "0xtrails";

function AaveLendButton({ userAddress }) {
  const { markets } = useEarnMarkets({
    chain: "polygon",
    type: "lending",
    provider: "aave",
    sortBy: "apy",
  });

  const topMarket = markets?.[0];

  const { sendTransaction } = useTrailsSendTransaction({
    to: {
      chain: "polygon",
      actions: topMarket
        ? [lend({ marketId: topMarket.id, token: "USDC", amount: dynamic() })]
        : [],
    },
  });

  return <button onClick={sendTransaction} disabled={!topMarket}>Lend</button>;
}
```

See [React hooks](/cross-chain/sdk/hooks) for the full `useEarnMarkets` reference.

## Available action builders

| Builder             | What it does                                            |
| ------------------- | ------------------------------------------------------- |
| `swap()`            | Token exchange via Uniswap V3 or SushiSwap V3           |
| `lend()`            | Supply to a lending market (Aave and others)            |
| `deposit()`         | Deposit into a vault (ERC-4626, Morpho, Yearn)          |
| `assertCondition()` | Onchain guard, reverts the batch if the condition fails |
| `custom()`          | Arbitrary contract call via ABI encoding                |

For the full parameter reference, see [Building actions](/cross-chain/sdk/composable-actions/building-actions).
