EIP-7702와 EOA 위임
도입
EIP-7702는 EOA가 account code를 설정해 smart account와 비슷한 UX를 사용할 수 있게 하는 core EIP다. 사용자는 authorization tuple에 서명하고, 그 결과 EOA의 code가 특정 contract code를 가리키는 delegation indicator로 설정된다.
결제 UX 관점에서는 batching, sponsorship, privilege de-escalation이 핵심이다. approve 후 pay를 묶고, relayer가 gas를 sponsor하고, sub-key가 제한된 stablecoin 결제만 실행하게 만들 수 있다. 하지만 delegation은 계정 권한에 직접 닿는다. 사용자가 무엇에 서명하는지 모르면 지갑 전체가 위험해질 수 있다.
학습 목표
- EOA 위임 모델의 편의성과 권한 위험을 설명한다.
- delegation authorization을 결제 보안 요구사항으로 변환한다.
개념 설명
EIP-7702와 EOA 위임을 제품 설계에 넣어도 되는가?
서명 권한과 지출 한도가 분리되는가
paymaster 정책이 설명 가능한가
세션키 오남용이 차단되는가
EIP-7702 authorization tuple은 [chain_id, address, nonce, y_parity, r, s] 형태다. 유효한 authorization이 처리되면 authorizing EOA의 code는 0xef0100 || address 형식의 delegation indicator가 된다. 이후 해당 EOA로 들어오는 execution은 indicator가 가리키는 code를 EOA context에서 실행한다.
| 요소 | 의미 | 결제 UX에서 표시할 것 |
|---|---|---|
chain_id | authorization이 유효한 chain | chain name, chainId |
address | delegate code 주소 | contract name, code hash, audit status |
nonce | EOA authorization replay 방지 | current nonce, expiry 또는 rotation plan |
| delegation indicator | EOA가 어떤 code를 따라 실행할지 표시 | delegated 상태 여부 |
| clear delegation | zero address로 code를 비우는 경로 | revoke 또는 reset action |
EIP-7702의 UX 동기는 세 가지다.
| 기능 | stablecoin checkout 예시 | 위험 |
|---|---|---|
| Batching | approve와 pay를 한 번에 실행 | 실패 시 어떤 단계가 실행됐는지 추적 필요 |
| Sponsorship | relayer가 gas를 내고 stablecoin으로 정산 | sponsor 조건과 charge reconciliation 필요 |
| Privilege de-escalation | sub-key가 하루 50 USDC까지만 결제 | delegate code가 실제로 권한 제한을 강제해야 함 |
중요한 점은 delegation이 persistent할 수 있다는 것이다. 한 번 설정된 위임은 단순 transaction 실패로 자동 rollback되지 않을 수 있고, 사용자는 reset 또는 revocation 경로를 이해해야 한다.
코드로 확인하기
EIP-7702 계열의 위임 모델은 EOA가 일시적으로 account logic을 갖는 상황을 만든다. 코드에서는 delegation 권한의 범위와 만료 조건을 명확히 드러내야 한다.
클라이언트위임 요청 envelope 만들기
type DelegationRequest = { delegator: `0x${string}`; implementation: `0x${string}`; chainId: bigint; validUntil: bigint; scopeHash: `0x${string}`;};function buildDelegationRequest(input: DelegationRequest) { return { domain: { name: "DelegatedCheckout", version: "1", chainId: input.chainId }, types: { Delegation: [ { name: "delegator", type: "address" }, { name: "implementation", type: "address" }, { name: "validUntil", type: "uint256" }, { name: "scopeHash", type: "bytes32" } ] }, primaryType: "Delegation" as const, message: input };}implementation은 실행될 account logic이고, scopeHash는 어떤 결제 행위를 허용하는지 묶는다. UI는 이 두 값을 사람이 이해할 수 있는 이름으로 바꿔 보여줘야 한다.
컨트랙트위임 실행 전 scope 검증
function executeDelegatedPayment( address target, uint256 value, bytes calldata callData, bytes32 scopeHash) external { if (!approvedScopes[msg.sender][scopeHash]) revert ScopeNotApproved(); if (!allowedTargets[target]) revert TargetNotAllowed(target); if (value > maxPaymentValue[msg.sender]) revert PaymentLimitExceeded(); (bool ok,) = target.call{value: value}(callData); if (!ok) revert DelegatedCallFailed();}위임 모델의 위험은 "한 번 허용한 logic이 너무 많은 일을 할 수 있다"는 점이다. 따라서 target, value, selector, 만료 시간을 별도 정책으로 줄여야 한다.
인덱서delegation revocation 누락 감시
select delegator, implementation, scope_hash, valid_untilfrom delegation_sessionswhere revoked_at is null and valid_until < now()order by valid_until asc;delegation은 생성보다 해제가 중요하다. 만료된 scope가 revoke 없이 남아 있으면 사용자는 권한이 끝났다고 생각하지만 indexer와 policy engine은 여전히 모호한 상태를 보게 된다.
강의 포인트
| 관점 | 확인할 질문 | 증거로 남길 것 |
|---|---|---|
| authorization 표시 | delegate address, code hash, chain, nonce가 사용자에게 보이는가 | wallet prompt field list |
| 권한 범위 | delegate code가 어떤 token, merchant, amount, function을 실행할 수 있는가 | permission table |
| 취소 경로 | delegation reset 또는 새로운 delegation으로 어떻게 회수하는가 | revocation flow |
| app compatibility | msg.sender == tx.origin 가정이 깨지는 contract가 있는가 | compatibility risk list |
| initialization | delegated account 초기화가 front-running되지 않는가 | initialization checklist |
실무 예시
checkout 앱이 사용자에게 "더 빠른 결제"를 위해 EIP-7702 authorization을 요청한다고 가정한다. 좋은 prompt는 아래 필드를 보여준다.
| 필드 | 사용자에게 보여줄 이유 |
|---|---|
| Delegate contract | 어떤 code가 내 EOA context에서 실행되는지 알 수 있어야 한다 |
| Code hash/version | 앱이 말한 contract와 실제 contract가 같은지 확인해야 한다 |
| Allowed actions | approve, pay, refund claim, session key 설정 중 무엇이 가능한지 보여야 한다 |
| Spending limit | 하루/merchant/token별 지출 한도가 있어야 한다 |
| Expiration or reset path | 사용자가 언제 어떻게 권한을 끝낼 수 있는지 알아야 한다 |
| Support contact/runbook | 위임 오작동 시 어떤 절차로 멈출지 명확해야 한다 |
흔한 오해와 실패 시나리오
| 오해 | 실제로 확인할 것 |
|---|---|
| EIP-7702는 임시 session처럼 쓰면 된다고 본다. | delegation은 persistent할 수 있으므로 reset/revoke UX가 필요하다. |
| delegate contract를 앱이 알아서 고르면 된다고 본다. | 사용자의 EOA context에서 실행되는 code이므로 wallet이 code identity를 검증해 보여줘야 한다. |
| 권한 제한은 UI 문구로 충분하다고 본다. | delegate code 또는 module이 token, amount, merchant, time limit을 실제로 강제해야 한다. |
tx.origin 기반 보안 체크가 계속 유효하다고 본다. | EOA가 code를 갖고 실행될 수 있어 기존 가정이 깨질 수 있다. |
| transaction 실패가 delegation도 되돌린다고 본다. | authorization 처리와 execution 실패의 rollback 관계를 따로 확인해야 한다. |
실습 과제
- EIP-7702와 EOA 위임 이해 점검: authorization tuple, delegation indicator, clear delegation, persistent delegation을 각각 한 문장으로 설명한다.
- 권한 표시 필드 설계: checkout 권한 요청 화면에 delegate address, code hash, allowed actions, token, merchant, spending limit, expiration/reset path를 넣는다.
- 취소 경로 정의: 사용자가 delegation을 끝내는 절차, 실패 시 support runbook, delegate contract upgrade 시 재승인 절차를 작성한다.
- compatibility risk 작성:
msg.sender == tx.origin, initialization front-running, storage management, relayer sponsorship 위험을 점검표로 만든다.
완료 기준
- EOA 위임 위험을 설명했다.
- 권한 표시 필드를 만들었다.
- 취소 경로를 정의했다.
근거 자료
- EIP7702 EOA 위임: 05-계정추상화-에이전트결제/02-EIP7702-EOA-위임.md
- EIP-7702: Set Code for EOAs: https://eips.ethereum.org/EIPS/eip-7702