Account abstraction seeks to improve user and developer experiences across the entire Ethereum ecosystem. Along with making on-chain experiences more accessible and enjoyable to users, it also empowers developers to be able to do more powerful things on Ethereum and serve users in even more meaningful ways.
Our classification of the approaches to account abstraction is as follows:
This approach features mechanisms which allow an EOA to transition to a CA, without having to move its assets, such as EIP 7377 and EIP 5003 (when considered alongside EIP 3074).
Various proposals have been previously made for the creation of smart accounts and account abstraction enshrinement at the protocol level; EIP-86 and EIP-2938 are some of the more cited ones. However, there was a lot of pushback due to the perceived complexity introduced by this design and the somewhat majority opinion that Ethereum isn’t ready for such complexity.
Following Vitalik’s revival of the topic after The Merge, ERC-4337 was proposed as an opt-in version of the smart account standard, similar to the PBS (Proposer-Builder Separation) infrastructure for MEV (Maximal Extractable Value). Thus, users who seek to access the benefits of smart accounts could simply use the ERC-4337 pipeline to redefine their account’s logic and transactions’ validity rules in structures referred to as a UserOperation (or UserOps for short).
ERC 4337 brings the benefits of smart accounts to present day Ethereum without enshrining any of the complexity, by functioning as an out-of-protocol alternative to enshrined smart accounts. However, this doesn’t mean that the infrastructure is optimal in its current state as its own complexity is still a considerable point-of-failure.
To address this complexity, RIP 7560 was drafted as an enshrined version of the ERC 4337 infrastructure across Ethereum and its L2s, so that it inherits the network’s sybil-resistance schemes rather than having to define a new suite of rules (as ERC 4337 does with ERC 7562).
In this report, we will be focused on exploring EOA programmability, evaluating the various EIPs that describe solutions along this line and discuss their merits and drawbacks. In Part 2 and 3 of this series, we will cover the remaining two classes of approach to account abstraction being explored within Ethereum.
In order to seek out what can be abstracted, we need a (somewhat) full picture of the current account design. This section will mostly serve as a revision of sorts for what accounts on Ethereum actually are, and how their transactions are validated and executed.
Ethereum accounts are entities with an ether (ETH) balance and the ability to send transactions on the Ethereum blockchain. They are represented as a 42-character hexadecimal “address”, which serves as a unique pointer to the account’s holdings and transactions.
An address acts as a key into the blockchain’s state trie. The leaf nodes of this trie are account data structures which can be decomposed into four fields:
The contents of these four fields are used to define an account’s type, and ultimately go on to define the extent of its functionalities. Thus, the two types of Ethereum accounts are:
EOAs have empty codeHash and storageHash fields and can only be controlled by anyone who possesses the private keys. Their addresses can be obtained from the corresponding public key by prefixing “0x” to the last twenty characters of the account’s public key’s keccak-256 hash.
Their transactions are entirely pull-based and predicated on their deployed code’s logic.
Since these accounts can only be controlled by their code content, they have no need for a private key and only have a public key. Thus, any agent who has the ability to update/change a contract account’s code content would be able to access its balance.
The address of a CA is derived from its creator’s address and its nonce up to the point of the contract’s deployment.
Transactions
We recently described accounts as entities that possess the ability to send transactions across Ethereum. We can therefore understand that a primary purpose of an account is to send and receive transactions, while the blockchain acts as a ledger recording history of transactions as well as describing how transactions alter account fields based on rules described in the blockchain protocol specification.
So what are these “transactions”?
Transactions are operations sent from an account, which cause a change in the “state” of the network. They are cryptographically signed instructions from accounts, which result in a network-wide state update when executed.
Permissionlessness comes with the cost of perverse incentives, to deal with these, stringent guidelines (or validity rules) have to be defined for interactions in such environments.
In this context, transactions have to follow certain validity rules to be considered valid and executed. Most of these validity rules are implemented via constraints placed on the account sending the transaction, and vary based on what type of account it is.
On Ethereum, EOAs are optimized for usability as they are end-user facing. They have the ability to send transactions in a specific manner and perfectly operate autonomously. They can also be created locally, the more common method being the use of wallet providers such as MetaMask, Rainbow, Rabby etc.
On the other hand, contract accounts can only send transactions permitted by their logic, in response to being “called”. Also, they can only be created by an EOA which has a sufficient balance to pay for its state storage.
A more high-level description would be that EOAs can only hold a balance, while CAs can hold both a balance and logic that dictates how this balance can be spent.
These properties are due to the following logic parameters which define the rules an account’s transactions must adhere to:
These parameters are designed to be rigid for EOAs thus:
More generally, the execution logic of EOAs constricts them to one transaction per valid signature.
On the other hand, CAs have more flexibility around these parameters:
In most practical cases, the logic used in this case is a multi-signature scheme which stipulates that an M of N valid signatures (where M < N) is required from specific accounts (commonly EOAs) in order for a change of the CA’s logic to be valid.
Evaluating these features, we observe that each type of account is designed to have a tradeoff between autonomy and programmability.
EOAs have full autonomy but limited programmability; they can authorize and send transactions whenever they want, but these transactions must follow a rigid format to be considered valid. CAs have full programmability (limited only by the EVM’s design) but limited autonomy; their transactions do not have to follow any rigid format, but can only be sent out due to their logic being called first.
In the following subsection, we will now study the implications of these design choices, in order to fully understand the proposition of each discussed EIP throughout this series.
Now that we have a somewhat succinct knowledge of the different accounts’ functionalities, we can easily identify their selling points as well as the issues they present to both user- and developer-experience on Ethereum.
As we previously mentioned, EOAs are designed as first-class accounts targeting end-users. Applications are designed to easily interact with them, there’s almost no complexity to them, and of course there’s no cost for creating one. However, its simplicity comes with a significant loss of novelty as they are designed to be strictly deterministic.
Some of the concerns around them are:
Not everyone wants to (or would be able to) always hold ETH (i mean look at that price action), so the viable solutions would be to either allow multiple gas currencies (too hard, breaks too many invariants as described in the “Currency” section here), or to allow gas payments to be settled by another account that isn’t the transaction’s origin.
On the other end of the account spectrum, CAs target developers and a more technical user base. They serve as vehicles for smart contracts (i.e. we consider smart contracts to be their contained logic or code content) and so can implement novel transaction formats as enabled by the EVM.
However, for all these features they are glorified second-class accounts since they have no autonomy. Some of their drawbacks are as follows:
Having reviewed the design choices which led to the issues defined in this subsection, we can now proceed to evaluate the proposed solutions.
The concept of account abstraction (via smart accounts at least) has always been an integral part of Ethereum’s roadmap. The lore is that the complexity surrounding its implementation threatened to further delay Ethereum’s launch, and so it was scrapped for the current design with different accounts offering different functionalities. It was delayed again by Ethereum’s focus on The Merge, and is now resurfacing as a principal part of the network’s next major upgrade– Pectra. However, its complexity is still considered a significant drawback preventing its enshrinement, especially as Ethereum has pivoted to a rollup-centric roadmap.
The requirements are now two-fold:
Intuitively this concept plays a bigger role in the context of chain abstraction and interoperability, however our scope throughout this report is limited to the technical initiatives taken to achieve account abstraction itself.
Account abstraction aims to combine the best features of EOAs and CAs into a new account standard– smart accounts, which allow full or partial separation of any account’s validity rules into a validation logic and an execution one; so that accounts can define their own validity rules –as permitted by the EVM– just like contract accounts, while remaining fully autonomous just like externally-owned accounts.
There is often confusion around the differences between smart accounts and smart contract wallets so let’s explicitly describe what these differences are below:
The commercialisation of smart contract wallets eased the adoption of CAs by a wider market, allowing less technical users to take advantage of the features they offer. However, they still face the pitfalls associated with CAs.
Back to the conversation; we had previously discussed the parameters which are used to define the validity rules of transactions of accounts:
The values of the first four parameters may collectively be referred to as an account’s validation logic, which are checks that occur before a transaction’s execution begins.
The last parameter defines how the execution of the transaction is to proceed.
In the introduction, we provided a high-level overview of the current AA landscape in the form of a classification of sorts for the various proposed designs. We will now focus on the first class of solutions to Ethereum’s account dilemma- EOA programmability.
Ethereum’s biggest appeal is its young but vibrant DeFi ecosystem which features a variety of decentralized applications that are its primary liquidity sinks. Most of these DApps are optimized to serve EOAs, thus they are hard to interface with CAs, and eventually smart accounts. While smart contract wallets do help CAs in this case, they come with their own limitations and an entirely different UX.
An interim solution being explored while both DApps and wallet providers get used to the smart account standard, is to provide temporary enhancements to EOAs that enable them to overcome most of their imposed restrictions, be it their validation or execution logic.
Below, we go over the specifications of three major EIPs which provide actionable routes to EOA programmability; from the less known EIP 5806, to the ambitious EIP 3074 and then finally to the victorious EIP 7702.
This proposal seeks to bring more functionality to the EOA standard by allowing it to perform delegate calls to a contract account’s logic (its smart contract). This effectively causes the smart contract to be executed in the context of the caller EOA, i.e., the EOA remains in control of its validation logic, while its execution logic is handled by the corresponding CA’s logic.
Before we proceed any further, let us take a trip down the Ethereum evolution memory lane to EIP-7.
EIP-7 proposed the creation of the 0xf4/DELEGATECALL opcode, which is used to send message calls into a primary account with a secondary account’s logic, while maintaining the values of the primary account’s [sender] and [value] fields.
In other words, the primary account “inherits” (or borrows if you prefer) the logic of the secondary account for some duration as specified in the message call, so that the latter’s logic is executed in the context of the former.
This opcode allowed dApp developers to split their application’s logic into multiple smart contracts while maintaining interdependence, so that they could easily skirt around code size barriers and gas barriers.
Okay, so what delegate calls allow CAs to be interdependent? Well EIP-5806 uses EIP-7 as an inspiration to propose the expansion of the delegate call functionality to EOAs as well; i.e., let us allow EOAs to also be interdependent with CAs, because why not.
EIP 5806 introduces a new EIP-2718-compliant transaction type which is packed as follows:
rlp([chainID, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, data, access_list, signature_y_parity, signature_r, signature_s]).
These transactions are designed so that the [to] field – which represents the recipient’s address – can only accept addresses as 20-byte inputs, disabling the sender from using the CREATE opcode.
The motivation behind each component of the RLP scheme are as follows:
While the packing of EIP-5806 transactions in EIP-2718 envelopes allows them to be greatly backwards compatible, EOAs aren’t equivalent to CAs. So certain restrictions must be defined in the way an EOA utilizes delegate calls to prevent invariant breakage.
These restrictions are targeted at the following opcodes:
The primary applicability of EIP 5806 is execution abstraction for EOAs. Allowing EOAs to trustlessly interact with smart contracts beyond simple calls to their logic grants them features such as:
The changes proposed by EIP-5806, while enabling needed features, aren’t particularly novel; its existence is mostly predicated on an already functional EIP-7. This allows it to bypass many potential hurdles to acceptance.
One of the major concerns voiced in its early days was the potential risk of allowing EOAs to access storage and change it, just like CAs currently do. This breaks a lot of network-enshrined invariants concerning how EOAs are to transact, and so was dealt with by introducing the restrictions mentioned in the previous subsection.
A second criticism (which is a bit of a double-edged sword) is the simplicity of EIP-5806; there’s some sentiment that the rewards due to accepting EIP-5806 might not be worth the cost, since it only enables execution abstraction and not much else. Every other validity restriction remains network-defined for EOAs which opt in to EIP-5806, in contrast to other somewhat similar EIPs which we discuss in the following subsections.
EIP-3074 proposes to allow EOAs to delegate most of their validation logic to specialized contract accounts, referred to as invokers, by superimposing the latter’s authorization logic over theirs for specific forms of transactions.
It achieves this by signing over their access policy to an invoker contract, which then becomes responsible for defining the EOA’s access policy.
This EIP proposes the addition of two new opcodes to the EVM:
These two opcodes allow an EOA to delegate control to a pre-established CA, and thus, act as one through it, without having to deploy a contract and incur the costs and externalities associated with that.
EIP-3074 allows transactions to use a [MAGIC] signing format to prevent collisions with other transaction signing formats. The active account to which [AUTHCALL] instructions are passed is defined as a context-variable field named [authorized], which only persists through a single transaction and must be redefined for every new [AUTHCALL].
Before addressing the complexities of each opcode, these are the entities involved in a EIP-3074 transaction:
Invoker contracts receive [AUTH] messages with a [COMMIT] value from [authority]; this value defines the restrictions the account wishes to place on [authorized]’s execution of [AUTHCALL] instructions.
Thus, invokers are responsible for ensuring that the [contract_code] defined in an [authorized] account is not malicious and has the ability to satisfy the invariants placed by the primary signing account in a [COMMIT] value.
The [AUTH] opcode has three stack element inputs; or more simply — it is defined by three inputs which compute a single output. These inputs are:
The last two inputs are used to describe a range of modifiable memory from 0 to 97, where:
The variables [yParity], [r] and [s] are collectively interpreted as an ECDSA signature, [magic], on the secp256k1 curve over the message:
[keccak256 (MAGIC || chainID || nonce || invoker address || COMMIT)]
where:
If the computed signature is valid and the signer’s address equal to [authority], the [authorized] field is updated to the value provided by [authority]. If any of these requirements aren’t satisfied, the [authorized] field remains unchanged in its previous state, or as an unset value.
The gas cost for this opcode is computed as the sum of:
[AUTH] is implemented to not modify memory, and takes [authority]’s value as an argument so that it is trivial to verify its value from the provided signature.
The [AUTHCALL] opcode has seven stack element inputs which are used to compute a single stack element output.
It has the same logic as the [CALL] opcode, i.e.; it is used to send message-calls into an account and trigger specific logic in its contracts. The only deviation in their logic is that [AUTHCALL] is designed to set the [CALLER]’s value before proceeding with execution.
Thus, [AUTHCALL] is used by the [authority] to trigger context-specific behavior in [authorized] with logical checks proceeding as follows:
The gas cost for [AUTHCALL] is computed as the sum of:
The data returned from an [AUTHCALL] is accessed through:
To bring it all together with much less of the tech-speak; Ethereum transactions typically specify two values:
In EOAs, as previously mentioned, authorization is tightly coupled with execution, i.e.; (tx.origin == msg.sender). This simple invariant gives rise to most of the issues we explained in the “Accounts and Transaction Validity” subsection of this report.
[AUTH] messages from [authority] allows it to offset the tx.origin function to [authorized], while remaining the msg.sender. It also allows it to define restrictions to this privilege using a [COMMIT] value.
[AUTHCALL] then allows [authorized] to access a contract’s logic, using an [invoker] as an intermediary to ensure the contract it wishes to access is harmless. That is, for every [AUTHCALL], [authorized] is to specify a particular [invoker] for their [COMMIT].
EIP 3074 is primarily responsible for allowing EOAs to delegate their authorization logic to a different account, however its open design enables a lot more in different contexts.
The entire validation logic of an EOA can be abstracted by applying various constrictions/innovations to the invoker as necessary, some of the possible designs based on their target logic include:
Also, execution logic is intuitively abstracted; after all the invoker (which is a CA) is now responsible for executing transaction requests on behalf of the EOA.
Quoting one of its authors: “I would not expect wallets to expose functionality to sign over arbitrary invokers …”. Perhaps the biggest problem poised by the 3074 initiative is that innovation atop it will very easily tend to permissioned and proprietary deal flows; just like the current iterations of Ethereum’s MEV and PBS markets.
By default, invoker contracts need to be greatly audited in order to prevent even worse attacks than are currently possible. This will inevitably tend to an ecosystem where only a handful of invoker contracts developed by influential figures will be adopted as the default for wallet developers. Thus, it boils down to a tradeoff between taking the hard decentralized pathway of constantly auditing and supporting invoker contracts at the risk of users’ security; or simply adopting invoker contracts from established and reputable sources with better guarantees for user security and less oversight on the contract’s safety.
Another aspect of this point is the cost function associated with designing, auditing, and marketing a functional and safe invoker. Smaller teams will almost always be outdone by bigger organizations –especially on the marketing front– which already have some established reputation, even if their product is better.
EIP-3074 entrenches the ECDSA signature scheme, since it is still considered more valid than the authorization scheme introduced via the invoker. While there are arguments that quantum-resistance isn’t currently a definitive problem, and that there’s much worse at stake in a future where ECDSA is corruptible; Ethereum’s somewhat unstated aim is to always be ahead of such problems. Potentially sacrificing quantum- and censorship-resistance for marginal improvements in UX might not be the best of choices in the near future.
Another point on the forward-compatibility argument is that while the benefits of 3074 were still being assessed, ERC-4337 (which doesn’t require any protocol changes) now has a great market, so you have to be compatible with it too to avoid compartmentalisation of ecosystems.
Even with the native account abstraction roadmap, the [AUTH] and [AUTHCALL] opcodes would eventually become obsolete in the EVM, introducing a great deal of technical debt to Ethereum in order to deliver a marginal amount of UX improvement.
After sending an [AUTH] message and delegating control, the EOA is expected to avoid the usual private key authorization scheme, as sending out a “normal” transaction causes the authorization it delegated to every invoker to be revoked.
Thus, the ECDSA scheme remains strictly superior to any other authorization scheme which the associated contracts may enable, meaning that a loss of private keys would result in a total loss of the account’s assets.
This proposal had initially set out as a somewhat minimalistic variation of EIP 3074, and was even meant to be an update to it. It was birthed to address the supposed inefficiencies of EIP 3074, especially the concerns around its incompatibility with the already flourishing 4337 ecosystem and the native account abstraction proposal– RIP 7560.
Its approach is the addition of a new EIP 2718-compliant transaction type –[SET_CODE_TX_TYPE]– which allows an EOA to behave as a smart account for specified transactions.
This design enables the same features as EIP 5806 and some more, while remaining compatible with the native account abstraction roadmap and existing initiatives.
EIP-7702 allows an EOA to “import” the code content of a contract through a [SET_CODE_TX_TYPE] 2718-compliant transaction of the format:
rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, value, data, access_list, authorization_list, signature_y_parity, signature_r, signature_s])
This payload is entirely similar to that of EIP 5806, except that it introduces an “authorization list”. This list is an ordered sequence of values of format:
[[chain_id, address, nonce, y_parity, r, s], …]
where each tuple defines the [address]’ value.
Before proceeding, the parties involved in a SET_CODE_TX_TYPE are:
When [authority] signs a SET_CODE_TX_TYPE specifying [address], a delegation designator is created. This is a “pointer programme” which causes all code retrieval requests due to the [authority]’s actions at any instant to be channeled to [address]’ observable code.
For each [chain_id, address, nonce, y_parity, r, s] tuple, the logic flow of a 7702-type transaction is as follows:
Phew! To tie it all back; this EIP allows EOAs to send transactions which set a pointer to a contract’s code, allowing them to implement this logic as their own in subsequent transactions. In this way it is strictly stronger than EIP 5806, because it allows EOAs to actually have code content for as long as they want (as opposed to EIP 5806 which simply allows EOAs to send delegate-calls).
While it could be argued that it isn’t an abstraction anymore since the EOA actively takes in the logic it wishes to execute, it still isn’t the “primary owner” of said logic. Also, it doesn’t directly contain logic, it simply specifies a pointer to the logic (in order to reduce computational complexity). So we’re going with execution abstraction!
While the require(msg.sender == tx.origin) invariant is broken to allow self-sponsorship, the EIP still allows the integrations of sponsored transaction relayers. However, the caveat is that such relayers need a reputation- or stake-based system in order to prevent griefing attacks.
EOAs can point only to a specific portion of the account’s code, so that only the logic of that portion is executable in their context.
This also enables the existence of sub keys which go on to enable “privilege de-escalation”, so that specific dAPPs only have access to an account’s balance under specific conditions. For example, you could imagine a permission to spend ERC-20 tokens but not ETH, or to spend up to 1% of the total balance per day, or to interact only with a specific applications.
Due to its non-restrictive nature, a EIP-7702 transaction could allow a user to access the CREATE2 opcode and use it to deploy bytecode to an address without any other restrictive parameters such as fee market logic (e.g. EIP-1559 and EIP-4844). This allows the address to be recovered and used across multiple state machines, with the same bytecode, where its account on each chain is then responsible for defining the other context-variable parameters.
While EIP-7702 is still very recent, there’s already been a lot of prototyping and testing for its dependencies and potential disadvantages, but its minimalistic model guarantees it a lot of flexibility, and thus utility, in different contexts. However it breaks way too many invariants and isn’t immediately backwards compatible.
Some of its logic includes:
Most users aren’t savvy to the actual contents of an account (or even the difference between an account and an address!), so that allowing address collisions means that an EOA could masquerade as a CA and attract user funds in a long-winded bit to eventually steal it all. EIP-3607 addressed this by stipulating that accounts which contain code should not be able to spend their balance using their own authorization logic. However, EIP 7702 breaks this invariant in order to enable EOAs to remain autonomous even after gaining some programmability.
Signing over an account’s address instead of its code content is basically just like 3074’s scheme with invokers. It doesn’t provide strict guarantees around cross-chain code content consistency, since an address could take on a different code content on different chains. This means that an address whose code content contains the same logic on one chain could be predatory or outright malicious on another chain, and this could lead to loss of user funds.
EOAs in their current form today are greatly limited as they don’t allow users to take advantage of the programmability features offered by the EVM. While there are various paths to upgrading accounts, as we outlined in the beginning of this report, the chosen solution has to maintain the principles of safe and secure self custody. Furthermore EOA upgrades may significantly impact both the user experience and application developers so all stakeholder voices must be considered.
Allowing EOAs to execute code in any manner immensely expands the functionality of accounts, but this new expressibility comes with meaningful risks and possible blindsides. Solving these tradeoffs is critical to delivering an upgrade with uncontested UX benefits for Ethereum users.
Ethereum’s culture of open discussion makes it a great testing ground for such innovations since almost every implication of every design is thoroughly deconstructed by subject experts. This comprehensive consideration should help mitigate risks of malfeasance from adversaries.
EIP-7702 is currently the poster child for mechanisms that seek to bring EVM programmability to EOAs, having been marked as a replacement for EIP 3074’s slot in the Pectra upgrade. It inherits the open design of 3074’s mechanism while greatly lowering the attack surface / risks. It also enables a lot more by avoiding 3074’s restrictions to certain classes of opcodes.
While there’s still some refinements being done on the proposal’s design, it has already garnered a lot of goodwill and support from developers, especially since it directly has Vitalik backing it.
Within the community there are claims that this approach to account abstraction might even be better than smart accounts. This commentary emphasizes that this path requires less changes and isn’t as complex, and that EOAs are already enshrined. However, we must remember the future security milestone of quantum resistance at every level of the Ethereum network. This quantum safety is infeasible with the current account model core due to the utilization of ECDSA-based signature schemes for EOA authorization.
Thus, EOA programmability is to be seen as a step along the path to smart accounts and not the destination. It supercharges EOAs and enables better user- and developer-experience, while remaining compatible with the ultimate account abstraction goal of smart accounts.
In our next report, we will be diving into EOA migration schemes to see how well they fit on the account abstraction roadmap, stay tuned!
Account abstraction seeks to improve user and developer experiences across the entire Ethereum ecosystem. Along with making on-chain experiences more accessible and enjoyable to users, it also empowers developers to be able to do more powerful things on Ethereum and serve users in even more meaningful ways.
Our classification of the approaches to account abstraction is as follows:
This approach features mechanisms which allow an EOA to transition to a CA, without having to move its assets, such as EIP 7377 and EIP 5003 (when considered alongside EIP 3074).
Various proposals have been previously made for the creation of smart accounts and account abstraction enshrinement at the protocol level; EIP-86 and EIP-2938 are some of the more cited ones. However, there was a lot of pushback due to the perceived complexity introduced by this design and the somewhat majority opinion that Ethereum isn’t ready for such complexity.
Following Vitalik’s revival of the topic after The Merge, ERC-4337 was proposed as an opt-in version of the smart account standard, similar to the PBS (Proposer-Builder Separation) infrastructure for MEV (Maximal Extractable Value). Thus, users who seek to access the benefits of smart accounts could simply use the ERC-4337 pipeline to redefine their account’s logic and transactions’ validity rules in structures referred to as a UserOperation (or UserOps for short).
ERC 4337 brings the benefits of smart accounts to present day Ethereum without enshrining any of the complexity, by functioning as an out-of-protocol alternative to enshrined smart accounts. However, this doesn’t mean that the infrastructure is optimal in its current state as its own complexity is still a considerable point-of-failure.
To address this complexity, RIP 7560 was drafted as an enshrined version of the ERC 4337 infrastructure across Ethereum and its L2s, so that it inherits the network’s sybil-resistance schemes rather than having to define a new suite of rules (as ERC 4337 does with ERC 7562).
In this report, we will be focused on exploring EOA programmability, evaluating the various EIPs that describe solutions along this line and discuss their merits and drawbacks. In Part 2 and 3 of this series, we will cover the remaining two classes of approach to account abstraction being explored within Ethereum.
In order to seek out what can be abstracted, we need a (somewhat) full picture of the current account design. This section will mostly serve as a revision of sorts for what accounts on Ethereum actually are, and how their transactions are validated and executed.
Ethereum accounts are entities with an ether (ETH) balance and the ability to send transactions on the Ethereum blockchain. They are represented as a 42-character hexadecimal “address”, which serves as a unique pointer to the account’s holdings and transactions.
An address acts as a key into the blockchain’s state trie. The leaf nodes of this trie are account data structures which can be decomposed into four fields:
The contents of these four fields are used to define an account’s type, and ultimately go on to define the extent of its functionalities. Thus, the two types of Ethereum accounts are:
EOAs have empty codeHash and storageHash fields and can only be controlled by anyone who possesses the private keys. Their addresses can be obtained from the corresponding public key by prefixing “0x” to the last twenty characters of the account’s public key’s keccak-256 hash.
Their transactions are entirely pull-based and predicated on their deployed code’s logic.
Since these accounts can only be controlled by their code content, they have no need for a private key and only have a public key. Thus, any agent who has the ability to update/change a contract account’s code content would be able to access its balance.
The address of a CA is derived from its creator’s address and its nonce up to the point of the contract’s deployment.
Transactions
We recently described accounts as entities that possess the ability to send transactions across Ethereum. We can therefore understand that a primary purpose of an account is to send and receive transactions, while the blockchain acts as a ledger recording history of transactions as well as describing how transactions alter account fields based on rules described in the blockchain protocol specification.
So what are these “transactions”?
Transactions are operations sent from an account, which cause a change in the “state” of the network. They are cryptographically signed instructions from accounts, which result in a network-wide state update when executed.
Permissionlessness comes with the cost of perverse incentives, to deal with these, stringent guidelines (or validity rules) have to be defined for interactions in such environments.
In this context, transactions have to follow certain validity rules to be considered valid and executed. Most of these validity rules are implemented via constraints placed on the account sending the transaction, and vary based on what type of account it is.
On Ethereum, EOAs are optimized for usability as they are end-user facing. They have the ability to send transactions in a specific manner and perfectly operate autonomously. They can also be created locally, the more common method being the use of wallet providers such as MetaMask, Rainbow, Rabby etc.
On the other hand, contract accounts can only send transactions permitted by their logic, in response to being “called”. Also, they can only be created by an EOA which has a sufficient balance to pay for its state storage.
A more high-level description would be that EOAs can only hold a balance, while CAs can hold both a balance and logic that dictates how this balance can be spent.
These properties are due to the following logic parameters which define the rules an account’s transactions must adhere to:
These parameters are designed to be rigid for EOAs thus:
More generally, the execution logic of EOAs constricts them to one transaction per valid signature.
On the other hand, CAs have more flexibility around these parameters:
In most practical cases, the logic used in this case is a multi-signature scheme which stipulates that an M of N valid signatures (where M < N) is required from specific accounts (commonly EOAs) in order for a change of the CA’s logic to be valid.
Evaluating these features, we observe that each type of account is designed to have a tradeoff between autonomy and programmability.
EOAs have full autonomy but limited programmability; they can authorize and send transactions whenever they want, but these transactions must follow a rigid format to be considered valid. CAs have full programmability (limited only by the EVM’s design) but limited autonomy; their transactions do not have to follow any rigid format, but can only be sent out due to their logic being called first.
In the following subsection, we will now study the implications of these design choices, in order to fully understand the proposition of each discussed EIP throughout this series.
Now that we have a somewhat succinct knowledge of the different accounts’ functionalities, we can easily identify their selling points as well as the issues they present to both user- and developer-experience on Ethereum.
As we previously mentioned, EOAs are designed as first-class accounts targeting end-users. Applications are designed to easily interact with them, there’s almost no complexity to them, and of course there’s no cost for creating one. However, its simplicity comes with a significant loss of novelty as they are designed to be strictly deterministic.
Some of the concerns around them are:
Not everyone wants to (or would be able to) always hold ETH (i mean look at that price action), so the viable solutions would be to either allow multiple gas currencies (too hard, breaks too many invariants as described in the “Currency” section here), or to allow gas payments to be settled by another account that isn’t the transaction’s origin.
On the other end of the account spectrum, CAs target developers and a more technical user base. They serve as vehicles for smart contracts (i.e. we consider smart contracts to be their contained logic or code content) and so can implement novel transaction formats as enabled by the EVM.
However, for all these features they are glorified second-class accounts since they have no autonomy. Some of their drawbacks are as follows:
Having reviewed the design choices which led to the issues defined in this subsection, we can now proceed to evaluate the proposed solutions.
The concept of account abstraction (via smart accounts at least) has always been an integral part of Ethereum’s roadmap. The lore is that the complexity surrounding its implementation threatened to further delay Ethereum’s launch, and so it was scrapped for the current design with different accounts offering different functionalities. It was delayed again by Ethereum’s focus on The Merge, and is now resurfacing as a principal part of the network’s next major upgrade– Pectra. However, its complexity is still considered a significant drawback preventing its enshrinement, especially as Ethereum has pivoted to a rollup-centric roadmap.
The requirements are now two-fold:
Intuitively this concept plays a bigger role in the context of chain abstraction and interoperability, however our scope throughout this report is limited to the technical initiatives taken to achieve account abstraction itself.
Account abstraction aims to combine the best features of EOAs and CAs into a new account standard– smart accounts, which allow full or partial separation of any account’s validity rules into a validation logic and an execution one; so that accounts can define their own validity rules –as permitted by the EVM– just like contract accounts, while remaining fully autonomous just like externally-owned accounts.
There is often confusion around the differences between smart accounts and smart contract wallets so let’s explicitly describe what these differences are below:
The commercialisation of smart contract wallets eased the adoption of CAs by a wider market, allowing less technical users to take advantage of the features they offer. However, they still face the pitfalls associated with CAs.
Back to the conversation; we had previously discussed the parameters which are used to define the validity rules of transactions of accounts:
The values of the first four parameters may collectively be referred to as an account’s validation logic, which are checks that occur before a transaction’s execution begins.
The last parameter defines how the execution of the transaction is to proceed.
In the introduction, we provided a high-level overview of the current AA landscape in the form of a classification of sorts for the various proposed designs. We will now focus on the first class of solutions to Ethereum’s account dilemma- EOA programmability.
Ethereum’s biggest appeal is its young but vibrant DeFi ecosystem which features a variety of decentralized applications that are its primary liquidity sinks. Most of these DApps are optimized to serve EOAs, thus they are hard to interface with CAs, and eventually smart accounts. While smart contract wallets do help CAs in this case, they come with their own limitations and an entirely different UX.
An interim solution being explored while both DApps and wallet providers get used to the smart account standard, is to provide temporary enhancements to EOAs that enable them to overcome most of their imposed restrictions, be it their validation or execution logic.
Below, we go over the specifications of three major EIPs which provide actionable routes to EOA programmability; from the less known EIP 5806, to the ambitious EIP 3074 and then finally to the victorious EIP 7702.
This proposal seeks to bring more functionality to the EOA standard by allowing it to perform delegate calls to a contract account’s logic (its smart contract). This effectively causes the smart contract to be executed in the context of the caller EOA, i.e., the EOA remains in control of its validation logic, while its execution logic is handled by the corresponding CA’s logic.
Before we proceed any further, let us take a trip down the Ethereum evolution memory lane to EIP-7.
EIP-7 proposed the creation of the 0xf4/DELEGATECALL opcode, which is used to send message calls into a primary account with a secondary account’s logic, while maintaining the values of the primary account’s [sender] and [value] fields.
In other words, the primary account “inherits” (or borrows if you prefer) the logic of the secondary account for some duration as specified in the message call, so that the latter’s logic is executed in the context of the former.
This opcode allowed dApp developers to split their application’s logic into multiple smart contracts while maintaining interdependence, so that they could easily skirt around code size barriers and gas barriers.
Okay, so what delegate calls allow CAs to be interdependent? Well EIP-5806 uses EIP-7 as an inspiration to propose the expansion of the delegate call functionality to EOAs as well; i.e., let us allow EOAs to also be interdependent with CAs, because why not.
EIP 5806 introduces a new EIP-2718-compliant transaction type which is packed as follows:
rlp([chainID, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, data, access_list, signature_y_parity, signature_r, signature_s]).
These transactions are designed so that the [to] field – which represents the recipient’s address – can only accept addresses as 20-byte inputs, disabling the sender from using the CREATE opcode.
The motivation behind each component of the RLP scheme are as follows:
While the packing of EIP-5806 transactions in EIP-2718 envelopes allows them to be greatly backwards compatible, EOAs aren’t equivalent to CAs. So certain restrictions must be defined in the way an EOA utilizes delegate calls to prevent invariant breakage.
These restrictions are targeted at the following opcodes:
The primary applicability of EIP 5806 is execution abstraction for EOAs. Allowing EOAs to trustlessly interact with smart contracts beyond simple calls to their logic grants them features such as:
The changes proposed by EIP-5806, while enabling needed features, aren’t particularly novel; its existence is mostly predicated on an already functional EIP-7. This allows it to bypass many potential hurdles to acceptance.
One of the major concerns voiced in its early days was the potential risk of allowing EOAs to access storage and change it, just like CAs currently do. This breaks a lot of network-enshrined invariants concerning how EOAs are to transact, and so was dealt with by introducing the restrictions mentioned in the previous subsection.
A second criticism (which is a bit of a double-edged sword) is the simplicity of EIP-5806; there’s some sentiment that the rewards due to accepting EIP-5806 might not be worth the cost, since it only enables execution abstraction and not much else. Every other validity restriction remains network-defined for EOAs which opt in to EIP-5806, in contrast to other somewhat similar EIPs which we discuss in the following subsections.
EIP-3074 proposes to allow EOAs to delegate most of their validation logic to specialized contract accounts, referred to as invokers, by superimposing the latter’s authorization logic over theirs for specific forms of transactions.
It achieves this by signing over their access policy to an invoker contract, which then becomes responsible for defining the EOA’s access policy.
This EIP proposes the addition of two new opcodes to the EVM:
These two opcodes allow an EOA to delegate control to a pre-established CA, and thus, act as one through it, without having to deploy a contract and incur the costs and externalities associated with that.
EIP-3074 allows transactions to use a [MAGIC] signing format to prevent collisions with other transaction signing formats. The active account to which [AUTHCALL] instructions are passed is defined as a context-variable field named [authorized], which only persists through a single transaction and must be redefined for every new [AUTHCALL].
Before addressing the complexities of each opcode, these are the entities involved in a EIP-3074 transaction:
Invoker contracts receive [AUTH] messages with a [COMMIT] value from [authority]; this value defines the restrictions the account wishes to place on [authorized]’s execution of [AUTHCALL] instructions.
Thus, invokers are responsible for ensuring that the [contract_code] defined in an [authorized] account is not malicious and has the ability to satisfy the invariants placed by the primary signing account in a [COMMIT] value.
The [AUTH] opcode has three stack element inputs; or more simply — it is defined by three inputs which compute a single output. These inputs are:
The last two inputs are used to describe a range of modifiable memory from 0 to 97, where:
The variables [yParity], [r] and [s] are collectively interpreted as an ECDSA signature, [magic], on the secp256k1 curve over the message:
[keccak256 (MAGIC || chainID || nonce || invoker address || COMMIT)]
where:
If the computed signature is valid and the signer’s address equal to [authority], the [authorized] field is updated to the value provided by [authority]. If any of these requirements aren’t satisfied, the [authorized] field remains unchanged in its previous state, or as an unset value.
The gas cost for this opcode is computed as the sum of:
[AUTH] is implemented to not modify memory, and takes [authority]’s value as an argument so that it is trivial to verify its value from the provided signature.
The [AUTHCALL] opcode has seven stack element inputs which are used to compute a single stack element output.
It has the same logic as the [CALL] opcode, i.e.; it is used to send message-calls into an account and trigger specific logic in its contracts. The only deviation in their logic is that [AUTHCALL] is designed to set the [CALLER]’s value before proceeding with execution.
Thus, [AUTHCALL] is used by the [authority] to trigger context-specific behavior in [authorized] with logical checks proceeding as follows:
The gas cost for [AUTHCALL] is computed as the sum of:
The data returned from an [AUTHCALL] is accessed through:
To bring it all together with much less of the tech-speak; Ethereum transactions typically specify two values:
In EOAs, as previously mentioned, authorization is tightly coupled with execution, i.e.; (tx.origin == msg.sender). This simple invariant gives rise to most of the issues we explained in the “Accounts and Transaction Validity” subsection of this report.
[AUTH] messages from [authority] allows it to offset the tx.origin function to [authorized], while remaining the msg.sender. It also allows it to define restrictions to this privilege using a [COMMIT] value.
[AUTHCALL] then allows [authorized] to access a contract’s logic, using an [invoker] as an intermediary to ensure the contract it wishes to access is harmless. That is, for every [AUTHCALL], [authorized] is to specify a particular [invoker] for their [COMMIT].
EIP 3074 is primarily responsible for allowing EOAs to delegate their authorization logic to a different account, however its open design enables a lot more in different contexts.
The entire validation logic of an EOA can be abstracted by applying various constrictions/innovations to the invoker as necessary, some of the possible designs based on their target logic include:
Also, execution logic is intuitively abstracted; after all the invoker (which is a CA) is now responsible for executing transaction requests on behalf of the EOA.
Quoting one of its authors: “I would not expect wallets to expose functionality to sign over arbitrary invokers …”. Perhaps the biggest problem poised by the 3074 initiative is that innovation atop it will very easily tend to permissioned and proprietary deal flows; just like the current iterations of Ethereum’s MEV and PBS markets.
By default, invoker contracts need to be greatly audited in order to prevent even worse attacks than are currently possible. This will inevitably tend to an ecosystem where only a handful of invoker contracts developed by influential figures will be adopted as the default for wallet developers. Thus, it boils down to a tradeoff between taking the hard decentralized pathway of constantly auditing and supporting invoker contracts at the risk of users’ security; or simply adopting invoker contracts from established and reputable sources with better guarantees for user security and less oversight on the contract’s safety.
Another aspect of this point is the cost function associated with designing, auditing, and marketing a functional and safe invoker. Smaller teams will almost always be outdone by bigger organizations –especially on the marketing front– which already have some established reputation, even if their product is better.
EIP-3074 entrenches the ECDSA signature scheme, since it is still considered more valid than the authorization scheme introduced via the invoker. While there are arguments that quantum-resistance isn’t currently a definitive problem, and that there’s much worse at stake in a future where ECDSA is corruptible; Ethereum’s somewhat unstated aim is to always be ahead of such problems. Potentially sacrificing quantum- and censorship-resistance for marginal improvements in UX might not be the best of choices in the near future.
Another point on the forward-compatibility argument is that while the benefits of 3074 were still being assessed, ERC-4337 (which doesn’t require any protocol changes) now has a great market, so you have to be compatible with it too to avoid compartmentalisation of ecosystems.
Even with the native account abstraction roadmap, the [AUTH] and [AUTHCALL] opcodes would eventually become obsolete in the EVM, introducing a great deal of technical debt to Ethereum in order to deliver a marginal amount of UX improvement.
After sending an [AUTH] message and delegating control, the EOA is expected to avoid the usual private key authorization scheme, as sending out a “normal” transaction causes the authorization it delegated to every invoker to be revoked.
Thus, the ECDSA scheme remains strictly superior to any other authorization scheme which the associated contracts may enable, meaning that a loss of private keys would result in a total loss of the account’s assets.
This proposal had initially set out as a somewhat minimalistic variation of EIP 3074, and was even meant to be an update to it. It was birthed to address the supposed inefficiencies of EIP 3074, especially the concerns around its incompatibility with the already flourishing 4337 ecosystem and the native account abstraction proposal– RIP 7560.
Its approach is the addition of a new EIP 2718-compliant transaction type –[SET_CODE_TX_TYPE]– which allows an EOA to behave as a smart account for specified transactions.
This design enables the same features as EIP 5806 and some more, while remaining compatible with the native account abstraction roadmap and existing initiatives.
EIP-7702 allows an EOA to “import” the code content of a contract through a [SET_CODE_TX_TYPE] 2718-compliant transaction of the format:
rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, value, data, access_list, authorization_list, signature_y_parity, signature_r, signature_s])
This payload is entirely similar to that of EIP 5806, except that it introduces an “authorization list”. This list is an ordered sequence of values of format:
[[chain_id, address, nonce, y_parity, r, s], …]
where each tuple defines the [address]’ value.
Before proceeding, the parties involved in a SET_CODE_TX_TYPE are:
When [authority] signs a SET_CODE_TX_TYPE specifying [address], a delegation designator is created. This is a “pointer programme” which causes all code retrieval requests due to the [authority]’s actions at any instant to be channeled to [address]’ observable code.
For each [chain_id, address, nonce, y_parity, r, s] tuple, the logic flow of a 7702-type transaction is as follows:
Phew! To tie it all back; this EIP allows EOAs to send transactions which set a pointer to a contract’s code, allowing them to implement this logic as their own in subsequent transactions. In this way it is strictly stronger than EIP 5806, because it allows EOAs to actually have code content for as long as they want (as opposed to EIP 5806 which simply allows EOAs to send delegate-calls).
While it could be argued that it isn’t an abstraction anymore since the EOA actively takes in the logic it wishes to execute, it still isn’t the “primary owner” of said logic. Also, it doesn’t directly contain logic, it simply specifies a pointer to the logic (in order to reduce computational complexity). So we’re going with execution abstraction!
While the require(msg.sender == tx.origin) invariant is broken to allow self-sponsorship, the EIP still allows the integrations of sponsored transaction relayers. However, the caveat is that such relayers need a reputation- or stake-based system in order to prevent griefing attacks.
EOAs can point only to a specific portion of the account’s code, so that only the logic of that portion is executable in their context.
This also enables the existence of sub keys which go on to enable “privilege de-escalation”, so that specific dAPPs only have access to an account’s balance under specific conditions. For example, you could imagine a permission to spend ERC-20 tokens but not ETH, or to spend up to 1% of the total balance per day, or to interact only with a specific applications.
Due to its non-restrictive nature, a EIP-7702 transaction could allow a user to access the CREATE2 opcode and use it to deploy bytecode to an address without any other restrictive parameters such as fee market logic (e.g. EIP-1559 and EIP-4844). This allows the address to be recovered and used across multiple state machines, with the same bytecode, where its account on each chain is then responsible for defining the other context-variable parameters.
While EIP-7702 is still very recent, there’s already been a lot of prototyping and testing for its dependencies and potential disadvantages, but its minimalistic model guarantees it a lot of flexibility, and thus utility, in different contexts. However it breaks way too many invariants and isn’t immediately backwards compatible.
Some of its logic includes:
Most users aren’t savvy to the actual contents of an account (or even the difference between an account and an address!), so that allowing address collisions means that an EOA could masquerade as a CA and attract user funds in a long-winded bit to eventually steal it all. EIP-3607 addressed this by stipulating that accounts which contain code should not be able to spend their balance using their own authorization logic. However, EIP 7702 breaks this invariant in order to enable EOAs to remain autonomous even after gaining some programmability.
Signing over an account’s address instead of its code content is basically just like 3074’s scheme with invokers. It doesn’t provide strict guarantees around cross-chain code content consistency, since an address could take on a different code content on different chains. This means that an address whose code content contains the same logic on one chain could be predatory or outright malicious on another chain, and this could lead to loss of user funds.
EOAs in their current form today are greatly limited as they don’t allow users to take advantage of the programmability features offered by the EVM. While there are various paths to upgrading accounts, as we outlined in the beginning of this report, the chosen solution has to maintain the principles of safe and secure self custody. Furthermore EOA upgrades may significantly impact both the user experience and application developers so all stakeholder voices must be considered.
Allowing EOAs to execute code in any manner immensely expands the functionality of accounts, but this new expressibility comes with meaningful risks and possible blindsides. Solving these tradeoffs is critical to delivering an upgrade with uncontested UX benefits for Ethereum users.
Ethereum’s culture of open discussion makes it a great testing ground for such innovations since almost every implication of every design is thoroughly deconstructed by subject experts. This comprehensive consideration should help mitigate risks of malfeasance from adversaries.
EIP-7702 is currently the poster child for mechanisms that seek to bring EVM programmability to EOAs, having been marked as a replacement for EIP 3074’s slot in the Pectra upgrade. It inherits the open design of 3074’s mechanism while greatly lowering the attack surface / risks. It also enables a lot more by avoiding 3074’s restrictions to certain classes of opcodes.
While there’s still some refinements being done on the proposal’s design, it has already garnered a lot of goodwill and support from developers, especially since it directly has Vitalik backing it.
Within the community there are claims that this approach to account abstraction might even be better than smart accounts. This commentary emphasizes that this path requires less changes and isn’t as complex, and that EOAs are already enshrined. However, we must remember the future security milestone of quantum resistance at every level of the Ethereum network. This quantum safety is infeasible with the current account model core due to the utilization of ECDSA-based signature schemes for EOA authorization.
Thus, EOA programmability is to be seen as a step along the path to smart accounts and not the destination. It supercharges EOAs and enables better user- and developer-experience, while remaining compatible with the ultimate account abstraction goal of smart accounts.
In our next report, we will be diving into EOA migration schemes to see how well they fit on the account abstraction roadmap, stay tuned!