Deep dive into EIP-7702

Intro : 이더리움 지갑
이더리움 지갑은 ‘0x’로 시작하는 40자리 16진수 문자열, 즉 주소(address)로 식별됩니다. 이러한 주소 형태를 갖춘 값이라면 코인과 토큰을 보관할 수 있는 지갑으로 사용할 수 있으며, 이더리움에서는 크게 두 가지 형태의 계정을 정의합니다.
- 외부 소유 계정(EOA: Externally Owned Account): 개인키(private key)로부터 파생된 공개키 주소
- 컨트랙트 계정(CA: Contract Account): 스마트 컨트랙트에 할당된 주소
EOA는 고유한 단일 개인키로부터 파생되며, 이 키를 소유한 사람이 지갑의 자산을 관리하는 주체가 됩니다. 하지만 이러한 구조는 개인키 관리가 매우 불편하며, 블록체인 사용자에게 불편한 UX를 야기합니다.
개인키 하나만 노출되어도 지갑 내 모든 자산이 탈취될 수 있다는 보안 위험도 존재합니다. 특히 개인키는 64자의 16진수 문자열로 이루어져 있어 은행 비밀번호처럼 외우기 어렵고, USB와 같은 이동식 매체에 저장하여 보관할 경우 오히려 보안이 취약해질 수 있습니다.
반면 CA는 지갑에 필요한 기능(전송, 잔액 조회, 소유권 검사 등)이 구현된 스마트 컨트랙트를 의미합니다. EOA가 가지는 보안 한계를 스마트 컨트랙트 수준에서 다양한 인증 절차로 구현하여 보완할 수 있습니다. 예를 들어 멀티 시그(Multi-Sig) 지갑, ERC-4337 기반 Smart Wallet, MPC(Multi-Party Computation)를 활용한 계정 복구 및 상속 기능 등이 대표적입니다.
Why EIP-7702
하지만 개인키에서 지갑 주소가 파생되는 EOA와 달리 CA의 지갑 주소는 컨트랙트 배포 과정에서 생성되기 때문에 자체적으로 서명할 수 없습니다. 또한 스마트 컨트랙트는 누구나 호출할 수 있으므로, 호출 주체가 실제 소유자인지를 확인하려면 EOA와 마찬가지로 개인키로 생성된 디지털 서명을 전달받아 검증하는 과정이 필요합니다. 결국 CA를 호출하기 위해서도 EOA의 개인키가 필요한 구조이다 보니, 여전히 불편한 개인키 관리가 필요합니다.
이러한 아이러니한 상황을 해소하기 위해 EIP-7702는 EOA와 CA의 경계를 허물고, EOA가 CA처럼 동작할 수 있도록 만들어 사용자 경험을 크게 개선하는 것을 목표로 합니다.
Account Architecture

