Ink is an OP Stack layer 2 that settles to Ethereum and uses ETH for gas, so the standard Ethereum libraries and frameworks work against an Ink node without modification. Chainstack serves Ink Mainnet on Global Nodes with archive data and both the debug_* and trace_* namespaces. See Debug and trace APIs.
Chain configuration
Add Ink as a custom network. On Chainstack, get your Ink endpoint, then in MetaMask select Add a custom network and fill in:
- Network name — Ink
- Default RPC URL — your Chainstack Ink endpoint
- Chain ID —
57073
- Currency symbol — ETH
- Block explorer URL —
https://explorer.inkonchain.com
ethers.js
Install ethers.js:
To receive new blocks as Ink produces them, connect to the WSS endpoint and subscribe:
viem
viem ships an ink chain definition in viem/chains. Its default RPC URLs are Ink’s public endpoints, so pass your Chainstack endpoint to http(). The publicActionsL2 extension from viem/op-stack adds OP Stack actions such as L1 data fee estimation.
estimateL1Fee and estimateTotalFee estimate without sending anything, but the account must hold enough ETH for the value. Replace it with your own address. See L1 data fees.
web3.py
Install web3.py:
Foundry
Install Foundry and pass your Chainstack endpoint with --rpc-url.
Read chain data with cast:
Deploy a contract with forge create. Without --broadcast, forge create only simulates the deployment.
Verify the deployed contract on the Ink Blockscout. The API does not need a key.
Hardhat
In a Hardhat 3 project that uses @nomicfoundation/hardhat-toolbox-viem, add Ink to hardhat.config.ts. Hardhat already includes the Ink Blockscout explorer for chain 57073, so hardhat verify needs no extra configuration.
configVariable reads INK_RPC_URL and INK_PRIVATE_KEY from environment variables or the Hardhat keystore, which keeps the endpoint and the key out of the config file.
Deploy with an Ignition module, for example ignition/modules/Counter.ts:
L1 data fees are charged on top of gas
Every Ink transaction pays an L1 data fee for posting its data to Ethereum, in addition to the L2 execution fee. eth_estimateGas covers only L2 execution, and the total cost of a transaction is gasUsed × effectiveGasPrice + l1Fee. Transaction receipts carry the L1 portion in the l1Fee, l1GasUsed, l1GasPrice, and l1BlobBaseFee fields.
To estimate the L1 data fee before sending, call getL1Fee on the GasPriceOracle predeploy at 0x420000000000000000000000000000000000000F, or use viem’s estimateL1Fee and estimateTotalFee, as in the viem example.
Pending transactions are never delivered
Ink is an OP Stack chain, so pending transactions stay with the sequencer. eth_subscribe("newPendingTransactions") and eth_newPendingTransactionFilter return an ID but deliver nothing, and txpool_status always reads empty. See What gives you mempool access.
Filters are node-local
A Global Node endpoint is load balanced across backends, and a filter created by eth_newFilter or eth_newBlockFilter lives on the backend that created it. A follow-up eth_getFilterChanges that lands elsewhere returns -32602 filter not found. Poll eth_getLogs over an explicit block range instead, or hold a WSS subscription, which keeps one connection to one backend for its lifetime.
Block-count limits and the proof window
Ink produces a block about every second, so a 10,000-block eth_getLogs request covers under 3 hours of chain time. eth_getProof serves the latest block only. See EVM range limits and EVM eth_getProof history limits. Last modified on October 6, 2026