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