ADR-012: ERC-4337 Paymaster + Bundler + SharedAccount for L2
| Status | Accepted |
| Date | 2026-03-17 |
| Supersedes | ADR-002 |
Context
ADR-002 proposed replacing the custom L2 relayer with an ERC-4337 Paymaster but left several open questions: smart account strategy, EBEMT contract compatibility with UserOperations, and gas limits for ZK proof calldata. ADR-004 defined a partner authentication model for relayer security. ADR-005 introduced a SharedAccount pattern for L3 graph privacy.
This ADR resolves those open questions for L2 and extends the SharedAccount pattern from L3 to L2.
Key insight: All three L2 operations can be called by any address — users do not need individual smart accounts:
revealAmount— nomsg.sendercheck; the ZK proof is the sole authorization.concealedTransfer(authorizedCaller=address(0))— nomsg.sendercheck; the ZK proof authorizes.concealAmountWithSig— being added; uses an EIP-712 signature to burn from the signer's balance, notmsg.sender.
Proposal
Replace the custom L2 relayer with three components:
1. SharedAccount
A single ownerless ERC-4337 smart account — the same pattern as ADR-005, extended to L2. All L2 (and L3) operations are submitted as UserOperations with sender = SharedAccount. The SharedAccount is a generic forwarder with an unrestricted execute() function. Since it holds no ETH and has no EntryPoint deposit, only paymaster-sponsored UserOperations can execute through it.
The nonce key is derived from keccak256(callData) to avoid nonce collisions between concurrent users submitting different operations.
2. EBPaymaster (on-chain)
A minimal on-chain paymaster that trusts a single signer — the Paymaster Backend's key. validatePaymasterUserOp verifies the backend's ECDSA signature over the UserOperation hash. The on-chain contract has no knowledge of partners, budgets, or rate limits.
3. Paymaster Backend (off-chain)
An off-chain service that holds the paymaster signing key and the entire partner authentication layer from ADR-004:
- Partner registry — partner IDs, API keys, public keys (all off-chain, not visible on-chain)
- Budget enforcement — per-partner gas caps, rate limits, spending tracking
- Operation allowlisting — inspects UserOperation callData to decide which operations to sponsor
- Billing — per-partner usage tracking for invoicing
Partners send UserOperations to the Paymaster Backend via HTTP. The backend validates the partner, checks budgets, and returns a signed paymasterData that the on-chain paymaster will accept.
Bundler
Use a third-party bundler (Pimlico or Alchemy) on Base. The bundler API is standardized (ERC-4337 RPC methods), so switching providers or self-hosting later is straightforward. The bundler learns nothing beyond what any blockchain observer sees — the only additional exposure is the user's IP address, same as the current relayer and any RPC provider.
Consequences
What becomes easier:
- No custom relayer server for L2 — replaced by a stateless Paymaster Backend (no IMT, no nullifier sync, no TX queue)
- SharedAccount is shared with L3 (ADR-005) — one deployment serves both layers
- Standard ERC-4337 infrastructure; composable with any bundler, wallet, or tooling
- Partner identities stay off-chain — no on-chain visibility into who uses the system
What becomes harder:
- Three components to deploy and maintain (SharedAccount, Paymaster contract, Paymaster Backend) vs. one relayer binary — though each component is simpler and more focused
- Users must wait for Paymaster Backend to co-sign before submitting UserOperations (extra round-trip, same as current relayer)
- EntryPoint v0.9 (
0x433709009B8330FDa32311DF1C2AFA402eD8D009) must be available on the target chain
What stays the same:
- User flow: generate proof client-side, submit, get tx hash
- Privacy: amounts hidden, graph visible (L2 properties unchanged)
- On-chain EBEMT logic: no changes to existing functions (
revealAmount,concealedTransfer)