Account Abstraction
While Account Abstraction is not built into the core viem library, you can use a third-party library like permissionless.js, ZeroDev and Biconomy to integrate with ERC-4337.
permissionless.js
permissionless.js is a TypeScript library built on viem for interacting with ERC-4337 bundlers, paymasters, and User Operations.
Below are instructions for setting up a Bundler Client.
1. Install
npm i permissionless2. Set up a Bundler Client
import { createClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { bundlerActions } from 'permissionless'
 
const bundlerClient = createClient({ 
  chain: mainnet,
  transport: http("https://api.pimlico.io/v1/goerli/rpc?apikey=YOUR_API_KEY_HERE")
}).extend(bundlerActions)3. Consume Actions
Now you can consume Actions that are supported by permissionless.js.
See a full list of Bundler Actions.
import { createClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { bundlerActions } from 'permissionless'
 
const bundlerClient = createClient({ 
  chain: mainnet,
  transport: http("https://api.pimlico.io/v1/goerli/rpc?apikey=YOUR_API_KEY_HERE")
}).extend(bundlerActions)
 
const supportedEntryPoints = await bundlerClient.supportedEntryPoints() ZeroDev
ZeroDev is an SDK for building wallets and DApps using modular smart accounts. The SDK uses Viem's client-action architecture to model smart accounts and their plugins.
Below are instructions for setting up a smart account client (which interacts with bundlers using a modular smart account).
1. Install
Install the core SDK and a plugin.
npm i @zerodev/sdk @zerodev/ecdsa-validator2. Create a Public Client
import { createPublicClient, http } from 'viem'
 
const publicClient = createPublicClient({
  transport: http("RPC_URL"),  // use your RPC provider or bundler
})3. Create an Account
This can be any Viem account type. In this case we use a Local Account.
import { privateKeyToAccount } from 'viem/accounts'
 
const account = privateKeyToAccount('0x...')  // replace with actual private key4. Create a Validator Plugin
In this case, we are creating a smart account that uses ECDSA for validation (just like EOAs).
import { signerToEcdsaValidator } from '@zerodev/ecdsa-validator'
 
const ecdsaValidator = await signerToEcdsaValidator(publicClient, {
  signer: account,
})5. Create a Smart Account
import { createKernelAccount } from '@zerodev/sdk'
 
const smartAccount = await createKernelAccount(publicClient, {
  plugins: {
    validator: ecdsaValidator,
  },
})6. Create an account client
import { createKernelAccountClient } from '@zerodev/sdk'
import { http } from 'viem'
import { polygonMumbai } from 'viem/chains'
 
const kernelClient = createKernelAccountClient({
  account: smartAccount,
  chain: polygonMumbai,
  transport: http('BUNDLER_RPC'),  // use your bundler RPC
  sponsorUserOperation,  // optional -- only if you want to use a paymaster
})7. Send UserOps
Now you can send UserOps using the account client:
const txnHash = await kernelClient.sendTransaction({
  to: '0x...',
  value: parseEther('0.1'),
})You can also extend the account client with bundlerActions from Permissionless.js if you need to call any bundler RPCs:
import { bundlerActions } from 'permissionless'
 
const bundlerClient = kernelClient.extend(bundlerActions)
const receipt = await bundlerClient.waitForUserOperationReceipt({
  hash: userOpHash,
})Biconomy
Biconomy offers a viem compatible SDK that can be used to interact with ERC-4337 Bundlers and Paymasters very easily with minimal integration required.
Below are instructions for setting up a smart account and sending a sponsored user operation.
1. Install
npm i @biconomy/account2. Create an Account
This can be any Viem Account type. In this case we use a Local Account.
import { privateKeyToAccount } from 'viem/accounts'
 
const account = privateKeyToAccount('0x...')  // replace with actual private key3. Create a Smart Account Client
Head over to https://dashboard.biconomy.io/ to get your bundlerUrl and biconomyPaymasterApiKey.
import { createSmartAccountClient } from '@biconomy/account'
 
const smartAccount = await createSmartAccountClient({
  bundlerUrl,
  biconomyPaymasterApiKey,
  signer: account,
})4. Send a Sponsored User Operation
const { wait } = await smartAccount.sendTransaction([{
  data: '0x...',
  to: '0x...',
}], {
  paymasterServiceData: {
    mode: PaymasterMode.SPONSORED,
  }
})
