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

# Execute Trade

> Execute trades directly using the DZap SDK

> Execute trades by building transaction data and sending it with your wallet signer. The SDK handles transaction building, gas estimation, and execution automatically.

The `trade` method combines transaction building and execution into a single operation. This approach simplifies the trading process while maintaining full control over transaction parameters.

<Note>
  Before executing trades, tokens typically require approval to allow the DZap
  contracts to spend them on your behalf. Learn more about gas-optimized
  approval mechanisms in the [Approval Mechanisms](/sdk/approval-mechanisms)
  section.
</Note>

<Note>
  **Rate Limits**: Our API and SDK have rate limits in place to ensure fair
  usage. If you need increased rate limits for your application, please reach
  out to our team on [Telegram](https://t.me/shivam0x).
</Note>

## Trade Execution

Execute a trade using the trade method:

```typescript theme={null}
import { DZapClient, TxnStatus } from "@dzapio/sdk";
import type { TradeBuildTxnRequest, TradeBuildTxnResponse } from "@dzapio/sdk";

const dZap = DZapClient.getInstance();

// Build trade request
const request: TradeBuildTxnRequest = {
  fromChain: 42161, // Arbitrum
  sender: userAccount,
  refundee: userAccount,
  gasless: false,
  data: [
    {
      amount: "1000000", // 1 USDC
      srcToken: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC
      destToken: "0x4200000000000000000000000000000000000006", // WETH
      toChain: 8453, // Base
      protocol: "relayLink", // From quotes response
      recipient: userAccount,
      slippage: 1, // 1% slippage
    },
  ],
};

// Option 1: Build and execute in one call

const result = await dZap.trade({
  request,
  signer,
});

if (result.status === TxnStatus.success) {
  console.log("Trade executed successfully:", result.txnHash);
} else {
  console.error("Trade execution failed:", result.errorMsg);
}

// Option 2: Build transaction data separately and execute

let buildResponse: TradeBuildTxnResponse;
try {
  buildResponse = await dZap.buildTradeTxn(request);
  console.log("Build response:", buildResponse);
} catch (error) {
  console.error("Error building trade transaction:", error);
  return;
}

const txnResponse = await dZap.trade({
  request,
  signer,
  txnData: buildResponse,
});

if (txnResponse.status === TxnStatus.success) {
  console.log("Trade executed successfully:", txnResponse.txnHash);
} else {
  console.error("Trade failed:", txnResponse.errorMsg);
}
```

## Parameters

The `trade` function expects an object with these parameters:

### Required Parameters

| Parameter | Type                   | Required | Description                                                  |
| --------- | ---------------------- | -------- | ------------------------------------------------------------ |
| `request` | TradeBuildTxnRequest   | yes      | The trade build request containing all trade details         |
| `signer`  | Signer \| WalletClient | yes      | Ethers signer or viem wallet client for signing transactions |
| `txnData` | TradeBuildTxnResponse  | no       | Pre-built transaction data (skips build step if provided)    |

### TradeBuildTxnRequest Structure

| Parameter                        | Type                        | Required | Description                                                              |
| -------------------------------- | --------------------------- | -------- | ------------------------------------------------------------------------ |
| `fromChain`                      | number                      | yes      | Source chain ID                                                          |
| `sender`                         | HexString                   | yes      | Wallet address sending the transaction                                   |
| `refundee`                       | HexString                   | yes      | Address to receive refunds                                               |
| `gasless`                        | boolean                     | yes      | Set to `false` for standard execution; `true` for gasless (if supported) |
| `private`                        | boolean                     | no       | Request private/MEV-protected execution                                  |
| `data`                           | TradeBuildTxnRequestData\[] | yes      | Array of trade data                                                      |
| `disableEstimation`              | boolean                     | no       | Disable gas estimation (default: false)                                  |
| `hasPermit2ApprovalForAllTokens` | boolean                     | no       | Set `true` if Permit2 approval already exists for all tokens in `data`   |
| `publicKey`                      | string                      | no       | Public key for some chains (e.g., Bitcoin)                               |

### TradeBuildTxnRequestData Structure

| Parameter        | Type           | Required | Description                           |
| ---------------- | -------------- | -------- | ------------------------------------- |
| `amount`         | string         | yes      | Amount to trade (in token units)      |
| `srcToken`       | string         | yes      | Source token address                  |
| `srcDecimals`    | number         | no       | Decimals of the source token          |
| `destToken`      | string         | yes      | Destination token address             |
| `destDecimals`   | number         | no       | Decimals of the destination token     |
| `toChain`        | number         | yes      | Destination chain ID                  |
| `protocol`       | string         | yes      | Protocol identifier from quotes       |
| `recipient`      | string         | yes      | Address to receive destination tokens |
| `slippage`       | number         | yes      | Slippage tolerance percentage         |
| `additionalInfo` | AdditionalInfo | no       | Additional route-specific data        |
| `permitData`     | string         | no       | Pre-signed permit data                |

### TradeBuildTxnResponse (build response)

`buildTradeTxn(request)` returns an object with (non-gasless, i.e. `gasless: false`):

* **status** - `"success"` when the build succeeds
* **txId** - Unique build/transaction ID (hex string)
* **chainId** - Chain where the transaction is to be executed
* **transaction** - Chain-specific payload, one of `EvmTxData` (`{ from, data, to, value, gasLimit }`), `SvmTxData`, `BtcTxData`, `BtclnTxData`, or `HyperLiquidTxData`
* **gasless** - `false` for this response shape
* **private** - `boolean`, echoes whether private/MEV-protected execution was used
* **quotes** - Per-pair summary keyed by pair ID: `{ additionalInfo?, provider, destAmount, minDestAmount, priceImpact?, duration? }`
* **data**, **from**, **to?**, **value?**, **gasLimit?** - `@deprecated` top-level mirror of the EVM transaction fields
* **svmTxData?** - `{ blockhash, lastValidBlockHeight }` for Solana transactions
* **btcTxData?** - `{ inputs, outputs, feeRate }` for Bitcoin transactions
* **btclnTxData?** - `{ paymentRequestType: "bolt11", paymentRequest, paymentExpiry }` for Bitcoin Lightning
* **additionalInfo** - `Record<string, Record<string, unknown>>`
* **updatedQuotes** - `Record<string, string>`, refreshed destination amounts keyed by pair ID

When `gasless: true` is requested, the shape is `GaslessTradeBuildTxnResponse` instead: `{ status: "success", txId, transaction: BridgeGaslessTxData | SwapGaslessTxData, quotes, gasless: true, onlySwapData: false }`.

Pass this object as `txnData` to `trade({ request, signer, txnData })` to skip the build step. See [Types reference](/sdk/reference/types#tradebuildtxnresponse-build-response) for the full shape.

## Complete Example with Quotes and Approvals

Here's a full example that gets quotes, handles approvals, and executes a trade. The `getAllowance` response has `data` keyed by token address; each entry has `allowance` (bigint) and `type` (`'dzap' | 'permit2' | 'eip2612'`) — derive whether approval/signature is needed from those. See [Approvals](/sdk/approvals) for details.

```typescript theme={null}
import {
  DZapClient,
  Services,
  ApprovalModes,
  PermitTypes,
  TxnStatus,
} from "@dzapio/sdk";
import type { TradeQuotesRequest, TradeBuildTxnRequest } from "@dzapio/sdk";

const dZap = DZapClient.getInstance();
const tokenAddress = "0xaf88d065e77c8cC2239327C5EDb3A432268e5831" as const;

// Step 1: Get quotes
const quotesRequest: TradeQuotesRequest = {
  fromChain: 42161, // Arbitrum
  data: [
    {
      amount: "1000000", // 1 USDC
      srcToken: tokenAddress,
      destToken: "0x4200000000000000000000000000000000000006",
      toChain: 8453, // Base
      slippage: 1,
    },
  ],
  account: userAccount,
};

const quotes = await dZap.getTradeQuotes(quotesRequest);
const pairKey = Object.keys(quotes)[0];
const pairData = quotes[pairKey];
const recommendedSource =
  pairData.recommendedSource ?? pairData.bestReturnSource;

// Step 2: Check allowances (data is keyed by token address)
const tokens = [{ address: tokenAddress as `0x${string}`, amount: "1000000" }];

const allowanceCheck = await dZap.getAllowance({
  chainId: 42161,
  sender: userAccount,
  tokens,
  service: Services.trade,
  mode: ApprovalModes.AutoPermit,
});

const allowanceData = allowanceCheck.data ?? {};
const isApprovalNeeded = tokens.some((t) => {
  const entry = allowanceData[t.address];
  return entry && entry.type !== "eip2612" && entry.allowance < BigInt(t.amount);
});
const isSignatureNeeded = tokens.some(
  (t) => allowanceData[t.address]?.type !== "dzap"
);

if (isApprovalNeeded) {
  await dZap.approve({
    chainId: 42161,
    signer,
    sender: userAccount,
    tokens,
    service: Services.trade,
    mode: ApprovalModes.AutoPermit,
    approvalTxnCallback: async ({ txnDetails, address }) => {
      console.log(`Approval for ${address}:`, txnDetails);
    },
  });
}

let permitData: string | undefined;
if (isSignatureNeeded) {
  const signatures = await dZap.sign({
    chainId: 42161,
    sender: userAccount,
    tokens: tokens.map((t) => ({ address: t.address, amount: t.amount })),
    signer,
    service: Services.trade,
    permitType: PermitTypes.AutoPermit,
    signatureCallback: async (res) => {
      permitData = res.permitData;
    },
  });
  if (signatures.status === TxnStatus.success && "tokens" in signatures) {
    permitData = signatures.tokens?.[0]?.permitData;
  }
}

// Step 3: Build trade request from selected quote
const request: TradeBuildTxnRequest = {
  fromChain: 42161,
  sender: userAccount,
  refundee: userAccount,
  gasless: false,
  data: [
    {
      amount: "1000000",
      srcToken: tokenAddress,
      destToken: "0x4200000000000000000000000000000000000006",
      toChain: 8453,
      protocol: recommendedSource,
      recipient: userAccount,
      slippage: 1,
      permitData,
    },
  ],
};

// Step 4: Execute the trade (trade() accepts only request and signer)
const tradeResult = await dZap.trade({ request, signer });

if (tradeResult.status === TxnStatus.success) {
  console.log("Transaction hash:", tradeResult.txnHash);
  const status = await dZap.getTradeTxnStatus({
    txHash: tradeResult.txnHash!,
    chainId: 42161,
  });
  console.log("Trade status:", status);
} else {
  console.error("Trade failed:", tradeResult.errorMsg);
}
```

<Note>
  **Viem/wagmi**: If using wagmi v2 or viem v2, you may need to cast the wallet
  client: `signer: walletClient as any` when passing to `approve()` or
  `trade()`.
</Note>

## Error handling and retry (TRY\_ANOTHER\_ROUTE)

When a trade fails, the response may include `action: "TRY_ANOTHER_ROUTE"`. In that case, retry the trade using the fallback route (`bestReturnSource` from the quote) instead of `recommendedSource`:

```typescript theme={null}
let tradeResult = await dZap.trade({ request, signer });

if (
  tradeResult.status !== TxnStatus.success &&
  tradeResult.action === "TRY_ANOTHER_ROUTE"
) {
  // Rebuild request with bestReturnSource for each pair
  const fallbackData = request.data.map((d, i) => {
    const pairKey = Object.keys(quotes)[i];
    const fallbackSource = quotes[pairKey]?.bestReturnSource;
    return fallbackSource ? { ...d, protocol: fallbackSource } : d;
  });
  tradeResult = await dZap.trade({
    request: { ...request, data: fallbackData },
    signer,
  });
}

if (tradeResult.status !== TxnStatus.success) {
  throw new Error(tradeResult.errorMsg ?? "Trade failed");
}
```

## Best Practices

1. **Always validate balances** before execution
2. **Check allowances** and execute approvals if needed
3. **Implement proper error handling** with retry logic (including `TRY_ANOTHER_ROUTE`)
4. **Use appropriate slippage settings** based on market conditions
5. **Monitor transaction status** for cross-chain trades

## Next Steps

After executing trades:

1. [Track the trade status](/sdk/trade/status-tracking) to monitor progress

<Warning>
  Always ensure users have sufficient balance for both the trade amount and gas
  fees before execution.
</Warning>
