DEV Community

SwiftNodes
SwiftNodes

Posted on Originally published at swiftnodes.io

What Is EIP-7702? EOAs That Act Like Smart Accounts

Run this against Ethereum mainnet right now:

curl -X POST "https://rpc.swiftnodes.io/rpc/eth?key=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_getCode",
       "params":["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045","latest"]}'
Enter fullscreen mode Exit fullscreen mode

That's vitalik.eth — an externally owned account, a plain wallet address. For ten years the correct answer was 0x: EOAs have no code, contracts do. Today it returns something like:

0xef01005a7fc11397e9a8ad41bf10bf13f22b0a63f96f6d
Enter fullscreen mode Exit fullscreen mode

Twenty-three bytes of code on an EOA. That's EIP-7702, live on mainnet since the Pectra upgrade in May 2025, and it quietly breaks one of the oldest assumptions in Ethereum tooling. This post explains what it is, what those bytes mean, and what changes for you as a developer reading and writing over RPC.

The problem: EOAs are stuck, and ERC-4337 asked you to move

Externally owned accounts have exactly one capability: a secp256k1 key signs transactions. No batching (approve + swap is always two transactions), no gas sponsorship (a new user with zero ETH can't do anything), no session keys, no spending limits, no recovery if the key leaks. Every one of those features requires logic, and EOAs can't hold logic.

ERC-4337 account abstraction solved this by putting your account in a smart contract — but that means a new account at a new address. Your assets, your token approvals, your history, your ENS name all live at the old EOA. Migration friction is exactly why most users never made the jump.

EIP-7702 takes the opposite approach: keep your address, keep your key, and let the EOA borrow a contract's code.

How it works: the delegation designator

Pectra added a new transaction type, 0x04 (the set-code transaction). Alongside the usual fields, it carries an authorizationList: one or more tuples of {chainId, address, nonce, yParity, r, s}, each signed by an EOA's key. Each authorization says: "set my account's code to delegate to this contract address."

When the transaction is processed, the protocol writes a delegation designator into the EOA's code slot:

0xef0100 || <20-byte delegate address>
Enter fullscreen mode Exit fullscreen mode

That's what the eth_getCode call above returned: the 0xef0100 prefix, then the delegate contract. (The 0xef prefix is reserved by EIP-3541 — no regular deployed contract can start with it, so a designator can never be confused with real bytecode.)

From that point on, any call or transaction sent to the EOA executes the delegate contract's code in the EOA's own context — its storage, its balance, its address. The EOA effectively becomes an instance of the delegate contract, while the original private key keeps working for normal transactions too.

A few mechanics worth knowing:

  • Delegation is persistent. It's not per-transaction. It stays until replaced by a new authorization or cleared by authorizing the zero address, which resets the account to a plain EOA.
  • chainId can be 0, which makes the authorization valid on every chain — convenient for wallets, but it means one signature can take effect on chains you weren't thinking about.
  • The authorization embeds the account's nonce, so it can't be replayed after the account moves on. If you self-sponsor (the delegating EOA also sends the transaction), sign the authorization with nonce + 1, because the transaction consumes the current nonce first — the classic off-by-one that ties back to nonce management.
  • Each authorization costs gas (25,000 for a fresh account), paid by the transaction sender — which can be someone other than the delegating EOA. That's how a wallet with zero ETH gets upgraded: a sponsor submits the type-4 transaction carrying the user's signed authorization.

What it unlocks

Once an EOA delegates to a well-designed smart-account implementation, it gets the ERC-4337 feature set without moving addresses: batch an approve and a swap into a single atomic call, let a dApp or paymaster sponsor gas, hand a game a session key with a spend limit, set up recovery. Major wallets shipped exactly this — MetaMask's smart-account upgrade is a 7702 delegation under the hood, which is why tens of millions of EOAs now return code.

7702 and ERC-4337 are complements, not competitors. A delegated EOA can point at 4337-compatible account code and then ride the whole 4337 stack — UserOperations, bundlers, paymasters. 7702 fixes the migration problem; 4337 provides the infrastructure.

ERC-4337 EIP-7702 Native AA (zkSync, Starknet)
Protocol change None (contracts + alt mempool) New tx type 0x04 (Pectra) Built into the chain
Your address New contract address Same EOA address Contract account from day one
Key still works n/a Yes — key retains full control Depends on account code
Where it works Any EVM chain with bundlers Ethereum + L2s that shipped it That chain only

What changes when you're building over RPC

1. "No code = EOA" is dead. Any classifier, indexer, or security check that calls eth_getCode and treats a non-empty result as "this is a contract" now misfires on millions of wallets. Check for the designator:

import { createPublicClient, http } from "viem";
import { mainnet } from "viem/chains";

const client = createPublicClient({
  chain: mainnet,
  transport: http("https://rpc.swiftnodes.io/rpc/eth?key=YOUR_API_KEY"),
});

const code = await client.getCode({ address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" });

if (!code || code === "0x") {
  // plain EOA
} else if (code.startsWith("0xef0100")) {
  const delegate = `0x${code.slice(8)}`; // the contract this EOA delegates to
} else {
  // regular deployed contract
}
Enter fullscreen mode Exit fullscreen mode

2. Wallets can be callers and callees. A delegated EOA emits events, receives calls, and shows internal-call behavior like a contract, while still originating ordinary transactions with its key. If your indexer keys behavior on "sender must be an EOA" or "recipient with code must be a contract," revisit both branches, and confirm outcomes from the receipt, not from account shape.

3. Type 0x04 shows up in your feeds. eth_getTransactionByHash and block bodies now include set-code transactions with an authorizationList field. If you decode raw transactions yourself (the eth_sendRawTransaction path), handle the new type rather than dropping it on the floor.

4. The security model is sharp-edged. The delegate contract controls the account completely — a signature over a malicious delegation is total compromise, which is why "sign this one message" phishing got more dangerous and why wallets only delegate to a shortlist of audited implementations. And the original key always retains full control: 7702 adds capabilities, it does not remove the key. Nothing here changes consensus or the mempool — it's account behavior, visible through perfectly ordinary eth_* calls.

The takeaway

EIP-7702 is the quiet one of the big upgrades: no new namespace, no new mempool to integrate, just a 23-byte designator that upgrades the humble EOA in place. If your code touches eth_getCode, transaction types, or any EOA-versus-contract logic, it's already affected — the one-curl check at the top of this post is the fastest way to see it live.

You can run that check — and everything else in this post — on any Ethereum RPC endpoint from SwiftNodes: flat-rate, HTTP and WebSocket, no KYC. The free tier takes about 30 seconds to set up.


Originally published on the SwiftNodes blog. SwiftNodes provides flat-rate multi-chain RPC endpoints — HTTP + WebSocket, 75+ chains, no per-request metering. Grab a free key.

Top comments (0)