zks_ RPC

Public ZKsync zks_* RPC methods exposed on the adapters via client.zks (Bridgehub address, 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

interface ZksRpc {
  getBridgehubAddress(): Promise<Address>;
  getL2ToL1LogProof(txHash: Hex, index: number): Promise<ProofNormalized>;
  getReceiptWithL2ToL1(txHash: Hex): Promise<ReceiptWithL2ToL1 | null>;
  getGenesis(): Promise<GenesisInfo>;
}

Methods

getBridgehubAddress() → Promise<Address>

Fetch the on-chain Bridgehub contract address.

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

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(rcpt?.l2ToL1Logs); // always an array

Types (overview)

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

type ReceiptWithL2ToL1 = {
  // …standard receipt fields…
  l2ToL1Logs: unknown[];
};

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

type GenesisInput = {
  initialContracts: {
    address: Address;
    bytecode: `0x${string}`;
  }[];
  additionalStorage: {
    key: `0x${string}`;
    value: `0x${string}`;
  }[];
  executionVersion: number;
  genesisRoot: `0x${string}`;
};

Usage

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

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

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

// Public RPC surface:
const bridgehub = await client.zks.getBridgehubAddress();
Viem
import { createPublicClient, http } from 'viem';
import { createViemClient } from '@matterlabs/zksync-js/viem';

const l1 = createPublicClient({ transport: http(process.env.ETH_RPC!) });
const l2 = createPublicClient({ transport: http(process.env.ZKSYNC_RPC!) });

// Provide a WalletClient with an account for L1 operations.
const l1Wallet = /* your WalletClient w/ account */;

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

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