Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
f31beb6
feat(experimental): add EIP-8130 AA transaction support
chunter-cb Jun 9, 2026
c793f86
feat(experimental): add EIP-8130 transaction signing
chunter-cb Jun 9, 2026
0f854de
feat(experimental): add EIP-8130 CREATE2 account address derivation
chunter-cb Jun 9, 2026
b2a8ef9
feat(experimental): add EIP-8130 account configuration helpers
chunter-cb Jun 9, 2026
78c8bbd
feat(experimental): add EIP-8130 cross-chain portability helpers
chunter-cb Jun 9, 2026
4ed8ff7
feat(experimental): add toSmartAccount8130 (ERC-4337 wallet adapter)
chunter-cb Jun 9, 2026
97b1f68
feat(experimental): add ergonomic EIP-8130 DevX (account, keys, sendC…
chunter-cb Jun 9, 2026
688510c
feat(experimental): add ERC-8168 payer web service client
chunter-cb Jun 9, 2026
55ebaac
feat(experimental): wire base/eip-8130 Base Sepolia deployment addresses
chunter-cb Jun 10, 2026
2f1c8eb
feat(eip8130): ABI-encode actor-change data to match AccountConfigura…
chunter-cb Jun 10, 2026
a0a0bd7
feat(eip8130): self-bundle scripts + raw userOpHash signing in adapter
chunter-cb Jun 10, 2026
7e98879
feat(eip8130): encode validation-phase signed actor-changes signature
chunter-cb Jun 10, 2026
b28db29
chore(eip8130): update Base Sepolia deployment addresses
chunter-cb Jun 10, 2026
46d3791
fix(eip8130): include opAuth in validation-phase signature; update de…
chunter-cb Jun 10, 2026
f5f020d
chore(eip8130): consolidate manual scripts under scripts/eip8130 + ad…
chunter-cb Jun 10, 2026
58d324e
docs(eip8130): add README for the manual scripts folder
chunter-cb Jun 10, 2026
b89df37
feat(eip8130): support ERC-5792 call value on the native path
chunter-cb Jun 10, 2026
a98d11d
fix(eip8168): align implementation with ERC-8168 spec
chunter-cb Jun 11, 2026
7a88350
feat(eip8130): RPC nonce/estimate/receipt actions, policies, signers
chunter-cb Jun 24, 2026
16b5bdf
fix(eip8168): align payer client with latest ERC-8168 spec
chunter-cb Jun 24, 2026
85e5ae3
feat(eip8130): add getConfigSequence8130 action
chunter-cb Jun 25, 2026
6343bf5
fix(eip8130): correct payer hash and update canonical deployment addr…
chunter-cb Jun 25, 2026
948b869
feat(eip8130): getTransaction8130, waitForTransactionReceipt8130, typ…
chunter-cb Jun 25, 2026
728f457
test(eip8130): add P256 smart account create + follow-up tx tests (7 …
chunter-cb Jun 25, 2026
1d01cf4
feat(eip8130): extend estimateGas8130 to support full tx body
chunter-cb Jun 26, 2026
fe39316
feat(eip8130): pass senderAuthScheme hint in full-body estimateGas
chunter-cb Jun 26, 2026
9f4567b
feat(eip8130): DX improvements — newSmartAccount8130, toEoa8130Accoun…
chunter-cb Jun 26, 2026
69cf58a
fix(eip8130): to8130Account supports address-only mode for delegated …
chunter-cb Jun 26, 2026
3852a47
feat(eip8130): give toEoa8130Account the full interface — delegate + …
chunter-cb Jun 26, 2026
d6fd5f0
feat(eip8130): add recoverSenderAddress8130 helper
chunter-cb Jun 26, 2026
eef1c7a
fix(eip8130): correct canonical vibenet erc4337 + upgradeable addresses
chunter-cb Jun 26, 2026
0e20d5a
feat(eip8130): estimateGas8130 speaks raw sender/payer auth blobs
chunter-cb Jul 7, 2026
43950d1
feat(eip8130): default to UpgradeableAccount + repin AA tx type
chunter-cb Jul 8, 2026
c7a9089
docs(eip8130): add EIP-8130 developer guide
chunter-cb Jul 8, 2026
7a03931
fix(eip8130): repin core AA tx type references to 0x79
chunter-cb Jul 8, 2026
5ca53b4
fix(eip8130): correct trusted-executor sentinel + add key.trustedExec…
chunter-cb Jul 8, 2026
41c93f2
feat(eip8130): add DefaultAccount + BackwardsCompatible4337Account to…
chunter-cb Jul 8, 2026
97f77b0
docs(eip8130): 4337 account is now deployed by canonical Deploy.s.sol
chunter-cb Jul 8, 2026
9700e74
feat(eip8130): accept senderActorId hint on estimateGas8130
chunter-cb Jul 9, 2026
ba81c6f
fix(eip8130): serialize config changes for estimateGas RPC shape
chunter-cb Jul 9, 2026
4553aad
onchain
chunter-cb Jul 10, 2026
1a7d69e
clean up
chunter-cb Jul 16, 2026
46956e4
fix(eip8130): send scope + policyData for create initialActors in est…
chunter-cb Jul 16, 2026
9056b06
feat(eip8130): add toDelegate8130Signer for sub-account delegate signing
chunter-cb Jul 16, 2026
319a1ad
fix(eip8130): encode account_changes entry as a single flat RLP list
chunter-cb Jul 16, 2026
2720b54
feat(eip8130): port example policies to base/eip-8130 #43
chunter-cb Jul 17, 2026
13b8594
feat(eip8168): carry accountChanges through sendSponsoredCalls
chunter-cb Jul 17, 2026
0560c20
feat(eip8130): scope-driven nonce mode (nonce-free for admin / non-SC…
chunter-cb Jul 18, 2026
74a9df9
feat(eip8168): carry accountChanges through sendSponsoredCalls
chunter-cb Jul 17, 2026
820de38
feat(eip8130): scope-driven nonce mode (nonce-free for admin / non-SC…
chunter-cb Jul 18, 2026
2b72375
feat(eip8130): derive nonce mode from on-chain actor scope at prepare
chunter-cb Jul 18, 2026
ea5d3a3
feat(eip8130): map data suffixes to transaction metadata
chunter-cb Jul 20, 2026
48620a3
feat(eip8168): describe flexible token payment offers
chunter-cb Jul 20, 2026
bae82d7
feat(eip8130): update canonical deployment addresses
chunter-cb Jul 20, 2026
b80b6c1
Merge branch 'feat/eip-8130-policy-v43' into feat/eip-8130
chunter-cb Jul 20, 2026
e31b1f7
fix(eip8130): drop duplicate NonceScopeError export after merge
chunter-cb Jul 20, 2026
ca4c291
feat(eip8130): fail wait on expired transactions
chunter-cb Jul 20, 2026
467aeee
fix(eip8130): admin actors may use ordered nonces, not just nonce-free
chunter-cb Jul 21, 2026
9e83a17
feat(eip8130): parity with finalized Keystore contracts
chunter-cb Aug 10, 2026
934ab72
fix(eip8130): align actor IDs + reads with finalized Keystore
chunter-cb Aug 11, 2026
6a8f695
refactor(eip8130): graduate eip8130 + eip8168 out of experimental
chunter-cb Aug 11, 2026
dc81022
docs(eip8130): correctness pass on demos + guides post-graduation
chunter-cb Aug 11, 2026
4466f3e
feat(eip8168): discover and aggregate multiple payer sources
chunter-cb Aug 11, 2026
100aeb6
feat(eip8130): finalize newSmartAccount API, canonical addresses, and…
chunter-cb Aug 11, 2026
bdcdf0f
chore(eip8130): sync canonical addresses with base/eip-8130#79
chunter-cb Aug 11, 2026
be2bdf9
feat(eip8130): add incrementLocalEpoch change builder
chunter-cb Aug 11, 2026
fc485a7
docs(eip8130): pass config sequence as bigint, not Number()
chunter-cb Aug 11, 2026
0dcaaa9
feat(eip8130): add ERC-7715 → SessionPolicy adapter (toSessionPolicy)
chunter-cb Aug 11, 2026
94e1fb0
feat(eip8130): fulfillGrantPermissions — session + external-pull roles
chunter-cb Aug 11, 2026
c0f9e49
feat(eip8130): auto-register manager in fulfillGrantPermissions
chunter-cb Aug 11, 2026
566687c
feat(eip8130): fulfillAddSubAccount — ERC-7895 → delegate-linked sub-…
chunter-cb Aug 12, 2026
3d54e17
feat(eip8130): EIP-5792 capabilities advertisement + scoped sub-accou…
chunter-cb Aug 12, 2026
df44fa5
feat(eip8130): permissionsContext routing (sendCalls-level grant rede…
chunter-cb Aug 12, 2026
338286d
feat(eip8130): repin SessionPolicy address + document native-ETH fail…
chunter-cb Aug 12, 2026
fb5162e
Merge remote-tracking branch 'upstream/main' into feat/eip-8130-produ…
chunter-cb Aug 13, 2026
3d72534
chore: drop stray unrelated docs/test wording edits (tempo, circle-usdc)
chunter-cb Aug 13, 2026
24aa695
chore(eip8130): drop manual network-gated script harnesses from PR
chunter-cb Aug 13, 2026
25847b8
feat(eip8130): default keystore on getConfigSequence + unsequenced lo…
chunter-cb Aug 24, 2026
4282bb2
refactor(eip8130): single, unchangeable keystore (drop config-address…
chunter-cb Aug 24, 2026
21cd31e
chore(eip8130): update canonical deployment addresses
chunter-cb Aug 26, 2026
ebedf5c
docs(eip8130): correct per-chain framing; clarify keystore vs policy …
chunter-cb Aug 26, 2026
dc9785c
refactor(eip8130)!: sendCalls -> sendTransaction, prepareTransaction …
chunter-cb Aug 26, 2026
68f6db6
feat(eip8168): payment as a capability of the fill (prepareTransactio…
chunter-cb Aug 26, 2026
c8b2127
feat(eip8168): add sendTransactionSync for the sponsored path
chunter-cb Aug 26, 2026
4ceb45c
feat(eip8130,eip8168): add namespaced client decorators
chunter-cb Aug 26, 2026
0768b7c
feat(eip8130): add eip8130ChainConfig to fold receipts into core
chunter-cb Aug 27, 2026
4f4ee78
refactor(eip8130): drop getTransactionReceipt from the decorator
chunter-cb Aug 27, 2026
f4e2ab6
feat(eip8130): fold native AA sends into core client.sendTransaction
chunter-cb Aug 27, 2026
cddb35b
feat(eip8130): estimate gas in the send fold + guard sponsored sends
chunter-cb Aug 27, 2026
711e728
feat(eip8168): estimate gas ourselves by default, payer as opt-in oracle
chunter-cb Aug 27, 2026
413df23
test(eip8130): assert non-null call data when decoding routed calls
chunter-cb Aug 27, 2026
c7856db
docs(eip8130): fix stale estimateGas hint name (senderAuthVerifier ->…
chunter-cb Aug 27, 2026
add52b3
refactor(eip8130): rename Account Configuration references to Keystore
chunter-cb Aug 27, 2026
7a07a58
docs(eip8130): showcase native core actions, decorators, and capabili…
chunter-cb Aug 27, 2026
fdd2a0a
feat(eip8130): make nonce-free validBefore time source configurable
chunter-cb Aug 27, 2026
0964604
fix(eip8130): accept flat calls in estimateGas, matching sendTransaction
chunter-cb Aug 27, 2026
7992598
Merge upstream main into feat/eip-8130-production
jxom Aug 27, 2026
47710b6
feat(eip8130): message-signing envelope, dataSuffix→metadata, contrac…
chunter-cb Sep 2, 2026
ad18b24
feat(eip8130): register drive-only contracts as k1 operators
chunter-cb Sep 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
"src": {
"entry": [
"index.ts!",
"{account-abstraction,accounts,actions,celo,chains,ens,experimental,experimental/erc7739,experimental/erc7821,experimental/erc7811,experimental/erc7846,experimental/erc7895,linea,node,nonce,op-stack,siwe,tempo,tempo/actions,tempo/chains,tokens,utils,window,zksync}/index.ts!",
"{account-abstraction,accounts,actions,celo,chains,ens,eip8130,eip8168,experimental,experimental/erc7739,experimental/erc7821,experimental/erc7811,experimental/erc7846,experimental/erc7895,linea,node,nonce,op-stack,siwe,tempo,tempo/actions,tempo/chains,tokens,utils,window,zksync}/index.ts!",
"chains/utils.ts!"
],
"ignore": [
Expand Down
166 changes: 166 additions & 0 deletions site/pages/eip8130.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
---
description: Getting started with EIP-8130 native account abstraction in Viem
---

# EIP-8130 (Native Account Abstraction) [Overview]

[EIP-8130](https://github.com/base/eip-8130) is a native account-abstraction transaction type (`AA_TX_TYPE`, `0x79`). Every account is a smart account governed by an onchain **Keystore** contract, and transactions are sent directly to the chain — no bundler, no EntryPoint. Viem exposes the full flow through the `viem/eip8130` entrypoint.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Remove em dashes from the new documentation

This page and the newly added EIP-8130 guides contain many em dashes, starting here, despite the site documentation convention explicitly prohibiting them; rewrite these occurrences using commas, colons, parentheses, or separate sentences.

AGENTS.md reference: AGENTS.md:L17-L18

Useful? React with 👍 / 👎.


:::warning[Warning]
EIP-8130 is not yet enabled on mainnet and is currently in audit. Do not rely on it in production yet.
:::

## What you get

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Convert documentation headings to Title Case

This heading and many other newly added headings use sentence case rather than the required Title Case, so they should be updated consistently across the EIP-8130 documentation.

AGENTS.md reference: AGENTS.md:L22-L26

Useful? React with 👍 / 👎.


**Auth**
- **Multiple key types** — sign for the account with secp256k1, P-256, or WebAuthn passkeys, and **rotate keys** at any time.
- **Sub-accounts** — many accounts per owner, linked via delegate actors.
- **Session keys & scoped permissions** — policy-gated actors (spend limits, target/selector allowlists).
- **Account recovery & multisig** — available today (recover via actor sets, require multiple actors to authorize).

**Gas abstraction**
- **Sponsorship** and **ERC-20 gas payment**.

**Account**
- **Backwards compatible** with existing ERC-4337 accounts — every account works.
- **Portable** — one account for everything: an EOA, an existing smart account, or a new one — the same on **any EVM chain**.

**Execution**
- **Guaranteed atomic batching**.
- **Call phases** — sequentially-committed atomic call groups.
- **Expiring transactions**.
- **High-throughput accounts** — 100s of tps.

## Mental model

| Concept | Meaning |
| --- | --- |
| **Account** | Smart account at a CREATE2 address derived from `userSalt`, wallet `code`, and `initialActors`. |
| **Actor** | A key authorized on the account (`{ actorId, authenticator }`), built via the [`key`](/eip8130/rotating-owners#actors-and-keys) helpers. |
| **Authenticator** | A contract that validates an auth blob and returns the `actorId` it authenticates (`bytes32(0)` if invalid). Secp256k1 is built in (`address(1)`); P-256, WebAuthn, and delegate authenticators are contracts. |
| **Account change** | A `create`, `config` (actor changes), or `delegation` operation applied atomically within a transaction. |
| **Auth blob** | `sender_auth` / `payer_auth` bytes: a bare 65-byte signature for the implicit EOA path, or `authenticator(20) || data` for a configured actor. |

Every authenticator implements a single view function — given a hash and the auth `data`, it returns the actor it proves (or `bytes32(0)`):

```solidity
interface IAuthenticator {
function authenticate(bytes32 hash, bytes data) external view returns (bytes32 actorId);
}
```

## Installation

The helpers live under the dedicated entrypoint:

```ts
import {
newSmartAccount,
sendTransaction,
estimateGas,
} from 'viem/eip8130'
```

## Setup

There are three ways to use EIP-8130, from most native to most explicit. They interoperate: pick per call site.

### 1. Native Core Actions (`eip8130ChainConfig`)

Spread [`eip8130ChainConfig`](/eip8130/sending-a-transaction#native-core-actions) into your chain and EIP-8130 flows through the standard viem actions you already know. Core `client.sendTransaction` submits a native `AA_TX_TYPE` for an EIP-8130 account (gas is estimated for you), and core `client.getTransactionReceipt` / `client.waitForTransactionReceipt` return the `eip8130` receipt fields.

```ts
import { createClient, http, defineChain } from 'viem'
import { eip8130ChainConfig, register8130Chains } from 'viem/eip8130'

export const vibenet = defineChain({
...eip8130ChainConfig,
id: 84_538_453,
name: 'Vibenet Devnet',
nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
rpcUrls: { default: { http: ['http://127.0.0.1:8545'] } },
})

export const client = createClient({ chain: vibenet, transport: http() })

// Mark the chain as EIP-8130 enabled (empty by default).
register8130Chains(vibenet.id)
```

### 2. Namespaced Client Decorators

`.extend(eip8130Actions())` adds the full read/write suite under `client.eip8130.*`, and `.extend(eip8168Actions())` adds the [payer service](/eip8130/payer-services) flow under `client.payer.*`. These are namespaced (rather than folded into core) because viem's protected actions like `sendTransaction` require core-conforming signatures.

```ts
import { createClient, http } from 'viem'
import { eip8130Actions } from 'viem/eip8130'
import { eip8168Actions, createPayerClient } from 'viem/eip8168'
import { vibenet } from './viem.config'

const payerClient = createPayerClient({ url: 'https://payer.example.com/v1' })

export const client = createClient({ chain: vibenet, transport: http() })
.extend(eip8130Actions()) // client.eip8130.*
.extend(eip8168Actions({ payerClient })) // client.payer.*

const hash = await client.eip8130.sendTransaction({ account, calls, gas: 200_000n })
```

### 3. Standalone Actions

Every action is also importable directly and takes a `Client` as its first argument. Handy when you don't want to extend the client.

```ts
import { createClient, http } from 'viem'
import { sendTransaction } from 'viem/eip8130'
import { vibenet } from './viem.config'

const client = createClient({ chain: vibenet, transport: http() })
const hash = await sendTransaction(client, { account, calls, gas: 200_000n })
```

## Deployment addresses

Every protocol contract is deployed through a deterministic CREATE2 factory with a per-contract mined salt, so each address is a pure function of its bytecode — **identical on every chain**. The `viem/eip8130` actions already default to this canonical set, so you normally don't pass any addresses at all.

The keystore itself is enshrined in the execution client and is not configurable: it lives at the fixed `keystoreAddress` constant, so it is not part of the per-chain deployment record. The rest of the addresses fall back to `canonicalEip8130Deployment`, and can be overridden only if a chain ever pins a different set:

```ts
import { keystoreAddress, getEip8130Deployment, canonicalEip8130Deployment } from 'viem/eip8130'

keystoreAddress // Keystore — factory + actor-config registry (enshrined, fixed)

const deployment =
getEip8130Deployment(chainId) ?? // per-chain override, if one is ever registered
canonicalEip8130Deployment // canonical default (every chain today)

deployment.accounts.default // DefaultAccount — EIP-7702 delegate / proxy impl
deployment.accounts.defaultHighRate // CanonicalHighRatePayerAccount — immutable (ERC-1167)
deployment.authenticators.p256 // P-256 (webAuthn, delegate, k1, alwaysValid alongside)
```

The canonical set is **`DefaultAccount`** (the bare building block and the direct EIP-7702 delegation target for EOAs) and **`CanonicalHighRatePayerAccount`** (immutable, behind a 45-byte ERC-1167 proxy). **`CoinbaseSmartWalletV2`** (the upgradeable implementation, behind an ERC-1967 [`UpgradeableProxy`](https://github.com/base/smart-wallet-v2/blob/master/src/proxy/UpgradeableProxy.sol); 7702 EOAs delegate via [`EIP7702ProxyForEIP8130`](https://github.com/base/smart-wallet-v2/blob/master/src/proxy/EIP7702ProxyForEIP8130.sol)) and **`BackwardsCompatible4337Account`** (the ERC-4337 portable implementation for non-native chains) are supplied explicitly if you choose those paths.

### Policies are app-level, not protocol

Policy contracts are **not** part of the EIP-8130 protocol. A policy-gated actor is simply gated to a `manager` address that forwards committed call plans — and both the manager and the policies it enforces are **extensible**: add a new policy under the same manager, or deploy a whole new manager. Base ships one **audited** `PolicyManager` and one `SessionPolicy` in use today:

```ts
deployment.policies?.manager // PolicyManager (audited)
deployment.policies?.sessionPolicy // SessionPolicy — the policy in use today
```

To use your own, point `authorizeActor`'s `policy.manager` at your contract — see [Session Keys](/eip8130/session-keys).

## Guides

- [Creating an Account](/eip8130/creating-an-account) — K1, P-256, and passkey accounts.
- [Sending a Transaction](/eip8130/sending-a-transaction) — estimate, deploy-on-first-use, sponsor gas, batch calls.
- [Calls & Batching](/eip8130/calls-and-batching) — atomic phases and value-bearing calls.
- [Receipts](/eip8130/receipts) — per-phase statuses, payer, and metadata.
- [Metadata](/eip8130/metadata) — attach opaque, authenticated application data.
- [Rotating Owners](/eip8130/rotating-owners) — authorize and revoke actors.
- [Session Keys](/eip8130/session-keys) — policy-gated, scoped signing keys.
- [Sub Accounts](/eip8130/sub-accounts) — many accounts per owner, linked via delegate actors.
- [Sponsoring Transactions](/eip8130/sponsoring-transactions) — pay another account's gas with a co-signing payer.
- [Payer Services (ERC-8168)](/eip8130/payer-services) — negotiate sponsorship / token payment with a web service.
99 changes: 99 additions & 0 deletions site/pages/eip8130/calls-and-batching.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
---
description: Group EIP-8130 calls into atomic phases and control how value-bearing calls execute
---

# Calls & Batching

Every EIP-8130 transaction carries a list of **calls** grouped into ordered **phases**. A phase is an atomic batch: if any call in a phase reverts, that phase's state changes are discarded and every later phase is skipped — but completed phases persist, and the transaction is still included (nonce consumed, fee paid). This phased model is what powers deploy-on-first-use, sponsor-then-act, and multi-step flows.

## The `AaCalls` shape

`calls` is a nested array — an array of phases, each an array of `AaCall`:

```ts
import { type AaCalls, parseEther } from 'viem/eip8130'

const calls: AaCalls = [
// phase 0 — runs first, atomically
[{ to: tokenA, data: approveData }],
// phase 1 — runs only if phase 0 succeeded
[
{ to: router, data: swapData },
{ to: recipient, value: parseEther('0.01') },
],
]
```

Each `AaCall` is `{ to, data?, value? }`:

- `to` — target address.
- `data` — calldata (defaults to `'0x'`).
- `value` — wei to send (defaults to `0n`). This is an ERC-5792-style *intent*; it is realized by the account's wallet bytecode and never travels on the EIP-8130 wire.

## Flat vs. phased

`sendTransaction` accepts either shape. A **flat** array is sugar for a single phase; pass a **nested** array to control phases explicitly:

```ts
import { sendTransaction } from 'viem/eip8130'

// One atomic phase (flat):
await sendTransaction(client, {
account,
calls: [{ to: a, data }, { to: b, data }],
gas: 300_000n,
})

// Two phases (nested):
await sendTransaction(client, {
account,
calls: [[{ to: a, data }], [{ to: b, data }]],
gas: 300_000n,
})
```

`estimateGas` and `prepareTransactionRequest` always take the **phased** form (`AaCalls`).

## How value-bearing calls execute

A phase with no `value` passes each call straight to the wire as `[to, data]`. As soon as a phase contains any value-bearing call, the whole phase is collapsed into a single wallet-routed call — by default a self-call to the account's `executeBatch(Call[])`, which performs each value-bearing `CALL` while preserving the phase's atomicity. `encodeWalletCalls` implements this normalization:

```ts
import { encodeWalletCalls, parseEther } from 'viem/eip8130'

const wire = encodeWalletCalls({
account: account.address,
calls: [[{ to: recipient, value: parseEther('1'), data: '0x' }]],
})
// -> [[{ to: account.address, data: executeBatch([...]) }]]
```

## Custom executors

Wallets whose bytecode does not expose `executeBatch` must supply their own `encodeExecute` — a function mapping a phase's normalized calls to a single wallet call. Pass it to `sendTransaction` (or `encodeWalletCalls`):

```ts
import { type EncodeExecute, sendTransaction } from 'viem/eip8130'
import { encodeFunctionData } from 'viem'

const encodeExecute: EncodeExecute = ({ account, calls }) => ({
to: account,
data: encodeFunctionData({
abi: myWalletAbi,
functionName: 'execute',
args: [calls],
}),
})

await sendTransaction(client, { account, calls, gas: 300_000n, encodeExecute })
```

## Choosing phases

- **Single atomic batch** → one phase. Everything succeeds together or nothing does.
- **Ordered, independently-committing steps** → multiple phases. Use this for pay-then-act (a [sponsored](/eip8130/sponsoring-transactions) phase-0 token transfer followed by the user's calls), or any flow where an early step must persist even if a later one reverts.

## Next

- Inspect per-phase outcomes on the [receipt](/eip8130/receipts).
- Attach application data with [metadata](/eip8130/metadata).
Loading