Validium Docs
  • Overview
  • Connect to Validium
  • Start Coding 🚀
    • Quickstart
      • Overview
      • Deploy using Validium CLI
      • Deploy using Quickstart Repository
      • Deploy your first contract
      • Create an ERC20 token
  • Tooling
    • Block Explorers
    • Hardhat-Validium
      • Overview
      • Installation
      • Guides
        • Getting started
        • Migrating Hardhat project to Validium
        • Compiling non-inlinable libraries
      • Plugins
        • hardhat-zksync
        • hardhat-zksync-solc
        • hardhat-zksync-vyper
        • hardhat-zksync-deploy
        • hardhat-zksync-upgradable
        • hardhat-zksync-verify
        • hardhat-zksync-verify-vyper
        • hardhat-zksync-ethers
        • hardhat-zksync-node
        • Hardhat Community Plugins
    • Foundary
      • Overview
      • Installation
      • Getting Started
      • Migration Guide
        • Overview
        • Compilation
        • Deployment
        • Testing
  • Test and Debug
    • Getting Started
    • Docker L1 - L2 Nodes
    • In-Memory Node
    • Continuous Integration
    • Hardhat
    • Foundry
  • API Reference
    • Overview
    • Conventions
    • ZKs JSON-RPC API
    • Debug JSON-RPC API
    • Ethereum JSON-RPC API
    • PubSub JSON-RPC API
  • Concepts
    • Transaction Lifecycle
    • Blocks and Batches
    • Validium Network Fee Mechanism
    • Finality
    • System Upgrades
    • ZK Chains
    • Data Availability
      • Overview
      • Recreating L2 state from L1 pubdata
      • Validiums
    • Account Abstraction
    • L1 <-> L2 Communication
  • Components
    • Overview
    • Smart & System Contracts
      • Smart Contracts
      • System Contracts
    • Shared Bridges
    • Sequencer / Server
    • Validium Network EVM
      • Overview
      • Bootloader
      • Precompiles
      • Virtual Machine Specification
        • ZKsync Virtual Machine primer
        • VM Formal Specification
    • Prover
      • Overview
      • ZK Terminology
      • Running the Prover
      • Circuits
        • Overview
        • Circuit Testing
        • CodeDecommitter
        • DemuxLogQueue
        • ECRecover
        • KeccakRoundFunction
        • L1MessagesHasher
        • LogSorter
        • Main VM
        • RAMPermutation
        • Sha256RoundFunction
        • StorageApplication
        • Sorting and Deduplicating
          • Overview
          • SortDecommitments
          • StorageSorter
          • LogSorter
      • Boojum Gadgets
      • Boojum Function - `check_if_satisfied`
    • Compiler
      • Compiler Toolchain Overview
        • Compiler Toolchain Overview
        • Solidity Compiler
        • Vyper Compiler
        • LLVM Framework
      • Specification
        • Overview
        • Code Separation
        • System Contracts
        • Exception Handling
        • EVM Legacy Assembly Translator
        • Instructions
          • Instruction Reference
          • EVM
            • Native EVM Instructions
            • Arithmetic
            • Bitwise
            • Block
            • Call
            • Create
            • Environment
            • Logging
            • Logical
            • Memory
            • Return
            • Sha3
            • Stack
          • Extensions
            • Overview
            • Validium Network Extension Simulation (call)
            • Validium Network Extension Simulation (verbatim)
          • EVM Legacy Assembly
          • Yul
        • EraVM Binary Layout
    • Fee Withdrawer
    • Portal - Wallet + Bridge
    • Block Explorer
    • Transaction filtering
Powered by GitBook
On this page
  • Prerequisites
  • What is a Paymaster?
  • Paymaster smart contract code
  • How to send a transaction through a paymaster?
  • Interacting with the testnet paymaster
  • Run the script
  • Takeaways
  • Next steps
  1. Start Coding 🚀
  2. Quickstart

Paymasters introduction

