npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@gelatocloud/gasless

v0.0.7

Published

Gelato Gasless SDK: All-in-one solution for gasless transactions

Readme

@gelatocloud/gasless

npm version

All-in-one solution for gasless transactions.

Features

  • Three abstraction levels - Choose the optimal integration model for your application::
    • Turbo Relayer: The fastest, most efficient way to submit transactions on-chain with zero gas overhead, ideal for latency-sensitive workflows.
    • Turbo Relayer with Smart Account - Leverage Smart Accounts for streamlined transaction encoding and signing while retaining Turbo-level performance.
    • ERC-4337 Bundler - A fully compliant ERC-4337 bundler for native Account Abstraction flows.
  • Sponsorship via Gas Tank - Support for sponsored transactions using your Gas Tank.
  • 2D nonce support - Advanced nonce management using both nonce and nonceKey for parallelized execution.
  • Type-safe - Implemented on top of viem, offering complete TypeScript type safety and developer ergonomics.
  • Synchronous methods: Send transaction and get the receipt in a single call

Learn more in our docs

Installation

pnpm install viem @gelatocloud/gasless

Peer dependencies: viem

Quick Start

  1. Get your API key at https://app.gelato.cloud/
  2. Set your environment variable:
export GELATO_API_KEY="your-api-key"

Usage

Turbo Relayer

Direct gasless transaction relay without smart accounts. Best for simple sponsored transactions.

Synchronous:

import { createGelatoEvmRelayerClient } from '@gelatocloud/gasless';
import { baseSepolia } from 'viem/chains';

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

// Send and wait for inclusion in one call
const receipt = await relayer.sendTransactionSync({
  chainId: baseSepolia.id,
  to: '0xTargetContract...',
  data: '0xCalldata...'
});

console.log(`Transaction hash: ${receipt.transactionHash}`);

Asynchronous:

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

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

// Send transaction (returns immediately with task ID)
const taskId = await relayer.sendTransaction({
  chainId: baseSepolia.id,
  to: '0xTargetContract...',
  data: '0xCalldata...'
});

// Poll for status separately
const { status, receipt } = await relayer.waitForStatus({ id: taskId });

if (status.status === StatusCode.Success) {
  console.log(`Transaction hash: ${receipt.transactionHash}`);
}

Account (Gelato Smart Account)

Gelato's smart account implementation with ERC-7821 delegation pattern.

Synchronous:

import {
  createGelatoSmartAccountClient,
  toGelatoSmartAccount } from '@gelatocloud/gasless';
import { createPublicClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { baseSepolia } from 'viem/chains';

const owner = privateKeyToAccount('0xYourPrivateKey...');

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

// Create a Gelato smart account
const account = toGelatoSmartAccount({ client: publicClient, owner });

// Create the smart account client
const client = await createGelatoSmartAccountClient({
  account,
  apiKey: process.env.GELATO_API_KEY
});

// Send and wait for inclusion in one call
const receipt = await client.sendTransactionSync({
  calls: [
    { to: '0xContract1...', data: '0xCalldata1...' },
    { to: '0xContract2...', data: '0xCalldata2...' }
  ]// Optional: nonce or nonceKey for 2D nonce management
});

console.log(`Transaction hash: ${receipt.transactionHash}`);

Asynchronous:

import {
  createGelatoSmartAccountClient,
  toGelatoSmartAccount,
  StatusCode } from '@gelatocloud/gasless';

// ... same setup as above ...

// Send transaction (returns immediately with task ID)
const taskId = await client.sendTransaction({
  calls: [{ to: '0xContract...', data: '0xCalldata...' }] });

// Poll for status separately
const status = await client.waitForStatus({ id: taskId });

if (status.status === StatusCode.Success) {
  console.log(`Transaction hash: ${status.receipt.transactionHash}`);
}

Bundler (ERC-4337)

Compatible with any ERC-4337 smart account.

import { createGelatoBundlerClient } from '@gelatocloud/gasless';
import { to7702SimpleSmartAccount } from 'permissionless/accounts';
import { createPublicClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { baseSepolia } from 'viem/chains';

const owner = privateKeyToAccount('0xYourPrivateKey...');

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

// Create a smart account 
const account = await to7702SimpleSmartAccount({
  client,
  owner
});

// Create the Gelato bundler client
const bundler = await createGelatoBundlerClient({
  account,
  client,
  apiKey: process.env.GELATO_API_KEY,
  sponsored: true
});

// Send a user operation
const hash = await bundler.sendUserOperation({
  calls: [{ to: '0x...', data: '0x...' }]
});

// Wait for the receipt
const { receipt } = await bundler.waitForUserOperationReceipt({ hash });

console.log(`Transaction hash: ${receipt.transactionHash}`);

API Reference

Relayer API

createGelatoEvmRelayerClient(config)

Creates a low-level relayer client for direct transaction submission.

const client = createGelatoEvmRelayerClient({
  apiKey: string,    // Your Gelato API key
  testnet: boolean   // true for testnets, false for mainnet
});

Methods:

| Method | Parameters | Returns | Description | |--------|------------|---------|-------------| | sendTransaction | { chainId, to, data, authorizationList?, context? } | Promise<Hex> | Submit a transaction | | sendTransactionSync | { chainId, to, data, timeout?, pollingInterval?, ... } | Promise<TransactionReceipt> | Send and wait for receipt | | getStatus | { id: string } | Promise<Status> | Get transaction status | | waitForStatus | { id: string, timeout?, pollingInterval? } | Promise<TerminalStatus> | Wait for final status | | waitForReceipt | { id: string, timeout?, pollingInterval? } | Promise<TransactionReceipt> | Wait for receipt, throws on failure | | getCapabilities | - | Promise<Capabilities> | Get supported chains | | getFeeData | { chainId, gas, l1Fee? } | Promise<FeeData> | Get network fee data |


Account API

toGelatoSmartAccount(params)

Creates a Gelato smart account using ERC-7821 delegation.

const account = toGelatoSmartAccount({
  client: Client,   // viem public client
  owner: Account    // EOA that owns the smart account
});

createGelatoSmartAccountClient(config)

Creates a client for interacting with a Gelato smart account.

const client = await createGelatoSmartAccountClient({
  apiKey: string,              // Your Gelato API key
  account: SmartAccount        // From toGelatoSmartAccount()
});

Methods:

| Method | Parameters | Returns | Description | |--------|------------|---------|-------------| | sendTransaction | { calls, nonce?, nonceKey?} | Promise<Hex> | Send transaction(s) | | sendTransactionSync | { calls, nonce?, nonceKey?, timeout?, pollingInterval?, ... } | Promise<TransactionReceipt> | Send and wait for receipt | | getStatus | { id: string } | Promise<Status> | Get transaction status | | waitForStatus | { id: string, timeout?, pollingInterval? } | Promise<TerminalStatus> | Wait for final status | | waitForReceipt | { id: string, timeout?, pollingInterval? } | Promise<TransactionReceipt> | Wait for receipt, throws on failure | | getCapabilities | - | Promise<Capabilities> | Get supported chains |

Nonce Options:

  • nonce: Explicit nonce value
  • nonceKey: Key for 2D nonce (allows parallel transactions)

Polling Configuration:

All synchronous methods (sendTransactionSync, sendUserOperationSync, waitForStatus, waitForReceipt) support customizable polling behavior:

  • timeout (optional): Maximum wait time in milliseconds
    • Default: 120000 (2 minutes)
    • Must not exceed 600000 (10 minutes)
  • pollingInterval (optional): Frequency to check status in milliseconds
    • Default: 1000 (1 second)

Example:

// Wait up to 30 seconds, checking every 500ms
const receipt = await relayer.sendTransactionSync({
  chainId: baseSepolia.id,
  to: '0xTargetContract...',
  data: '0xCalldata...',
  timeout: 30000,
  pollingInterval: 500
});

Bundler API

createGelatoBundlerClient(config)

Creates an ERC-4337 bundler client. Extends viem's BundlerClient.

const bundler = await createGelatoBundlerClient({
  account: SmartAccount,       // Any ERC-4337 smart account
  client: Client,              // viem public client
  apiKey: string,              // Your Gelato API key
  sponsored: boolean,          // Whether to use sponsored payment via Gas Tank
  pollingInterval?: number     // Polling interval in ms
});

Methods:

| Method | Parameters | Returns | Description | |--------|------------|---------|-------------| | sendUserOperation | { calls } | Promise<Hex> | Send a user operation | | sendUserOperationSync | { calls, timeout?, pollingInterval? } | Promise<UserOperationReceipt> | Send and wait for receipt | | waitForUserOperationReceipt | { hash } | Promise<{ receipt }> | Wait for receipt | | estimateUserOperationGas | UserOperationParams | Promise<GasEstimate> | Estimate gas | | prepareUserOperation | UserOperationParams | Promise<UserOperation> | Prepare operation | | getUserOperationGasPrice | - | Promise<GasPrice> | Get current gas prices | | getUserOperationQuote | UserOperationParams | Promise<Quote> | Get fee quote |


Types

StatusCode

enum StatusCode {
  Pending = 100,    // Transaction pending
  Submitted = 110,  // Submitted to network
  Success = 200,   // Successfully included
  Rejected = 400,   // Rejected by relayer
  Reverted = 500    // Reverted on-chain
}

ErrorCode

enum ErrorCode {
  // JSON-RPC
  ParseError = -32700,
  InvalidRequest = -32600,
  MethodNotFound = -32601,
  InvalidParams = -32602,
  InternalError = -32603,
  TimeoutError = -32070,

  // Relayer
  Unauthorized = 4100,
  UnsupportedPaymentToken = 4202,
  InsufficientPayment = 4200,
  InsufficientBalance = 4205,
  UnsupportedChain = 4206,
  UnknownTransactionId = 4208,
  InvalidAuthorizationList = 4210,
  SimulationFailed = 4211,

  // Bundler
  ValidationFailed = -32500,
  PaymasterValidationFailed = -32501,
  InvalidSignature = -32507,
  ExecutionFailed = -32521
}

Call

type Call = {
  to: Address;      // Target contract address
  data?: Hex;       // Calldata (optional)
  value?: bigint;   // ETH value (optional)
};

Status Handling

import { StatusCode } from '@gelatocloud/gasless';

const status = await client.waitForStatus({ id: hash });

switch (status.status) {
  case StatusCode.Success:
    console.log('Success:', status.receipt.transactionHash);
    break;
  case StatusCode.Rejected:
    console.log('Rejected:', status.message);
    break;
  case StatusCode.Reverted:
    console.log('Reverted:', status.data);
    break;
}

Error Handling

Timeout Errors

Synchronous methods (sendTransactionSync, waitForStatus, waitForReceipt) throw TimeoutError when operations don't complete within the configured timeout:

import { TimeoutError } from '@gelatocloud/gasless';

try {
  const receipt = await relayer.sendTransactionSync({
    chainId: baseSepolia.id,
    to: '0xTargetContract...',
    data: '0xCalldata...',
    timeout: 10000
  });
} catch (error) {
  if (error instanceof TimeoutError) {
    console.error('Transaction timed out:', error.message);
    // Transaction may still be pending - you can retry with longer timeout
    // or use async methods to check status manually
  } else {
    console.error('Other error:', error);
  }
}

Automatic Fallback on Timeout

When sendTransactionSync times out, it automatically falls back to polling for the transaction status. If you see a warning message like:

Transaction 0x... sync call timed out, falling back to polling for completion. DO NOT RETRY this transaction.

This means your transaction was successfully submitted but the sync method timed out. The SDK will continue polling for completion automatically. Do not retry the operation as this could result in duplicate transactions.

Recovery Strategies

If a timeout occurs:

  1. Wait for automatic fallback: sendTransactionSync automatically polls after timeout
  2. Check status manually: Use getStatus({ id }) to check if transaction is still processing
  3. Retry with longer timeout: Increase timeout and call waitForStatus again
  4. Use async methods: Switch to async pattern for more control
try {
  // Try with default 10s timeout
  const receipt = await relayer.sendTransactionSync({
    chainId: baseSepolia.id,
    to: '0xTargetContract...',
    data: '0xCalldata...',
  });
} catch (error) {
  if (error instanceof TimeoutError) {
    // Retry with 60s timeout
    const taskId = await relayer.sendTransaction({
      chainId: baseSepolia.id,
      to: '0xTargetContract...',
      data: '0xCalldata...',
    });

    const status = await relayer.waitForStatus({
      id: taskId,
      timeout: 60000
    });

    console.log('Transaction completed:', status);
  }
}

Configuration Limits

The SDK enforces the following limits to prevent denial of service:

import {
  MIN_TIMEOUT,
  MAX_TIMEOUT,
  MIN_POLLING_INTERVAL,
  MAX_POLLING_INTERVAL
} from '@gelatocloud/gasless';

console.log(MIN_TIMEOUT); // 1000ms (1 second)
console.log(MAX_TIMEOUT); // 600000ms (10 minutes)
console.log(MIN_POLLING_INTERVAL); // 100ms
console.log(MAX_POLLING_INTERVAL); // 300000ms (5 minutes)

You can set default timeout and polling interval at the client level:

const relayer = createGelatoEvmRelayerClient({
  apiKey: process.env.GELATO_API_KEY,
  timeout: 30000, // Default 30 second timeout
  pollingInterval: 500 // Default 500ms polling interval
});

// Methods use client defaults unless overridden
const receipt = await relayer.sendTransactionSync({
  chainId: baseSepolia.id,
  to: '0xTargetContract...',
  data: '0xCalldata...',
  // timeout: 60000 // Optional: override client default
});

Requirements

  • Node.js >= 23
  • Peer dependencies: viem, zod
  • Optional: typescript

Examples

See the /examples directory for complete working examples:

Run an example:

cd examples/account/sponsored
npm install
GELATO_API_KEY=your-key npm run dev

Links

License

MIT