Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.cloud.coinbase.com/llms.txt

Use this file to discover all available pages before exploring further.

EIP-7702 upgrades an existing EOA with smart account capabilities (batched transactions, gas sponsorship, and spend permissions) while keeping the same address. Unlike ERC-4337 smart accounts, which create a separate contract account, EIP-7702 upgrades your user’s existing EOA in place.
Mainnet delegations are sponsored by Coinbase, so end users do not need to hold any ETH before delegating on Base, Arbitrum, Ethereum, Optimism, or Polygon.On testnets (Base Sepolia, Ethereum Sepolia), the delegation transaction requires ETH in the user’s EOA. Use the CDP Faucet to fund accounts for testing.

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.

Create an EIP-7702 delegation

useCreateEvmEip7702Delegation creates the delegation and automatically polls until it reaches a terminal state.
import { EvmEip7702DelegationNetwork } from "@coinbase/cdp-api-client";
import { useCreateEvmEip7702Delegation, useCurrentUser } from "@coinbase/cdp-hooks";

function DelegateAccount() {
  const { createEvmEip7702Delegation, data, status: operation, error } = useCreateEvmEip7702Delegation();
  const { currentUser } = useCurrentUser();

  const handleDelegate = async () => {
    const eoaAddress = currentUser?.evmAccountObjects?.[0]?.address;
    if (!eoaAddress) return;

    await createEvmEip7702Delegation({
      address: eoaAddress,
      network: EvmEip7702DelegationNetwork["base-sepolia"],
      enableSpendPermissions: false,
    });
  };

  const isInProgress = !!data && !operation && !error;

  return (
    <div>
      <button onClick={handleDelegate} disabled={isInProgress}>
        {isInProgress ? "Delegating..." : "Upgrade Account"}
      </button>

      {isInProgress && <p>Waiting for delegation to complete...</p>}

      {operation?.status === "COMPLETED" && (
        <p>Delegation complete! Tx: {operation.transactionHash}</p>
      )}

      {operation?.status === "FAILED" && <p>Delegation failed. Please try again.</p>}
      {error && <p>Error: {error.message}</p>}
    </div>
  );
}

Poll for completion

After creating a delegation, poll for its status to know when the account is ready to send user operations.
useCreateEvmEip7702Delegation polls automatically. For standalone polling, use useWaitForEvmEip7702Delegation:
import { useWaitForEvmEip7702Delegation } from "@coinbase/cdp-hooks";

function DelegationStatus({ delegationOperationId }: { delegationOperationId: string }) {
  const { data, error } = useWaitForEvmEip7702Delegation({
    delegationOperationId,
    enabled: true, // set to false to pause polling
  });

  if (error) return <p>Error: {error.message}</p>;
  if (!data) return <p>Loading...</p>;

  return (
    <div>
      <p>Status: {data.status}</p>
      {data.transactionHash && <p>Tx: {data.transactionHash}</p>}
      {data.delegateAddress && <p>Delegate: {data.delegateAddress}</p>}
    </div>
  );
}
For a one-shot status check without polling, use useGetEvmEip7702DelegationOperation:
import { useGetEvmEip7702DelegationOperation } from "@coinbase/cdp-hooks";

function CheckStatus() {
  const { getEvmEip7702DelegationOperation, data } = useGetEvmEip7702DelegationOperation();

  return (
    <div>
      <button onClick={() => getEvmEip7702DelegationOperation({ delegationOperationId: "your-operation-id" })}>
        Check Status
      </button>
      {data && <p>Status: {data.status}</p>}
    </div>
  );
}

Use the delegated account

Once delegation is complete, the EOA has full smart account capabilities. Send user operations the same way as with ERC-4337 smart accounts.
After delegation completes, use useSendUserOperation with the user’s EOA address. No extra setup needed.
import { useSendUserOperation, useCurrentUser } from "@coinbase/cdp-hooks";

function SendOperation() {
  const { sendUserOperation, status } = useSendUserOperation();
  const { currentUser } = useCurrentUser();

  const handleSend = async () => {
    const eoaAddress = currentUser?.evmAccountObjects?.[0]?.address;
    if (!eoaAddress) return;

    await sendUserOperation({
      evmSmartAccount: eoaAddress,
      network: "base-sepolia",
      calls: [{ to: "0x000...000", value: 0n, data: "0x" }],
    });
  };

  return (
    <button onClick={handleSend} disabled={status === "pending"}>
      {status === "pending" ? "Sending..." : "Send"}
    </button>
  );
}

Supported networks

Mainnets

Arbitrum, Base, Ethereum, Optimism, PolygonDelegation transactions are sponsored by Coinbase. No ETH required. Pair with the CDP Paymaster on Base, or any ERC-7677-compatible paymaster on other networks, for gasless user operations.

Testnets

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