Guide

Creating accounts

newSmartAccount turns a signer into a counterfactual EIP-8130 smart account. The account is not deployed yet; deployment happens atomically inside its first transaction.

Default smart account

By default (proxy: 'upgradeable') the account is an UpgradeableAccount (CoinbaseSmartWalletV2) behind an ERC-1967 proxy, swappable later via an admin-signed upgrade. That implementation is pending deployment against the canonical Keystore, so until it lands you must pass an explicit implementation or choose proxy: 'erc1167' for an immutable minimal proxy to the DefaultAccount.

secp256k1 ownerts
import { privateKeyToAccount, generatePrivateKey } from 'viem/accounts'
import { newSmartAccount } from 'viem/eip8130'
const owner = privateKeyToAccount(generatePrivateKey())
const account = newSmartAccount({ signer: owner })
account.address // counterfactual address
account.createChange // include in accountChanges to deploy on first use
// First create bumps the local config sequence 0 → 1

Pass a fixed salt to recover the same address across sessions and chains:

Fixed saltts
const account = newSmartAccount({
signer: owner,
salt: '0x0000000000000000000000000000000000000000000000000000000000000001',
})

Signer types

P-256

P-256 signerts
import * as P256 from 'ox/P256'
import { newSmartAccount, toP256Signer } from 'viem/eip8130'
const signer = toP256Signer({ privateKey: P256.randomPrivateKey() })
const account = newSmartAccount({ signer })

WebAuthn / passkey

Passkey signerts
import { createWebAuthnCredential, toWebAuthnAccount } from 'viem/account-abstraction'
import { newSmartAccount, toWebAuthnSigner } from 'viem/eip8130'
const credential = await createWebAuthnCredential({ name: 'vibes' })
const signer = toWebAuthnSigner(toWebAuthnAccount({ credential }))
const account = newSmartAccount({ signer })

Multiple initial keys

Register additional actors at creation with extraActors and the key.* builders. Viem sorts by actorId for you (a protocol requirement).

K1 + P-256 at creationts
import { key, newSmartAccount, toP256Signer } from 'viem/eip8130'
import * as P256 from 'ox/P256'
import { privateKeyToAccount, generatePrivateKey } from 'viem/accounts'
const owner = privateKeyToAccount(generatePrivateKey())
const p256 = toP256Signer({ privateKey: P256.randomPrivateKey() })
const account = newSmartAccount({
signer: owner,
extraActors: [key.p256(p256.publicKey)],
})

Plain / delegated EOAs

For the cheapest auth path (bare 65-byte signature, no contract required), use toEoaAccount. You can later install smart-account code with account.delegate(impl) in the first transaction's account changes. Full EOA k1 revoke is pending the bridge upgrade.

EOA accountts
import { privateKeyToAccount, generatePrivateKey } from 'viem/accounts'
import { toEoaAccount } from 'viem/eip8130'
const account = toEoaAccount(privateKeyToAccount(generatePrivateKey()))
// Later: account.delegate(impl) in the first tx's accountChanges

Deployment templates

ConceptMeaning
UpgradeableDefault (proxy: 'upgradeable'). ERC-1967 proxy to CoinbaseSmartWalletV2; admin-signed upgrade. Pending deployment: pass an explicit implementation for now.
DefaultHighRateImmutable ERC-1167. Prefer for parallel / high-throughput accounts.
DefaultStandalone building block; EIP-7702 delegation target.
ERC-4337Portable implementation for chains without native 8130 + bundler providers.

Cross-chain (ERC-4337) portability

On chains without native EIP-8130, wrap the same account as a Viem Smart Account with the ERC-4337 implementation. Authorize the EntryPoint as a K1 operational actor (key.k1(entryPoint) with actorScope.operator) so it can drive executeBatch.

Portable accountts
import {
canonicalEip8130Deployment,
toSmartAccount,
} from 'viem/eip8130'
const account = await toSmartAccount({
client,
owner,
userSalt: '0x…',
initialActors: [/* key.k1(owner.address), … */],
implementation: canonicalEip8130Deployment.accounts.erc4337,
})

Same salt + initial actors give the same counterfactual address on native Vibenet and on portable providers. More in Multichain.