이더리움 계정은 EOA와 CA 모두 위 이미지와 같이 네 가지 필드—nonce, balance, storage hash, code hash—를 가집니다. 이때 스마트 컨트랙트의 코드는 code hash를 통해 참조됩니다. 계정이 트랜잭션에 의해 호출되면, EVM은 code hash가 가리키는 컨트랙트 코드를 불러와 실행합니다.
실행 과정에서 생성되거나 수정된 데이터는 MPT(Merkle Patricia Trie) 구조로 storage에 저장되며, 최종 머클 루트 해시가 storage hash에 기록됩니다. 반면 EOA는 일반적으로 실행 가능한 코드와 별도의 storage를 가지지 않습니다. 그러나 EIP-7702를 적용하면 EOA에 특수한 코드를 설정하여, EOA가 마치 CA처럼 동작하도록 확장할 수 있습니다.
Set EOA account code for one transaction
지금까지 EIP-7702의 역할을 살펴보았지만, EIP-7702는 EIP-2718에 따라 추가된 새로운 트랜잭션 유형이기도 합니다. EIP-7702는 type 4 트랜잭션으로 지정되며, 이를 통해 사용자는 특정 EOA에 특수한 형태의 코드를 설정할 수 있습니다.
이때 계정 코드에는 ‘Delegation Indicator(이하 DI)’라는 데이터가 저장됩니다. DI는 EOA가 스마트 컨트랙트처럼 동작할 수 있도록, 계정의 실행 코드를 특정 스마트 컨트랙트에 위임한 상태를 나타내는 특수한 코드 형태입니다. DI가 설정된 EOA가 호출되면, EVM은 해당 Indicator에 명시된 컨트랙트 주소의 코드를 불러와 실행합니다. EIP-7702는 이러한 방식을 통해 EOA를 CA처럼 사용할 수 있도록 만듭니다.
Delegation Indicator (DI)
0xef0100 || contract_addressDelegation Indicator는 0xef0100 + 위임할 스마트 컨트랙트 주소(contract_address)를 결합한 총 23바이트의 데이터로 구성됩니다. 여기서 접두사 0xef는 EIP-3541에 의해 새로운 컨트랙트 코드의 시작 바이트로 사용할 수 없도록 예약된 값입니다. 따라서 일반적인 EVM 컨트랙트 코드의 시작 부분에는 등장할 수 없으며, 이를 안전한 마커(marker)로 활용할 수 있습니다.
EIP-7702 도입 이후에는 해당 마커가 EVM 내 CALL·DELEGATECALL·STATICCALL 등의 호출 연산에서 특별한 의미를 가집니다. 계정의 코드가 0xEF0100으로 시작하는 것을 확인하면, “해당 코드를 직접 실행하지 않고 뒤따르는 20바이트 주소가 가리키는 컨트랙트의 코드를 불러와 실행한다”는 특수 로직이 적용됩니다. 즉, 0xef0100은 일반적인 EVM 코드와 Delegation Indicator를 구분하기 위한 전용 마커 역할을 합니다.
컨트랙트 코드 정보 조회 Opcode의 변화
CODESIZE & CODECOPY vs EXTCODESIZE & EXTCODECOPY opcode의 동작 차이
위 Opcode는 모두 스마트 컨트랙트의 코드 정보를 조회하는 역할을 합니다. 차이가 있다면 CODE## 계열은 현재 실행 중인 계정의 코드를 기준으로 동작하고, EXTCODE## 계열은 파라미터로 전달된 특정 주소에 저장된 코드를 조회한다는 점입니다.
하지만 DI(0xef0100)가 설정된 EOA를 대상으로 사용할 경우 두 Opcode 계열의 동작에는 차이가 발생합니다.
CODE##는 Delegation Indicator가 가리키는 스마트 컨트랙트 주소(contract_address)의 코드 정보를 반환합니다.EXTCODE##는 Delegation Indicator 자체(0xef0100 || contract_address)의 정보를 그대로 반환합니다. 따라서 계정에 저장된 코드의 크기를 반환하는EXTCODESIZE는 항상 23 바이트를 반환합니다.
EIP-7702 Signature and Transaction
다음으로 EIP-7702를 호출하기 위해 트랜잭션을 어떻게 구성하고, 어떤 데이터를 서명해야 하는지 살펴보겠습니다.
Transaction payload
# Transaction payload
rlp([ chain_id,
nonce,
max_priority_fee_per_gas,
max_fee_per_gas,
gas_limit,
destination,
data,
access_list,
authorization_list, // => New field about EIP-7702
signature_y_parity,
signature_r,
signature_s
])
authorization_list = [[chain_id, contract_address, nonce, y_parity, r, s], ...]Transaction payload는 트랜잭션 실행에 필요한 데이터 필드를 의미합니다. EIP-7702의 payload는 위와 같이 구성되며, 기본적인 EIP-1559 트랜잭션 구조에 authorization_list 필드가 추가된 형태입니다.
authorization_list에는 EOA의 개인키로 생성한 디지털 서명(y_parity, r, s)과 DI에 기록할 스마트 컨트랙트 주소(contract_address)가 포함됩니다. 이더리움 네트워크가 EIP-7702 트랜잭션을 수신하면 해당 디지털 서명으로부터 EOA 주소를 복구하고, 복구된 EOA에 DI 형태로 해당 contract_address를 설정합니다.
즉, EOA의 유효한 서명이 있어야만 Delegation Indicator를 설정할 수 있는 구조입니다. 또한 authorization_list는 배열 타입이므로 하나의 EIP-7702 트랜잭션에 여러 개의 authorization을 포함할 수 있습니다.
만약 EOA에 설정된 DI를 제거하고 싶다면 contract_address에 Zero Address(0x00…00)를 지정한 authorization에 서명하여 기존 위임을 초기화할 수 있습니다.
msg = keccak(MAGIC || rlp([chain_id, address, nonce]))
# Generate Sig
( y_parity, r, s ) = ECDSA_sig(msg)
# Verify Sig
ecrecover(msg, y_parity, r, s)Authorization에 포함되는 서명 데이터의 스킴은 위와 같이 구성됩니다. chain_id, address, nonce를 RLP 인코딩한 뒤 MAGIC 값을 결합하여 메시지(msg)를 생성하고, 해당 메시지를 ECDSA로 서명하도록 EIP-7702 표준에서 정의하고 있습니다. 이후 검증 과정에서는 동일한 메시지와 서명 값(y_parity, r, s)을 이용해 서명자의 EOA 주소를 복구합니다.
EIP-7702 주의사항
- EIP-7702 트랜잭션의
authorization_list배열 길이(length)가 0인 경우 해당 트랜잭션은 유효하지 않은 것으로 간주합니다. - EIP-7702 트랜잭션은 새로운 스마트 컨트랙트를 배포할 수 없도록
destination필드를 비워둘 수 없습니다.
Relayer와 Authorizer

