EC4337: Account Abstraction
Account abstraction is the way to onboard the next billion users to Ethereum? Great, but how?
The problem is, ERC4337 is not straight forward.
Even for seasoned blockchain developers, its very hard to understand the implementation and its details.
There are a number of services that abstract the complexity away, like stackup and alchemy are offering easy-to-use javascript libraries. However, that is only partly helpful.
If you try to build something for a company, you need to understand the underlaying technology - thereās money at risk and you need to know what that risk is.
This guide is going deep into the weeds of erc4337. It is not directed at Ethereum beginners, its definitely advanced - meant for people who are already solidity developers. If you want to get started with Ethereum, you donāt need to make my own other tutorials, you could come from any other free or paid course. However, just doin the crypto zombies and then coming here will probably not be enough.
Let me walk you through what weāre building:
First, we build a small chat application the normal way. For the contracts we will use a simple contract and test and deploy it using Foundry. For the frontend weāll be building something from scratch using NextJS, Tailwindcss, Rainbowkit with Wagmi and Viem. I intentionally do not want to use HardHat or web3js here, as foundry and is much faster than hardhat and viem is (in my personal opinion) much easier to use than web3js.
Video
Loading video player...
Interactive Tutorials
I will try to put most of the things into codesandbox mini containers embedded into this site. If you donāt know what they are: Itās like SSHāing into docker container that is spun up just for you while visiting the page. If you donāt know what that is, then you are probably not the right audience for this tutorial anyways.
So without further ado, lets dive into what weāre building. Here is a Link to the codesandboxā
The Result
The final application can be seen here: https://erc4337-chatter-nextjs-app.vercel.app/ā
The result will be a chat-like application. There will be 4 different functions here to chat:
- Through your normal wallet - you connect your wallet and when you send a transaction you pay for it.
- Through Stackup. When you send a transaction through an on-chain walletI will use their pay-as-you-go paymaster
- Through Candide with a naive Paymaster that simply pays for everything
- Through Alchemy Accountkit without any paymaster attached.
You can find that in the code sample above.
A lot of things changed since I recorded that video (yep - a week ago was that). Thereās a new abstractionkit version, a new viem version, a new wagmi version. The ecosystem is moving fast. So, below I am outlining the most prominent example using account abstraction.
What is Account Abstraction?
Alright, letās break it down simply. ERC-4337 is about making Ethereum accounts smarter and easier to use.
In Ethereum, you have two types of accounts:
- Externally Owned Accounts (EOAs) - These are your regular accounts controlled by private keys. You do something (like send Ether) by signing a transaction with your private key.
- Contract Accounts - These are controlled by code (smart contracts).
Now, EOAs are limited. You need the private key for every action, and if you lose it, youāre out of luck. They canāt do anything fancy on their own.
ERC-4337 lets you replace EOAs with smart contract accounts without needing to change the core of Ethereum.
Hereās what that enables:
Smart Wallets: You can have a wallet where spending rules, multi-signatures, or daily limits are baked into the code.
Recovery: Lose your key? No problem. The smart contract can have rules to get back control, like verifying your identity in another way.
Sponsored Transactions: Normally, you pay gas for transactions with ETH. With ERC-4337, someone else could pay the gas for you. This is good for dApps wanting to offer free transactions to users.
Batch Transactions: One transaction could trigger multiple actions, saving on fees and making complex operations easier.
ERC-4337 does this through a special contract called āThe Entrypoint.ā This Entrypoint acts like a traffic director. It routes transactions from these smart contract accounts and can handle the gas fees however the accountās code specifies.
Letās check out how that works exactly by converting a normal web3 app into an erc4337 appā¦
Step 1 - The Contracts
Install Foundry
To get started with Foundry, its actually pretty simple. Fire up a console and follow along with this getting started guideā
What I do first is download a bash script for the installation of foundry:
curl -L https://foundry.paradigm.xyz | bash
and then from there, its usually just foundryup
, but inbetween you might need to source your shell profile to get the path into the shell.
In the codesandbox example above, foundry is already installed
Init Project
The next step is to initialize a new project. Since foundry installs a few tools (forge, cast, anvil, and chisel), we will use forge to init a new project:
forge init chatter-contracts
Then we can delete the existing files in the src, test and scripts folder:
rm src/* test/* scripts/*
Create Chatter.sol
Letās create our Smart Contract first. Create a new file and add this to src/Chatter.sol
:
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Chatter {
event Message(address indexed sender, string message);
function sendMessage(string calldata message) public {
emit Message(msg.sender, message);
}
}
Letās also add a test in test/Chatter.t.sol
:
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Test, console2} from "forge-std/Test.sol";
import {Chatter} from "../src/Chatter.sol";
contract ChatterTest is Test {
Chatter public chat;
event Message(address indexed sender, string message);
function setUp() public {
chat = new Chatter();
}
function test_message() public {
vm.expectEmit(true, false, false, true);
emit Message(address(this), "hello 123");
chat.sendMessage("hello 123");
}
}
If you run forge test
on the terminal, it should execute the test. The test is setting up a new chat smart contract in the setUp()
function, and then with vm.expectEmit(...)
we can instruct the vm to assert an event is thrown. Which event? The one in the next line. Then we call chat.sendMessage() and it will hopefully emit this event and the test will pass.
Chatter solidity file
chatter test https://book.getfoundry.sh/forge/cheatcodesā chatter script
Step 2: Rainbowallet and layout
https://www.rainbowkit.com/docs/installationā npm install @rainbow-me/rainbowkit wagmi viem https://github.com/rainbow-me/rainbowkit/blob/main/examples/with-next-app/next.config.jsā
Jazzicon https://github.com/raugfer/jazzicon?tab=readme-ov-fileā
https://docs.stackup.sh/docs/account-abstractionā
https://github.com/stackup-wallet/userop.js/blob/main/src/preset/middleware/signature.tsā
https://mumbai.polygonscan.com/address/0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789#codeā
https://github.com/eth-infinitism/bundler-spec-tests/blob/master/tests/single/bundle/test_bundle.pyā https://www.stackup.sh/blog/a-guide-to-the-top-erc-4337-bundlers-features-performance-and-moreā https://github.com/silius-rs/siliusā
https://www.alchemy.com/account-abstraction-infrastructureā https://accountkit.alchemy.com/smart-accounts/accounts/guides/using-your-own.htmlā https://docs.safe.global/safe-smart-account/supported-networks/v1.4.1ā
https://www.candide.devā https://docs.candide.dev/wallet/guides/send-gasless-tx/#step-5-get-paymaster-dataā https://github.com/candidelabs/abstractionkit/blob/safe/src/utils.tsā https://blockpi.io/pricingā https://docs.candide.dev/wallet/abstractionkit/safe-account/ā
https://hackmd.io/@stackup/H1oIvV-qiā
Stackup
npm install userop