Guide
Sending transactions
An EIP-8130 transaction is an AA_TX_TYPE (0x79) envelope. sendCalls8130 fills nonce and fees, encodes calls, signs sender_auth (and payer_auth when sponsored), serializes, and submits via eth_sendRawTransaction.
Estimate gas
Unlike legacy EVM txs, the gas budget for an 8130 transaction is node-computed and required up front. estimateGas8130 prices authentication from the shape of the auth blob (never a real signature), so you can estimate before signing. Pass a senderAuthVerifier hint (a canonical authenticator address) matching your signer.
import { parseEther } from 'viem'import { canonicalAuthenticators, estimateGas8130,} from 'viem/experimental/eip8130'
const gas = await estimateGas8130(client, { sender: account.address, // Include createChange only on the first (deploying) transaction. accountChanges: [account.createChange], // Each inner array is one atomic executeBatch phase. calls: [[{ to: recipient, value: parseEther('0.001') }]], senderAuthVerifier: canonicalAuthenticators.k1, // .p256 / .passkey})For a policy-gated actor (a session key), also pass senderActorId so the node simulates against the intended acting actor and resolves the right policy, instead of the account's self-actor.
Deploy on first use
Include account.createChange in accountChanges to deploy and run the first calls in one transaction.
import { parseEther } from 'viem'import { canonicalAuthenticators, estimateGas8130, sendCalls8130, waitForTransactionReceipt8130,} from 'viem/experimental/eip8130'
const calls = [{ to: recipient, value: parseEther('0.001') }]
const gas = await estimateGas8130(client, { sender: account.address, accountChanges: [account.createChange], calls: [calls], senderAuthVerifier: canonicalAuthenticators.k1,})
const hash = await sendCalls8130(client, { account, accountChanges: [account.createChange], // omit on later txs calls, gas: (gas * 120n) / 100n,})
const receipt = await waitForTransactionReceipt8130(client, { hash })receipt.eip8130.phaseStatuses // e.g. ['0x1']Follow-up transactions
Once deployed, drop account changes and pass calls only. The 2D nonce sequence is read automatically.
const gas = await estimateGas8130(client, { sender: account.address, calls: [[{ to: token, data: transferData }]],})
const hash = await sendCalls8130(client, { account, calls: [{ to: token, data: transferData }], gas: (gas * 120n) / 100n,})Batching calls
A flat calls array runs as one atomic phase. Nested arrays control phases explicitly. The full model is in Calls & phases.
const hash = await sendCalls8130(client, { account, calls: [ { to: tokenA, data: approveData }, { to: router, data: swapData }, ], gas: 400_000n,})Sponsored (payer) gas
A payer account co-signs and pays gas: a key you hold or an ERC-8168 service. Token payment (e.g. USDV) typically uses an early call phase; details in Gas & payers.
const hash = await sendCalls8130(client, { account, calls: [{ to: recipient, data }], gas: 250_000n, payer: { account: sponsor },})Lower-level control
prepareTransaction8130fills chain id, nonce sequence, and EIP-1559 fees.account.signTransactionproduces auth blobs and a serialized envelope forsendRawTransaction.
Metadata
Transactions may carry an opaque, signed metadata field for attribution, memos, or off-chain commitments. It is covered by the same sender signature and never affects execution. See Metadata & attribution for the field and the experimental encoding.
- Full API: Viem. Sending a Transaction