ERC-4337 Account Abstraction
도입
계정추상화는 사용자의 결제 경험을 편하게 만들지만, 위험을 없애지는 않는다. ETH 없이 결제하고, 여러 행동을 batch로 묶고, Paymaster가 gas를 sponsor하고, session key가 반복 결제를 처리하려면 누가 무엇을 승인했는지 더 명확하게 기록해야 한다.
ERC-4337은 consensus layer를 바꾸지 않고 smart account 기반 account abstraction을 구현하는 모델이다. 사용자는 일반 transaction이 아니라 UserOperation을 만들고, bundler가 이를 EntryPoint contract로 제출한다. checkout 설계자는 이 흐름을 "사용자가 클릭하지 않아도 되는 UX"가 아니라 "새로운 검증 경로와 실패 경로가 생긴 결제 시스템"으로 읽어야 한다.
학습 목표
- UserOperation, bundler, paymaster, entry point 역할을 설명한다.
- AA가 checkout UX와 risk model을 어떻게 바꾸는지 파악한다.
개념 설명
UserOperation, bundler, paymaster, entry point 역할을 설명한다.
서명 권한과 지출 한도가 분리되는가
ERC-4337 구성요소를 설명했다.
ERC-4337 구성요소는 다음과 같다.
| 구성요소 | 역할 | checkout에서 확인할 것 |
|---|---|---|
| Smart Account | 사용자의 programmable account | 지출 정책, signature scheme, upgrade 권한 |
| UserOperation | 사용자가 원하는 실행 요청 | sender, nonce, callData, gas, paymaster, signature |
| Bundler | UserOperation을 모아 EntryPoint에 제출 | mempool acceptance, censorship, simulation result |
| EntryPoint | validation과 execution을 담당 | trusted EntryPoint address, deposit, handleOps result |
| Paymaster | gas를 대신 내거나 조건부 sponsor | sponsor 조건, griefing 방어, 정산 장부 |
| Factory | 계정이 없을 때 배포 | counterfactual address, init data |
| Aggregator | signature aggregation | wallet-specific signature model |
UserOperation lifecycle은 결제 상태와 별도로 추적한다.
ERC-4337에서 signature의 의미는 protocol이 아니라 smart account implementation이 정한다. 따라서 "ERC-4337 결제"라고만 쓰면 충분하지 않다. 어떤 wallet code가 어떤 signer, session key, module, recovery policy를 인정하는지 문서화해야 한다.
코드로 확인하기
ERC-4337은 결제 UX를 "사용자가 트랜잭션을 직접 보낸다"에서 "UserOperation을 검증하고 실행한다"로 바꾼다. 코드에서는 서명, nonce, paymaster, callData가 분리된 필드로 드러난다.
클라이언트checkout UserOperation 구성
type UserOperation = { sender: `0x${string}`; nonce: bigint; callData: `0x${string}`; callGasLimit: bigint; verificationGasLimit: bigint; maxFeePerGas: bigint; paymasterAndData: `0x${string}`; signature: `0x${string}`;};function buildCheckoutUserOp(input: { account: `0x${string}`; nonce: bigint; checkoutCallData: `0x${string}`; paymasterData: `0x${string}`;}): UserOperation { return { sender: input.account, nonce: input.nonce, callData: input.checkoutCallData, callGasLimit: 250_000n, verificationGasLimit: 180_000n, maxFeePerGas: 30_000_000_000n, paymasterAndData: input.paymasterData, signature: "0x" };}여기서 sender는 사용자의 smart account이고, paymasterAndData는 누가 gas를 낼지 설명한다. 결제 시스템은 이 두 필드를 audit log에 남겨야 한다.
컨트랙트smart account의 validateUserOp 경계
function validateUserOp( PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds) external returns (uint256 validationData) { if (msg.sender != entryPoint) revert OnlyEntryPoint(); if (!_isValidSignature(userOpHash, userOp.signature)) { return SIG_VALIDATION_FAILED; } _validateNonce(userOp.nonce); _payPrefund(missingAccountFunds); return 0;}이 함수는 결제를 실행하지 않는다. 먼저 "이 operation을 account가 인정하는가"를 검증한다. 실행 로직과 검증 로직이 섞이면 paymaster 정책과 replay 방어를 설명하기 어려워진다.
강의 포인트
| 관점 | 확인할 질문 | 증거로 남길 것 |
|---|---|---|
| 지출 주체 | UserOperation sender와 실제 사용자/agent가 어떻게 연결되는가 | account policy summary |
| nonce | replay 방지와 병렬 operation key를 어떻게 관리하는가 | nonce key plan |
| gas sponsor | Paymaster가 어떤 조건에서 gas를 내는가 | paymaster rule table |
| 실패 지점 | bundler rejection, validation failure, execution revert를 구분했는가 | failure code mapping |
| 정산 | gas cost와 stablecoin charge가 reconcile되는가 | gas/payment ledger |
실무 예시
stablecoin checkout을 ERC-4337로 만든다고 가정한다. 사용자는 ETH 없이 smart account에서 permit + pay + receipt를 batch로 실행한다. Paymaster는 이 checkout contract, token, amount, merchant가 allowlist 안에 있을 때만 gas를 sponsor한다.
| 단계 | 시스템 기록 | 사용자 안내 |
|---|---|---|
| UserOperation drafted | sender, nonce, callData hash, paymaster | 결제 요청 준비 중 |
| Bundler submitted | bundler endpoint, userOpHash | 결제 요청 제출됨 |
| Validation rejected | signature/paymaster/gas reason | 지갑 또는 sponsor 조건을 확인해야 함 |
| Included but reverted | transaction hash, revert reason | onchain 실행 실패 |
| Executed | receipt, token movement, gas cost | 결제 완료 |
흔한 오해와 실패 시나리오
| 오해 | 실제로 확인할 것 |
|---|---|
| ERC-4337을 쓰면 사용자가 gas를 신경 쓰지 않아도 된다고 본다. | 누군가는 gas를 내고, Paymaster 정산과 한도 정책이 필요하다. |
| UserOperation을 transaction과 같은 상태로 취급한다. | bundler mempool, simulation, EntryPoint inclusion, account execution이 분리된다. |
| signature 검증이 표준 하나로 정해져 있다고 본다. | signature 의미는 smart account implementation마다 다르다. |
| Paymaster를 UX 기능으로만 본다. | griefing, sponsor drain, postOp 실패, stablecoin charge reconciliation을 검토해야 한다. |
| session key를 편의 기능으로만 본다. | 권한 범위, 만료, merchant allowlist, daily cap을 강하게 제한해야 한다. |
실습 과제
- ERC-4337 Account Abstraction 이해 점검: UserOperation lifecycle을 Drafted, Submitted, Simulated, Included, Executed, Rejected, Failed 상태로 정리한다.
- checkout sequence 작성: ERC-4337 기반 stablecoin checkout과 기존 EOA checkout을 단계, signer, gas payer, failure point로 비교한다.
- Paymaster 위험 정리: sponsor 조건, per-user cap, per-merchant cap, griefing 방어, postOp accounting을 표로 작성한다.
- 운영 로그 설계: userOpHash, bundler, EntryPoint, sender, paymaster, callData hash, receipt를 어떤 테이블에 저장할지 정한다.
완료 기준
- ERC-4337 구성요소를 설명했다.
- UserOperation 상태를 정의했다.
- paymaster 위험을 정리했다.
근거 자료
- 계정추상화 에이전트결제 학습맵: 05-계정추상화-에이전트결제/00-계정추상화-에이전트결제-학습맵.md
- ERC4337 Account Abstraction: 05-계정추상화-에이전트결제/01-ERC4337-Account-Abstraction.md
- ERC-4337: Account Abstraction: https://eips.ethereum.org/EIPS/eip-4337