Account Abstraction for Everyone Else
The Complete Guide to Understanding AA in 2023
Most of the writing on account abstraction sucks
If you’re reading this, chances are you’ve read a couple of resources for understanding account abstraction. You probably agree that 99% of posts about account abstraction are shit.
You’ve found that almost all of them start by describing the difference between EOAs and smart contracts and vaguely mention UX improvements. They fail to explain what account abstraction *actually* is and instead focus on the byproducts of account abstraction.
This guide covers the entire line of thinking, from what account abstraction is to why everyone calls it the next big thing.
What is account abstraction?
I find it easier to start with what account abstraction is not:
- paying users’ gas fees
- native multi-sig
- web3auth type “social login”
You can do these things as a result of an account abstraction implementation.
If I could rename account abstraction to be more intuitive, it’d be called “programmable transaction validity.”
Account abstraction, in general, is the ability to set the validity conditions of a transaction programmatically.
EIP-4337, which we cover more in-depth later, written by Vitalik et al., says, “Achieve the key goal of account abstraction: allow users to use smart contract wallets containing arbitrary verification logic instead of EOAs as their primary account.”
Currently, on Ethereum, a transaction is valid if and only if:
1. There's sufficient balance to pay gas.
2. The nonce is correct.
3. It has a valid digital signature.
But what if developers could define a different set of conditions in which transactions are valid?
When I was doing my research, I talked to James, and looking back, he framed the problem account abstraction aims to answer in the simplest way possible, "What if you could auth by anything other than a key? What cool things could you do?"
You can’t automatically execute transactions
Stateless vs. stateful account abstraction
Before we move on, it's important to note that two types of account abstraction exist: stateless and stateful.
Many people describe account abstraction as a means to “automatically execute transactions once some condition is met.” Only a subset of those situations is possible if you’re implementing stateless account abstraction—which you should!
Stateless = doesn't depend on the external state, doesn’t have side effects.
Stateful = can depend on external state, has access to chain’s state.
In a stateful account abstraction implementation, the smart contract that defines validity conditions has access to the chain’s state. The problem with this is that a condition that is true at one instance may not be true at another. Practically speaking, this would look like a node sending a transaction that is currently valid and becomes invalid later. For example, say you wanted to execute a transaction at block 1000000 automatically. At block 1000000, you could submit a user operation into the mempool, which would be valid at the time. When the bundler tries to put it into the next block, it could be that it’s not valid because the block number increased.
The receiving node has to spend resources validating something that will never be on-chain and can’t blacklist what sent the transaction because it was valid at the time of sending.
In ERC4337, which we go into more detail about later, researchers spent a lot of time figuring out how to avoid this. The specification bans using specific opcodes like `blockNumber` for this reason.
With stateless account abstraction, you never run the risk of changing validity– it’s monotonic.
Fuel’s Implementation of stateless AA
We’ll talk about how other ecosystems implement account abstraction in a bit. By starting with Fuel, you’ll see the contrast between building a new system from the ground up and the modular thesis, compared to building for an existing system.
Fuel implements stateless AA with predicates. A predicate is just a condition under which you can spend a UTXO. Predicates are scripts where the main function returns a boolean. A pure function where assets under that predicate are unlocked and can be spent by the caller if evaluated to true. A predicate owns or controls UTXOs.
Note: UTXO stands for unspent transaction output. The core fundamental understanding of UTXOs is that for each transaction, the entirety of the balance, or amount of coins, gets spent. The amount you send to your intended recipient goes to them, and the rest gets burned, then minted again, resulting in new unspent output.
The key thing about Fuel predicates is that you can introspect, or examine, the inputs and outputs of predicates which allows you to have agreements that allow you to build an order book exchange or do atomic swap between multiple parties.
At the transaction level, UTXO transactions describe a subset of the exact effects of a transaction. This subset of effects can be conditioned on in stateless account abstraction. Fuel achieves this through the design decision of a UTXO model. This is what enables the system the possibility to know about the inputs and outputs of a transaction. On Ethereum, you only know about the inputs. With Fuel, you could use the outputs to write logic that says if you provide X then Y.
You could lock coins in a predicate with programmable validity that says, “these are spendable if, in return, X amount of Y asset was sent to a certain address. Similarly, you could have some logic that says this transaction is only valid if X is swapped at a certain price. The gotcha here is not that you’re *sending* anything. It’s already been sent. You’re seeing the final effects of the transaction, in this case, where coins have been sent.
Predicates aren’t checked during scoped execution. They’re checked at transaction validity time. A predicate can check that the transaction's inputs have specific properties, but it doesn't care if those are valid (existing, signed) inputs. They have to be valid inputs for the transaction to be valid, but it's not the predicate that enforces that validity.
Right now, Fuel predicates are constrained by the number of bytes as a way to meter them. In the future, the team is going to constrain predicates with gas, allowing for the use of loops. This makes it possible to do cryptography like custom hashing and signature verification, which usually require loops.
Benefits of Fuel’s Implementation
Note: Skip this section if you want to move on to what you can do with AA
On both Bitcoin and Ethereum, and the protocols that use similar implementations, you can’t introspect transactions. This means you can’t introspect the transaction spending it, and you can’t programmatically set what to do based on outputs.
At its core, Fuel’s implementation of AA offers developers and, in turn, users more flexibility because these are not things encoded at the protocol level. Fuel’s account abstraction allows developers to define custom verification schemes at the application level.
The Fuel Labs team has an EC Recover example for an Ethereum private key. If you wanted an EC Recover for different curves, a developer could write one at the application layer! Check out this implementation of BLS12-381 and Edwards25519 by Hashcloack, written in Sway.
EC RECOVER: When sending a transaction to the Ethereum network, you have to sign this transaction with your private key. EC Recover is moving this functionality of verifying a signature into a smart contract instead of it being something only an Ethereum node can do. With this, you can verify much more than just the transaction signature itself.
No state bloat
Stateless account abstraction doesn't bloat the state (as much) because even when it gets spent, it never enters the blockchain state, only the history.
With predicates, there’s no contracts, state, or storage. Predicates don’t have state initially, and then if someone spends on behalf of the predicate, you only get one database entry, just for the UTXO instead of a state tree.
How Other Ecosystems are doing Account Abstraction
Like most things in computer science, account abstraction can be implemented in myriad ways. No one implementation is standard across the industry.
EIP-2938 was an initial EIP to allow a contract to be the top-level account that pays fees and starts transaction executions. The implementation was around introducing a new EVM opcode to signal validity to extend the conditions of transactions with the execution of arbitrary EVM bytecode. This proposal didn’t make it into the protocol because devs were busy with other changes like the merge and couldn’t risk a protocol change of that magnitude.
ERC-4337 is the first account abstraction proposal/standard that brings on Ethereum account abstraction without requiring core protocol changes. It does this by moving the validation of transactions out of the protocol itself and moving it over to a higher level—the smart contract level with this special `entry point.`
On Ethereum, EOAs are accounts on Ethereum whose functionality is hardcoded into the protocol. Defining how they pay gas, how they sign transactions, how they use a nonce, etc. This standard moves away from the hard-coded nature of accounts that EOAs give us.
Starknet is a zk-rollup on Ethereum. Starkware implements a modified version of the model of EIP-4337 for Ethereum. Read more about it here.
zkSync is a zk-rollup on Ethereum. zkSync implements a modified version of EIP-4337. Read more on their implementation here.
Biconomy is a developer tooling platform focused on infrastructure and tooling for the Ethereum ecosystem. Biconomy implements a modified version of EIP-4337 and offers features like paying for users’ gas fees as part of an SDK. Read more about their implementation here.
The ethos of modular is not designing a system that is tightly coupled with another system, allowing for greater flexibility. Fuel’s implementation of account abstraction is a manifestation of that. Fuel’s implementation of account abstraction allows higher flexibility and a highly customizable environment where developers can, at the application level, define validity conditions without depending on the Fuel protocol to support it.
Because Fuel wasn’t built exclusively for Ethereum or any other system, Fuel’s implementation isn’t burdened by the baggage of another system and has room to innovate.
While zkSync, Starkware, and Biconomy all implement a modified version of EIP-4337, Fuel implemented a more unique and highly performant account abstraction. Because Fuel will be deployed as a rollup on Ethereum, by some accounts, Ethereum already has account abstraction.
What you can do with Account Abstraction
The new experiences you see being built are features made possible by account abstraction but not by account abstraction itself. Things like sponsoring gas fees for users and things like Web3Auth are application-layer things built on top of account abstraction. These things are inherently possible through account abstraction's core mechanism: the ability to set the validity conditions of a tx programmatically.
Examples of things built on top of account abstraction:
Paying gas fees for other users
Freedom of signature verification scheme
Check multiple signatures (native multi-sig)
Check out these projects who have leveraged Fuel’s account abstraction:
Authsome - Walletless login system. This wallet is then used as the basis for a pluggable authentication infrastructure, similar to Web3Auth.
Thunder - An NFT marketplace on Fuel that can bulk execute transactions with one click.
Poolshark - a protocol for directional liquidity. Poolshark matches conditional orders using Fuel's account abstraction with pooled liquidity to improve accessibility and reduce fees for advanced traders.
Social recovery of wallets
Applications can pay for the gas of their users’ transactions
Use wallets from different ecosystems (or same, that use different signature schemes)
Walletless web3 login
Users don’t need ETH in their “regular” wallet to initiate transactions
Ability to put 100% of funds in a multisig and initiate transactions from there directly
New Applications Unlocked
“No one knows, but it's provocative. It gets the people going!”
Here’s the truth: we don’t fully know what new types of applications can be unlocked (yet), but we can begin to make massive improvements to the UX of existing applications, and that’s a great start.
A couple of years ago, the UX problem with blockchains was that they were entirely financially inaccessible to most of the world. With the continued progress and proliferation of layer 2s, we arrive at a new frontier: UX.
Suddenly, we can get fees down low enough to make blockchains usable, but the applications' UX needs to be more pleasant and robust. Over the next cycle, I foresee more teams will focus on account abstraction-enabled UX improvements and flows. This will be another tool needed to bring a web2-like experience with the custodial properties of web3.
John Adler, Kristof Gazso, Yuan Han Li, James Prestwich, Ryan Sproule.
Thanks for reading cami’s Substack! Subscribe to receive new posts and support my work.
awesome article, thank you