Skip to main content

Overview

EIP-7702 delegation upgrades an EVM EOA (Externally Owned Account) with smart account capabilities. After delegation, the EOA can:
  • Batch transactions: send multiple calls in a single user operation
  • Use gas sponsorship: leverage a paymaster so the user doesn’t pay gas directly
  • Grant spend permissions: optionally allow third parties to spend on the account’s behalf
Unlike ERC-4337 smart accounts, which create a separate contract account, EIP-7702 upgrades your existing EOA in place — the address stays the same.
Mainnet delegations are sponsored by Coinbase, so your EOA does not need to hold any ETH before delegating on Base, Arbitrum, Ethereum, Optimism, or Polygon. Once delegated, pair with the CDP Paymaster on Base, or any ERC-7677-compatible paymaster on other networks, to make user operations gasless too.On testnets (Base Sepolia, Ethereum Sepolia), the delegation transaction requires ETH in the EOA. Use the CDP Faucet to fund your account before delegating.

Prerequisites

It is assumed you have already completed the Quickstart guide.

Operation lifecycle

Delegation is asynchronous. When you create a delegation, the API returns an operation ID immediately while the transaction is submitted and confirmed onchain. You poll the operation until it reaches COMPLETED, at which point the account is ready to send user operations.
StatusMeaning
PENDINGThe delegation operation has been created but not yet submitted to the network.
SUBMITTEDThe delegation transaction has been submitted to the network.
COMPLETEDThe delegation is active. The account can now submit user operations.
FAILEDThe delegation failed.

1. Create an EIP-7702 delegation

import { CdpClient } from "@coinbase/cdp-sdk";
import dotenv from "dotenv";

dotenv.config();

const cdp = new CdpClient();

const account = await cdp.evm.getOrCreateAccount({ name: "My-EIP7702-Account" });
console.log("Account address:", account.address);

const { delegationOperationId } = await cdp.evm.createEvmEip7702Delegation({
  address: account.address,
  network: "base-sepolia",
  enableSpendPermissions: false, // optional, defaults to false
});

console.log("Delegation operation created:", delegationOperationId);

Parameters

ParameterTypeDescription
addressstringThe 0x-prefixed address of the EOA account to delegate.
networkstringThe network for the delegation (e.g. "base-sepolia", "base"). See supported networks.
enableSpendPermissionsbooleanWhether to enable spend permissions on the delegated account. Optional, defaults to false.
idempotencyKeystringAn idempotency key for safe retries. Optional.
Returns: { delegationOperationId: string }

2. Poll for delegation completion

Use the wait method to poll the delegation operation until it reaches a terminal state (COMPLETED or FAILED).
const operation = await cdp.evm.waitForEvmEip7702DelegationOperationStatus({
  delegationOperationId,
  waitOptions: {           // optional
    timeoutSeconds: 60,    // default: 60
    intervalSeconds: 0.2,  // default: 0.2
  },
});

console.log("Delegation status:", operation.status);
console.log("Transaction hash:", operation.transactionHash);
You can also check the status of a delegation operation at any time without waiting:
const operation = await cdp.evm.getEvmEip7702DelegationOperationStatus(
  delegationOperationId,
);

console.log(operation.status);
// => "PENDING" | "SUBMITTED" | "COMPLETED" | "FAILED"

Response: EvmEip7702DelegationOperation

FieldTypeDescription
delegationOperationIdstringUnique identifier for the delegation operation.
statusstringOne of: PENDING, SUBMITTED, COMPLETED, FAILED.
transactionHashstringThe hash of the delegation transaction. Present once submitted to the network.
networkstringThe network the delegation was created on.
delegateAddressstringThe address the account has delegated to. Present when delegation is active.

3. Use the delegated account

After the delegation completes, convert the server account to a delegated account view using toEvmDelegatedAccount. This lets you call smart account methods like sendUserOperation.
import { CdpClient, toEvmDelegatedAccount } from "@coinbase/cdp-sdk";
import { parseEther } from "viem";

// ... (after delegation completes)

const delegatedAccount = toEvmDelegatedAccount(account);

const { userOpHash } = await delegatedAccount.sendUserOperation({
  network: "base-sepolia",
  calls: [
    {
      to: "0x0000000000000000000000000000000000000000",
      value: parseEther("0"),
      data: "0x",
    },
  ],
});

console.log("User operation submitted:", userOpHash);

Full end-to-end example

This example creates an EOA, funds it, delegates it with EIP-7702, and sends a user operation from the upgraded account.

Testnet (Base Sepolia)

The delegation transaction on Base Sepolia requires ETH in the EOA. The example below requests funds from the CDP Faucet automatically if the balance is zero.
import { CdpClient, toEvmDelegatedAccount } from "@coinbase/cdp-sdk";
import { createPublicClient, http, parseEther } from "viem";
import { baseSepolia } from "viem/chains";
import dotenv from "dotenv";

