Skip to main content
Send transactions across multiple chains in a single request, with gas payment settled on just one chain. This eliminates the need for users to hold gas tokens on every chain.
When using the relayer (without smart account), your transaction must include an ERC-20 transfer to Gelato’s fee collector. Use getCapabilities and getFeeQuote to get the fee collector address and fee amount, then include a token transfer in your transaction payload. This is handled automatically when using the EIP-7702 Smart Account.

Getting Started

1

Import Dependencies

import { createGelatoEvmRelayerClient } from '@gelatocloud/gasless';
2

Create Relayer Client

To create an API Key, visit the Gelato App and navigate to Relayer > API Keys.
const relayer = createGelatoEvmRelayerClient({
  apiKey: process.env.GELATO_API_KEY,
  testnet: true // Use false for mainnet
});
3

Send Multichain Transactions

Submit transactions to multiple chains. One transaction pays with a token, others are sponsored:
const taskIds = await relayer.sendTransactionMultichain([
  {
    // Transaction on Ethereum - pays for all transactions
    chainId: 1,
    to: '0x55f3a93f544e01ce4378d25e927d7c493b863bd7',
    data: '0x29cb0f49',
    payment: {
      type: 'token',
      address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' // USDC
    }
  },
  {
    // Transaction on Base - sponsored
    chainId: 8453,
    to: '0x45f3a93f544e01ce4378d25e927d7c493b863bd7',
    data: '0x19ca0f49',
    payment: {
      type: 'sponsored'
    }
  },
  {
    // Transaction on Arbitrum - sponsored
    chainId: 42161,
    to: '0x35f3a93f544e01ce4378d25e927d7c493b863bd7',
    data: '0x39cb0f49',
    payment: {
      type: 'sponsored'
    }
  }
]);

console.log('Task IDs:', taskIds);
4

Track Transaction Status

Each transaction returns its own task ID. Track them independently:
const statuses = await Promise.all(
  taskIds.map(id => relayer.waitForStatus({ id }))
);

statuses.forEach((status, index) => {
  console.log(`Transaction ${index}: ${status.status}`);
  if (status.receipt) {
    console.log(`  Hash: ${status.receipt.transactionHash}`);
  }
});

Parameters

Each transaction in the array accepts the following parameters:
ParameterTypeRequiredDescription
chainIdstringYesTarget chain ID
toAddressYesTarget contract address
dataHexYesTransaction calldata
paymentPaymentYesPayment configuration (see below)
contextunknownNoOptional context data
authorizationListAuthorization[]NoEIP-7702 authorizations

Payment Types

TypeFormatDescription
token{ type: 'token', address: '0x...' }Pay with ERC-20 token at the specified address
sponsored{ type: 'sponsored' }Covered by another transaction’s payment
Exactly one transaction in the batch must have a token payment type. All other transactions must use sponsored. The paying transaction can be at any position in the array.

Response

The method returns an array of task IDs, one for each transaction in the same order as the request:
const taskIds = await relayer.sendTransactionMultichain([...]);
// Returns: ['0x0e670ec6...', '0x0cf041f5...', '0x1ab234c7...']
Each task ID is a unique 32-byte identifier that can be used to track the transaction status.

Tracking Status

Track each transaction independently using its task ID:
// Track all transactions
const statuses = await Promise.all(
  taskIds.map(id => relayer.waitForStatus({ id }))
);

// Check results
statuses.forEach((status, index) => {
  console.log(`Transaction ${index}: ${status.status}`);
  if (status.receipt) {
    console.log(`  Hash: ${status.receipt.transactionHash}`);
  }
});

Additional Resources