Using viem with ZKsync

Learn how to use the viem/zksync plugin to interact with ZKsync.

This guide outlines how to use the ZKsync viem plugin to interact with ZKsync and use specific actions like sending transcations via paymasters.

What you'll learn:

  • How to install viem and the ZKsync plugin
  • How to send RPC requests to ZKsync
  • How to use ZKsync-specific methods
GitHub

Tools:

  • - viem
guideviem
Last Updated: May 09, 2024

viem is a TypeScript interface for Ethereum that now includes support for ZKsync, offering low-level stateless primitives for interacting with both Ethereum and ZKsync. You can use viem to interact seamlessly with smart contracts deployed on ZKsync. For more information on ZKsync specific support please refer to viem documentation here.

You can use viem to interact with smart contracts deployed on ZKsync.

Installation

Start by adding Viem to your project. Open your terminal and execute the following command:

npm install --save viem

This command installs the latest version of Viem and adds it to your project's dependencies.

Initial Setup

Client Configuration

Before using viem, you need to setup a Client with a chosen Transport and Chain.

Example

import { createPublicClient, http } from "viem";
import { zkSyncSepoliaTestnet } from "viem/chains";

// Initialize the Viem client
const client = createPublicClient({
  chain: zkSyncSepoliaTestnet, // Specify the ZKsync network
  transport: http(), // Define the transport method
});
  • To use the ZKsync Sepolia Testnet, specify zkSyncSepoliaTestnet as the chain.
  • For ZKsync Era Mainnet, replace zkSyncSepoliaTestnet with zkSync.

Reading Data

Access ZKsync data by invoking Public Actions that mirror Ethereum RPC methods.

Fetch the Latest Block Number

const blockNumber = await client.getBlockNumber();
console.log(`Current block number: ${blockNumber}`);

Writing Data

To write data, such as sending transactions, you need to set up a Wallet client.

Sending Transactions

import { createWalletClient, custom } from "viem";
import { zkSyncSepoliaTestnet } from "viem/chains";

// Request account access from the Ethereum provider
const [account] = await window.ethereum.request({ method: "eth_requestAccounts" });

// Configure the wallet client
const client = createWalletClient({
  account,
  chain: zkSyncSepoliaTestnet,
  transport: custom(window.ethereum),
});

// Example transaction
client.sendTransaction({
  /* transaction details */
});

Advanced Usage

Utilizing Paymasters

Paymasters cover transaction fees, facilitating a smoother user experience. To utilize ZKsync Era's native account abstraction and Paymasters, extend the Wallet client with eip712WalletActions:

Setup

import 'viem/window';
import { createWalletClient, custom } from 'viem';
import { zkSync } from 'viem/chains';
import { eip712WalletActions, getGeneralPaymasterInput } from 'viem/zksync';

// Initialize and extend the wallet client
const walletClient = createWalletClient({
  chain: zkSync,
  transport: custom(window.ethereum!),
}).extend(eip712WalletActions());

Sending a Transaction with a Paymaster

const paymasterAddress = "<DEPLOYED_PAYMASTER_ADDRESS>"; // Replace with your paymaster address

// Send the transaction example
const hash = await walletClient.sendTransaction({
  account: "0xA0Cf798816D4b9b9866b5330EEa46a18382f251e",
  to: "0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
  value: 1000000000000000000n,
  paymaster: paymasterAddress,
  paymasterInput: getGeneralPaymasterInput({ innerInput: new Uint8Array() }),
});
Ensure your paymaster contract is set up and funded appropriately.

For a live example, check out this StackBlitz demo. Remember to replace PAYMASTER_CONTRACT_ADDRESS with your own!

Contract Interactions with Paymasters

Contract Function Call

const paymasterAddress = "<DEPLOYED_PAYMASTER_ADDRESS>"; // Replace with actual address

// Call the contract function
const hash = await walletClient.writeContract({
  address: "0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2",
  abi: parseAbi(["function setGreeting(string _greeting) nonpayable"]),
  functionName: "setGreeting",
  args: ["ZKsync!"],
  paymaster: paymasterAddress,
  paymasterInput: getGeneralPaymasterInput({ innerInput: new Uint8Array() }),
});
Ensure your paymaster contract is set up and funded appropriately.

For a live example, check out this StackBlitz demo. Remember to replace PAYMASTER_CONTRACT_ADDRESS with your own!

Smart Contract Interactions

Interact with smart contracts by creating a Contract instance, providing ABI, address, and the client.

Example

import { getContract } from "viem";
import { yourContractAbi } from "./abi"; // Your contract's ABI
import { client } from "./client"; // Your initialized Viem client

// Initialize the contract instance
const contract = getContract({
  address: "YOUR_CONTRACT_ADDRESS", // Replace with your contract's address
  abi: yourContractAbi,
  client,
});

// Interact with your contract
const result = await contract.read.totalSupply();
console.log(`Total Supply: ${result}`);

Made with ❤️ by the ZKsync Community