Skip to main content

Overview

The ExecuteIntent endpoint initiates the execution of a committed intent. This endpoint triggers the actual cross-chain transaction flow, including deposits, swaps, bridges, and destination calls.

Use Cases

  • Execute a committed cross-chain transaction
  • Initiate gasless transactions with deposit signatures
  • Trigger intent execution after deposit confirmation
  • Start the cross-chain bridging process

Request Parameters

Required Fields

  • intentId (string): The unique identifier returned from CommitIntent

Optional Fields

  • depositTransactionHash (string): Hash of the deposit transaction if already executed
  • depositSignature (DepositSignature): Signature for gasless execution
    • intentSignature (string): EIP-712 signature of the intent
    • permitSignature (string): ERC-2612 permit signature (if applicable)
    • permitDeadline (number): Permit expiration timestamp
    • permitAmount (number): Amount authorized by permit
    • selectedGasFeeOption (FeeOption): Selected gas fee payment option
    • userNonce (number): User’s nonce for replay protection
    • deadline (number): Signature expiration timestamp

Response

The response includes:
  • intentId (string): The intent identifier
  • intentStatus (IntentStatus): Current status of the intent
    • QUOTED: Initial quote generated
    • COMMITTED: Intent committed and ready
    • EXECUTING: Currently executing
    • FAILED: Execution failed
    • SUCCEEDED: Successfully completed

Execution Options

Mode 1: With Deposit Transaction Hash

First, deposit tokens to the intent address, then call ExecuteIntent with the transaction hash:
import { encodeFunctionData } from 'viem';

// Step 1: Send tokens to the intent address
 const depositTx = await walletClient.sendTransaction({
    to: intent.depositTransaction.tokenAddress, // Intent address from quote
    value: 0n, // 0 for ERC20 tokens, or native ETH amount
    data: encodeFunctionData({
        abi: erc20Abi,
        functionName: 'transfer',
        args: [
            intent.depositTransaction.toAddress as `0x${string}`,
            BigInt(intent.depositTransaction.amount)
        ]
    })
});

// Step 2: Wait for confirmation
const receipt = await publicClient.waitForTransactionReceipt({
  hash: depositTx
});

// Step 3: Execute the intent with the deposit transaction hash
const executeResponse = await fetch('https://trails-api.sequence.app/rpc/Trails/ExecuteIntent', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Access-Key': 'YOUR_ACCESS_KEY'
  },
  body: JSON.stringify({
    intentId: 'intent_123abc',
    depositTransactionHash: depositTx
  })
});

const { intentStatus } = await executeResponse.json();
console.log('Execution started:', intentStatus);

Mode 2: With Deposit Signature (Gasless)

Trails also supports paying end to end in non-native gas tokens that are permit compatible:
// Prepare signature
const signature = await signIntent(intent, walletClient);

const executeResponse = await fetch('https://trails-api.sequence.app/rpc/Trails/ExecuteIntent', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Access-Key': 'YOUR_ACCESS_KEY'
  },
  body: JSON.stringify({
    intentId: 'intent_123abc',
    depositSignature: {
      intentSignature: signature,
      selectedGasFeeOption: gasFeeOptions.feeOptions[0],
      userNonce: 1,
      deadline: Math.floor(Date.now() / 1000) + 3600
    }
  })
});

const { intentStatus } = await executeResponse.json();
console.log('Execution started:', intentStatus);
For complete details on preparing the deposit signature with permit and intent signatures, see the Alternative Fee Token Flow in the Getting Started guide.

Transaction Flow

Once executed, the intent goes through several stages:
  1. Deposit: Tokens are deposited to the origin intent address
  2. Relaying: Transaction is relayed to destination chain (if cross-chain)
  3. Execution: Destination calls are executed if calldata is passed
  4. Completion: Final status is recorded

Example: Full Flow

import { TradeType, TrailsApi } from '@0xtrails/api'
const trailsApi = new TrailsApi('YOUR_API_KEY')

const quoteRequest = {
    ownerAddress: "0x0709CF2d5D4f3D38f5948d697fE64d7FB3639Eb1",
    originChainId: 1, // Ethereum
    originTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
    originTokenAmount: 100000000n, // 100 USDC (6 decimals)
    destinationChainId: 8453, // Base
    destinationTokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC on Base
    destinationToAddress: "0x0709CF2d5D4f3D38f5948d697fE64d7FB3639Eb1",
    tradeType: TradeType.EXACT_INPUT,
    options: {
        slippageTolerance: 0.005, // 0.5%
        quoteProvider: "RELAY"
    }
};

// Step 1: Quote
const quoteResponse = await trailsApi.quoteIntent(quoteRequest);
const { intent, gasFeeOptions } = quoteResponse;

// Step 2: Commit
const { intentId } = await trailsApi.commitIntent({ intent });

// Step 3: Execute
const { intentStatus } = await trailsApi.executeIntent({
    intentId,
    depositSignature: {
        intentSignature: await signIntent(intent),
        selectedGasFeeOption: gasFeeOptions.feeOptions[0],
        userNonce: 1,
        deadline: Math.floor(Date.now() / 1000) + 3600
    }
});

console.log('Status:', intentStatus); // EXECUTING

// Step 4: Monitor
const receipt = await trailsApi.waitIntentReceipt({ intentId });
console.log('Receipt:', receipt);

Error Handling

If execution fails, the intent status will be set to FAILED. Check the statusReason field in the receipt for details.

Next Steps

After executing an intent:
  1. Use GetIntentReceipt to poll for transaction status
  2. Use WaitIntentReceipt for streaming updates
  3. Check transaction hashes on block explorers
  4. Verify final balances on destination chain