What the fuck is account abstraction? Besides being a nice buzzword to raise your next 3 at 30 round, account abstraction removes all current limitations on what we currently consider wallets.
Want to send transactions and have someone else pay for gas? -> Paymasters
Want to have social recovery? -> Add multiple keys
Want to build tornado cash into the wallet layer?
Want to send ETH to someone's twitter handle since you don't know their wallet address? -> CREATE2 with some twitter hash and send it before they deploy their wallet
There's already a shit ton of resources out there on account abstraction, so here are some notes. I'm assuming you understand the following
Operations
, Paymasters
, Bundler
, EntryPoint
, and Aggregator
:(Read this before you continue
https://www.alchemy.com//blog/account-abstraction
https://www.alchemy.com/blog/account-abstraction-paymasters
https://www.alchemy.com/blog/account-abstraction-wallet-creation
skip this section if you aren't a noob
aawallet
: A smart contract account abstraction wallet.
EOA
: Externally Owned Account
Motivation: Users want to run a transaction from a smart contract instead of from their own private key EOA.
This is a fancy name for a transaction that a user wants to execute. It looks something like this:
struct UserOp {
// Normal eth_sendTransaction Parameters
address to;
bytes data;
uint256 value; // Amount of ETH sent
uint256 gas;
bytes signature; // Can be signed in many ways, just needs correct validation
uint256 nonce; // To prevent replay attacks
// Tells Entrypoint which wallet to check for validation and charge for gas
address sender;
}
This is the object you pass into UserOp
, it specifies everything you need to run a transaction.
Motivation: Without an entrypoint, an EOA would need to call aawallet.executeOp()
and trust the aawallet
will pay the gas costs for the transaction.
Why is it called an entrypoint? This is the only place where EOAs call functions.
How it works:
executeOp()
and know exactly what will happen(they get their gas refunded and the transaction executes successfully)executeOp()
is hard to simulate, as differences in on-chain storage and block.timestamp
, block.number
, etc. could differ between the simulation and executionhandleOp()
) to do the following
UserOp
might use, rejectaawallet.executeOp()
and track how much gas was usedaawallet
to my walletMotivation: Right now, we only have a single method that takes a UserOp
and executes it. However, we want to break this into two parts - validating that someone with the correct permissions sent the UserOp
and executing the UserOp
. Otherwise, some malicious actor could just come in, submit a bunch of invalid transactions, and burn all the gas in the aawallet
Now, EntryPoint's handleOp()
should do the following
UserOp
might use, rejectaawallet.executeOp()
and track how much gas it usesaawallet
to my walletMotivation: Save gas by aggregating executions of UserOp
as each transaction in EVMs require a fixed 21,000 gas fee.
Why is it called a Bundler? It bundles multiple transactions and executes them together.
How it works:
UserOp
, call validateOp()
on the sender's walletUserOp
, call executeOp()
on the sender's wallet, then transfer ETH to the executor to pay for gasvalidateOp()
rules aren't brokenSide Note: If bundlers smell like flashbots, that's because there's a massive MEV opportunity here where you can order UserOps as a bundler to let MEV searchers to bid on them
Motivation: We can allow dApps to pay for user's gas, OlympusDAO to charge users OHM instead of ETH for gas, etc.
Why is it called paymaster?
It handles paying for gas for UserOp
How it works:
verifcationGasLimit
is used in validateUserOp
When a client receives a UserOperation, it must first run some basic sanity checks, namely that:
What is a client in this context?In the following specification, “entity” is either address that is explicitly referenced by the UserOperation: sender, factory, paymaster and aggregator. Clients maintain two mappings with a value for staked entities:
What is the fun equivalent for each of these(sender-?, factory-FunWalletFactory, paymaster-Token/Gasless, aggregator-?)No possibility for “passive” paymasters (eg. that accept fees in some ERC-20 token at an exchange rate pulled from an on-chain DEX)
Why is this the case? We have this with tokenpaymaster right?Do we need the funwalletfactory to be staked with the entrypoint?
If so, we don't have any functions in FunWalletFactory with the ability to stake from there(at minimum we should stake in the constructor)