authorization_list에 서명하는 EOA를 Authorizer라고 부릅니다. 이때 EIP-7702 트랜잭션을 반드시 Authorizer가 직접 전송해야 하는 것은 아닙니다. Authorizer가 생성한 authorization 서명만 포함되어 있다면 다른 EOA가 대신 트랜잭션을 전송할 수 있으며, 이렇게 실제 트랜잭션을 전송하는 EOA를 Relayer라고 부릅니다.
Storage Collision
지갑의 Storage는 code hash에 저장된 코드가 실행되는 과정에서 생성되거나 변경되는 데이터를 저장하는 공간입니다. 이제 EOA도 코드를 실행할 수 있게 되었기 때문에, EOA의 Storage에도 데이터를 저장할 수 있습니다. 하지만 EOA의 DI가 변경되는 과정에서는 Storage slot 충돌 문제가 발생할 수 있습니다.

예를 들어, 어느 EOA의 DI에 Implementation A 컨트랙트가 설정되어 있다고 가정해 보겠습니다. 이때 A 컨트랙트의 함수가 특정 storage slot에 address 타입(20바이트)의 데이터를 저장한다고 하겠습니다.
몇 블록이 지난 뒤 해당 EOA의 DI를 _Implementation B_로 변경했는데, B 컨트랙트 역시 동일한 slot에 bytes32 타입(32바이트)의 데이터를 저장하는 함수를 가지고 있다고 가정해 보겠습니다. 두 구현체가 동일한 slot을 사용하면서 저장하는 데이터의 타입과 크기도 다르기 때문에, 이 경우 storage slot이 충돌하여 의도한 값을 정상적으로 읽거나 저장하지 못할 수 있습니다.
이는 _delegatecall_을 사용하는 업그레이더블 컨트랙트에서 발생하는 스토리지 충돌 문제와 동일합니다. 이러한 문제를 방지하기 위해, DI 변경이 예상되는 경우에는 ERC-7201에서 제안하는 스토리지 레이아웃을 활용하는 것이 권장됩니다.
Security Considerations
Storage Collision 외에도 EIP-7702를 도입할 때 개발자가 고려해야 할 다양한 보안 사항이 커뮤니티에서 언급되고 있는데요. 그중 몇 가지 주요 내용을 살펴보겠습니다.
서명 검증 순서
이더리움이 EIP-7702 트랜잭션을 처리하는 순서를 이해하면, EVM이 어떤 방식으로 동작하고 최종적으로 어떤 결과를 반환하는지 명확하게 파악할 수 있습니다.

EIP-7702 트랜잭션에는 두 가지 서명이 포함됩니다. 하나는 authorization_list에 기록되는 Authorizer 서명이고, 다른 하나는 Relayer의 트랜잭션 서명입니다. 노드에 트랜잭션이 전달되면 먼저 Relayer의 서명을 검증하고, 이후 authorization_list에 포함된 Authorizer의 서명을 검증합니다. Authorizer의 서명이 유효하면 해당 EOA에 DI(Delegation Indicator)를 기록합니다. 이러한 검증 과정이 완료되면 Relayer가 전송한 트랜잭션의 내용에 따라 EVM이 동작합니다. 만약 data 필드에 스마트 컨트랙트 함수를 호출하기 위한 calldata가 포함되어 있다면, 새롭게 설정된 EOA의 DI를 통해 해당 함수가 이어서 실행됩니다.
https://sepolia.etherscan.io/tx/0xcf8384c7e25e236f8f927a6279076c717a941cf67f01add7d40b6e17833da207 확인
이때 개발자가 유의해야 할 핵심은 코드 실행 중 revert()가 발생하더라도, Authorizer의 서명 검증이 성공하여 설정된 DI는 롤백되지 않는다는 점입니다. 실제 해당 케이스의 트랜잭션을 스캐너에서 확인해 보면, 내부 코드 실행 과정에서는 revert()가 발생했지만 트랜잭션 자체는 성공으로 처리된 것을 확인할 수 있습니다.
즉, 이후 코드 실행 과정에서 트랜잭션이 실패하더라도 Authorizer 서명이 유효했다면 EOA에는 DI가 유지되어 CA처럼 동작할 수 있으므로, 필요한 경우 이를 고려한 추가 확인 절차를 도입해야 합니다.
Nonce 충돌

