Hemi RPC: A Developer's Guide (Chain ID 43111)
Hemi is an OP Stack chain with one unusual feature: its EVM can read Bitcoin. Every Hemi node runs a Bitcoin indexer alongside the execution client, and contracts query it through precompiles to check a Bitcoin address's balance, look up a transaction or read the latest block header. Hemi calls this the hVM. Everything else is an OP Stack chain that pays gas in ETH and posts its data to Ethereum, so standard Ethereum tooling works unchanged.
This guide is measured against the live chain on October 9, 2026, through the same endpoint SwiftNodes customers use.
The endpoint
https://rpc.swiftnodes.io/rpc/hemi?key=YOUR_API_KEY
wss://rpc.swiftnodes.io/ws/hemi?key=YOUR_API_KEY
With viem, define the chain once:
import { createPublicClient, defineChain, http } from "viem";
const hemi = defineChain({
id: 43111,
name: "Hemi",
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
rpcUrls: { default: { http: ["https://rpc.swiftnodes.io/rpc/hemi?key=YOUR_API_KEY"] } },
});
const client = createPublicClient({ chain: hemi, transport: http() });
What we measured
| Property | Value |
|---|---|
| Chain ID | 43111 (0xa867) |
| Client | Hemi's fork of op-geth |
| Block time | 12.0 s, every block (10,000- and 100,000-block averages, and every gap in a 60-block sample) |
| Gas limit | 30,000,000 per block |
| Base fee | 252 wei |
eth_maxPriorityFeePerGas |
1,000,000 wei (0.001 gwei) |
eth_gasPrice |
1,000,252 wei |
| ETH transfer | 21,000 gas |
| Cost of that transfer | ~0.00000018 ETH, 88% of it L1 data fee |
safe behind head |
4 blocks, ~1 minute |
finalized behind head |
100 blocks, ~20 minutes |
| Historical state | full archive |
| Tracing | debug_* yes, trace_* no |
Fees: the L1 data fee is most of the bill
Blocks are mostly empty (gasUsedRatio around 0.2% in eth_feeHistory), so the base fee sits at its floor of 252 wei. eth_gasPrice returns 1,000,252 wei because the node suggests a 0.001 gwei tip on top. The tip isn't needed for inclusion: the 50th-percentile reward in eth_feeHistory was 0.
The execution part of a transfer is tiny: 21,000 × 1,000,252 wei ≈ 0.000000021 ETH. The bigger part is the L1 data fee, which pays for posting your transaction's bytes to Ethereum. A real transfer receipt from October 9 showed l1Fee of 157,616,284,800 wei, about 0.000000158 ETH, or 88% of the total.
Hemi's fee oracle at 0x420000000000000000000000000000000000000F reports baseFeeScalar 1,000,000 and blobBaseFeeScalar 0, so the L1 fee is priced entirely off Ethereum's execution base fee, not its blob fee. When Ethereum gas rises, Hemi transfers get more expensive even if Hemi itself is idle. Estimate it before sending:
const l1Fee = await client.readContract({
address: "0x420000000000000000000000000000000000000F",
abi: [{ name: "getL1Fee", type: "function", stateMutability: "view",
inputs: [{ type: "bytes" }], outputs: [{ type: "uint256" }] }],
functionName: "getL1Fee",
args: [serializedTx],
});
Receipts carry the actual charge in l1Fee, l1GasUsed and l1GasPrice, like other OP Stack chains. Wallets that show only gasUsed × effectiveGasPrice will understate the cost by about eight times.
Reading Bitcoin from a contract
The hVM precompiles sit at 0x40 through 0x46. Hemi's docs list them as:
| Address | Name | Returns |
|---|---|---|
0x40 |
BtcBalAddr | balance of a Bitcoin address, in satoshis |
0x41 |
BtcUtxosAddrList | unspent outputs of an address |
0x42 |
BtcTxByTxid | parts of a transaction, selected by bit flags |
0x43 |
BtcTxConfirmations | confirmation count of a transaction |
0x44 |
BtcLastHeader | latest Bitcoin header known to Hemi |
0x45 |
BtcHeaderN | header at a given height |
0x46 |
BtcAddrToScript | output script for an address |
They are precompiles, not contracts, so eth_getCode returns 0x for all of them. You call them with raw input bytes, not an ABI-encoded function call. Two worked through our endpoint:
// Latest Bitcoin header known to Hemi: no input.
const last = await client.call({ to: "0x0000000000000000000000000000000000000044", data: "0x" });
// Balance of a Bitcoin address: the address as UTF-8 bytes.
import { toHex } from "viem";
const bal = await client.call({
to: "0x0000000000000000000000000000000000000040",
data: toHex("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"),
});
0x44 returned 116 bytes: a 4-byte block height, the 32-byte block hash, then the 80-byte header (version, previous hash, merkle root, time, bits, nonce) in big-endian order. At the time it reported height 970,591, two blocks behind the tip on mempool.space, so allow for a short lag between Bitcoin and what contracts see.
0x40 returned an 8-byte integer for Bitcoin's genesis address: 5,758,290,105 satoshis, exactly what mempool.space showed for the same address.
The Bitcoin data reaches Hemi through its own system transactions. Alongside the usual OP Stack deposit transaction (type 0x7e) in every block, we saw type 0x7c transactions from 0x8888…8888 to itself, about four an hour, with a Bitcoin block hash in their input. A second system type, 0x7d, came from the same sender to a contract about twelve times an hour. If your indexer decodes transactions by type, handle these rather than failing on them.
Blocks and logs
Blocks arrive every 12 seconds exactly, whether or not there is anything to put in them, so block counts are a usable clock: 300 blocks is an hour. In our 158-block receipt sample, 67 of 236 transactions were user transactions. In our halt survey across 110 chains, Hemi had no gap of 10 minutes or more between August 25 and October 6.
Logs are dense for the activity level: a few busy contracts emit several events per transaction. Unfiltered eth_getLogs over 1,000 blocks returned 2,411 logs (1.7 MB) in 3.5 seconds. 5,000 blocks returned 18,789 logs (13.6 MB) in 14.2 seconds, and 10,000 blocks returned 51,446 logs (37 MB) in 34.6 seconds. At 50,000 blocks the upstream nodes ran past our time budget and the endpoint answered:
-32005 query timed out upstream; narrow the block range or add an address filter
Page unfiltered scans at 1,000 to 2,000 blocks and filter by contract wherever you can. More on eth_getLogs on Hemi, and how other chains compare in our getLogs range cap survey.
History and tracing
State reads work at any depth: eth_getBalance at block 1 and eth_getCode on the fee oracle at block 1,000 both returned data. debug_traceBlockByNumber with the callTracer returned full traces, and eth_getBlockReceipts works. trace_block is not available.
Finality: Ethereum's, then Bitcoin's
safe trailed the head by 4 blocks (about a minute) and finalized by 100 blocks (about 20 minutes). These tags have the usual OP Stack meaning: finalized means the block's data is in a finalized Ethereum block.
Hemi adds a second, slower guarantee through Proof-of-Proof: miners publish Hemi's state to Bitcoin, and Hemi's docs describe blocks as Bitcoin-final about nine Bitcoin blocks (roughly 90 minutes) after that publication. The RPC block tags don't expose this. If you need Bitcoin-level finality, for example before releasing funds on a bridge, use Hemi's own tooling for it rather than finalized. For the general picture, see soft vs hard finality on L2s.
Summary
- OP Stack chain, chain ID 43111, ETH for gas, 12-second blocks.
- Base fee 252 wei; a transfer costs about 0.00000018 ETH, 88% of it the L1 data fee priced off Ethereum's base fee.
- Contracts read Bitcoin through precompiles
0x40to0x46, called with raw bytes; Hemi's view ran two blocks behind Bitcoin's tip. - Expect system transaction types
0x7cand0x7dalongside0x7e. - Unfiltered
eth_getLogsgets heavy fast: page at 1,000 to 2,000 blocks or filter by address. - Full archive and
debug_*tracing;finalized~20 min (Ethereum), Bitcoin finality is separate.
Hemi endpoints, live gas and method support are on our Hemi RPC page and Hemi gas tracker, alongside the rest of the 128 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
- 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.
- Katana RPC: A Developer's Guide to the DeFi-First L2
Katana (chain ID 747474) is an OP Stack L2 with ZK proofs and 1-second blocks. Measured finality, fees, getLogs limits, archive access and code.