Special thanks to Péter Garamvölgyi for feedback and review.
EIP-7702 introduces a new transaction type that allows an Externally Owned Account (EOA) to specify an address as the pointer to its implementation. For example, this address could be a generic proxy or minimal proxy contract that forwards call messages to an upgradable wallet implementation.
To make the explanation clearer, it is important to distinguish between the "delegated" code and the "delegator" account. For this reason, this article will sometimes refer to an EOA that has delegated to code as a "smart EOA".
EIP-7702 effectively upgrades EOAs to function like Smart Contract (SC) wallets, unlocking programmability, and composability for EOA users, and enabling features like:
EIP-7702's composability with ERC-4337 also brings significant advantages. This composability allows smart EOAs to seamlessly integrate with the existing ecosystem of SC wallets and infrastructure built around ERC-4337, simplifying development and adoption of new features. Once a user authorizes an address with a smart contract wallet supporting ERC-4337, the EOA address can serve as the sender
field of UserOperation
in ERC-4337.
Although smart EOAs can address the issue of "your private key is now known by no one" through mechanisms like social recovery, they do not resolve the issue of "your private key is now known by others," as private keys still grant full authorization over the EOA. Proposals like EIP-7377, which enable migrating EOAs to account abstraction wallets, or future proposals allowing users to deactivate (and potentially reactivate) private key permissions post-EIP-7702, will be necessary to address this gap.
In the meantime, in the absence of protocol-level security guarantees, wallet clients can delete their locally stored "hot" private keys and prompt users to delete any local or external backups of their private keys after authorizing the EOA as a contract wallet. However, such measures cannot fully eliminate the risks of private key leaks, particularly in scenarios involving supply chain attacks, such as backdoors in the libraries used by the wallet or in the wallet client itself.
So, do smart EOAs offer more interesting or convenient features compared to SC wallets? In my initial thoughts, retaining EOA functionalities offers several distinct advantages:
Of course, all of these are just preliminary speculations, and the actual impact on user experience will likely depend on how different creative wallet applications leverage these features to gather meaningful feedback and preferences from diverse user groups. For instance, Ethereum's subcultures, such as Cypherpunks, Regens, and Degens (as categorized in this article), may each have unique needs and perspectives on wallet design. Hopefully, we will see more diverse use cases and applications emerge in the future.
Next, let’s dive into the protocol itself.
EIP-7702 introduces a new transaction type, SET_CODE_TX_TYPE
(0x04
), with the TransactionPayload
defined as:
Where the authorization_list
is defined as:
The address
field in the authorization_list
represents the delegated code's address, while the EOA's address can be recovered from the payload (chain_id
, address
,nonce
) and the signature (y_parity
, r
, s
). This decoupling of the EOA address and the EIP-7702 transaction's address
allows the authorization to be submitted on behalf of the original EOA by another EOA account, enabling more flexible delegation and sponsored transactions.
The transaction receipt is defined as:
Before diving into the code, the following sections highlight a few notable features as warm-ups.
authorization_list
The authorization_list
must not be empty, ensuring that every EIP-7702 transaction includes an explicit intention to authorize an implementation address. Additionally, the protocol validates the parameters of each authorization_list
tuple, including the address
length and reasonable ranges for chain_id
, nonce
, y_parity
, r
, and s
.
authorization_list
In each tuple of the authorization_list
, the address
field represents the authorized address, while the signer’s address is derived from signature and payload. This design allows EIP-7702 to delegate the responsibility of gas payment away from the EOAs being authorized, enabling what is widely known as sponsored transactions. For instance, Layer 2 sequencers could integrate EIP-7702 wallet creation interfaces directly or add APIs to collect user authorizations and batch-submit them with an authorization_list
. Wallet service providers could also assist users without balance in submitting transactions.
Importantly, even if an authorization in the batch fails validation, other authorizations remain unaffected. This design helps the execution of (sponsored) batch authorization transactions.
EIP-7702 introduces a new mechanism that increments the nonce of an EOA after each successful authorization. The handling process of nonce is as follows:
For the code path, please refer to the Nonce Increment Logic session.
This means that if a transaction includes an authorization list and the authorization signer is the same as the transaction signer, you must set tx.nonce
to account.nonce
and authorization.nonce
to account.nonce + 1
. If a transaction contains multiple authorizations signed by the same EOA (which will not happen in practical use cases), the nonce of each authorization must be incremented sequentially. Overall, this mechanism may add some complexity for SDKs to initialize delegate transactions, especially when handling all cases.
With EIP-7702, from the perspective of an EOA, ETH balances can now decrease not only through signed transactions but also through transactions triggering contract executions. From the view of smart contracts, EOAs can directly send transactions to change account states. This introduces the following considerations:
Users can utilize EIP-7702 to modify the authorized address. If the address
field is set to 0x0000000000000000000000000000000000000000
, the previous authorization will be revoked. This clears the account’s code and resets the account’s code hash to the empty hash.
Re-delegating an account requires careful storage management to avoid collisions, which can otherwise lead to undefined behavior. To address the challenge in account migration, ERC-7201 roots storage layouts at unique slots, avoiding storage location collision during re-delegation. ERC-7779 (draft) also provides a standardized re-delegation process for EIP-7702 wallets, by:
EIP-7702 adopts the gas fee model defined by EIP-1559, requiring the sender to specify max_priority_fee_per_gas
and max_fee_per_gas
instead of a single gas_price
field. The transaction can also include fields such as access_list
and data
, allowing it to retain most of the capabilities of other Ethereum transactions (though it cannot carry blobs). Similar to EIP-4844, EIP-7702 enforces a restriction that the destination
(also known as to
in other types of transactions) field cannot be empty, aligning with the common practice of restricting contract creation.
Another well-known ban in Ethereum involves banning storage-related instructions (e.g. EIP-7562). EIP-7702 does not impose such a ban, since storage instructions are important for SC wallets.
Further details will be introduced in the next section.
In this section, we will dig into:
The code analysis focuses on the open-sourced repo Geth, one of the major Ethereum clients listed on the Client Diversity Dashboard. The full pull request for the EIP-7702 feature can be found here.
Before doing anything, we assume that the node has activated EIP-7702, whether through a hard fork (from a block height, or from a timestamp) or from the genesis block.
To send an EIP-7702 transaction, the user first needs to fill in all non-signature fields outside of the authorization_list
(definition of SetCodeTx
here). Then, the user constructs the authorization_list
here. For each authorization tuple
, the user fills in the non-signature fields first, and then signs it using the SignAuth function.
The user's EOA private key is required for signing. Signing involves hashing the authorization details, which include a magic number 0x05
, a chain ID, the delegated code address, and the current nonce of the EOA. The magic number 0x05
is also a domain separator in EIP-7202 (another is SET_CODE_TX_TYPE
0x04
) to ensure that when data of different types happens to encode into the same byte representation, the resulting hash being signed does not collide across domains. More discussions of current signing domain constants can be found here.
Notably, setting the chain ID to 0
allows the authorization to be replayed across all EVM-compatible chains supporting EIP-7702, provided the nonce matches. However, since the nonce must be the same, reusing authorization across chains in practice may be challenging. For example, for EOAs with non-zero nonces.
Once all fields except the signature fields of transaction are prepared, the user initializes the transaction (instructions here) and a "prague signer" (which adds support for EIP-7702 transaction hashing). The user then signs the transaction using SignTx and serializes it into a byte array using RLP encoding via MarshalBinary. Finally, the RLP byte array of transaction is hex-encoded and sent via the eth_sendRawTransaction
RPC method.
When a node receives the transaction through JSON-RPC, it validates it and adds it to the transaction pool[4], broadcasting it to other nodes. Eventually, a block proposer attempts to include it in a block. Before inclusion, the proposer performs preCheck, which includes some additional checks for EIP-7702 transactions:
Before executing the transaction, the node calculates IntrinsicGas, accounting for the gas cost of accessing the authorization_list
(details here). A 25000
gas cost for each authorization tuple, defined as CallNewAccountGas (also the PER_EMPTY_ACCOUNT_COST
in EIP-7702) is consumed when the destination address did not previously exist, and a partial refund for each tuple is added to the global refund counter during applying delegation if the account already exists in state (i.e. delegated before this transition).
Finally, during state transition, the node applies each tuple in the authorization_list
(implementation here). The process includes validating the tuple, refunding gas for existing accounts, incrementing nonce, and handling code modifications for authorization or revocation. Importantly, even if applyAuthorization errors out (e.g. due to validateAuthorization failure), other authorizations in the batch remain unaffected. This design minimizes denial-of-service (DoS) attacks risk in batch authorization scenarios, which is particularly useful for sponsored transactions.
During authorization validation, the node first verifies that the auth.ChainID
is 0
or matches the chain ID. It then checks that the auth.Nonce
does not exceed the maximum allowed value (2^64-1
per EIP-2681) and validates the signature values and recovers the signer address. The touched address is then added to the access list, and the node ensures the address has no code or has exisiting delegation (i.e. it's not a contract) and that the account nonce matches the provided auth.Nonce
.
Before executing the EVM call, the node marks EIP-7702 addresses as warm addresses following EIP-2929.
EIP-7702 introduces a new nonce increment path due to its inclusion of an authorization_list
. Thus adding this section for the whole landscape of nonce handling. Below is the detailed process for nonce handling:
authorization_list
, the auth.Nonce
is validated to ensure it matches the current nonce of the signing account (validation here). After successful validation, the nonce associated with the authorization is incremented (increment here).Users can use eth_getTransactionByHash
and eth_getTransactionReceipt
to query a transaction's status. The execution path for EIP-7702 transactions is identical to other transactions. The node adds special handling for EIP-7702 fields in the transaction payload. However, there are no additional fields in the transaction receipt compared to other transaction types (definition in Geth for overall receipt fields), so no special handling is required for receipts.
The above methods only confirm whether a transaction was included in a block. However, in the case of authorizations, if an authorization tuple fails validity checks, it will be skipped. An approach to maintain the latest mapping of an EOA address to its delegated code address after the transaction is included would be:
eth_getTransactionByHash
to fetch the transaction (code) and get the authorization list. For each authorization tuple, attempt recovering the authority:
eth_getCode
to query the code at the recovered address (a calling example). This will return the full code (23
bytes) of the address (different from EXTCODECOPY
, which only returns the first 2 bytes of the designator, i.e., 0xef01
), which can then be processed using ParseDelegation to determine whether the account has delegated to code (second return value) and the code address it is delegated to (first return value).As for instruction set changes, in the implementation, the node builds on the previous instruction set, adds the instruction set modifications for EIP-7702, and initializes a new instruction set that supports EIP-7702. This updated instruction set is enabled in the EVM interpreter once the hard fork is detected. The specific changes to the instruction set include:
EXTCODECOPY
only returns 0xef01
, which marks the address as a delegator EOA address by identifying it with the first two bytes of the DelegationPrefix 0xef0100
, i.e 0xef01
.EXTCODESIZE
only returns 2
, which is the byte length of 0xef01
.EXTCODEHASH
only computes the Keccak256 hash of 0xef01
.CALL
, CALLCODE
, DELEGATECALL
, and STATICCALL
will load the code from the delegated code address and execute it in the context of the smart EOA. This is achieved by retrieving the code hash and code during the execution of these opcodes. Invalid delegations (e.g. those without valid code or a precompiled contract address) will be ignored and treated as having no code.CALL
, CALLCODE
, DELEGATECALL
, STATICCALL
): These adjustments are to consider EOA address and code address accesses. Geth encapsulates this logic into a unified function and deducts the appropriate gas costs according to the EIP-2929. The gas calculation before EIP-7720 is here. The difference comes from the extra access of the delegated code address.Interacting with a smart EOA works similarly to calling a smart contract. Users simply need to set the to
field of the transactions (or the destination
field for EIP-7702 transactions) as the smart EOA address. This applies whether the call originates from an external transaction or from within another contract.
The following are protocol implementations worth noting:
tx.origin
. For detailed implementations, the proposer reads the account's code and uses ParseDelegation
to identify whether the address is a smart EOA or a contract.0xef0100 || address
(where ||
denotes concatenation), ensuring no conflict with existing contract codes. This encoding leverages EIP-3541, which rejects contract code starting with the 0xef
byte. The 0xef01
prefix ensures no conflict with 0xef00
(reserved by EIP-3540), and the 0x00
following 0xef01
is reserved to allow for potential future upgrades of EIP-7702. The delegation encoding and decoding logic is implemented here.After walking through the code with conceptual examples, let us now analyze the implementation and functionalities of EIP-7702 through concrete examples.
We use the EXP-0001 example provided by Ithaca for illustration. This example provides a concise implementation for creating wallets. Here's how it works:
odyssey_sendTransaction
interface proposed here. Its implementation is a sponsored transaction service. In a real use case, requiring users to authenticate or pass social verification (e.g. Gitcoin Passport Scorer) with rate limiting would be a first defense against Sybil attacks and losing funds.address(this)
of SC wallet is exactly the EOA address). To construct the transaction, the EOA signs the authorization information, which is then passed as part of the calldata.Following the wallet creation, users can transfer funds by signing and executing calls. The user uses the WebAuthn key to sign the contract call, and extract the needed fields in the signature based on the specific wallet implementation. The parameters are prepared and used to invoke the contract. In this demo, the transaction is sent through the odyssey_sendTransaction
interface. For an ERC-4337-compatible wallet, it can instead be constructed as a UserOperation
and sent to a bundler.
execute
function. To enhance interoperability and simplify SDK and wallet development, a standardized ERC could be designed around the multiSend
functionality.The EXP-0001 demo opens many functional possibilities. Though it is not implemented as ERC-4337-compatible, this can easily be achieved by replacing the demo’s deployed contract with an ERC-4337-compatible contract, such as Coinbase’s Smart Wallet. Thus the wallet can inherit all ERC-4337 features seamlessly.
Based on the implementation from the previous example, it is already possible to achieve account recovery. When the private key is lost, the user can simply use their registered signing key to transfer assets from the EOA account. This is particularly useful for existing EOA users who want to safeguard against losing their private key. In real usage, a more secure approach would be configuring social recovery permissions properly. For instance, instead of allowing frequently used hot signing keys to transfer all assets, a more secure setup would require signatures from multiple guardians to move the balance.
For new users, wallets can help simplify the process of configuring guardians. For example, they could offer a 2-of-3 scheme that uses:
EIP-7702 enables wallet recovery by Zero-Knowledge Proof (ZKP), through delegating to a contract that supports these functionalities. One advantage of ZKP is verifying user information without compromising privacy. For instance, the authentication can leverage OpenID providers like Google or Facebook to issue JSON Web Tokens (JWTs) as a witness for ZKP, utilizing established identity verification infrastructure.
Here's an example of a ZK recovery based on EIP-7702 provided by zklogin. To change the wallet's signing key, the user must use a new WebAuthn key to go through the login flow of an OpenID provider (in the example, Google) to obtain a JWT. This JWT is then used to generate the proof. Finally, the proof along with additional metadata from the JWT and the new WebAuthn public key are submitted to the contract to update the signing key.
Nowadays, users frequently interact with wallet prompt windows to authorize actions, which can lead to fatigue in high-frequency, low-value payment scenarios. In contrast, in traditional systems like credit cards, "trusted" subscription-based payment services can reduce the cognitive cost of authorization.
One way to simplify user operations is by separating keys for different usages (e.g. signing low permission transactions, encrypting and decrypting messages[6]) from the wallet's private key (which has the top privilege). Continuing with the example from Ithaca's EXP-0002, during wallet creation, the demo program generates a signing key using the Web Crypto API and then stores it in IndexedDB. This allows websites with the same origin as the demo to access the signing key through specific interfaces, enabling frontend applications to perform signing operations without triggering wallet prompts.
The demo does not specify the subsequent handling of the signing key. In practice, wallet clients can assign lifespans and permissions to a signing key and delegate it to a private key management service. For instance, Privy has demonstrated how to create and store a "session key" in this demo video.
EIP-7702 can help EOA users experience the functionalities of SC wallets, such as social recovery, subscriptions, etc. However, because it retains the existence of private keys, it cannot completely replace ERC-4337. For users who have applied EIP-7702, how can they fully obtain the security guarantees of SC wallets?
The author thinks that this can be achieved through compatibility patches to enable full migration to SC wallets, such as the concept of Migration Transactions proposed in EIP-7377. With slight modifications, it could support the migration of EIP-7702 accounts to SC accounts. e.g. adding a deactivated
field in the account state for deactivated EOA private keys. If users need to revoke the deactivated status, it would require the highest permissions of SC wallets, such as requiring M-of-N signatures from guardians.
The purpose of retaining the ability to "revoke the deactivated status" is to address migration scenarios that cannot be fully fulfilled through the upgrade of upgradable contracts (or the contract is not upgradable). In such cases, it would be necessary to re-enable the private key's permissions and send another EIP-7702 transaction to delegate the EOA to another code address.
For example, a user can upgrade its delegated code to fully migrate to an EVM Object Format (EOF) contract, taking advantage of the new upgrade schemes supported by EOF and removing the need for a legacy proxy contract. While EOF allows legacy to EOF paths for existing proxy contracts to be able to use EOF upgrades, removing the proxy contract can reduce transaction costs by eliminating the overhead of forwarding calls through the proxy.
Moreover, the Ethereum and L2 communities are actively discussing native AA. Assuming the Ethereum ecosystem will gradually move towards a native AA world, how compatible would EIP-7702 be with these proposals?
On L2, RIP-7560 has been designed to pioneer the experimentation and implementation of native AA on L2, along with related proposals: RIP-7711, RIP-7712, and RIP-7696. RIP-7560 integrates the tooling provided by ERC-4337 with the design of native AA in EIP-2938, introducing a new AA_TX_TYPE
transaction. Compared to ERC-4337, it enjoys the benefits of native transactions, such as eliminating the need for additional RPC interfaces, using the contract address as tx.origin
, having lower gas costs (extra gas overhead of ~42k for a basic UserOperation
compared to ~21k for a basic transaction), and benefiting from protocol-level censorship resistance mechanisms.
When RIP-7560 becomes widely adopted, users relying on ERC-4337 wallets or other wallets incompatible with RIP-7560 can update their delegated contracts using EIP-7702 to support RIP-7560's new interfaces. This is necessary because RIP-7560 introduces changes to wallet interfaces compared to ERC-4337, such as handling errors via callback functions, which aim to reduce technical debt. Users utilizing proxy contracts can alternatively upgrade the implementation address to adopt RIP-7560 interfaces, ensuring a smooth transition.
On Ethereum, EIP-7701 builds upon the design of RIP-7560 to propose a native AA mechanism. The key difference lies in the use of EOF to define entry point function interfaces, addressing technical debt caused by the current reliance on Solidity's function selectors for entry points (e.g. an idiosyncratic or malicious wallet could use unreadable function names to create the same function hash as a wallet interface). By leveraging EOF, users can upgrade their smart EOAs using EIP-7702 to ensure compatibility with EIP-7701, either by migrating to new EOF-based contracts or by updating their proxy contract's implementation address.
As discussed in this blog, wallets can implement a simple guardians strategy, such as a 2-of-3 scheme. This includes verifying the user's email address via zk-email, a local key stored on the user's device (e.g. a passkey), and a backup key held by a service provider. ↩︎
Arbitrary signing keys are actively supported in L2 through precompiled contracts like RIP-7212 and RIP-7696, enabling AA wallets to verify signatures from various key types. ↩︎
One potential approach to address these privacy concerns is to distribute a user's SBTs and on-chain activities across multiple privacy wallet addresses while maintaining a global perspective on these assets. When verification is required, zk-proofs can be submitted to prove ownership or participation, without revealing sensitive details. ↩︎
Although EIP-7702 introduces a new scenario where the EOA nonce can be incremented, the transaction pool can still handle addresses with updated nonces by monitoring newly added blocks on the node. This ensures that transactions with lower nonce will be evicted. However, once an EOA has delegated to code, anyone can call that code at any point in a transaction, breaking a widely used invariant for account balance to invalidate pending transactions with insufficient balance through iterating the senders of new blocks: EOAs have only been able to send value via a transaction. This requires the transaction pool logic to be updated accordingly. See here for more details. ↩︎
Here the demo is using viem's signAuthorization EIP-7702 experimental function. ↩︎
This is commonly seen in end-to-end encrypted messaging or email services that integrate ERC-4361: Sign-In with Ethereum, such as MetaMail. ↩︎