ERC20 Paymaster
Available on ZKsync Era mainnet, ZKsync Sepolia, Cronos zkEVM Mainnet, Cronos zkEVM Tesnet, Abstract Tesnet.
This guide will help you get started with the Zyfi API to transform a normal transaction in a paymaster one.
For advanced usage and detailed explanation of each parameter and feature, please explore our detailed API documentation.
The basic flow consists of the following steps:
- Collect the desired transaction payload and the ERC20 the user desires to pay with 
- Send an API request 
- Receive back the quote and transaction payload for the user to sign 
Step 1: Send the API request
Send the required data to the erc20_paymaster endpoint. Below an example implementation using Javascript fetch (natively supported in most environments)
// Define the payload
const payload = {
  chainId: 324, // Optional, defaults to zkSync Era Mainnet; valid options are 324, 300 (ZkSync-Sepolia), 388 (Cronos zkEVM mainnet), 282 (Cronos zkEVM Tesnet) and 11124 (Abstract Testnet).
  feeTokenAddress: // ERC20 the user desires to use as gas token
  txData: {
    from: "0x...",
    to: "0x...",
    data: "0x.."
  }
};
// Define the function to perform the POST request
async function postTransactionData() {
  try {
    const response = await fetch('https://api.zyfi.org/api/erc20_paymaster/v1', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(payload),
    });
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    const data = await response.json();
    console.log(data); // Process the response data
  } catch (error) {
    console.error('Error during the API call:', error);
  }
}
The returned object does not change the original transaction calldata, but add the paymaster fields necessary to process the transaction.
Step 2: Show the quote to the user
The response, on top of the transaction payload, returns a series of helper values that can be used by the UI to better inform the user. In particular:
- tokenAddress: ERC20 token address used to pay for the gas fee (feeToken)
- tokenPrice: the estimated cost of the feeToken
- feeTokenAmount: Max amount of the ERC20 token that the user will pay as fee (before refunds). The user need to have this balance for the transaction to not fail
- feeUSD: Equivalent value of feeTokenAmount in USD
- markup: Markup or discount applied on the gas fee
- expirationTime:- block.timestampof the quote expiration. Currently it's one hour
Step 3: Execute the transaction 
Ensure you are using zksync-ethers V5 or V6.
Below an example implementation with
import { Signer, Web3Provider } from "zksync-ethers";
import * as ethers from "ethers";
const signer = Web3Provider.getSigner
rawTx = Apiresponse.txData
//since the API returns the transaction payload in the ethers format, we can use it as is
txHash = await signer.sendTransaction(rawTx);
Make sure to check https://viem.sh/zksync to enable zkSync specific features
import { createWalletClient, custom } from 'viem'
import { zkSync } from 'viem/chains'
import { eip712WalletActions } from 'viem/zksync'
 
const walletClient = createWalletClient({ 
  chain: zkSync, 
  transport: custom(window.ethereum!), 
}).extend(eip712WalletActions()) 
  const nonce = await provider.getTransactionCount({
    address: account!.address,
  });
rawTx = Apiresponse.txData
// We need to reshuffle the response from the api
txPayload = {
      account: account,
      to: rawTx.to,
      value: BigInt(rawTx.value!),
      chain: (signer).chain,
      gas: BigInt(rawTx.gasLimit),
      gasPerPubdata: BigInt(rawTx.customData.gasPerPubdata),
      maxFeePerGas: BigInt(rawTx.maxFeePerGas),
      maxPriorityFeePerGas: BigInt(0),
      data: rawTx.data,
      paymaster: rawTx.customData.paymasterParams.paymaster,
      paymasterInput: rawTx.customData.paymasterParams.paymasterInput,
      nonce,
  }
  const txHash = await walletClient.sendTransaction(txPayload);Last updated
