The simplest way to enable ERC-20 gas payments. Gelato’s SDK handles token payment automatically - just specify the payment token and send your UserOperation.
Installation
npm install @gelatocloud/gasless viem
Implementation
Create an API Key
Check out our How-To Guide for detailed instructions on generating an API key. Create Smart Account
import { createGelatoBundlerClient, token, toGelatoSmartAccount } from '@gelatocloud/gasless';
import { createPublicClient, http, type Hex } from 'viem';
import { privateKeyToAccount } from "viem/accounts";
import { baseSepolia } from "viem/chains";
const owner = privateKeyToAccount(process.env.PRIVATE_KEY as Hex);
const client = createPublicClient({
chain: baseSepolia,
transport: http(),
});
const account = await toGelatoSmartAccount({
client,
owner,
});
Create Bundler Client with Token Payment
Specify the ERC-20 token address using token():const USDC_ADDRESS = "0x036CbD53842c5426634e7929541eC2318f3dCF7e"; // USDC (Base Sepolia)
const bundler = await createGelatoBundlerClient({
account,
apiKey: process.env.GELATO_API_KEY,
client,
payment: token(USDC_ADDRESS),
});
Send UserOperation
const hash = await bundler.sendUserOperation({
calls: [
{
to: '0xE27C1359cf02B49acC6474311Bd79d1f10b1f8De',
data: '0xd09de08a', // increment()
}
]
});
console.log(`User operation hash: ${hash}`);
const { receipt } = await bundler.waitForUserOperationReceipt({ hash });
console.log(`Transaction hash: ${receipt.transactionHash}`);
How It Works
When using direct payment with Gelato:
- Fee Calculation - Gelato calculates the gas fee in the specified ERC-20 token
- Token Approval - Ensure your smart account has approved Gelato’s paymaster to spend the token
- Automatic Deduction - The fee is automatically deducted from your smart account’s token balance
- Transaction Execution - Gelato sponsors the native gas and executes your UserOperation
Your smart account must have sufficient ERC-20 token balance to cover the gas fee. Use getUserOperationQuote() to estimate the fee before sending.
Get Fee Quote
Estimate the fee before sending:
const quote = await bundler.getUserOperationQuote({
calls: [
{
to: '0xE27C1359cf02B49acC6474311Bd79d1f10b1f8De',
data: '0xd09de08a',
}
]
});
console.log('Fee:', quote.fee); // Fee in token units
console.log('Total gas:', quote.gas); // Total gas
console.log('L1 fee:', quote.l1Fee); // L1 data fee (L2 chains)
Additional Resources