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.

estimateGas8130ts
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.

First transactionts
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.

Subsequent sendts
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.

Atomic batchts
const hash = await sendCalls8130(client, {
account,
calls: [
{ to: tokenA, data: approveData },
{ to: router, data: swapData },
],
gas: 400_000n,
})

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.

Payer co-signts
const hash = await sendCalls8130(client, {
account,
calls: [{ to: recipient, data }],
gas: 250_000n,
payer: { account: sponsor },
})

Lower-level control

  • prepareTransaction8130 fills chain id, nonce sequence, and EIP-1559 fees.
  • account.signTransaction produces auth blobs and a serialized envelope for sendRawTransaction.

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.