ZKsync Era is a cutting-edge Layer 2 scaling solution designed to bring high throughput and low-cost transactions to Ethereum while maintaining security and decentralization. One of its key features is full compatibility with the standard Ethereum JSON-RPC API, enabling developers to seamlessly port Ethereum dApps to ZKsync with minimal changes.
However, due to architectural differences between Ethereum Layer 1 and ZKsync’s optimistic rollup design, there are important distinctions you must understand when interacting with the network via RPC calls.
👉 Discover how ZKsync Era enhances Ethereum scalability and unlocks new development possibilities.
Key Differences in ZKsync Era’s JSON-RPC Implementation
While ZKsync supports most Ethereum-standard RPC methods, two notable deviations affect block data retrieval and transaction handling:
1. Block Data Retrieval Methods
Methods that return block information — such as eth_getBlockByHash, eth_getBlockByNumber, and Geth’s eth_subscribe with the newHeads parameter — do not provide actual values for receiptsRoot, transactionsRoot, and stateRoot.
Instead, these fields contain zero (0x0) values. This occurs because ZKsync’s L2 blocks do not maintain a state root; only L1 batches (aggregated L2 data published on Ethereum) include this concept.
This architectural difference reflects ZKsync’s rollup model, where final state commitments occur periodically on Layer 1 rather than per-block on Layer 2.
2. Unsupported Transaction Method
The method eth_sendTransaction is intentionally not supported in ZKsync. Unlike Ethereum, where nodes can sign and broadcast transactions directly, ZKsync requires all transactions to be pre-signed and submitted using eth_sendRawTransaction.
This ensures greater control over transaction flow and aligns with secure wallet integration patterns.
Core Ethereum JSON-RPC Methods on ZKsync Era
Below is a comprehensive overview of essential JSON-RPC methods supported by ZKsync Era, complete with parameters, return types, and example usage.
eth_chainId
Retrieves the current chain ID in hexadecimal format.
- Parameters: None
- Returns:
QUANTITY– Hexadecimal representation of the chain ID
{
"jsonrpc": "2.0",
"result": "0x144",
"id": 1
}This value helps identify the network (e.g., mainnet vs. testnet) and prevents cross-chain replay attacks.
eth_call
Executes a read-only smart contract function call without broadcasting a transaction.
Parameters:
Object: Transaction call object (to,data)BlockIdVariant(optional): Target block ("latest", "pending", etc.)
- Returns:
DATA– Contract output in hex
Useful for querying token balances, contract states, or simulating interactions before sending real transactions.
eth_estimateGas
Estimates the gas required to execute a transaction or contract interaction.
- Parameters: Same as
eth_call - Returns:
QUANTITY– Estimated gas in hex
Note: The from address cannot be a non-SmartAccount smart contract, or an exception will be thrown.
👉 Learn how gas optimization boosts performance and reduces costs on Layer 2 networks.
eth_gasPrice
Returns the current average gas price in gwei.
- Returns:
QUANTITY– Gas price in hex
This value helps dynamically set gas fees based on real-time network conditions, improving transaction inclusion speed.
Event Filtering & Log Retrieval
ZKsync supports Ethereum-style event filtering for real-time dApp updates:
eth_newFilter: Create a filter for specific contract eventseth_newBlockFilter: Monitor new block arrivalseth_newPendingTransactionFilter: Track pending transactionseth_getFilterLogs: Retrieve logs matching a filtereth_getFilterChanges: Get logs since last poll
These tools are essential for building responsive frontends and backend monitoring systems.
Account & Balance Queries
eth_getBalance
Fetches an account’s balance at a specific block.
Parameters:
address: Account addressblock: Block identifier ("latest", number, etc.)
- Returns: Balance in gwei (hex)
Ideal for tracking wallet balances or historical token holdings.
eth_getTransactionCount
Gets the number of transactions sent from an address (nonce).
Used primarily for constructing valid transactions with correct nonce values.
Block Information Methods
eth_getBlockByNumber / eth_getBlockByHash
Retrieve full block details including:
- Hash, parent hash, timestamp
- Gas used, limit, base fee
- Transaction list (hashes or full objects)
- L1 batch metadata (
l1BatchNumber,l1BatchTimestamp)
Despite zeroed-out roots, these methods offer valuable insights into block composition and timing.
eth_getBlockTransactionCountByNumber / ...ByHash
Returns the number of transactions in a block — useful for analyzing block congestion or validator activity.
Smart Contract Interaction
eth_getCode
Fetches deployed bytecode at a contract address.
- Returns
0xif the address isn’t a contract
Helpful for verifying contract existence or inspecting proxy implementations.
eth_getStorageAt
Reads raw storage value at a given position (slot) in a contract.
Used in advanced debugging, forensics, or storage layout analysis.
Transaction Lifecycle Management
eth_getTransactionByHash
Retrieve detailed transaction data:
- Sender, receiver, value
- Gas price, gas limit
- Input data, nonce
- Block confirmation status
Critical for tracking user actions and debugging failed transactions.
eth_getTransactionReceipt
Returns post-execution receipt:
- Status (
0x1= success) - Gas used, effective gas price
- Logs, contract creation address
- L2-to-L1 logs (for message bridging)
Always check the receipt to confirm transaction success and extract emitted events.
eth_sendRawTransaction
Submits a signed transaction to the mempool.
- Input: RLP-encoded signed transaction
- Returns: Transaction hash if accepted
This is the only way to send transactions on ZKsync Era.
Fee & Client Metadata
eth_feeHistory
Fetches historical base fees and rewards across recent blocks.
Enables EIP-1559-aware fee estimation strategies for better UX.
web3_clientVersion / eth_protocolVersion
Returns client software and protocol version strings (e.g., "ZKsync/v2.0").
Useful for diagnostics and compatibility checks.
Frequently Asked Questions (FAQ)
Q: Why are stateRoot and receiptsRoot always zero?
A: Because ZKsync uses a rollup architecture where state commitments are batched and posted to Ethereum Layer 1 periodically. Individual L2 blocks don’t store full state roots — only L1 batches do.
Q: Can I use MetaMask or Ethers.js with ZKsync?
A: Yes! Standard Ethereum libraries work seamlessly. Just ensure your provider points to a ZKsync RPC endpoint (like https://mainnet.era.zksync.io/) and use eth_sendRawTransaction for sending transactions.
Q: Is eth_call accurate on ZKsync?
A: Absolutely. Read operations reflect the true state of contracts on ZKsync and are fully consistent with Ethereum semantics.
Q: How do I handle nonces on ZKsync?
A: Use eth_getTransactionCount with the "latest" tag for pending nonce tracking, just like on Ethereum.
Q: What tools support ZKsync RPC?
A: Hardhat, Foundry, Ethers.js, Web3.js, The Graph, and many indexers support ZKsync through standard RPC interfaces.
Q: Are there rate limits on public RPC endpoints?
A: Public nodes may apply throttling under heavy load. For production apps, consider using dedicated RPC providers or running your own node.
👉 Explore advanced developer tools and resources to build powerful dApps on ZKsync Era.