Appearance
Account Abstraction with Safe ​
TIP
Privy now allows you to natively use smart wallet for a better developer experience. Check out the docs here.
Safe Smart Accounts is a product by Safe for creating ERC-4337-compatible smart accounts for your users, using the user's EOA as the smart account's signer. The product builds off of the smart contract infrastructure powering the widely-used Safe wallet and allows you to easily add Account Abstraction and other Safe features into your 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. Safe'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 Safe). The smart wallet (Safe) holds all assets and submits all transactions to the network, but the signer (Privy) is responsible for producing signatures and "kicking off" transaction flows.
To create Safe smart accounts for your users, simply follow our Pimlico integration guide. Safe does not operate its own paymaster and bundler infrastructure, and developers generally compose the Safe smart account with paymasters or bundlers from Pimlico.
When integrating Safe alongside Pimlico, the only change from the default Pimlico setup is to replace the signerToSimpleSmartAccount
method with signerToSafeSmartAccount
. This modifies the setup to deploy a Safe smart account for the user instead of a simple smart account.
For example, when initializing the smart account from a viem
wallet client for the user's Privy embedded wallet, you should update your code as follows:
tsx
import {
createSmartAccountClient,
walletClientToCustomSigner,
ENTRYPOINT_ADDRESS_V07,
} from 'permissionless';
import {signerToSimpleSmartAccount} from 'permissionless/accounts';
import {signerToSafeSmartAccount} from 'permissionless/accounts';
import {createPimlicoPaymasterClient} from 'permissionless/clients/pimlico';
import {createPublicClient, http} from 'viem';
// The `privyClient` is simply a viem Wallet Client for the user's embedded wallet
const customSigner = walletClientToCustomSigner(privyClient);
// Create a viem public client for RPC calls
const publicClient = createPublicClient({
chain: sepolia, // Replace this with the chain of your app
transport: http(),
});
// Initialize the smart account for the user
const simpleSmartAccount = await signerToSimpleSmartAccount(publicClient, {
entryPoint: '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789',
signer: customSigner,
factoryAddress: '0x9406Cc6185a346906296840746125a0E44976454',
});
const safeSmartAccount = await signerToSafeSmartAccount(publicClient, {
signer: customSigner,
safeVersion: '1.4.1',
entryPoint: ENTRYPOINT_ADDRESS_V07,
});
// Create the Paymaster for gas sponsorship using the API key from your Pimlico dashboard
const pimlicoPaymaster = createPimlicoPaymasterClient({
transport: http('https://api.pimlico.io/v2/sepolia/rpc?apikey=YOUR_PIMLICO_API_KEY'),
});
// Create the SmartAccountClient for requesting signatures and transactions (RPCs)
const smartAccountClient = createSmartAccountClient({
account: simpleSmartAccount,
account: safeSmartAccount,
chain: sepolia, // Replace this with the chain for your app
transport: http('https://api.pimlico.io/v1/sepolia/rpc?apikey=YOUR_PIMLICO_API_KEY'),
sponsorUserOperation: pimlicoPaymaster.sponsorUserOperation, // If your app uses a paymaster for gas sponsorship
});
TIP
You can also store the user's smart account address on Privy's user object. See this guide for more.