Skip to main content

Smart accounts

Create and manage smart accounts for your users with just a few lines of code, using Embedded Wallets smart accounts. Smart accounts offer enhanced control and programmability, enabling powerful features that traditional wallets can't provide. Key features include:

  • Gas abstraction: Cover transaction fees for users, or allow users to pay for their own transactions using ERC-20 tokens.
  • Batch transactions: Perform multiple transactions in a single call.
  • Automated transactions: Allow users to automate actions, like swapping ETH to USDT when ETH hits a specific price.
  • Custom spending limits: Allow users to set tailored spending limits.

Embedded Wallets smart accounts are powered by the MetaMask Smart Accounts kit, so you can create and manage ERC-4337 compatible smart accounts using your preferred libraries like viem, ethers.js, and Wagmi.

info

For more about ERC-4337 and its components, read this blog post: An ultimate guide to Web3 Wallets.

note

This is a paid feature and the minimum pricing plan to use this SDK in a production environment is the Growth Plan. You can use this feature on Sapphire Devnet for free.

Enable smart accounts

Go to the Smart Accounts section in the Embedded Wallets dashboard, and Set up Smart accounts. Embedded Wallets supports MetaMask Smart Accounts as a smart account provider.

Enable Smart accounts

Install the account abstraction provider

To use native account abstraction, install @web3auth/account-abstraction-provider, which allows you to create and interact with smart accounts. This package simplifies the process by managing the configuration of the account abstraction provider, the bundler, and user operations.

npm install --save @web3auth/account-abstraction-provider

Configure account abstraction

When instantiating the account abstraction provider, you can pass configuration objects to the constructor. Configure your preferred smart account provider, bundler, and paymaster.

import {
AccountAbstractionProvider,
SafeSmartAccount,
} from '@web3auth/account-abstraction-provider'

const chainConfig = {
chainNamespace: CHAIN_NAMESPACES.EIP155,
chainId: '0xaa36a7',
rpcTarget: 'https://rpc.sepolia.org',
displayName: 'Ethereum Sepolia Testnet',
blockExplorerUrl: 'https://sepolia.etherscan.io',
ticker: 'ETH',
tickerName: 'Ethereum',
logo: 'https://cryptologos.cc/logos/ethereum-eth-logo.png',
}

const accountAbstractionProvider = new AccountAbstractionProvider({
config: {
chainConfig,
smartAccountInit: new SafeSmartAccount(),
bundlerConfig: {
// Get the pimlico API Key from dashboard.pimlico.io
url: `https://api.pimlico.io/v2/11155111/rpc?apikey=${pimlicoAPIKey}`,
},
},
})

Configure the smart account provider

Choose your preferred smart account provider. Embedded Wallets currently supports Safe, Kernel, Biconomy, and Trust.

import {
AccountAbstractionProvider,
SafeSmartAccount,
} from '@web3auth/account-abstraction-provider'

const chainConfig = {
chainNamespace: CHAIN_NAMESPACES.EIP155,
chainId: '0xaa36a7',
rpcTarget: 'https://rpc.sepolia.org',
displayName: 'Ethereum Sepolia Testnet',
blockExplorerUrl: 'https://sepolia.etherscan.io',
ticker: 'ETH',
tickerName: 'Ethereum',
logo: 'https://cryptologos.cc/logos/ethereum-eth-logo.png',
}

const accountAbstractionProvider = new AccountAbstractionProvider({
config: {
chainConfig,
smartAccountInit: new SafeSmartAccount(),
bundlerConfig: {
// Get the pimlico API Key from dashboard.pimlico.io
url: `https://api.pimlico.io/v2/11155111/rpc?apikey=${pimlicoAPIKey}`,
},
},
})

Configure the bundler

The bundler aggregates user operations and submits them onchain via a global entry point contract. Configure any bundler of your choice; the following examples use Pimlico and ZeroDev:

import {
AccountAbstractionProvider,
SafeSmartAccount,
} from '@web3auth/account-abstraction-provider'

const chainConfig = {
chainNamespace: CHAIN_NAMESPACES.EIP155,
chainId: '0xaa36a7',
rpcTarget: 'https://rpc.sepolia.org',
displayName: 'Ethereum Sepolia Testnet',
blockExplorerUrl: 'https://sepolia.etherscan.io',
ticker: 'ETH',
tickerName: 'Ethereum',
logo: 'https://cryptologos.cc/logos/ethereum-eth-logo.png',
}

const accountAbstractionProvider = new AccountAbstractionProvider({
config: {
chainConfig,
smartAccountInit: new SafeSmartAccount(),
bundlerConfig: {
// Get the pimlico API Key from dashboard.pimlico.io
url: `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${pimlicoAPIKey}`,
},
},
})

Configure the paymaster

You can configure the paymaster of your choice to sponsor gas fees for your users, along with the paymaster context. The paymaster context lets you set additional parameters, like the token for ERC-20 paymasters or gas policies.

The following examples use Pimlico and ZeroDev to configure a sponsored paymaster:

import {
AccountAbstractionProvider,
SafeSmartAccount,
} from '@web3auth/account-abstraction-provider'

const chainConfig = {
chainNamespace: CHAIN_NAMESPACES.EIP155,
chainId: '0xaa36a7',
rpcTarget: 'https://rpc.sepolia.org',
displayName: 'Ethereum Sepolia Testnet',
blockExplorerUrl: 'https://sepolia.etherscan.io',
ticker: 'ETH',
tickerName: 'Ethereum',
logo: 'https://cryptologos.cc/logos/ethereum-eth-logo.png',
}

