EIP-7702 quickstart
This page demonstrates how to upgrade your externally owned account (EOA) to support MetaMask smart account functionality using an EIP-7702 transaction. This enables your EOA to leverage the benefits of account abstraction, such as batch transactions, gas sponsorship, and ERC-7710 delegation capabilities.
Prerequisites
Steps
1. Set up a Public Client
Set up a Viem Public Client using Viem's createPublicClient
function.
This client will let the EOA query the account state and interact with blockchain network.
import { createPublicClient, http } from "viem";
import { sepolia as chain } from "viem/chains";
const publicClient = createPublicClient({
chain,
transport: http(),
});
2. Set up a Bundler Client
Set up a Viem Bundler Client using Viem's createBundlerClient
function.
This lets you use the bundler service to estimate gas for user operations and submit transactions to the network.
import { createBundlerClient } from "viem/account-abstraction";
const bundlerClient = createBundlerClient({
client: publicClient,
transport: http("https://your-bundler-rpc.com"),
});
3. Set up a Wallet Client
Set up Viem Wallet Client using Viem's createWalletClient
function.
This lets you sign and submit EIP-7702 authorization.
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(),
});
4. Authorize a 7702 delegation
Create an authorization to map the contract code to an EOA, 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 smart account.
import {
Implementation,
toMetaMaskSmartAccount,
getDeleGatorEnvironment,
} from "@metamask/delegation-toolkit";
import { privateKeyToAccount } from "viem/accounts";
const environment = getDeleGatorEnvironment(sepolia.id);
const contractAddress = environment.implementations.EIP7702StatelessDeleGatorImpl;
const authorization = await walletClient.signAuthorization({
account,
contractAddress,
executor: "self",
});
5. 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,
});
6. Create a MetaMask smart account
Create a smart account instance for the EOA and start leveraging the benefits of account abstraction.
import {
Implementation,
toMetaMaskSmartAccount,
} from "@metamask/delegation-toolkit";
const addresses = await walletClient.getAddresses();
const address = addresses[0];
const smartAccount = await toMetaMaskSmartAccount({
client: publicClient,
implementation: Implementation.Stateless7702,
address,
signatory: { walletClient },
});
7. Send a user operation
Send a user operation 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
});