EIPs
EIP-4337 — Account abstraction via entry-point
The “smart account” standard. Replaces an EOA’s nonce + signature + tx_type flow with a UserOperation object that gets routed through a singleton EntryPoint contract. Bundlers aggregate user-operations into blocks; paymasters can sponsor gas.
import {
ENTRY_POINT_V07_ADDRESS,
eth_sendUserOperation,
type UserOperation,
} from "@ethernauta/eip/4337";
import { create_writer, encode_chain_id, http } from "@ethernauta/transport";
import { eip155_1 } from "@ethernauta/chain/eip155-1";
const CHAIN_ID = encode_chain_id({ namespace: "eip155", reference: eip155_1.chainId });
const writer = create_writer([
{ chainId: CHAIN_ID, transports: [http("https://ethereum-rpc.publicnode.com")] },
]);
declare const user_op: UserOperation;
const hash = await eth_sendUserOperation({
op: user_op,
entryPoint: ENTRY_POINT_V07_ADDRESS,
})(writer({ chain_id: CHAIN_ID }));
void hash; Surface
Entry points
| Export | Value |
|---|---|
ENTRY_POINT_V06_ADDRESS | 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 |
ENTRY_POINT_V07_ADDRESS | 0x0000000071727De22E5E9d8BAf0edAc6f37da032 |
RPC methods
| Method | Shape | Purpose |
|---|---|---|
eth_estimateUserOperationGas | Signable<EstimateUserOperationGasResult> | Gas estimation for a UserOp. |
eth_sendUserOperation | Signable<Hash32> | Submit a UserOp to a bundler. |
eth_getUserOperationByHash | Readable<UserOperationByHash> | Look up a submitted UserOp. |
eth_getUserOperationReceipt | Readable<UserOperationReceipt> | Receipt for a UserOp. |
eth_supportedEntryPoints | Readable<Address[]> | Which entry-point addresses the node supports. |
Packing
UserOperations have two on-the-wire shapes: the v0.6 form (separate fields) and the v0.7 form (packed into bytes32 fields). The packers convert between them:
| Export | Purpose |
|---|---|
pack_user_operation | Full v0.6 → v0.7 packing. |
pack_account_gas_limits | (uint128, uint128) → bytes32. |
pack_gas_fees | Priority fee + max fee → bytes32. |
pack_init_code | Factory + factoryData → bytes. |
pack_paymaster_and_data | Paymaster + gas limits + data. |
unpack_uint128_pair | Reverse the gas-pair packing. |
Signing
import { parse } from "valibot";
import type { Address, Uint } from "@ethernauta/core";
import { AddressSchema, UintSchema } from "@ethernauta/core";
import { sign_user_op, type UserOperation } from "@ethernauta/eip/4337";
import type { Provider } from "@ethernauta/eip/1193";
import { create_provider, encode_chain_id } from "@ethernauta/transport";
import { eip155_1 } from "@ethernauta/chain/eip155-1";
const CHAIN_ID = encode_chain_id({ namespace: "eip155", reference: eip155_1.chainId });
declare const provider: Provider; // see /eips/6963 for discovery
const { signer } = create_provider(provider);
declare const op: UserOperation;
const owner: Address = parse(AddressSchema, "0x70997970C51812dc3A010C7d01b50e0d17dc79C8");
const entryPoint: Address = parse(AddressSchema, "0x0000000071727De22E5E9d8BAf0edAc6f37da032");
const chainId: Uint = parse(UintSchema, "0x1");
const signature = await sign_user_op({ op, owner, entryPoint, chainId })(
signer({ chain_id: CHAIN_ID }),
);
void signature; sign_user_op computes the UserOp hash and signs it. Used in test fixtures and off-wallet flows; the wallet does the same composition internally when serving an eth_sendTransaction-equivalent for smart accounts.
Types and schemas
UserOperation, PackedUserOperation, UserOperationByHash, UserOperationReceipt, EstimateUserOperationGasResult — all with matching Valibot schemas (*Schema).
A note on scope
EIP-4337 as written requires off-chain infrastructure (bundlers, paymasters). The library ships the protocol shapes — packing, hashing, signing, the RPC method bindings — but does not stand up a hosted bundler or paymaster. That keeps M4 (no hosted infrastructure) intact.
A dapp using 4337 today still needs a bundler endpoint somewhere (its own, a third-party service, or a chain whose node speaks the methods natively). The library is bundler-agnostic.
See also
- EIP-7702 — the alternative path (EOAs delegating to contract code, no bundler).
- Concepts → no paid services — why the bundler stays external.