Learn about paymasters and use one to pay transaction fees with your own token

Last updated 8 months ago


This tutorial makes use of smart contracts deployed in the previous two tutorials, and . This section introduces one of the custom features of Validium: native account abstraction and paymasters.

In this tutorial we will:

  • Learn about paymasters.

  • Review the testnet paymaster smart contract code.

  • Use the testnet paymaster to pay transaction fees with our own ERC20 token.

Prerequisites

  1. Before you start, make sure .

  2. In addition, fund your wallet with Validium Sepolia Testnet ETH using .

What is a Paymaster?

Paymasters in the Validium ecosystem represent a groundbreaking approach to handling transaction fees. They are special accounts designed to subsidize transaction costs for other accounts, potentially making certain transactions free for end-users. This feature is particularly useful for dApp developers looking to improve their platform's accessibility and user experience by covering transaction fees on behalf of their users.

Every paymaster has the following two functions:

  • validateAndPayForPaymasterTransaction : this function uses the transaction parameters (fields like from, amount , to ) to execute the required validations and pay for the transaction fee.

  • postTransaction: this optional function runs after the transaction is executed.

Validium paymaster

Paymaster smart contract code

Although application developers are encouraged to create their own paymaster smart contract, Validium provides a testnet paymaster for convenience and testing purposes.

The paymaster smart contract code is provided "as-is" without any express or implied warranties.

  • Users are solely responsible for ensuring that their design, implementation, and use of the paymaster smart contract software complies with all applicable laws, including but not limited to money transmission, anti-money laundering (AML), and payment processing regulations.

  • The developers and publishers of this software disclaim any liability for any legal issues that may arise from its use.

TestnetPaymaster.sol

In the validateAndPayForPaymasterTransaction it is:

  1. Checking that the paymasterInput is approvalBased.

  2. Checking that the allowance of a given ERC20 is enough.

  3. Transferring the transaction fee (requiredETH) in ERC20 from the user’s balance to the paymaster.

  4. Transferring the transaction fee in ETH from the paymaster contract to the bootloader.

How to send a transaction through a paymaster?

In order to send a transaction through a paymaster, the transaction must include the following additional parameters:

  • paymasterAddress: the smart contract address of the paymaster

  • type: should be General or ApprovalBased (to pay fees with ERC20 tokens)

  • minimalAllowance: the amount of ERC20 tokens to be approved for spending (for approvalBased type paymasters only).

  • innerInput: any payload we want to send to the paymaster (optional).

We’ll see an example next.

Interacting with the testnet paymaster

We’re going to interact with the ZeekMessages.sol contract that we created in the first tutorial and use the ERC20 token that we deployed in the second tutorial to pay the transaction fees.

AtlasRemix

Click the following button to open the project in Atlas:

It’ll open the script to send a transaction via the paymaster. Let’s go through the most important parts:

Retrieve the token balance

// retrieve and print the current balance of the wallet
let ethBalance = await provider.getBalance(walletAddress)
let tokenBalance = await tokenContract.balanceOf(walletAddress)
console.log(`Account ${walletAddress} has ${ethers.formatEther(ethBalance)} ETH`);
console.log(`Account ${walletAddress} has ${ethers.formatUnits(tokenBalance, 18)} tokens`);

In this part we’re retrieving the ETH and ERC20 token balances of the account. We’ll compare them after the transaction is executed to see the difference.

Estimate transaction fee

// retrieve the testnet paymaster address
const testnetPaymasterAddress = await zkProvider.getTestnetPaymasterAddress();

console.log(`Testnet paymaster address is ${testnetPaymasterAddress}`);

const gasPrice = await zkProvider.getGasPrice();

// define paymaster parameters for gas estimation
const paramsForFeeEstimation = utils.getPaymasterParams(testnetPaymasterAddress, {
  type: "ApprovalBased",
  token: TOKEN_CONTRACT_ADDRESS,
  // set minimalAllowance to 1 for estimation
  minimalAllowance: ethers.toBigInt(1),
  // empty bytes as testnet paymaster does not use innerInput
  innerInput: new Uint8Array(0),
});

