Guide

Multichain

An EIP-8130 account has one deterministic address on every chain. Where the chain supports EIP-8130 natively you transact directly; elsewhere the same address is driven through ERC-4337. Actor changes can be signed once and replayed everywhere.

Same address everywhere

The address is a deterministic function of the wallet code, salt, and initial actors, so it is identical across chains. Tell Viem which chains run EIP-8130 natively with register8130Chains; the account actions then pick the native path where available and fall back to ERC-4337 elsewhere.

Register native chainsts
import { defineChain } from 'viem'
import { is8130Enabled, register8130Chains } from 'viem/experimental/eip8130'
export const vibenet = defineChain({
id: 84_538_453,
name: 'Vibenet Devnet',
nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
rpcUrls: { default: { http: ['https://rpc.vibes.base.org'] } },
})
// Mark chains where EIP-8130 is native (Vibenet today).
register8130Chains(vibenet.id)
is8130Enabled(client.chain.id) // → true on a native chain

Portable to non-8130 chains

On a chain without native EIP-8130, wrap the account as a Viem ERC-4337 Smart Account with toSmartAccount8130. Same address, same owner, driven through a bundler and EntryPoint. The full setup (initial actors, factory data) lives in Creating accounts.

ERC-4337 fallbackts
import { toSmartAccount8130 } from 'viem/experimental/eip8130'
// On a non-8130 chain, drive the SAME address via ERC-4337 (bundler + EntryPoint).
const smartAccount = await toSmartAccount8130({
client, // pointed at the non-8130 chain
owner, // the controlling signer
address, // the account's canonical address
})

Replayable actor changes

A config change signed against chainId 0 is valid on any chain, so you can rotate keys once and land the change everywhere. It is ordered by a separate multichain sequence (distinct from the per-chain local one).

Sign a portable changets
import {
actorScope,
authorizeActor,
getConfigSequence8130,
getEip8130Deployment,
key,
} from 'viem/experimental/eip8130'
const { accountConfiguration } = getEip8130Deployment(client.chain.id)!
const { multichain: sequence } = await getConfigSequence8130(client, {
accountConfiguration,
account: account.address,
})
// chainId 0 => the signed change is valid on ANY chain.
const portableChange = await account.change(
[authorizeActor(key.p256({ x, y }), { scope: actorScope.sender })],
{ chainId: 0, sequence: Number(sequence) },
)

Land it by including portableChange in a transaction's accountChanges on an 8130 chain, or apply it as a plain EVM call on any chain with encodeApplySignedActorChangesData:

Apply anywherets
import { encodeApplySignedActorChangesData } from 'viem/experimental/eip8130'
// Apply the same signed change on any chain as a plain EVM call.
const data = encodeApplySignedActorChangesData({
account: account.address,
chainId: 0,
actorChanges: portableChange.actorChanges,
auth: portableChange.auth,
})