ERC 4337
What is ERC-4337?
ERC-4337 is an Ethereum standard that implements account abstraction without requiring changes to the core Ethereum protocol. Instead of relying on traditional Externally Owned Accounts (EOAs) controlled by private keys, users can operate through smart contract wallets with enhanced flexibility, security, and usability.
Why is ERC-4337 Important?
Traditionally, Ethereum has two types of accounts:
Externally Owned Accounts (EOAs):
Controlled by private keys (e.g., MetaMask, Ledger).
Only EOAs can sign transactions.
If the private key is lost, funds are permanently inaccessible.
Smart Contract Accounts:
Can include custom logic (multi-signature, social recovery, spending limits).
Require an EOA to initiate transactions, limiting usability.
ERC-4337 removes the dependency on EOAs, allowing transactions to be validated directly by smart contracts, enabling features like: - Multi-Factor Authentication - Gas fee payment in any ERC-20 token - Social recovery and key rotation - Transaction batching
ERC-4337 Architecture Overview
Key Components of ERC-4337
ERC-4337 introduces a new mempool and several key actors:
User Operation (
UserOp
) – A new transaction format sent to the network.Smart Contract Wallet – A contract that verifies and executes transactions instead of a private key signing it.
Bundler – A specialized node that collects multiple UserOps and submits them as a single Ethereum transaction.
EntryPoint Contract – A singleton contract that ensures security and execution of transactions.
Paymaster – Allows gas fee abstraction (users can pay gas in stablecoins or get sponsorships).
ERC-4337 Architecture Diagram
+-------------------------------------------------------+
| Ethereum Network |
| (Settlement Layer) |
+-------------------------------------------------------+
| |
| |
+------------+ +----------------+
| EntryPoint |<---[Executes]--| Bundler |
| (Singleton SC)| | (Relayer) |
+------------+ +----------------+
^ |
| [Validation & Execution] |
+----------------+ +-----------------+
| Smart Contract | | Paymaster |
| Wallet | | (Optional Gas |
| (User Account) | | Sponsor) |
+----------------+ +-----------------+
^
|
+---------------+
| UserOp | <---- Transaction sent by User
+---------------+
ERC-4337 Code Structure
1. Smart Contract Wallet (Minimal Implementation)
The smart contract wallet must be able to validate transactions without relying on EOAs. Below is a basic implementation of an ERC-4337-compatible wallet:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
interface IEntryPoint {
function handleOps(address user, bytes calldata txData) external;
}
contract ERC4337Wallet is Ownable {
using ECDSA for bytes32;
address public entryPoint;
constructor(address _entryPoint) {
entryPoint = _entryPoint;
}
function validateUserOp(
bytes32 hash,
bytes memory signature
) external view returns (bool) {
address signer = hash.toEthSignedMessageHash().recover(signature);
return signer == owner();
}
function executeTransaction(
address to,
uint256 value,
bytes calldata data
) external onlyOwner {
(bool success, ) = to.call{value: value}(data);
require(success, "Tx failed");
}
}
Key Features:
- The wallet can validate User Operations (UserOps) via validateUserOp()
.
- Allows execution of transactions without an EOA using executeTransaction()
.
- Owner-based control using OpenZeppelin’s Ownable
.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract EntryPoint {
mapping(address => bool) public authorizedWallets;
function handleOps(
address user,
bytes calldata txData
) external {
require(authorizedWallets[user], "Unauthorized wallet");
(bool success, ) = user.call(txData);
require(success, "Tx failed");
}
function registerWallet(address wallet) external {
authorizedWallets[wallet] = true;
}
}
Key Features: - Ensures only authorized wallets can send UserOps. - Acts as a universal validation layer. - Bundlers interact with this contract to process transactions.
import { ethers } from "ethers";
async function bundleTransactions(userOps) {
const provider = new ethers.JsonRpcProvider("https://mainnet.infura.io/v3/YOUR_API_KEY");
const signer = new ethers.Wallet("YOUR_PRIVATE_KEY", provider);
const entryPoint = new ethers.Contract(
"ENTRYPOINT_CONTRACT_ADDRESS",
["function handleOps(address user, bytes txData)"],
signer
);
for (let op of userOps) {
await entryPoint.handleOps(op.user, op.txData);
}
}
bundleTransactions(userOps);
Key Features:
- Aggregates multiple UserOps into one transaction to reduce fees.
- Sends transactions via the EntryPoint
contract.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IERC20 {
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
contract Paymaster {
address public token;
address public relayer;
constructor(address _token, address _relayer) {
token = _token;
relayer = _relayer;
}
function payForUserOp(address user, uint256 amount) external {
IERC20(token).transferFrom(user, relayer, amount);
}
}
Key Features: - Allows gas sponsorship (dApps can cover user gas fees). - Users can pay fees in USDT, DAI, or any ERC-20 token.
Advantages
Improved UX: No need to manage private keys directly.
Gas Fee Flexibility: Pay gas in any ERC-20 token.
Multi-Factor Authentication (MFA): Enhanced security.
Social Recovery: No risk of losing funds due to lost private keys.
Transaction Batching: Execute multiple transactions at once.
Disadvantages
Higher Gas Costs: Smart contract wallets consume more gas than EOAs.
Increased Complexity: Requires new infrastructure (bundlers, paymasters).
Adoption Hurdles: dApps and wallets must integrate ERC-4337 support.
Last updated
Was this helpful?