zkSync Era RPC: What's Different from Ethereum

By John Sullivan · July 2, 2026 · 4 min read · #zksync #zksync era #zksync rpc #layer 2 #chain spotlight

zkSync Era is EVM-compatible, so you can point ethers or viem at it and eth_blockNumber, eth_call, and eth_getLogs just work. That lulls people into treating it like any other EVM chain — and then a contract deployment fails, a gas estimate is wildly off, or a transaction reverts for reasons that make no sense on Ethereum. zkSync is a zkEVM, not an EVM clone, and the differences show up exactly where you interact with it over RPC. Here's the map.

It's compatible, not equivalent

Ethereum L2s come in two flavors: EVM-equivalent (run standard Ethereum bytecode as-is, like the OP-stack chains) and EVM-compatible (support Solidity but compile to a different VM). zkSync Era is the latter — Solidity/Vyper compile through zksolc/zkvyper to zkSync's own bytecode. For reading state, this is invisible; for deploying and low-level work, it matters a lot.

Mainnet chain ID is 324. Standard read RPC works:

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

const client = createPublicClient({
  chain: zksync,
  transport: http("https://rpc.swiftnodes.io/rpc/zksync?key=YOUR_API_KEY"),
});
await client.getBlockNumber();   // just works

The four things that actually differ

1. Native account abstraction — every account is a smart account. On Ethereum, EOAs and contracts are different beasts. On zkSync, account abstraction is built into the protocol: accounts can carry validation logic, and transactions can be sponsored by paymasters. This introduces a zkSync-specific transaction type (EIP-712 / type 0x71) for AA and paymaster flows. Standard type-2 transactions still work for basic transfers, but if you want AA or gasless UX, you're building type-113 transactions — which the standard ethers sendTransaction won't construct for you. That's what the zksync-ethers SDK is for.

2. The zks_ RPC namespace. Alongside eth_*, zkSync exposes L2-specific methods under zks_. The ones you'll actually reach for:

Method What it gives you
zks_L1BatchNumber current L1 batch (see finality below)
zks_estimateFee accurate fee incl. pubdata (see gas below)
zks_getL2ToL1LogProof proof for L2→L1 messages (withdrawals)
zks_getAllAccountBalances all token balances for an address in one call
zks_getBridgeContracts canonical bridge addresses
zks_getBlockDetails L2 block + which L1 batch it's in

If your provider only proxies eth_* and strips zks_, half of zkSync-native development breaks. A zkSync endpoint needs to pass the zks_ namespace through.

3. The gas model includes pubdata. This is the single biggest "why is my estimate wrong" gotcha. zkSync's cost has two parts: L2 execution gas and the cost of the pubdata it posts to Ethereum L1 (gasPerPubdataByteLimit). A plain eth_estimateGas doesn't capture the pubdata dimension well, so estimates can be off — sometimes a lot. Use zks_estimateFee (or let zksync-ethers handle it) for transactions that write meaningful state:

curl -s -X POST https://rpc.swiftnodes.io/rpc/zksync?key=YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"zks_estimateFee","params":[{"from":"0x…","to":"0x…","data":"0x"}],"id":1}'

4. Deployment is not standard. You can't take EVM bytecode and eth_sendRawTransaction a deployment the Ethereum way. Contracts are deployed through a system contract (ContractDeployer), the bytecode must be zksolc-compiled, and CREATE/CREATE2 address derivation differs from Ethereum — so an address you precompute with standard CREATE2 math will be wrong. Use hardhat-zksync / zksync-ethers for deploys; don't expect a vanilla Hardhat/Foundry deploy script to work unchanged.

Blocks, batches, and finality

zkSync has two levels you'll see over RPC:

  • L2 blocks — produced by the sequencer every ~1 second. eth_blockNumber returns these. This is your fast, soft-confirmed view (see What Is a Sequencer?).
  • L1 batches — many L2 blocks are rolled into a batch that gets committed, proven, and executed on Ethereum. zks_L1BatchNumber and zks_getBlockDetails tell you which batch a block belongs to and its status.

Finality mirrors the L2 pattern: the sequencer gives you near-instant soft confirmation, but hard finality only arrives once the batch's validity proof is verified and executed on L1 — which can take hours. If you're doing anything settlement-sensitive (large withdrawals, bridging), check batch execution status via zks_, don't trust the L2 block alone. This is the same soft-vs-hard distinction we covered in Soft vs Hard Finality on L2s — and the pubdata that gets posted is part of Ethereum's blob data-availability story.

What carries over unchanged

Don't overcorrect — most of your read-side tooling is fine:

  • eth_call, eth_getBalance, eth_getLogs, eth_getTransactionReceipt, eth_blockNumber all behave normally.
  • WebSocket subscriptions (eth_subscribe) for new heads and logs work.
  • Event indexing works like any EVM chain (mind reorgs at the sequencer level — see Handling Chain Reorgs).
  • Reading contract state via ABI + eth_call is identical.

The rule of thumb: reading zkSync is standard EVM; writing and deploying to it is zkSync-specific. Reach for zksync-ethers and the zks_ methods the moment you go beyond reads.

The short version

zkSync Era gives you the familiar eth_* surface for reads, then diverges where it counts: native account abstraction (type-113 txs, paymasters), a zks_ namespace for L2 data and proofs, a two-part gas model where pubdata dominates (use zks_estimateFee), and non-standard deployment (zksolc, ContractDeployer, different CREATE2). Treat reads as normal EVM and writes as zkSync-native, and it stops surprising you.

For that you need an endpoint that passes through both eth_* and zks_* — many generic proxies drop the latter. Our zkSync RPC exposes the full namespace, flat-rate, alongside dozens of other chains under one key. Grab a free key and connect:

https://rpc.swiftnodes.io/rpc/zksync?key=YOUR_API_KEY
J
John Sullivan
Infrastructure Writer, SwiftNodes

John Sullivan covers RPC infrastructure, node operations, and multi-chain development at SwiftNodes — what it actually takes to keep endpoints fast, fresh, and reliable across EVM and non-EVM networks.

Related posts

  • Boba Network RPC: Chain ID 288 and the Hybrid-Compute Rollup

    Boba Network mainnet RPC endpoint and chain ID 288 — the EVM optimistic rollup where smart contracts can call off-chain compute and APIs. Live fee numbers, block cadence, what carries over from Ethereum, and what to verify.

  • Optimism RPC: The Chain That Became a Template

    Optimism (chain ID 10) is both a mature optimistic rollup — 2-second blocks, ETH gas, fault proofs live since 2024 — and the origin of the OP Stack, the codebase behind Base, Zora, opBNB, Unichain, and Soneium. The developer map: what the two-layer fee model means for gas estimation, why traces are uneven there, and how everything you learn on OP Mainnet carries across the family.

  • Scroll RPC: The zkEVM That Runs Ethereum Bytecode Unchanged

    Scroll is a bytecode-equivalent zkEVM rollup (chain ID 534352) — it targets opcode-level equality with Ethereum, so your existing contracts, audits, and tooling work with zero changes, while ZK validity proofs give ~1-hour hard finality instead of the 7-day optimistic window. Standard eth_* (viem/ethers/foundry). Here's the developer map, including how it differs from zkSync Era.

Try SwiftNodes free — multi-chain RPC across 75+ networks, flat-rate pricing, pay by card or crypto, no KYC. Get an API key in 30 seconds →