Zyfi
  • Introduction
    • What is Zyfi?
    • Paymaster Flow
  • Gasless Program
    • Gas Grants Program
  • Integration Guide
    • Paymasters Integration
      • ERC20 Paymaster
      • Sponsored Paymaster
      • API Key management
    • API documentation
    • Intent Based
    • Paymaster Sybil Defense
    • Supported Tokens
      • Supported Tokens on ZKsync
      • Supported Tokens on Abstract
    • Case Studies
      • Case Study: SyncSwap
      • Case Study: Venus Protocol
      • Case Study: PancakeSwap
      • Case Study: Koi Finance
      • Case Study: Nodle
      • Case Study: Click
      • Case Study: Ebisu's Bay
      • Case Study: Mithraeum
      • Case Study: Gravita
      • Case Study: Router Nitro
    • UI Ideas
    • Audits
  • Permissionless Multi-signer Paymaster
    • About
    • How to set up?
    • Technical Details
    • Permissionless paymaster contract
    • Audits
  • ZFI & stZFI
    • Tokenomics
    • First Airdrop
  • Governance
    • Zyfi DAO
    • Association
  • Support
    • FAQ
    • Contract Addresses
    • Brand Assets
    • Mobile work-around
  • Socials
    • Twitter
    • Youtube
    • Discord
    • Telegram
    • Mirror
    • Dune Analytics Dashboard
Powered by GitBook
On this page
  • Step 1: Send the API request
  • Step 2: Show the quote to the user
  • Step 3: Execute the transaction
  1. Integration Guide
  2. Paymasters Integration

ERC20 Paymaster

Available on ZKsync Era mainnet, ZKsync Sepolia, Cronos zkEVM Mainnet, Cronos zkEVM Tesnet, Abstract Tesnet.

PreviousPaymasters IntegrationNextSponsored Paymaster

Last updated 8 months ago

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 .

The basic flow consists of the following steps:

  1. Collect the desired transaction payload and the ERC20 the user desires to pay with

  2. Send an API request

  3. 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 (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.

ETH can't be used by the paymaster as feeToken; in this case, the normal transaction flow will proceed.

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.timestamp of the quote expiration. Currently it's one hour

Transactions on zkSync overestimate the gas needed and receive a refund at the end, which is difficult to know in advance.

The unspent gas is refunded to the user in the feeToken.

We suggest to each protocol to implement their own estimation for the final cost by observing the actual gas being used on their transaction. We also provide a very rough estimation with estimatedFinalFeeTokenAmount and estimatedFinalFeeUSD

Step 3: Execute the transaction

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);
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);

Ensure you are using V5 or V6.

Make sure to check to enable zkSync specific features

API documentation
fetch
zksync-ethers
https://viem.sh/zksync