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
.
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. To address this gap, proposals like EIP-7851, which allow users to deactivate (and reactivate) private key permissions post-EIP-7702, will be necessary.
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? Some initial thoughts:
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 (though it will not happen in practical use cases), the nonce of each authorization must be incremented sequentially. Overall, this mechanism requires SDKs to handle nonces correctly.
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, since the authors do not expect much demand for atomic delegation and blob submission). 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, to reduce the test vectors and keep the scope of focusing on improving UX.
A well-known ban in some EIPs involves banning storage-related instructions (e.g. EIP-7562). EIP-7702 does not impose such a ban, since storage instructions are very important for SC wallets.
Further details will be introduced in the next section.
In this section, we will dig into "how an EIP-7702 transaction's journey is implemented". The code analysis focuses on the open-sourced repo Geth, one of the major Ethereum clients listed on the Client Diversity Dashboard.
We assume that the node has activated EIP-7702 throughout the discussions of this session.
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 SignSetCode function.
The user's EOA private key is required for signing. Signing involves hashing the authorization, 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 (code here) and a "Prague signer" (which adds support for EIP-7702 transactions). 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, the node validates this transaction 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
(code here). A 25000
gas cost for each authorization tuple, defined as CallNewAccountGas (named 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
(code 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 in batch authorization scenarios, which is particularly useful for sponsored transactions.
During authorization validation, the node first verifies that the auth.ChainID
chain ID is null or equal to current 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 (a concept from 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). For 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 here) and get the authorization list. For each authorization tuple, attempt recovering the authority:
eth_getCode
to query the code at the recovered address (a code snippet to call it). The API will return the code of the address, 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:
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. addresses without code or precompiled contract addresses) 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-7702 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 need to set the to
field of the transactions (or named destination
field for EIP-7702 transactions) as the smart EOA address. This applies whether the call originates from an external transaction or 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 "imaginary" 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 production, requiring users to authenticate or pass social verification (e.g. Gitcoin Passport Scorer) with rate limiting would be a first line of defense against Sybil attacks.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 contract) development, there is a draft-ERC-7638 to unify batch call encoding.The EXP-0001 demo opens many functional possibilities. Though it is not implemented as ERC-4337-compatible, this can be achieved by replacing the demo’s deployed contract with an ERC-4337 and EIP-7702 compatible contract. There are some work-in-progresses to support ERC-4337 and EIP-7702 in the meantime, such as EIP-7702 support for Safe Smart Account.
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. For a life-saving wallet, a more secure approach would be to configure social recovery permissions properly, instead of a single signing key in EXP-0001 demo.
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, small-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[5]) from the wallet's private key (which has the top privilege). Taking Ithaca's EXP-0002 as an example, 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.
EXP-0002 is a very simple PoC, and there is another EXP-0003 demo which (i) integrates essential conceptual components (a user client for signing authorizations, a server for key management, a wallet SDK for interaction with each parties) for session keys in smart EOAs to work; (ii) allowing setting granular control over delegated actions via permission rules.
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. A draft-EIP-7851 enables users to deactivate their private keys of smart EOAs through a precompiled contract (only after the address is delegated), and they can further deactivate their private keys through invoking the same precompiled contract using the delegated contract, which enables flexible re-delegations.
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 L2s, RIP-7560 has been designed to pioneer the experimentation and implementation of native AA, along with related proposals: RIP-7711, RIP-7712, etc. RIP-7560 integrates the tooling provided by ERC-4337, combined with partial 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 might be 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 focus lies in: (i) defining formal entry point function interfaces, e.g. addressing technical debt caused by the current reliance on Solidity's function selectors for entry points (an idiosyncratic or malicious wallet could use unreadable function names to create the same function hash as a wallet interface); (ii) designing "what more are we in" opcodes. Users can optionally upgrade their smart EOAs using EIP-7702 to EIP-7701 compatible wallet implementations after EIP-7701 is rolled out.
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. ↩︎
EIP-7702 breaks two invariances: (1) a new scenario where the EOA nonce can be incremented, and (2) anyone can call the delegated code at any point in a transaction, breaking a claim that an EOA's balance can only be decreased by the transaction sender. Since the invariances are widely used in transaction pool's static checks, these changes require the transaction pool logic to be updated accordingly. For example, transaction pools may only accept one pending transaction for delegated EOAs to minimize invalidation risks. See here for more details. ↩︎
This is commonly seen in end-to-end encrypted messaging or email services that integrate ERC-4361: Sign-In with Ethereum, such as MetaMail. ↩︎