> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gelato.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# Pay with ERC-20 Tokens

Use third-party on-chain paymasters for ERC-20 gas payments. This approach gives you flexibility to use different paymaster providers while still benefiting from Gelato's high-performance bundler.

<Note>
  On-chain paymasters are smart contracts that sponsor gas fees by accepting ERC-20 tokens from users. They handle the token-to-ETH conversion on-chain, allowing users to pay gas with tokens they hold.
</Note>

## Implementations

<Tabs>
  <Tab title="Permissionless">
    This example uses [Pimlico's ERC-20 Paymaster](https://docs.pimlico.io/). You can substitute any compatible on-chain paymaster.

    <CodeGroup>
      ```bash npm theme={null}
      npm install permissionless viem
      ```

      ```bash yarn theme={null}
      yarn add permissionless viem
      ```

      ```bash pnpm theme={null}
      pnpm add permissionless viem
      ```
    </CodeGroup>

    <Steps>
      <Step title="Create an API Key">
        Check out our [How-To Guide](/paymaster-&-bundler/how-to-guides/create-a-api-key) for detailed instructions on generating a Gelato API key.

        You'll also need an API key from your paymaster provider (e.g., [Pimlico](https://dashboard.pimlico.io/)).
      </Step>

      <Step title="Create Smart Account">
        ```typescript theme={null}
        import { createSmartAccountClient } from "permissionless";
        import { createPimlicoClient } from "permissionless/clients/pimlico";
        import { prepareUserOperationForErc20Paymaster } from "permissionless/actions/erc20";
        import { createPublicClient, http, type Hex } from "viem";
        import { entryPoint07Address, toSoladySmartAccount } from "viem/account-abstraction";
        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 toSoladySmartAccount({
          client,
          owner,
        });
        ```
      </Step>

      <Step title="Create Paymaster Client">
        Set up the on-chain paymaster client. This example uses Pimlico:

        ```typescript theme={null}
        const pimlicoUrl = `https://api.pimlico.io/v2/${baseSepolia.id}/rpc?apikey=${process.env.PIMLICO_API_KEY}`;

        const paymasterClient = createPimlicoClient({
          chain: baseSepolia,
          transport: http(pimlicoUrl),
          entryPoint: {
            address: entryPoint07Address,
            version: "0.7",
          },
        });
        ```
      </Step>

      <Step title="Create Smart Account Client with Gelato Bundler">
        Combine Gelato's bundler with the on-chain paymaster:

        ```typescript theme={null}
        const bundlerUrl = `https://api.gelato.cloud/rpc/${baseSepolia.id}`;

        const smartClient = createSmartAccountClient({
          account,
          chain: baseSepolia,
          bundlerTransport: http(bundlerUrl, {
            fetchOptions: {
              headers: {
                'X-API-Key': process.env.GELATO_API_KEY
              }
            }
          }),
          paymaster: paymasterClient,
          userOperation: {
            estimateFeesPerGas: async ({ bundlerClient }) => {
              const gasPrices = await bundlerClient.request({
                method: "eth_getUserOperationGasPrice",
                params: [],
              });
              return {
                maxFeePerGas: BigInt(gasPrices.maxFeePerGas),
                maxPriorityFeePerGas: BigInt(gasPrices.maxPriorityFeePerGas),
              };
            },
            prepareUserOperation: prepareUserOperationForErc20Paymaster(paymasterClient),
          },
        });
        ```
      </Step>

      <Step title="Send Transaction">
        ```typescript theme={null}
        const USDC_ADDRESS = "0x036CbD53842c5426634e7929541eC2318f3dCF7e"; // USDC (Base Sepolia)

        const txHash = await smartClient.sendTransaction({
          to: "0xE27C1359cf02B49acC6474311Bd79d1f10b1f8De",
          value: 0n,
          data: "0xd09de08a", // increment()
          paymasterContext: {
            token: USDC_ADDRESS,
          },
        });

        console.log(`Transaction hash: ${txHash}`);
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="API Endpoints">
    When using the API directly, you need to obtain paymaster fields from your chosen paymaster provider and include them in the UserOperation.

    <Steps>
      <Step title="Create API Keys">
        You'll need:

        * A Gelato API key from [app.gelato.cloud](https://app.gelato.cloud)
        * A paymaster API key from your provider (e.g., Pimlico, Alchemy)
      </Step>

      <Step title="Get Paymaster Data">
        Request sponsorship data from your paymaster. Example with Pimlico:

        ```typescript theme={null}
        const USDC_ADDRESS = "0x036CbD53842c5426634e7929541eC2318f3dCF7e";

        const paymasterResponse = await fetch(
          `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${PIMLICO_API_KEY}`,
          {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({
              jsonrpc: "2.0",
              id: 1,
              method: "pm_getPaymasterStubData",
              params: [
                {
                  sender: "0xYourSmartAccountAddress",
                  nonce: "0x0",
                  callData: "0xCalldata",
                  maxFeePerGas: "0x...",
                  maxPriorityFeePerGas: "0x..."
                },
                "0x0000000071727De22E5E9d8BAf0edAc6f37da032", // EntryPoint v0.7
                chainId.toString(),
                { token: USDC_ADDRESS }
              ]
            })
          }
        );

        const paymasterData = await paymasterResponse.json();
        // Returns: paymaster, paymasterData, paymasterVerificationGasLimit, paymasterPostOpGasLimit
        ```
      </Step>

      <Step title="Build UserOperation with Paymaster Fields">
        Include the paymaster fields in your UserOperation:

        ```typescript theme={null}
        const userOperation = {
          sender: "0xYourSmartAccountAddress",
          nonce: "0x0",
          callData: "0xCalldata",
          callGasLimit: "0x...",
          verificationGasLimit: "0x...",
          preVerificationGas: "0x...",
          maxFeePerGas: "0x...",
          maxPriorityFeePerGas: "0x...",
          signature: "0xSignature",
          // Paymaster fields from step 2
          paymaster: paymasterData.result.paymaster,
          paymasterData: paymasterData.result.paymasterData,
          paymasterVerificationGasLimit: paymasterData.result.paymasterVerificationGasLimit,
          paymasterPostOpGasLimit: paymasterData.result.paymasterPostOpGasLimit,
        };
        ```
      </Step>

      <Step title="Send to Gelato Bundler">
        ```typescript theme={null}
        const response = await fetch(
          `https://api.gelato.cloud/rpc/${chainId}`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              "X-API-Key": process.env.GELATO_API_KEY
            },
            body: JSON.stringify({
              jsonrpc: "2.0",
              id: 1,
              method: "eth_sendUserOperation",
              params: [
                userOperation,
                "0x0000000071727De22E5E9d8BAf0edAc6f37da032" // EntryPoint v0.7
              ]
            })
          }
        );

        const data = await response.json();
        const userOpHash = data.result;
        console.log(`UserOperation hash: ${userOpHash}`);
        ```
      </Step>

      <Step title="Get Receipt">
        ```typescript theme={null}
        const response = await fetch(
          `https://api.gelato.cloud/rpc/${chainId}`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              "X-API-Key": process.env.GELATO_API_KEY
            },
            body: JSON.stringify({
              jsonrpc: "2.0",
              id: 1,
              method: "eth_getUserOperationReceipt",
              params: [userOpHash]
            })
          }
        );

        const data = await response.json();
        if (data.result) {
          console.log(`Transaction hash: ${data.result.receipt.transactionHash}`);
        }
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