// estimate gasLimit via paymaster
const gasLimit = await messagesContract.sendMessage.estimateGas(NEW_MESSAGE, {
  customData: {
    gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT,
    paymasterParams: paramsForFeeEstimation,
  },
});

// fee calculated in ETH will be the same in
// ERC20 token using the testnet paymaster
const fee = gasPrice * gasLimit;
  1. Retrieve the testnet paymaster address.

  2. Generate the paymaster parameters to estimate the transaction fees passing the paymaster address, token address, and ApprovalBased as the paymaster flow type.

  3. Retrieve the gasLimit of sending the transaction with the paymaster params.

  4. Calculate the final estimated fee which is equal to gasPrice multiplied by gasLimit.

Send the transaction

// new paymaster params with fee as minimalAllowance
  const paymasterParams = utils.getPaymasterParams(testnetPaymasterAddress, {
    type: "ApprovalBased",
    token: TOKEN_CONTRACT_ADDRESS,
    // provide estimated fee as allowance
    minimalAllowance: fee,
    // empty bytes as testnet paymaster does not use innerInput
    innerInput: new Uint8Array(0),
  });

  // full overrides object including maxFeePerGas and maxPriorityFeePerGas
  const txOverrides = {
    maxFeePerGas: gasPrice,
    maxPriorityFeePerGas: "1",
    gasLimit,
    customData: {
      gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT,
      paymasterParams,
    }
  }

  console.log(`Sign the transaction in your wallet`);

  // send transaction with additional paymaster params as overrides
  const txHandle = await messagesContract.sendMessage(NEW_MESSAGE, txOverrides);
  1. Create the new paymaster params with the calculated fee as minimalAllowance .

  2. Complete the transaction overrides object with maxFeePerGas, maxPriorityFeePerGas and gasPerPubdata

  3. Send the transaction including the txOverrides

Compare the final balance

ethBalance = await provider.getBalance(walletAddress)
tokenBalance = await tokenContract.balanceOf(walletAddress)
console.log(`Account ${walletAddress} now has ${ethers.formatEther(ethBalance)} ETH`);
console.log(`Account ${walletAddress} now has ${ethers.formatUnits(tokenBalance, 18)} tokens`);

Finally we retrieve and print the ETH and ERC20 balances to see how they’ve changed.

Run the script

// Address of the ZeekMessages contract
const ZEEK_MESSAGES_CONTRACT_ADDRESS = "";
// Address of the ERC20 token contract
const TOKEN_CONTRACT_ADDRESS = ""
// Message to be sent to the contract
const NEW_MESSAGE = "This tx cost me no ETH!";

Next, make sure the script file is selected in the Atlas editor and click on the “Deploy” button.

You’ll see the progress in the console.

If everything worked as expected, only the ERC20 balance will decrease, meaning the fee was paid with the ERC20 token instead of ETH.

Takeaways

  • Paymasters on Validium allow any account to pay fees with ERC20 tokens or enable gasless transactions.

  • Paymasters are smart contracts that can have any validations and rules.

  • To send a transaction through a paymaster, we only need to include additional parameters in the transaction.

Next steps

The testnet paymaster address is

To run the script, first enter the addresses of the ZeekMessages.sol and TestToken.sol contracts that we deployed previously ( and ) in the following variables at the beginning of the script:

ERC20 interact script in Remix

Learn more about paymasters and native account abstraction in .

Browse different paymaster examples in .

Continue learning in ZKsync 101 by building a .

0x3cb2b87d10ac01736a65688f3e0fb1b070b3eea3
Open script in Atlas
Deploy your first contract
Erc20 Token
this section of the docs
this open source repository
GoFundMe clone
Deploy your first contract
Create an ERC20 token
that you’ve configured the Validium Sepolia Testnet in your browser wallet by following the instructions here
one of the available faucets