Skip to main content
Allow users to pay gas fees using ERC-20 tokens like USDC, USDT, or other supported tokens.

Implementations

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 7702 Smart Account.
npm install @gelatocloud/gasless viem
1

Create an API Key

Check out our How-To Guide for detailed instructions on generating an API key.
2

Initialize Relayer Client

import { createGelatoEvmRelayerClient, StatusCode, token } from '@gelatocloud/gasless';
import { createPublicClient, encodeFunctionData, http } from 'viem';
import { baseSepolia } from 'viem/chains';

const USDC_ADDRESS = '0x036CbD53842c5426634e7929541eC2318f3dCF7e'; // Base Sepolia

const relayer = createGelatoEvmRelayerClient({
  apiKey: process.env.GELATO_API_KEY,
  testnet: true
});

const publicClient = createPublicClient({
  chain: baseSepolia,
  transport: http()
});
3

Get Fee Collector

Get the fee collector address for your chain:
const capabilities = await relayer.getCapabilities();
const feeCollector = capabilities[baseSepolia.id].feeCollector;
4

Get Fee Quote

Estimate gas and get the fee amount in your payment token:
const gasEstimate = await publicClient.estimateGas({
  to: '0xE27C1359cf02B49acC6474311Bd79d1f10b1f8De',
  data: '0xd09de08a'
});

const quote = await relayer.getFeeQuote({
  chainId: baseSepolia.id,
  gas: gasEstimate,
  token: USDC_ADDRESS
});

console.log('Fee:', quote.fee); // Fee amount in token units
5

Build Calldata with Fee Transfer

Build calldata that includes a token transfer to the fee collector:
// Encode ERC-20 transfer to fee collector
const transferData = encodeFunctionData({
  abi: [{
    name: 'transfer',
    type: 'function',
    inputs: [
      { name: 'to', type: 'address' },
      { name: 'amount', type: 'uint256' }
    ],
    outputs: [{ type: 'bool' }]
  }],
  functionName: 'transfer',
  args: [feeCollector, quote.fee]
});

// Your main transaction calldata
const targetCalldata = '0xd09de08a'; // increment()

// Use a multicall contract or your own contract to batch:
// 1. Transfer fee to feeCollector
// 2. Execute your target call
const data = encodeMulticall([
  { to: USDC_ADDRESS, data: transferData },
  { to: '0xE27C1359cf02B49acC6474311Bd79d1f10b1f8De', data: targetCalldata }
]);
6

Send Transaction

const id = await relayer.sendTransaction({
  chainId: baseSepolia.id,
  data: data,
  payment: token(USDC_ADDRESS),
  to: multicallContractAddress
});

console.log(`Gelato transaction id: ${id}`);

const status = await relayer.waitForStatus({ id });

if (status.status === StatusCode.Included) {
  console.log(`Transaction hash: ${status.receipt.transactionHash}`);
} else {
  console.log(`Transaction failed: ${status.message}`);
}

Supported Tokens

Check out the full list of ERC-20 Payment Tokens supported on each network.

Additional Resources