dotenv.config();

const cdp = new CdpClient();

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

// Step 1: Get or create an EOA account
const account = await cdp.evm.getOrCreateAccount({ name: "EIP7702-Example-Account" });
console.log("Account address:", account.address);

// Step 2: Ensure the account has ETH for gas (request faucet if needed)
const balance = await publicClient.getBalance({ address: account.address });
if (balance === 0n) {
  console.log("Requesting ETH from faucet...");
  const { transactionHash: faucetTxHash } = await cdp.evm.requestFaucet({
    address: account.address,
    network: "base-sepolia",
    token: "eth",
  });

  await publicClient.waitForTransactionReceipt({ hash: faucetTxHash });
  console.log("Faucet transaction confirmed.");
  await new Promise(resolve => setTimeout(resolve, 1000));
}

// Step 3: Create the EIP-7702 delegation
console.log("Creating EIP-7702 delegation...");
const { delegationOperationId } = await cdp.evm.createEvmEip7702Delegation({
  address: account.address,
  network: "base-sepolia",
  enableSpendPermissions: false,
});

console.log("Delegation operation created:", delegationOperationId);

// Step 4: Wait for the delegation operation to complete
console.log("Waiting for delegation to complete...");
const delegationOperation = await cdp.evm.waitForEvmEip7702DelegationOperationStatus({
  delegationOperationId,
});

console.log(
  `Delegation is complete (status: ${delegationOperation.status}). Explorer: https://sepolia.basescan.org/tx/${delegationOperation.transactionHash}`,
);

// Step 5: Send a user operation using the upgraded EOA (via toEvmDelegatedAccount)
console.log("Sending user operation with upgraded EOA...");
const delegatedAccount = toEvmDelegatedAccount(account);
const { userOpHash } = await delegatedAccount.sendUserOperation({
  network: "base-sepolia",
  calls: [
    {
      to: "0x0000000000000000000000000000000000000000",
      value: parseEther("0"),
      data: "0x",
    },
  ],
});

console.log("User operation submitted:", userOpHash);
console.log(`Check status: https://base-sepolia.blockscout.com/op/${userOpHash}`);

Mainnet (Base)

No ETH required. Coinbase sponsors mainnet delegation transactions.
import { CdpClient, toEvmDelegatedAccount } from "@coinbase/cdp-sdk";
import { parseEther } from "viem";
import dotenv from "dotenv";

dotenv.config();

const cdp = new CdpClient();

// Step 1: Get or create an EOA account
const account = await cdp.evm.getOrCreateAccount({ name: "EIP7702-Example-Account" });
console.log("Account address:", account.address);

// Step 2: Create the EIP-7702 delegation
console.log("Creating EIP-7702 delegation...");
const { delegationOperationId } = await cdp.evm.createEvmEip7702Delegation({
  address: account.address,
  network: "base",
  enableSpendPermissions: false,
});

console.log("Delegation operation created:", delegationOperationId);

// Step 3: Wait for the delegation operation to complete
console.log("Waiting for delegation to complete...");
const delegationOperation = await cdp.evm.waitForEvmEip7702DelegationOperationStatus({
  delegationOperationId,
});

console.log(
  `Delegation is complete (status: ${delegationOperation.status}). Explorer: https://basescan.org/tx/${delegationOperation.transactionHash}`,
);

// Step 4: Send a user operation using the upgraded EOA (via toEvmDelegatedAccount)
console.log("Sending user operation with upgraded EOA...");
const delegatedAccount = toEvmDelegatedAccount(account);
const { userOpHash } = await delegatedAccount.sendUserOperation({
  network: "base",
  calls: [
    {
      to: "0x0000000000000000000000000000000000000000",
      value: parseEther("0"),
      data: "0x",
    },
  ],
});

console.log("User operation submitted:", userOpHash);
console.log(`Check status: https://base.blockscout.com/op/${userOpHash}`);

Supported networks

Mainnets

Arbitrum, Base, Ethereum, Optimism, PolygonDelegation transactions are sponsored by Coinbase, so no ETH is required. Pair with the CDP Paymaster on Base, or a custom ERC-7677 paymaster on other networks, for fully gasless user operations.

Testnets

Base Sepolia, Ethereum SepoliaThe EOA must hold ETH to pay for the delegation transaction. Use the CDP Faucet to fund your account.

EIP-7702 vs ERC-4337 smart accounts

AspectEIP-7702 DelegationERC-4337 Smart Account
AddressSame EOA address, upgraded in placeNew contract address
Account typeEOA with smart account capabilitiesStandalone smart contract
CreationDelegation operation on existing accountSeparate smart account creation
OwnershipSelf-owned (the EOA is the account)Requires a separate owner account
User operationsSupported after delegationSupported after first user operation
Spend permissionsOptional via enableSpendPermissionsOptional via enableSpendPermissions