Guide

Recipes

Short, end-to-end checklists that combine the earlier chapters. Each links back to the chapter with the full detail.

Passkey wallet from zero

  1. Create a WebAuthn credential and wrap it as a signer.
  2. Build the account with newSmartAccount8130 (the address is deterministic; no pre-deploy needed).
  3. Send the first transaction: the account deploys on first use.
Passkey onboardingts
import {
createWebAuthnCredential,
toWebAuthnAccount,
} from 'viem/account-abstraction'
import {
newSmartAccount8130,
sendCalls8130,
toWebAuthnSigner,
} from 'viem/experimental/eip8130'
const credential = await createWebAuthnCredential({ name: 'vibes' })
const account = newSmartAccount8130({
signer: toWebAuthnSigner(toWebAuthnAccount({ credential })),
})
// Deploys on first use; the passkey signs sender_auth.
const hash = await sendCalls8130(client, {
account,
calls: [{ to: recipient, value: 1n }],
gas: 300_000n,
})

Detail: Creating accounts and Signing.

Gasless first transaction

  1. Point a payer client at an ERC-8168 endpoint.
  2. Call sendSponsoredCalls: it fetches terms, selects a sponsored offer, signs, and hands off.
  3. Confirm any token charge before re-signing.
Sponsored sendts
import { createPayerClient, sendSponsoredCalls } from 'viem/experimental/eip8168'
const payerClient = createPayerClient({ url: 'https://payer.example.com/v1' })
const { transactionHash } = await sendSponsoredCalls(client, {
account, // signs sender_auth
payerClient, // co-signs payer_auth and submits
calls: [{ to: recipient, data }],
})

Detail: Gas & payers.

Issue a spend-limited session key

  1. Author a policy config (token limits + allowlists) and bind it with defineSessionPolicy.
  2. Authorize the key with a restricted scope + policy and ride the install call in the same transaction.
  3. Hand the key to the app; it spends via executeCall within its committed policy.

Detail: Session keys.

Rotate a compromised key

  1. Read the next config sequence with getConfigSequence8130.
  2. Authorize the replacement and revoke the old key in one change.
  3. Land it as a config-only transaction.
Atomic rotationts
import {
actorScope,
authorizeActor,
key,
revokeActor,
sendCalls8130,
} from 'viem/experimental/eip8130'
const rotate = await account.change(
[
authorizeActor(key.k1('0xnewOwner…'), { scope: actorScope.sender }),
revokeActor(key.k1('0xoldOwner…')),
],
{ chainId: client.chain.id, sequence: Number(sequence) },
)
await sendCalls8130(client, { account, accountChanges: [rotate], calls: [], gas: 200_000n })

Detail: Keys & scopes.

High-throughput sends

  1. Use nonce.randomChannel() for independent, out-of-order lanes.
  2. Or use nonce.nonceless(...) for fully parallel, retry-safe sends bounded by expiry.

Detail: Nonces & throughput.

Take an account multichain

  1. Register native chains with register8130Chains; the same address works everywhere.
  2. On non-8130 chains, drive it through ERC-4337 with toSmartAccount8130.
  3. Rotate keys once with a chainId 0 change and apply it everywhere.

Detail: Multichain.