저자: Kong
편집자: 셰리
머리말
이더리움은 의심할 여지 없이 중요한 업데이트인 Pectra 업그레이드를 곧 선보일 예정입니다. 이 기회를 통해 여러 가지 중요한 이더리움 개선 제안이 소개될 것입니다. 이 중 EIP-7702는 이더리움 외부 계정(EOA)에 혁신적인 변화를 가져왔습니다. 이 제안은 EOA와 계약 계정 CA 간의 경계를 모호하게 만듭니다. 이는 EIP-4337 이후 기본 계정 추상화를 향한 핵심 단계로, 이더리움 생태계에 새로운 상호작용 모드를 제공합니다.
현재 Pectra는 테스트 네트워크에 배포되었으며, 곧 메인 네트워크에 출시될 예정입니다. 본 논문에서는 EIP-7702의 구현 메커니즘을 심층적으로 분석하고, 이것이 가져올 수 있는 기회와 과제를 살펴보며, 다양한 참여자를 위한 실질적인 운영 지침을 제공합니다.
프로토콜 분석
개요
EIP-7702는 EOA가 스마트 계약 주소를 지정하고 해당 주소를 위한 코드를 설정할 수 있도록 하는 새로운 거래 유형을 도입합니다. 이를 통해 EOA는 거래를 개시하는 기능을 유지하면서도 스마트 계약처럼 코드를 실행할 수 있습니다. 이 기능은 EOA에 프로그래밍 가능성과 구성 가능성을 제공하여 사용자가 소셜 복구, 권한 제어, 다중 서명 관리, zk 검증, 구독 결제, 거래 후원, 거래 배치와 같은 기능을 EOA에서 구현할 수 있도록 합니다. EIP-7702는 EIP-4337이 구현한 스마트 계약 지갑과 완벽하게 호환된다는 점이 언급할 가치가 있습니다. 두 가지가 완벽하게 통합됨으로써 새로운 기능의 개발 및 적용 프로세스가 크게 간소화되었습니다.
EIP-7702의 구체적인 구현은 다음과 같이 데이터 구조가 정의된 트랜잭션 유형 SET_CODE_TX_TYPE(0x04)을 갖는 트랜잭션을 도입하는 것입니다.
rlp([체인_ID, 논스, 가스당_최대_우선순위_수수료, 가스당_최대_수수료, 가스_한도, 대상, 값, 데이터, 액세스_목록, 권한_목록, 서명_y_패리티, 서명_r, 서명_s])
authorization_list 필드는 다음과 같이 정의됩니다.
권한 부여 목록 = [[체인 ID, 주소, 논스, y_패리티, r, s], ...]
새로운 거래 구조에서는 authorization_list 필드를 제외한 나머지는 EIP-4844와 동일한 의미 체계를 따릅니다. 이 필드는 목록 유형입니다. 목록에는 여러 개의 권한 항목이 포함될 수 있습니다. 각 권한 항목에서:
- chain_id 필드는 이 권한 위임이 적용되는 체인을 나타냅니다.
- 주소 필드는 위임의 대상 주소를 나타냅니다.
- nonce 필드는 현재 승인된 계정의 nonce와 일치해야 합니다.
- y_parity, r, s 필드는 권한 부여에 서명하는 권한 부여 계정의 서명 데이터입니다.
거래의 authorization_list 필드에는 여러 개의 서로 다른 승인 계정(EOA)에서 서명한 승인 항목이 포함될 수 있습니다. 즉, 거래 개시자는 승인자와 다를 수 있으므로 승인자의 승인된 작업에 대한 가스 지불을 실현할 수 있습니다.
성취하다
권한 부여 데이터에 서명할 때 권한 부여자는 먼저 chain_id, address, nonce에 대한 RLP 인코딩을 수행해야 합니다. 인코딩된 데이터는 Keccak256을 사용하여 MAGIC 번호와 함께 해시되어 서명될 데이터를 얻습니다[1]. 마지막으로 해시된 데이터는 권한이 있는 사람의 개인 키를 사용하여 서명되어 y_parity, r, s 데이터를 얻습니다. 이 중 MAGIC(0x05)은 서로 다른 유형의 서명 결과가 충돌하지 않도록 하기 위해 필드 구분 기호로 사용됩니다.
// Go-ethereum/core/types/tx_setcode.go#L109-L113func (a *SetCodeAuthorization) sigHash() 공통 해시 { 0x05, []any{ a.ChainID, a.Address, a.Nonce, })를 반환합니다.
권한 부여자가 허가한 chain_id가 0인 경우 권한 부여자가 [2] EIP-7702를 지원하는 모든 EVM 호환 체인에서 권한이 재생되도록 허용한다는 의미입니다(nonce도 일치하는 경우).
// Go-ethereum/core/state_transition.go#L562if !auth.ChainID.IsZero() && auth.ChainID.CmpBig(st.evm.ChainConfig().ChainID) != 0 { 권한 반환, ErrAuthorizationWrongChainID}
승인자가 승인 데이터에 서명한 후, 거래 개시자는 서명을 위해 authorization_list 필드에 해당 데이터를 수집하고 RPC를 통해 거래를 브로드캐스트합니다. 거래가 실행을 위해 블록에 포함되기 전에 제안자는 먼저 거래에 대한 사전 검사를 수행합니다.[3] 이 검사에서는 이 거래가 계약 생성 거래가 아닌지 확인하기 위해 주소에 대한 필수 검사가 수행됩니다. 즉, EIP-7702 형태의 트랜잭션을 보낼 때 트랜잭션의 수신 주소는 비어 있을 수 없다[4].
// Go-ethereum/core/state_transition.go#L388-L390if msg.To == nil { return fmt.Errorf("%w (발신자 %v)", ErrSetCodeTxCreate, msg.From)}
동시에, 이러한 트랜잭션은 트랜잭션의 authorization_list 필드에 최소한 하나의 권한 부여 항목이 포함되도록 강제합니다. 동일한 승인자가 여러 개의 승인 항목에 서명한 경우, 마지막 승인 항목만 적용됩니다.
// Go-ethereum/core/state_transition.go#L391-L393msg.SetCodeAuthorizations가 0이면 fmt.Errorf("%w(발신자 %v)", ErrEmptyAuthList, msg.From)을 반환합니다.
나중에 트랜잭션을 실행하는 동안 노드는 먼저 트랜잭션 개시자의 nonce 값을 증가시킨 다음, authorization_list의 각 authorization 항목에 대해 applyAuthorization을 실행합니다. applyAuthorization 작업에서 노드는 먼저 승인자의 nonce를 확인한 다음 승인자의 nonce를 증가시킵니다. 즉, 거래 개시자와 승인자가 동일한 사용자(EOA)인 경우 승인 거래에 서명할 때 nonce 값을 1만큼 늘려야 합니다.
// Go-ethereum/core/state_transition.go#L489-L497func(st *stateTransition) execute() (*ExecutionResult, error) { ... st.state.SetNonce(msg.From, st.state.GetNonce(msg.From)+1, tracing.NonceChangeEoACall)
// EIP-7702 권한을 적용합니다. if msg.SetCodeAuthorizations != nil { for _, auth := range msg.SetCodeAuthorizations { // 오류는 무시되고, 잘못된 인증은 건너뜁니다. st.applyAuthorization(&auth) } } ...}// Go-ethereum/core/state_transition.go#L604func(st *stateTransition) applyAuthorization(auth *types.SetCodeAuthorization) 오류 { 권한, 오류 := st.validateAuthorization(auth) ... st.state.SetNonce(권한, auth.Nonce+1, 추적.NonceChangeAuthorization) ...}// Go-ethereum/core/state_transition.go#L566func(st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorization) (권한 공통.주소, 오류) { ... auth.Nonce+1 < auth.Nonce이면 { 권한 반환, ErrAuthorizationNonceOverflow } ...}
노드가 권한 부여 항목을 적용할 때 오류가 발생하면 해당 권한 부여 항목은 건너뛰어지고 거래는 실패하지 않습니다. 다른 권한 항목은 계속 적용되므로 일괄 권한 부여 시나리오에서 DoS 위험이 발생하지 않습니다.
// Go-ethereum/core/state_transition.go#L494for _, auth := range msg.SetCodeAuthorizations { // 오류는 무시되고, 잘못된 인증은 건너뜁니다. st.applyAuthorization(&auth)}
승인 신청이 완료되면 승인자 주소의 코드 필드가 0xef0100 ||로 설정됩니다. 주소, 여기서 0xef0100은 고정 식별자이고 주소는 위임의 대상 주소입니다. EIP-3541의 제한으로 인해 사용자는 일반적인 방식으로 0xef 바이트로 시작하는 계약 코드를 배포할 수 없으며, 이러한 식별자는 SET_CODE_TX_TYPE(0x04) 유형의 트랜잭션을 통해서만 배포될 수 있습니다.
// Go-ethereum/core/state_transition.go#L612st.state.SetCode(권한, 유형.주소위임(인증.주소))
// Go-ethereum/core/types/tx_setcode.go#L45var 위임 접두사 = []byte{0xef, 0x01, 0x00}
주소 위임(주소 공통.주소) []byte { DelegationPrefix, 주소.Bytes()...에 추가합니다.)를 반환합니다.
권한 부여가 완료된 후, 권한 부여자가 권한을 해제하고 싶을 경우 위임의 대상 주소를 0 주소로 설정하기만 하면 됩니다.
EIP-7702에서 도입된 새로운 거래 유형을 사용하면 승인자(EOA)가 거래를 개시할 수 있는 기능을 유지하면서도 스마트 계약처럼 코드를 실행할 수 있습니다. EIP-4337과 비교했을 때 이 기능은 사용자에게 기본 계정 추상화(네이티브 AA)에 더 가까운 경험을 제공하고, 사용자의 사용 임계값을 크게 줄여줍니다.
모범 사례
EIP-7702는 이더리움 생태계에 새로운 활력을 불어넣었지만, 새로운 응용 프로그램 시나리오는 새로운 위험도 가져올 것입니다. 생태계 참여자들이 실습 중에 주의해야 할 측면은 다음과 같습니다.
개인 키 저장
EOA는 스마트 계약의 내장된 사회적 복구 기능을 사용하여 위탁 후 개인 키 분실로 인한 재정적 손실 문제를 해결할 수 있지만, 여전히 EOA 개인 키가 유출될 위험을 피할 수는 없습니다. 위임을 실행한 후에도 EOA 개인 키는 여전히 계정에 대한 가장 높은 통제권을 가지며, 개인 키를 보유한 사람은 원하는 대로 계정에 있는 자산을 처분할 수 있다는 점을 명확히 밝혀야 합니다. 사용자 또는 지갑 서비스 제공자가 EOA에 대한 수수료를 완료한 후 로컬에 저장된 개인 키가 완전히 삭제되더라도 개인 키 유출 위험을 완전히 배제할 수는 없습니다. 특히 공급망 공격 위험이 있는 상황에서는 더욱 그렇습니다.
위임된 계정을 사용하는 사용자의 경우 개인 키 보호를 가장 먼저 고려해야 하며, 항상 다음 사항을 기억해야 합니다. 키가 아니면 코인도 보호되지 않습니다.
멀티 체인 리플레이
위임 권한에 서명할 때 사용자는 chainId를 통해 위임이 적용될 수 있는 체인을 선택할 수 있습니다. 물론 사용자는 위임에 chainId 0을 사용하도록 선택할 수도 있으며, 이를 통해 위임을 재생하고 여러 체인에 적용할 수 있으므로 사용자가 하나의 서명으로 여러 체인에 위임하기 편리합니다. 그러나 여러 체인에 위임된 동일한 계약 주소에 서로 다른 구현 코드가 존재할 수 있다는 점에 유의해야 합니다.
지갑 서비스 제공자의 경우 사용자가 위임할 때 위임 유효 체인이 현재 연결된 네트워크와 일치하는지 확인해야 하며, chainId 0으로 위임에 서명하면 발생할 수 있는 위험을 사용자에게 상기시켜야 합니다.
사용자는 서로 다른 체인에 있는 동일한 계약 주소의 계약 코드가 항상 같지는 않다는 점을 유의해야 하며, 먼저 위임 대상을 이해해야 합니다.
초기화할 수 없습니다
현재 주류를 이루는 스마트 계약 지갑의 대부분은 프록시 모델을 사용합니다. 지갑 프록시가 배포되면 DELEGATECALL을 통해 계약 초기화 함수를 호출하여 지갑 초기화 및 프록시 지갑 배포의 원자적 작업을 달성하고 선점 문제를 방지합니다. 하지만 사용자가 위임을 위해 EIP-7702를 사용하는 경우, 해당 주소의 코드 필드만 업데이트되며, 위임 주소를 호출하여 초기화할 수 없습니다. 이로 인해 EIP-7702가 일반적인 ERC-1967 프록시 계약처럼 지갑을 초기화하기 위해 계약 배포 트랜잭션에서 초기화 함수를 호출하는 것이 불가능해집니다.
개발자의 경우 EIP-7702를 기존 EIP-4337 지갑과 결합할 때 지갑 초기화 작업 중에 권한 확인을 수행하는 데 주의해야 합니다(예: ecrecover를 통해 서명 주소를 복원하여 권한 확인을 수행하는 것).이렇게 하면 지갑 초기화 작업이 우선적으로 처리되는 위험을 피할 수 있습니다.
스토리지 관리
사용자가 EIP-7702 위임 기능을 사용할 때 기능 요구 사항 변경, 지갑 업그레이드 등으로 인해 다른 계약 주소로 재위임해야 할 수 있습니다. 그러나 다른 계약의 저장 구조는 다를 수 있습니다(예: 다른 계약의 slot0은 다른 유형의 데이터를 나타낼 수 있음). 재위임의 경우 새로운 계약이 실수로 이전 계약의 데이터를 재사용할 수 있으며, 이로 인해 계정 잠금, 자금 손실 등의 부정적인 결과가 초래될 수 있습니다.
사용자의 경우 재위임은 신중하게 처리해야 합니다.
개발자의 경우, ERC-7201에서 제안한 네임스페이스 공식에 따라 개발 프로세스를 진행하여 변수를 지정된 독립된 저장 위치에 할당하여 저장 충돌 위험을 완화해야 합니다. 또한 ERC-7779(초안)는 EIP-7702에 대한 표준 재위임 프로세스도 제공합니다. 여기에는 ERC-7201을 사용하여 저장소 충돌을 방지하고, 재위임 전에 저장소 호환성을 확인하고, 이전 위임 인터페이스를 호출하여 이전에 저장된 데이터를 정리하는 것이 포함됩니다.
가짜 충전
사용자가 수수료를 지불한 후에는 EOA를 스마트 계약으로도 사용할 수 있으므로 중앙 집중형 거래소(CEX)는 보편적인 스마트 계약 충전이라는 상황에 직면할 수 있습니다.
CEX는 스마트 계약에서 잘못된 충전이 발생하는 위험을 방지하기 위해 추적 기능을 통해 각 충전 거래의 상태를 확인해야 합니다.
계정 전환
EIP-7702 위임을 구현한 후에는 사용자의 계정 유형을 EOA와 SC 간에 자유롭게 전환할 수 있으며, 이를 통해 해당 계정에서 거래를 시작하고 호출할 수 있습니다. 즉, 해당 계정이 자기 자신에게 전화를 걸고 외부 호출을 할 때 msg.sender도 tx.origin이 되는데, 이는 EOA 전용 프로젝트의 일부 보안 가정을 위반하는 것입니다.
더 이상 계약 개발자가 tx.origin이 항상 EOA라고 가정할 수 없습니다. 마찬가지로, msg.sender == tx.origin을 확인하여 재진입 공격을 방지하는 방법도 실패합니다.
개발자는 개발 과정에서 미래의 참여자가 모두 스마트 계약이 될 수 있다고 가정해야 합니다.
계약 호환성
기존 ERC-721 및 ERC-777 토큰은 계약으로 전송할 때 Hook 기능이 있는데, 이는 수신자가 토큰을 성공적으로 받으려면 해당 콜백 함수를 구현해야 함을 의미합니다.
개발자의 경우, 사용자가 위임한 대상 계약은 주류 토큰과의 호환성을 보장하기 위해 해당 콜백 함수를 구현해야 합니다.
낚시 체크
EIP-7702 위임을 구현한 후에는 사용자 계정의 자산을 스마트 계약으로 제어할 수 있습니다. 사용자가 악의적인 계약에 계정을 위임하면 공격자가 자금을 훔치는 것이 쉬워집니다.
특히 지갑 서비스 제공자는 가능한 한 빨리 EIP-7702 유형의 거래를 지원하는 것이 중요하며, 사용자가 위임된 계약에 서명할 때 위임 대상 계약을 사용자에게 강조 표시하여 피싱 공격의 위험을 완화해야 합니다.
또한, 계정 위임 대상 계약에 대한 보다 심층적인 자동 분석(오픈소스 검사, 권한 검사 등)을 통해 사용자가 이러한 위험을 피하는 데 더 큰 도움이 될 수 있습니다.
요약하다
이 기사에서는 Ethereum의 다가올 Pectra 업그레이드에서 제안된 EIP-7702에 대해 설명합니다. EIP-7702는 새로운 거래 유형을 도입하여 EOA를 프로그래밍하고 구성할 수 있게 만들고, EOA와 계약 계정의 경계를 모호하게 합니다. 현재 EIP-7702와 호환되는 실제 적용이 가능한 스마트 계약 표준이 없기 때문에 사용자, 지갑 서비스 제공자, 개발자, CEX 등 다양한 생태계 참여자들은 많은 어려움과 기회에 직면하게 됩니다. 이 글에서 설명하는 모범 사례는 잠재적 위험을 모두 포괄할 수는 없지만, 모든 당사자가 실제 운영에 참고하고 적용할 만한 가치가 있습니다.
예
[EOA 계정 코드 설정]
https://holesky.etherscan.io/tx/0x29252bf527155a29fc0df3a2eb7f5259564f5ee7a15792ba4e2ca59318080182
[EOA 계정 코드 설정 해제]
https://holesky.etherscan.io/tx/0xd410d2d2a2ad19dc82a19435faa9c19279fa5b96985988daad5d40d1a8ee2269
관련 링크
[1] https://github.com/ethereum/go-ethereum/blob/7fed9584b5426be5db6d7b0198acdec6515d9c81/코어/유형/tx_setcode.go#L109-L113
[2] https://github.com/ethereum/go-ethereum/blob/7fed9584b5426be5db6d7b0198acdec6515d9c81/core/state_transition.go#L562
[3] https://github.com/ethereum/go-ethereum/blob/7fed9584b5426be5db6d7b0198acdec6515d9c81/core/state_transition.go#L304
[4] https://github.com/ethereum/go-ethereum/blob/7fed9584b5426be5db6d7b0198acdec6515d9c81/core/state_transition.go#L388-L390
참고문헌
[EIP-7702] https://eips.ethereum.org/EIPS/eip-7702
[EIP-4844]https://eips.ethereum.org/EIPS/eip-4844
[이더리움으로 이동]https://github.com/ethereum/go-ethereum/tree/7fed9584b5426be5db6d7b0198acdec6515d9c81
[EIP-3541]https://eips.ethereum.org/EIPS/eip-3541#역호환성
[코보: EIP-7702 실용 가이드]
한국어: https://mp.weixin.qq.com/s/ojh9uLw-sJNArQe-U73lHQ
[비엠]https://viem.sh/experimental/eip7702/signAuthorization
[ERC-7210]https://eips.ethereum.org/EIPS/eip-7201
[ERC-7779]https://eips.ethereum.org/EIPS/eip-7779