Skip to main content

EIP-7702 quickstart

This quickstart demonstrates how to upgrade your EOAExternally owned account (EOA) A private-key-controlled account with no built-in programmable execution logic. to support MetaMask smart accountMetaMask smart account A smart contract account created using the Smart Accounts Kit that supports programmable behavior, flexible signing options, and ERC-7710 delegations. functionality using an EIP-7702 transaction. This enables your EOA to leverage the benefits of account abstractionAccount abstraction A conceptual model for programmable onchain accounts, including flexible validation logic, custom signature schemes, and gas abstraction. ERC-4337 defines a mechanism for account abstraction., such as batch transactions, gas sponsorship, and delegationDelegation The ability for a MetaMask smart account to authorize another account to perform specific executions on its behalf..

Prerequisites

Steps

1. Install the Smart Accounts Kit

Install the Smart Accounts Kit:

npm install @metamask/smart-accounts-kit

2. Set up a Public Client

Set up a Public Client using Viem's createPublicClient function. This client will let the EOA query the account state and interact with the blockchain network.

import { createPublicClient, http } from 'viem'
import { sepolia as chain } from 'viem/chains'

const publicClient = createPublicClient({
chain,
transport: http(),
})

3. Set up a Bundler Client

Set up a Bundler Client using Viem's createBundlerClient function. This lets you use the bundlerBundler An ERC-4337 component that manages the alternate mempool: it collects user operations from smart accounts, packages them, and submits them to the network. service to estimate gas for user operationsUser operation A pseudo-transaction object defined by ERC-4337 that describes what a smart account should execute. User operations are submitted to the alternate mempool managed by bundlers. and submit transactions to the network.

import { createBundlerClient } from 'viem/account-abstraction'

const bundlerClient = createBundlerClient({
client: publicClient,
transport: http('https://your-bundler-rpc.com'),
})

4. Set up a Wallet Client

Set up a Wallet Client using Viem's createWalletClient function. This lets you sign and submit EIP-7702 authorizations.

import { createWalletClient, http } from 'viem'
import { sepolia as chain } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'

export const account = privateKeyToAccount('0x...')

export const walletClient = createWalletClient({
account,
chain,
transport: http(),
})

5. Authorize a 7702 delegation

Create an authorization to map the contract code to an EOAExternally owned account (EOA) A private-key-controlled account with no built-in programmable execution logic., and sign it using Viem's signAuthorization action. The signAuthorization action does not support JSON-RPC accounts.

This example uses EIP7702StatelessDeleGator as the EIP-7702 delegator contract. It follows a stateless design, as it does not store signer data in the contract's state. This approach provides a lightweight and secure way to upgrade an EOA to a MetaMask smart accountMetaMask smart account A smart contract account created using the Smart Accounts Kit that supports programmable behavior, flexible signing options, and ERC-7710 delegations..

import {
Implementation,
toMetaMaskSmartAccount,
getSmartAccountsEnvironment,
} from '@metamask/smart-accounts-kit'
import { privateKeyToAccount } from 'viem/accounts'

const environment = getSmartAccountsEnvironment(sepolia.id)
const contractAddress = environment.implementations.EIP7702StatelessDeleGatorImpl

const authorization = await walletClient.signAuthorization({
account,
contractAddress,
executor: 'self',
})

6. Submit the authorization

Once you have signed an authorization, you can send an EIP-7702 transaction to set the EOA code. Since the authorization cannot be sent by itself, you can include it alongside a dummy transaction.

import { zeroAddress } from 'viem'

const hash = await walletClient.sendTransaction({
authorizationList: [authorization],
data: '0x',
to: zeroAddress,
})

7. Create a MetaMask smart account

Create a smart accountMetaMask smart account A smart contract account created using the Smart Accounts Kit that supports programmable behavior, flexible signing options, and ERC-7710 delegations. instance for the EOA and start leveraging the benefits of account abstractionAccount abstraction A conceptual model for programmable onchain accounts, including flexible validation logic, custom signature schemes, and gas abstraction. ERC-4337 defines a mechanism for account abstraction..

import { Implementation, toMetaMaskSmartAccount } from '@metamask/smart-accounts-kit'

const addresses = await walletClient.getAddresses()
const address = addresses[0]

const smartAccount = await toMetaMaskSmartAccount({
client: publicClient,
implementation: Implementation.Stateless7702,
address,
signer: { walletClient },
})

8. Send a user operation

Send a user operationUser operation A pseudo-transaction object defined by ERC-4337 that describes what a smart account should execute. User operations are submitted to the alternate mempool managed by bundlers. through the upgraded EOA, using Viem's sendUserOperation method.

import { parseEther } from 'viem'

// Appropriate fee per gas must be determined for the specific bundler being used.
const maxFeePerGas = 1n
const maxPriorityFeePerGas = 1n

const userOperationHash = await bundlerClient.sendUserOperation({
account: smartAccount,
calls: [
{
to: '0x1234567890123456789012345678901234567890',
value: parseEther('1'),
},
],
maxFeePerGas,
maxPriorityFeePerGas,
})

Next steps