## How It Works

```mermaid theme={null}
sequenceDiagram
    participant User
    participant SmartAccount
    participant Paymaster
    participant Bundler as Gelato Bundler
    participant EntryPoint

    User->>SmartAccount: Sign UserOperation
    SmartAccount->>Paymaster: Request sponsorship
    Paymaster-->>SmartAccount: Return paymaster fields
    SmartAccount->>Bundler: Submit UserOperation
    Bundler->>EntryPoint: Bundle & execute
    EntryPoint->>Paymaster: Validate & charge tokens
    Paymaster->>SmartAccount: Deduct ERC-20 tokens
    EntryPoint-->>Bundler: Execution result
    Bundler-->>User: Transaction receipt
```

1. **Request Sponsorship** - Your app requests paymaster data from the on-chain paymaster provider
2. **Build UserOperation** - Include the paymaster fields (`paymaster`, `paymasterData`, gas limits)
3. **Submit to Bundler** - Gelato validates and bundles the UserOperation
4. **On-Chain Execution** - The paymaster validates the operation and charges ERC-20 tokens

## Compatible Paymasters

Any ERC-4337 compatible paymaster works with Gelato's bundler:

| Provider | Documentation                                                                             |
| -------- | ----------------------------------------------------------------------------------------- |
| Pimlico  | [docs.pimlico.io](https://docs.pimlico.io/)                                               |
| Alchemy  | [docs.alchemy.com](https://docs.alchemy.com/reference/account-abstraction-api-quickstart) |
| Biconomy | [docs.biconomy.io](https://docs.biconomy.io/)                                             |
| StackUp  | [docs.stackup.sh](https://docs.stackup.sh/)                                               |

## Additional Resources

* [ERC-20 Payment Tokens](/paymaster-&-bundler/additional-resources/erc20-payment-tokens) - Supported tokens
* [Estimate Gas](/paymaster-&-bundler/how-to-guides/estimate-gas) - Gas estimation methods
