Guide

Nonces & throughput

An EIP-8130 nonce is 2D: a channel key plus a sequence. Sequenced channels give independent ordered lanes for parallelism; the reserved nonce-free channel drops sequencing entirely and leans on expiry. Viem's nonce helper produces the right fields for each.

Three strategies

The nonce helper returns { nonceKey, nonceSequence?, expiry? } that you spread straight into sendCalls8130 or prepareTransaction8130.

nonce helperts
import { nonce, sendCalls8130 } from 'viem/experimental/eip8130'
// Standard single-file ordering (channel 0):
await sendCalls8130(client, { account, calls, gas, ...nonce.sequential() })
// A specific parallel channel (its own counter):
await sendCalls8130(client, { account, calls, gas, ...nonce.channel(1n) })
// A fresh random channel per send (fire-and-forget):
await sendCalls8130(client, { account, calls, gas, ...nonce.randomChannel() })
// Nonce-free: no counter, replay-protected by expiry alone:
await sendCalls8130(client, { account, calls, gas, ...nonce.nonceless({ expiresIn: 600 }) })

Parallel channels

Each 2D channel maintains its own sequential counter, so transactions in different channels are independent and may be mined out of order relative to one another. Use a fixed channel(key) for a stable lane, or randomChannel() for collision-free fire-and-forget sends. The next sequence is read from the node when you do not supply one.

Independent lanests
// Two independent channels can be mined in either order.
await sendCalls8130(client, { account, calls: a, gas, ...nonce.channel(1n) })
await sendCalls8130(client, { account, calls: b, gas, ...nonce.channel(2n) })
// Each channel's next sequence is read from the node automatically.

Nonce-free (expiring) mode

The reserved NONCE_KEY_MAX channel reads and increments no counter, so a transaction is not ordered against any other; replay protection comes solely from expiry. It is ideal for fully parallel, retry-safe sends. The expiry must fall within the chain's NONCE_FREE_EXPIRY_WINDOW; the mechanics and the fee-invariant replay_id are covered in 2D nonces & nonceless.

nonce.noncelessts
import { nonce, sendCalls8130 } from 'viem/experimental/eip8130'
// Not ordered against anything; valid until a near-future expiry.
const hash = await sendCalls8130(client, {
account,
calls,
gas: 250_000n,
...nonce.nonceless({ expiresIn: 600 }),
})

Reading a sequence manually

sendCalls8130 reads the next sequence for you. When you need it directly (e.g. to build and batch several sends yourself), read the per-channel counter with getTransactionCount8130 (nonce-free channels have no counter and return an error).

getTransactionCount8130ts
import { getTransactionCount8130 } from 'viem/experimental/eip8130'
const sequence = await getTransactionCount8130(client, {
address: account.address,
nonceKey: 1n, // per-channel counter
})