zks_ RPC

Public ZKsync zks_* RPC methods exposed on the adapters via client.zks (Bridgehub address, Bytecode Supplier address, block metadata, L2→L1 log proofs, receipts with l2ToL1Logs).

Standard Ethereum RPC (eth_*)

Use your base library for all eth_* methods. The client.zks surface only covers ZKsync-specific RPC (zks_*). For standard Ethereum JSON-RPC (e.g., eth_call, eth_getLogs, eth_getBalance), call them through your chosen library (ethers or viem).

zks_ Interface

export interface ZksRpc {
  // Fetches the Bridgehub contract address.
  getBridgehubAddress(): Promise<Address>;
  // Fetches the Bytecode Supplier contract address.
  getBytecodeSupplierAddress(): Promise<Address>;
  // Fetches a proof for an L2→L1 log emitted in the given transaction.
  getL2ToL1LogProof(txHash: Hex, index: number): Promise<ProofNormalized>;
  // Fetches the transaction receipt, including the `l2ToL1Logs` field.
  getReceiptWithL2ToL1(txHash: Hex): Promise<ReceiptWithL2ToL1 | null>;
  // Fetches block metadata for the given block number.
  getBlockMetadataByNumber(blockNumber: number): Promise<BlockMetadata | null>;
  // Fetches the genesis configuration returned by `zks_getGenesis`.
  getGenesis(): Promise<GenesisInput>;
}

Methods

getBridgehubAddress() → Promise<Address>

Fetch the on-chain Bridgehub contract address.

const addr = await client.zks.getBridgehubAddress();

getBytecodeSupplierAddress() → Promise<Address>

Fetch the on-chain Bytecode Supplier contract address.

const addr = await client.zks.getBytecodeSupplierAddress();

getL2ToL1LogProof(txHash: Hex, index: number) → Promise<ProofNormalized>

Return a normalized proof for the L2→L1 log at index in txHash.

Parameters

NameTypeRequiredDescription
txHashHexyesL2 transaction hash that emitted one or more L2→L1 logs.
indexnumberyesZero-based index of the target L2→L1 log within the tx.
const proof = await client.zks.getL2ToL1LogProof(l2TxHash, 0);
/*
{
  id: bigint,
  batchNumber: bigint,
  proof: Hex[]
}
*/

[!INFO] If a proof isn’t available yet, this method throws a typed STATE error. Poll according to your app’s cadence.


getReceiptWithL2ToL1(txHash: Hex) → Promise<ReceiptWithL2ToL1 | null>

Fetch the transaction receipt; the returned object always includes l2ToL1Logs (empty array if none).

const rcpt = await client.zks.getReceiptWithL2ToL1(l2TxHash);
console.log("L2 to L1 logs:", rcpt?.l2ToL1Logs); // always an array

getBlockMetadataByNumber(blockNumber: number)

What it does Fetches per-block metadata used by the node (pubdata price, native price, execution version). Returns null if the block metadata is unavailable. Price fields are returned as bigint.

Example

const meta = await client.zks.getBlockMetadataByNumber(2);
if (meta) {
  console.log(meta.pubdataPricePerByte, meta.nativePrice, meta.executionVersion);
}

Returns

type BlockMetadata = {
  pubdataPricePerByte: bigint;
  nativePrice: bigint;
  executionVersion: number;
};

getGenesis()

What it does Retrieves the L2 genesis configuration exposed by the node, including initial contract deployments, storage patches, execution version, and the expected genesis root.

Example

const genesis = await client.zks.getGenesis();

for (const contract of genesis.initialContracts) {
  console.log('Contract at', contract.address, 'with bytecode', contract.bytecode);
}

console.log('Execution version:', genesis.executionVersion);
console.log('Genesis root:', genesis.genesisRoot);

Returns

export type GenesisInput = {
  initialContracts: GenesisContractDeployment[];
  additionalStorage: GenesisStorageEntry[];
  executionVersion: number;
  genesisRoot: Hex;
};

Types (overview)

export interface ZksRpc {
  // Fetches the Bridgehub contract address.
  getBridgehubAddress(): Promise<Address>;
  // Fetches the Bytecode Supplier contract address.
  getBytecodeSupplierAddress(): Promise<Address>;
  // Fetches a proof for an L2→L1 log emitted in the given transaction.
  getL2ToL1LogProof(txHash: Hex, index: number): Promise<ProofNormalized>;
  // Fetches the transaction receipt, including the `l2ToL1Logs` field.
  getReceiptWithL2ToL1(txHash: Hex): Promise<ReceiptWithL2ToL1 | null>;
  // Fetches block metadata for the given block number.
  getBlockMetadataByNumber(blockNumber: number): Promise<BlockMetadata | null>;
  // Fetches the genesis configuration returned by `zks_getGenesis`.
  getGenesis(): Promise<GenesisInput>;
}

type ProofNormalized = {
  id: bigint;
  batchNumber: bigint;
  proof: Hex[];
  root: Hex;
};

type ReceiptWithL2ToL1 = {
  transactionIndex: Hex;
  transactionHash?: Hex;
  status?: string | number;
  blockNumber?: string | number;
  logs?: Array<{
    address: Address;
    topics: Hex[];
    data: Hex;
    transactionHash: Hex;
  }>;
  // ZKsync-specific field
  l2ToL1Logs?: L2ToL1Log[];
};

type BlockMetadata = {
  pubdataPricePerByte: bigint;
  nativePrice: bigint;
  executionVersion: number;
};

export type GenesisInput = {
  initialContracts: GenesisContractDeployment[];
  additionalStorage: GenesisStorageEntry[];
  executionVersion: number;
  genesisRoot: Hex;
};

Usage

Ethers
import { JsonRpcProvider, Wallet } from 'ethers';
import { createEthersClient, createEthersSdk } from '@matterlabs/zksync-js/ethers';

const l1 = new JsonRpcProvider(process.env.L1_RPC!);
const l2 = new JsonRpcProvider(process.env.L2_RPC!);
const signer = new Wallet(process.env.PRIVATE_KEY!, l1);

const client = createEthersClient({ l1, l2, signer });
const sdk = createEthersSdk(client);

// Public RPC surface:
const addr = await client.zks.getBridgehubAddress();
Viem
import { createPublicClient, createWalletClient, http, parseEther } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { createViemClient, createViemSdk } from '@matterlabs/zksync-js/viem';
import { ETH_ADDRESS } from '@matterlabs/zksync-js/core';

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);

const l1 = createPublicClient({ transport: http(process.env.L1_RPC!) });
const l2 = createPublicClient({ transport: http(process.env.L2_RPC!) });
const l1Wallet = createWalletClient({ chain: l1Chain, account, transport: http(process.env.L1_RPC!) });
const l2Wallet = createWalletClient({ chain: l2Chain, account, transport: http(process.env.L2_RPC!) });

const client = createViemClient({ l1, l2, l1Wallet, l2Wallet });
const sdk = createViemSdk(client);

// Public RPC surface:
const addr = await client.zks.getBridgehubAddress();