Abstract RPC: A Developer's Guide (Chain ID 2741)
Abstract is an Ethereum ZK rollup built on ZKsync's ZK Stack, aimed at consumer apps: games, NFTs and social products, most of them used through the Abstract Global Wallet. It speaks Ethereum JSON-RPC, so viem and ethers connect without special setup. But the chain underneath is the ZKsync VM, not the EVM, and that shows up in gas numbers, transaction types and finality.
This guide is measured against the live chain on October 7, 2026, through the same endpoint SwiftNodes customers use.
The endpoint
https://rpc.swiftnodes.io/rpc/abstract?key=YOUR_API_KEY
wss://rpc.swiftnodes.io/ws/abstract?key=YOUR_API_KEY
import { createPublicClient, http, defineChain } from "viem";
const abstract = defineChain({
id: 2741,
name: "Abstract",
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
rpcUrls: { default: { http: ["https://rpc.swiftnodes.io/rpc/abstract?key=YOUR_API_KEY"] } },
});
const client = createPublicClient({ chain: abstract, transport: http() });
viem also ships an abstract chain definition in viem/chains, and its viem/zksync extensions add the ZKsync-specific actions; swap in the URL above as the transport.
What we measured
| Property | Value |
|---|---|
| Chain ID | 2741 (0xab5) |
| Block time | 0.58 s (0.588 s over 100,000 blocks, 0.565 s over 10,000) |
| Gas limit | 1,125,899,906,842,624 (2^50) per block |
Base fee / eth_gasPrice |
0.04525 gwei, flat |
eth_maxPriorityFeePerGas |
0 |
| Plain ETH transfer, gas used | 94,647 (sampled transaction) |
Same sender, eth_estimateGas |
200,894 |
| Fee for that transfer | ~0.0000043 ETH |
safe behind head |
~23 minutes |
finalized behind head |
~3.8 hours |
eth_getLogs |
capped at 10,000 results per call, not by block range |
| Historical state | back to block 1 (October 25, 2024) |
Gas: don't hardcode Ethereum numbers
The gas limit is 2^50, which is effectively unbounded. It tells you nothing about what a transaction can use. The real limit on ZK Stack is the batch, and zks_getFeeParams shows its parameters: 200 million gas and 700,000 bytes of pubdata per batch, and a minimum L2 gas price of 45,250,000 wei. That minimum is exactly the base fee every block reported, so on a quiet chain the fee doesn't move.
A plain ETH transfer is not 21,000 gas here. The one we sampled used 94,647, because ZKsync charges for account validation and for the state diff it publishes to Ethereum. eth_estimateGas for the same sender returned 200,894, more than twice what the transfer used. That is normal on ZK Stack: estimates include a pubdata allowance, and unused gas is refunded, so the cost is the 94,647 actually used, about 0.0000043 ETH at that gas price. Use the estimate as the limit and don't treat it as the cost.
zks_estimateFee returns the same gas limit plus gas_per_pubdata_limit, which you need when building EIP-712 (type 0x71) transactions yourself:
const fee = await client.request({
method: "zks_estimateFee" as any,
params: [{ from: sender, to: recipient, value: "0x1" }],
});
// { gas_limit, gas_per_pubdata_limit, max_fee_per_gas, max_priority_fee_per_gas }
Estimating from an address with no account behind it fails with invalid sender. can't start a transaction from a non-account. Use a real sender, not a zero or placeholder address.
Most transactions come from smart accounts
In a 100-transaction sample of recent blocks, 72 were type 0x71 (ZKsync's EIP-712 transaction), 21 were EIP-1559 type 2 and 7 were legacy. The sender of the plain transfer we measured returned bytecode from eth_getCode: it is a smart contract account, not an externally owned key. That is the Abstract Global Wallet at work. ZK Stack has native account abstraction, so any account can be a contract with its own validation logic, no ERC-4337 bundler needed.
Two practical consequences for indexers and wallets:
- Don't assume "has code" means "is a contract someone deployed as an app". On Abstract most active users have code.
- Signature checks for off-chain messages should use ERC-1271 (
isValidSignature) rather thanecrecover, or smart-account users can't sign in.
Blocks, batches and finality
Abstract produces a block about every 0.58 seconds, and blocks carry two extra fields, l1BatchNumber and l1BatchTimestamp. Blocks are grouped into L1 batches; a recent batch spanned 1,300 blocks (about 12.5 minutes), and another held 2,078 L2 transactions. zks_getL1BatchDetails shows each batch's lifecycle on Ethereum:
| Stage | Batch 92,904 (October 3, 2026) |
|---|---|
| Committed to L1 | 12:13:39 UTC |
| Proven | 12:32:43 UTC (+19 min) |
| Executed | 15:32:04 UTC (+3 h 18 min after commit) |
That gap between proof and execution is why finalized trails the head by about 3.8 hours, while safe trails by about 23 minutes. Our finality survey across 62 chains puts that in context. Show users latest for UX, and wait for finalized before crediting withdrawals or deposits that can't be reversed. More on that split in soft vs hard finality on L2s.
Logs and history
eth_getLogs here limits results, not block ranges. Every query that would return more than 10,000 logs failed with Query returned more than 10000 results. Try with this block range [...], and the error hands you a range that fits. A filter on one token contract returned 6,923 logs over 10,000 blocks (about 1.6 hours). Wider windows hit the result cap, not a range cap. On busy contracts, page by result count: start wide, and when the error comes back, retry with the suggested range. Method details are on eth_getLogs on Abstract.
Historical state reads worked at every depth we tried, down to block 1, from October 25, 2024. Tracing is partial: debug_traceTransaction and debug_traceBlockByNumber with callTracer returned full call trees (including the system-contract calls ZKsync makes on every transaction), but the trace_* namespace is not available. eth_getBlockReceipts works.
ZKsync methods
The zks_ namespace is partly available:
| Method | Result |
|---|---|
zks_L1BatchNumber, zks_getL1BatchDetails, zks_getL1BatchBlockRange |
work |
zks_getBlockDetails, zks_getFeeParams, zks_estimateFee |
work |
zks_getMainContract, zks_L1ChainId, zks_getBaseTokenL1Address |
work |
zks_getBridgecontracts |
refused (not whitelisted on Abstract's own RPC either) |
txpool_*, eth_sendRawTransactionSync |
not available |
zks_getBaseTokenL1Address returns 0x…0001, the ZK Stack marker for ETH as the base token.
WebSocket
eth_subscribe with newHeads and logs works on the WebSocket URL above, which streams Abstract's official node. At 0.58 s blocks expect close to two heads a second; a logs subscription filtered to your contracts is usually cheaper than polling eth_getLogs.
Summary
- ZK Stack rollup on Ethereum, chain ID 2741, ETH for gas, 0.58 s blocks.
- Flat 0.04525 gwei gas price; transfers use ~95k gas and estimate ~200k. Always estimate.
- Most senders are smart accounts: verify signatures with ERC-1271.
safe~23 min,finalized~3.8 h behind the head.eth_getLogscaps results at 10,000 and suggests a range; history goes back to block 1.
Abstract endpoints, live gas and method support are on our Abstract RPC page and Abstract gas tracker, alongside 127 other chains on one key. SwiftNodes has a free tier to try it.
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
- MegaETH RPC: A Developer's Guide (Chain ID 4326)
MegaETH runs 1 s EVM blocks over ~10 ms mini-blocks. Measured: a 10-billion gas limit, transfers estimating 63,349 gas, a bogus eth_feeHistory oldestBlock, ~32 min to finalized, and what works over standard RPC.
- Ronin RPC After the Move to Ethereum L2: A Developer's Guide (Chain ID 2020)
Ronin became an OP Stack layer 2 in May 2026. Measured: 2 s blocks, a fixed 20 gwei base fee, a 200-block getLogs cap, ~23 min to finalized, and no pre-migration history.
- opBNB RPC: A Developer's Guide (Chain ID 204)
opBNB is an OP Stack L2 settling to BNB Smart Chain, with 250 ms blocks. Measured finality, fees, the 50,000-block getLogs cap and a stale-finality trap.