Relayer와 Authorizer는 서로 다른 EOA일 수도 있고, 동일한 EOA일 수도 있습니다. 다만 두 역할을 동일한 EOA가 수행하는 경우에는 nonce 처리에 주의해야 합니다. Relayer의 트랜잭션이 처리되는 과정에서 해당 EOA의 nonce가 먼저 증가하기 때문에, 이후 Authorizer 서명 검증에서 기존과 동일한 nonce를 사용하면 검증에 실패할 수 있습니다. 따라서 동일한 EOA가 Relayer와 Authorizer 역할을 모두 수행한다면, **authorization_list**에 기록하는 nonce는 현재 트랜잭션 nonce보다 1만큼 증가한 값을 사용해야 합니다.
앞서 설명한 것처럼, 트랜잭션 실행이 실패하더라도 Authorizer 서명이 유효하게 검증되었다면 EOA의 DI는 기록될 수 있습니다. 반대로 트랜잭션 자체가 성공하더라도 Authorizer 서명 검증이 nonce 충돌 등의 이유로 실패하면 해당 authorization은 적용되지 않아 DI가 기록되지 않을 수 있습니다.
따라서 개발자는 트랜잭션의 성공 여부만으로 위임 성공 여부를 판단하지 않고, 실제 EOA에 DI가 정상적으로 설정되었는지 추가로 확인하는 절차를 구현할 필요가 있습니다.
onlyEOA() 함수의 무력화

onlyEOA()는 호출자(msg.sender)가 EOA인지 검사하기 위해 사용되는 함수입니다. NFT나 플래시론 등 다양한 컨트랙트에서 EOA만 접근할 수 있도록 제한하는 목적으로 활용되어 왔습니다.
그러나 EOA를 CA처럼 동작할 수 있게 만드는 EIP-7702가 도입되면서, 기존의 onlyEOA() 기반 검증 방식은 더 이상 안전한 구분 기준으로 활용하기 어려워질 수 있습니다. 이로 인해 기존에는 고려하지 않았던 새로운 형태의 보안 취약점이 발생할 가능성이 있습니다.
——————————————
위에서 살펴본 3가지 보안 사항 외에도, elyx0님이 X에 작성한 글을 보면 EIP-7702 도입 시 보안적으로 고려해야 할 부분이 상당히 많아 보입니다. 추가적인 내용을 확인하고 싶다면 아래 글을 함께 참고하면 좋을 것 같습니다.
마무리
이더리움은 개인키에 의존하는 EOA의 보안성과 유연성을 개선하기 위해 2020년 EIP-2938을 시작으로 계정 추상화(Account Abstraction) 도입을 꾸준히 시도해 왔습니다. 그러나 EOA와 CA의 경계를 허물기 위해서는 프로토콜 수준의 업데이트가 필요했고, 탈중앙화 원칙을 중요하게 여기는 이더리움 생태계에서 이러한 대규모 변경을 적용하는 것은 쉽지 않았습니다.
이후 ERC-4337을 통해 프로토콜 변경 없이 계정 추상화를 구현할 수 있게 되었지만, 여전히 복잡한 UX와 가스비 비효율 문제를 완전히 해결하지는 못했습니다. EIP-7702의 도입으로 EOA는 단순히 트랜잭션을 전송하는 역할을 넘어 스마트 컨트랙트의 복잡한 로직을 수행할 수 있게 되었으며, 이를 통해 트랜잭션 자동화나 가스비 최적화와 같은 다양한 기능을 활용할 수 있게 되었습니다.
WEB3 지갑은 여전히 사용자의 진입 장벽이 가장 높은 영역 중 하나입니다. EIP-7702가 이러한 사용자 경험을 비약적으로 개선하고, 더 많은 사용자가 자연스럽게 블록체인을 활용할 수 있도록 하여 생태계 활성화에 기여하기를 기대하며 글을 마칩니다.
Reference
https://eips.ethereum.org/EIPS/eip-7702
https://eips.ethereum.org/EIPS/eip-7201
https://eips.ethereum.org/EIPS/eip-3541
https://x.com/_hrkrshnn/status/1911012420396650952
https://zyfiofficial.medium.com/into-the-future-with-eip-7702-part-1-a1fc80b00bd6
https://zyfiofficial.medium.com/into-the-future-with-eip-7702-part-2-77860ed037db
https://medium.com/decipher-media/account-abstraction-erc-4337-2b8dff6b0a34