Skip to main content

Account Abstraction with ZeroDev

ZeroDev is a toolkit for creating ERC-4337-compatible smart wallets for your users, using the user's EOA as the smart wallet's signer. This allows you to easily add Account Abstraction features into your app.

You can easily integrate ZeroDev alongside Privy to create smart wallets from your user's embedded or external wallets, allowing you to enhance your app with gas sponsorship, batched transactions, and more!

Read below to learn how to configure your app to create smart wallets for all your users!

tip

Want to see an end-to-end integration of Privy with ZeroDev? Check out our example app!

What is an EOA?

An EOA, or externally-owned account, is any Ethereum account that is controlled by a private key. Privy's embedded wallets and most external wallets (MetaMask, Coinbase Wallet, Rainbow Wallet, etc.) are EOAs.

EOAs differ from contract accounts, which are instead controlled by smart contract code and do not have their own private key. ZeroDev's smart wallet is a contract account. Contract accounts have enhanced capabilities, such as gas sponsorship and batched transactions.

Since they do not have their own private key, contract accounts cannot directly produce signatures and initiate transaction flows. Instead, each contract account is generally "managed" by an EOA, which authorizes actions taken by the contract account via a signature; this EOA is called a signer.

In this integration, the user's EOA (from Privy) serves as the signer for their smart wallet (from ZeroDev). The smart wallet (ZeroDev) holds all assets and submits all transactions to the network, but the signer (Privy) is responsible for producing signatures and "kicking off" transaction flows.

How much does deploying a smart wallet for a user cost?

The transaction to deploy a ZeroDev smart wallet requires approximately 258522 in gas. At time of writing, this corresponds to:

  • 0.0168 ETH (28 USD) on Ethereum Mainnet
  • 0.04 MATIC (0.024 USD) on Polygon
  • 0.00005 ETH (0.08 USD) on Arbitrum

The exact deployment cost you see will vary depending on the current gas price.

Importantly, ZeroDev deploys smart wallets lazily, ensuring that you do not pay deployment costs for functionally unused wallets.

When you first initialize a ZeroDev smart wallet for a user, ZeroDev does not yet deploy the wallet, but instead predicts the smart wallet's address (via the CREATE2 opcode). This allows you to associate a smart wallet with your user, without any upfront deployment costs.

ZeroDev only deploys the smart wallet to the predicted address when the user sends their first transaction with the smart wallet. This ensures that you only ever pay deployment costs for wallets that are actually used to transact on-chain.

1. Install Privy and ZeroDev

In your app's repository, install the @privy-io/react-auth and @zerodev/privy SDKs:

npm i @privy-io/react-auth @zerodev/privy

2. Configure your app's PrivyProvider

First, follow the instructions in the Privy Quickstart to get your app set up with Privy.

Then, update the config.embeddedWallets property of your PrivyProvider to have the following values:

  • createOnLogin: 'users-without-wallets'. This will configure Privy to create an embedded wallet for users logging in via a web2 method (email, phone, socials), ensuring that all of your users have a wallet that can be used as an EOA.
  • noPromptOnSignature: true. This will configure Privy to not show its default UIs when your user must sign messages or send transactions. Instead, we recommend you use your own custom UIs for showing users the UserOperations they sign.

Your PrivyProvider should then look like:

<PrivyProvider
appId='insert-your-privy-app-id'
config={{
/* Replace this with your desired login methods */
loginMethods: ['email', 'wallet'],
/* Replace this with your desired appearance configuration */
appearance: {
theme: 'light',
accentColor: '#676FFF',
logo: 'your-logo-url'
}
embeddedWallets: {
createOnLogin: 'users-without-wallets',
noPromptOnSignature: true
}
}}
>
{/* Your app's components */}
</PrivyProvider>

3. Add ZeroDev to your app

First, go to the ZeroDev dashboard, set up a new project, and retrieve your ZeroDev Project ID. You can configure your ZeroDev project per the instructions here.

Then, where you render your PrivyProvider, wrap it with a ZeroDevProvider. In the projectId property of the ZeroDevProvider, add your Project ID from the ZeroDev dashboard.

For example, in NextJS or Create React App, this might look like:

_app.jsx
import type {AppProps} from 'next/app';
import {PrivyProvider} from '@privy-io/react-auth';
import {ZeroDevProvider} from '@zerodev/privy';

function MyApp({Component, pageProps}: AppProps) {
return (
<>
<ZeroDevProvider projectId='insert-your-zerodev-project-id'>
<PrivyProvider
appId='insert-your-privy-app-id'
config={/* insert your PrivyProvider config */}
>
<Component {...pageProps} />
</PrivyProvider>
</ZeroDevProvider>
</>
);
}

4. Just usePrivySmartAccount!

With the steps above, when a user logs into your app, they will either create a Privy embedded wallet or have an external wallet (e.g. MetaMask) that can be used as an EOA. Behind-the-scenes, ZeroDev will create a smart wallet for the user, and use this EOA as the smart wallet's signer.

You can now use the ZeroDev smart wallet from within your app's components, by calling ZeroDev's usePrivySmartAccount hook:

  • Before taking any actions with the smart wallet, you should verify that the smart wallet has initialized by inspecting the boolean zeroDevReady from usePrivySmartAccount.
  • Once zeroDevReady is true, you can then call methods like sendTransaction and getEthereumProvider to use the smart wallet.
Sending a transaction with the smart wallet
import {usePrivySmartAccount} from '@zerodev/privy';

const {zeroDevReady, sendTransaction} = usePrivySmartAccount();

if (zeroDevReady) {
const transactionHash = await sendTransaction({
to: '0xYourDestinationAddress',
value: 100000
});
} else {
throw new Error('Smart wallet has not yet initialized. Try again once zeroDevReady is true.');
}

usePrivySmartAccount will expose all of the same fields and methods as usePrivy, but will override all wallet-related flows (signMessage, sendTransaction, getEthereumProvider) to use the ZeroDev smart wallet instead of the user's EOA.

That's it! You've configured your app to create smart wallets for all of your users, and can seamlessly add in AA features like gas sponsorship, batched transactions, and more. 🎉