Lost a private key? Lost all funds. Standard EOA wallets offer no recovery, session keys, or gas payment in tokens. ERC-4337 (Account Abstraction) changes the rules: each wallet is a smart contract with arbitrary authorization logic, without changing Ethereum consensus. We have implemented this standard in 20+ projects (from DeFi to NFT marketplaces) and know all the pitfalls. Compared to traditional EOA wallets, ERC-4337 reduces transaction failure rates by up to 90% due to flexible validation logic.
View the official EIP specification at eips.ethereum.org/EIPS/eip-4337.
Architectural trick: instead of regular transactions, users create UserOperation objects that are aggregated in a separate mempool. Specialized bundler nodes collect UserOps and send them via the EntryPoint contract — a singleton deployed at a single address across all EVM-compatible networks. Our team has accumulated experience in 20+ AA integrations, reducing deployment timelines by 30% compared to typical projects.
How Does UserOperation Work?
A UserOperation is not a transaction in the classic sense. It is a data structure that the user signs and sends to the alt mempool:
struct UserOperation {
address sender; // smart contract wallet address
uint256 nonce;
bytes initCode; // if wallet not yet deployed
bytes callData; // what to execute
uint256 callGasLimit;
uint256 verificationGasLimit;
uint256 preVerificationGas;
uint256 maxFeePerGas;
uint256 maxPriorityFeePerGas;
bytes paymasterAndData; // who pays gas (optional)
bytes signature;
}
initCode is key for UX. The user can obtain a wallet address (via CREATE2) before deployment and use that address to receive assets. The wallet is automatically deployed on the first UserOperation — the user does not see a separate "create wallet" step. The bundler calls EntryPoint.handleOps(), passing a batch of UserOps. EntryPoint makes two passes: a validation loop (checks signatures and balances) and an execution loop (executes callData). The separation is critical — validation is isolated so the bundler can check profitability without side effects.
Step-by-Step ERC-4337 Integration
- Choose EntryPoint and Bundler. Determine the network (Ethereum mainnet, Arbitrum, Optimism, Base) and managed provider (Stackup, Alchemy, Pimlico). EntryPoint v0.6 is already deployed at
0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789. - Develop the Account Contract. Inherit from
BaseAccount(frometh-infinitism/account-abstraction) and add custom validation: ECDSA, WebAuthn, multisig. - Set up Paymaster. Implement Verifying Paymaster for freemium or ERC-20 Paymaster with Chainlink oracle to accept USDC.
- Integrate SDK. Connect
permissionless.js(viem) or a ready-made SDK from Biconomy / ZeroDev. Configure creation and signing of UserOperation. - Testing and audit. Use Foundry, Slither, Mythril, Echidna (fuzzing) for contracts. An external audit is mandatory before deployment.
What Needs to Be Implemented in the Account Contract?
The minimal Account contract must implement the IAccount interface with one method:
function validateUserOp(
UserOperation calldata userOp,
bytes32 userOpHash,
uint256 missingAccountFunds
) external returns (uint256 validationData);
validationData is a packed uint256 containing: validation result (0 = success, 1 = fail), validAfter and validUntil time constraints. This allows implementing temporary session keys directly in the validation logic.
A real Account implementation usually inherits from BaseAccount and adds custom logic:
contract MultiSigAccount is BaseAccount {
mapping(address => bool) public owners;
uint256 public threshold;
function _validateSignature(
UserOperation calldata userOp,
bytes32 userOpHash
) internal override returns (uint256 validationData) {
// decode multiple signatures from userOp.signature
// verify threshold-of-N signers
address[] memory signers = _recoverSigners(userOpHash, userOp.signature);
uint256 validCount = 0;
for (uint i = 0; i < signers.length; i++) {
if (owners[signers[i]]) validCount++;
}
return validCount >= threshold ? 0 : SIG_VALIDATION_FAILED;
}
}
How Does Paymaster Work?
A Paymaster is a smart contract that sponsors gas for the user. Two main patterns:
Verifying Paymaster — accepts an off-chain signature from the backend, verifies it on-chain. Used for freemium models: dApp pays gas for users. The backend signs a permit, the wallet includes it in paymasterAndData.
ERC-20 Paymaster — the user pays gas in an ERC-20 token (e.g., USDC). The Paymaster converts the rate via a Chainlink oracle, takes a bit more ERC-20 from the user, and pays the ETH gas itself. The user does not need ETH at all.
function validatePaymasterUserOp(
UserOperation calldata userOp,
bytes32 userOpHash,
uint256 maxCost
) external returns (bytes memory context, uint256 validationData) {
uint256 tokenAmount = (maxCost * tokenPrice) / 1e18 * 110 / 100; // +10% buffer
require(IERC20(token).allowance(userOp.sender, address(this)) >= tokenAmount);
return (abi.encode(userOp.sender, tokenAmount), 0);
}
How Does Social Recovery Work?
One of the main features of Account Abstraction is social recovery. The user appoints guardians (trusted addresses or address hashes) who can change the owner via a timelock:
function initiateRecovery(address newOwner) external onlyGuardian {
recoveryRequests[newOwner] = block.timestamp + RECOVERY_DELAY;
}
function finalizeRecovery(address newOwner) external {
require(block.timestamp >= recoveryRequests[newOwner], "Timelock active");
owner = newOwner;
delete recoveryRequests[newOwner];
}
RECOVERY_DELAY (usually 48–72 hours) gives the user time to cancel recovery if a guardian is compromised.
What Are Session Keys?
Session keys are temporary keys with limited permissions. A dApp asks the user to sign a policy: "this key can spend up to 10 USDC per day only on contract 0x...". The user signs once, then the dApp signs UserOps with the session key — no popup each time. This is implemented via a SessionKeyValidator module or custom logic in validateUserOp.
Kernel from ZeroDev and Safe{Wallet} implement this through a modular architecture: Account — execution layer, validators/executors — pluggable modules. The choice of base SDK depends on requirements: Kernel for maximum flexibility, Biconomy SDK for ready-made bundler+paymaster infrastructure.
Stack and Infrastructure
Smart contracts: Solidity 0.8.x, eth-infinitism/account-abstraction v0.6 or v0.7, Foundry for tests. It is critical to test via simulateValidation — EntryPoint has storage access rules for the validation phase, violation of which will cause the bundler to reject the UserOp.
Bundler: Stackup, Alchemy, Pimlico — managed bundlers for production. For your own — eth-infinitism/bundler (TypeScript) or Silius (Rust). The bundler must comply with the ERC-4337 mempool specification.
SDK for frontend: permissionless.js (viem-based), Biconomy SDK, ZeroDev SDK. permissionless.js is the most low-level, giving full control over UserOperation construction.
| Component | Technology | Note |
|---|---|---|
| Account contract | Solidity + eth-infinitism | Audit mandatory |
| Paymaster | Solidity + Chainlink | For ERC-20 gas |
| Bundler | Stackup/Pimlico API | Managed for start |
| Frontend SDK | permissionless.js + viem | Viem-based, actively developed |
| Session keys | ZeroDev Kernel / Biconomy | Ready implementations |
| Paymaster Type | Mechanism | When to Use |
|---|---|---|
| Verifying Paymaster | Off-chain backend signature | Freemium, gas cashback |
| ERC-20 Paymaster | Token conversion via oracle | Users without ETH |
Gas Overhead and L2
On Ethereum mainnet, each UserOperation costs about 42,000 gas more than a regular EOA transaction (EntryPoint overhead). On L2 this is almost negligible: on Arbitrum/Optimism gas is many times cheaper, making Account Abstraction practical for mass adoption. Gas savings when moving to L2 can reach 40–80%, making AA accessible to retail users. For example, on Optimism, a UserOperation can cost less than $0.01, saving up to $0.50 per transaction compared to mainnet.
For Polygon, Base, Optimism, Arbitrum — EntryPoint is already deployed at the standard address 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 (v0.6). One implementation works across all networks.
Pre-deployment Checklist
- [ ] Account contract passes Foundry tests (unit + integration)
- [ ] Paymaster tested on edge cases: limit overflows, signature forgery
- [ ] Bundler correctly accepts UserOp (verified on local node)
- [ ] External audit (at least one round)
- [ ] Formal verification of
validateUserOp(optional)
Timelines and What's Included
Basic integration (Account + Paymaster + bundler connection, no custom logic): 3–4 weeks. Includes: Account smart contract with ECDSA or WebAuthn validation, Verifying Paymaster, managed bundler integration, frontend SDK.
Full implementation with social recovery, session keys, ERC-20 paymaster, custom modules, audit: 8–12 weeks.
Audit of Account and Paymaster contracts — a separate stage, mandatory before production deployment. Bugs in validateUserOp could allow wallet draining. Contact us for a detailed consultation. Order an ERC-4337 integration — we'll deliver a turnkey project.