const accountAbstractionProvider = new AccountAbstractionProvider({
config: {
chainConfig,
smartAccountInit: new SafeSmartAccount(),
bundlerConfig: {
// Get the pimlico API Key from dashboard.pimlico.io
url: `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${pimlicoAPIKey}`,
},
paymasterConfig: {
// Get the pimlico API Key from dashboard.pimlico.io
url: `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${pimlicoAPIKey}`,
},
},
})

ERC-20 paymaster

When using an ERC-20 paymaster, ensure you include the approval transaction, as Embedded Wallets does not handle the approval internally.

For Pimlico, specify your desired token and sponsorship policies in the paymasterContext. See the tokens supported by Pimlico's ERC-20 paymaster.

import {
AccountAbstractionProvider,
SafeSmartAccount,
} from '@web3auth/account-abstraction-provider'

const chainConfig = {
chainNamespace: CHAIN_NAMESPACES.EIP155,
chainId: '0xaa36a7',
rpcTarget: 'https://rpc.sepolia.org',
displayName: 'Ethereum Sepolia Testnet',
blockExplorerUrl: 'https://sepolia.etherscan.io',
ticker: 'ETH',
tickerName: 'Ethereum',
logo: 'https://cryptologos.cc/logos/ethereum-eth-logo.png',
}

const accountAbstractionProvider = new AccountAbstractionProvider({
config: {
chainConfig,
bundlerConfig: {
// Get the pimlico API Key from dashboard.pimlico.io
url: `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${pimlicoAPIKey}`,
paymasterContext: {
token: 'SUPPORTED_TOKEN_CONTRACT_ADDRESS',
},
},
smartAccountInit: new SafeSmartAccount(),
paymasterConfig: {
// Get the pimlico API Key from dashboard.pimlico.io
url: `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${pimlicoAPIKey}`,
},
},
})

Set up Embedded Wallets

Configure Embedded Wallets

Configure the Embedded Wallets web3auth instance:

import { EthereumPrivateKeyProvider } from '@web3auth/ethereum-provider'
import {
AccountAbstractionProvider,
SafeSmartAccount,
} from '@web3auth/account-abstraction-provider'
import Web3Auth, { WEB3AUTH_NETWORK } from '@web3auth/react-native-sdk'
import * as WebBrowser from '@toruslabs/react-native-web-browser'
import EncryptedStorage from 'react-native-encrypted-storage'
import { CHAIN_NAMESPACES } from '@web3auth/base'

const chainConfig = {
chainNamespace: CHAIN_NAMESPACES.EIP155,
chainId: '0xaa36a7',
rpcTarget: 'https://rpc.sepolia.org',
displayName: 'Ethereum Sepolia Testnet',
blockExplorerUrl: 'https://sepolia.etherscan.io',
ticker: 'ETH',
tickerName: 'Ethereum',
logo: 'https://cryptologos.cc/logos/ethereum-eth-logo.png',
}

const accountAbstractionProvider = new AccountAbstractionProvider({
config: {
chainConfig,
bundlerConfig: {
// Get the pimlico API Key from dashboard.pimlico.io
url: `https://api.pimlico.io/v2/11155111/rpc?apikey=${pimlicoAPIKey}`,
},
smartAccountInit: new SafeSmartAccount(),
},
})

const privateKeyProvider = new EthereumPrivateKeyProvider({
config: { chainConfig },
})

const web3auth = new Web3Auth(WebBrowser, EncryptedStorage, {
clientId,
redirectUrl,
network: WEB3AUTH_NETWORK.SAPPHIRE_MAINNET, // or other networks
privateKeyProvider,
accountAbstractionProvider: aaProvider,
})

Configure the signer

Embedded Wallets smart accounts are compatible with popular signer SDKs, including Wagmi, ethers.js, and viem. Choose your preferred package to configure the signer. Retreive the provider to configure the signer from the web3auth instance.

Wagmi

Wagmi does not require any special configuration to use the signer with smart accounts. Once you have set up your Embedded Wallets provider and connected your wallet, Wagmi's hooks (such as useSigner or useAccount) will automatically use the smart account as the signer. You can interact with smart accounts using Wagmi just like you would with an externally owned account (EOA) signer, with no additional setup.

import { createWalletClient } from 'viem'

// Use your Web3Auth instance to retreive the provider.
const provider = web3auth.provider

const walletClient = createWalletClient({
transport: custom(provider),
})

Get the smart account address

Once the signers or Wagmi configuration is set up, you can use it to retrieve the user's smart account address.

// Use walletClient instance from previous step
const addresses = await walletClient.getAddresses()

const smartAccountAddress = addresses[0]
const eoaAddress = addresses[1]

Send a transaction

You can use your preferred signer or Wagmi hooks to initiate onchain transactions, while Embedded Wallets manages the creation and submission of the user operation. You only need to provide the to, data, and value fields. Any additional parameters will be ignored and automatically `overridden.

To ensure reliable execution, the bundler client sets maxFeePerGas and maxPriorityFeePerGas. If custom values are required, use Viem's Bundler Client to manually construct and send the user operation.

Since smart accounts are deployed smart contracts, the user's first transaction also triggers the onchain deployment of their wallet.

// Convert 1 ether to WEI format
const amount = parseEther('1')

// Submits a user operation to the blockchain
const hash = await walletClient.sendTransaction({
to: 'DESTINATION_ADDRESS',
value: amount,
// This will perform the transfer of ETH
data: '0x',
})

// Wait for the transaction to be mined
const receipt = await publicClient.waitForTransactionReceipt({ hash })

Next steps

For supported transaction methods and batch transactions, see the React SDK smart accounts page.

See the following end-to-end tutorials: