Solidity custom error의 revert data는 error의 canonical signature를 Keccak-256한 앞 4바이트 selector 뒤에 ABI-encoded arguments를 붙인 형식입니다. 예를 들어 InsufficientBalance(uint256,uint256)의 selector 뒤에는 requested와 available 두 32바이트 word가 옵니다. Error(string)은 0x08c379a0, Panic(uint256)은 0x4e487b71 형식이고 out-of-gas·잘못된 opcode·returndata 없는 low-level 실패는 빈 bytes일 수 있습니다. 외부 계약은 임의 revert bytes를 만들 수 있으므로 selector가 ABI 이름과 맞는다는 사실만으로 오류 출처나 진실성을 신뢰해서는 안 됩니다.
첫 네 바이트는 error signature의 selector입니다
Custom error 선언 error Unauthorized(address caller)의 canonical signature 문자열은 Unauthorized(address)이고 keccak256 결과의 첫 4바이트가 selector입니다. Revert 시 selector 뒤에 caller를 ABI word로 encode합니다. Parameter 이름은 signature에 들어가지 않고 tuple·array는 canonical type 표기를 따라야 합니다.
Function selector와 같은 4바이트 공간을 사용하므로 충돌 가능성이 있으며 selector database의 이름 후보는 증거가 아닙니다. Verified source 또는 배포 bytecode에 대응하는 ABI에서 error definition을 가져오고 returndata length·offset·padding이 전체 schema와 맞는지 확인합니다.
Revert selector는 오류 이름표 후보일 뿐입니다. 어느 호출 frame이 어떤 조건으로 그 bytes를 만들었는지는 trace가 증명합니다.
JOBCOIN 해설

그림은 이 주제의 공통 개념을 단순화한 설명입니다. 아래 항목에서 이 글의 구체적인 조건과 예외를 함께 읽어보세요.
- 첫 네 바이트는 error signature의 selector입니다
Custom error 선언 error Unauthorized(address caller)의 canonical signature 문자열은 Unauthorized(address)이고 keccak256 결과의 첫 4바이트가 selector입니다.
- 표준적인 세 형식과 빈 데이터를 구분합니다
require(false, string)와 revert(string)는 일반적으로 Error(string) selector 0x08c379a0 뒤 dynamic string offset·length·bytes를 반환합니다.
- 잔액 부족 예제를 word 단위로 풉니다
error InsufficientBalance(uint256 requested,uint256 available)를 선언하고 requested=100, available=40으로 revert했다고 하겠습니다.
AI로 제작한 개념도 · 실제 가격·거래 내역·통계가 아닙니다.
표준적인 세 형식과 빈 데이터를 구분합니다
require(false, string)와 revert(string)는 일반적으로 Error(string) selector 0x08c379a0 뒤 dynamic string offset·length·bytes를 반환합니다. assert 실패나 arithmetic overflow 같은 compiler panic은 Panic(uint256) selector 0x4e487b71과 panic code를 사용합니다. Custom error는 선언별 selector와 arguments를 가집니다.
호출 대상에 code가 없는데 interface call을 했거나 out-of-gas, invalid opcode, returndata 복사 전 실패 등에서는 빈 bytes가 보일 수 있습니다. 빈 데이터만으로 원인을 하나로 확정하지 말고 call target code, gas, opcode trace와 client error를 대조합니다.
| 형식 | 앞부분 | 다음 확인 |
|---|---|---|
| Error(string) | 0x08c379a0 | offset·length·UTF-8 bytes |
| Panic(uint256) | 0x4e487b71 | panic code 의미 |
| Custom error | keccak(signature)[0:4] | 신뢰 ABI와 인수 |
| 빈 bytes | 길이 0 | gas·target code·trace |
| 알 수 없는 bytes | 기타 selector | 충돌·forwarding·malformed |
잔액 부족 예제를 word 단위로 풉니다
error InsufficientBalance(uint256 requested,uint256 available)를 선언하고 requested=100, available=40으로 revert했다고 하겠습니다. Returndata 앞 4바이트를 signature hash와 비교하고, 남은 64바이트를 두 uint256으로 decode합니다. Static types라 offset이 없지만 string이나 bytes 인수가 있으면 head의 offset을 따라 tail length와 범위를 검사합니다.
Decoder가 selector를 제거하지 않고 전체 bytes를 abi.decode하면 word alignment가 4바이트 밀립니다. 반대로 길이가 짧은 데이터를 억지로 slice하면 예외가 또 생겨 원래 오류를 가립니다. 최소 길이와 모든 dynamic offset이 returndata 범위 안인지 확인한 뒤 사람이 읽을 메시지를 만듭니다.
- Success flag와 returndata hex·길이를 먼저 보존합니다.
- 4바이트 selector를 분리해 알려진 세 형식을 분류합니다.
- 배포 주소·code hash에 맞는 ABI를 선택합니다.
- Static word와 dynamic offset 범위를 검증합니다.
- 실패 frame과 caller의 catch·bubble 동작을 trace합니다.
오류는 외부 계약에서 위조되어 올라올 수 있습니다
Solidity ABI 명세는 error data가 호출 chain을 타고 올라오며 어떤 contract도 다른 contract의 error처럼 보이는 bytes를 만들 수 있다고 경고합니다. Router가 token의 custom error를 그대로 bubble할 수도 있고 악성 token이 router 자체 오류 selector를 반환할 수도 있습니다. UI는 ‘Router가 Unauthorized를 발생시켰다’고 단정하지 않습니다.
try/catch Error(string)와 Panic(uint256)는 알려진 형식을 분기할 수 있지만 custom error는 low-level bytes catch와 selector decoding이 필요할 수 있습니다. Catch가 실패를 정상 fallback처럼 처리한다면 state transition이 안전한지도 검토합니다. 오류 설명은 권한 판단 자료가 아닙니다.
eth_call 오류와 채굴 receipt를 같은 증거로 보지 않습니다
eth_call·estimateGas는 node가 선택한 block state에서 실행해 revert data를 돌려줄 수 있지만 pending state, sender·value·gas 설정이 실제 transaction과 다르면 결과도 달라집니다. RPC provider가 error.data를 감싸거나 생략하는 방식도 client별로 다를 수 있습니다.
채굴된 receipt status 0은 실패를 증명하지만 receipt 자체에는 revert data가 저장되지 않습니다. Transaction을 같은 historical block state에서 replay하거나 debug trace가 필요할 수 있으며 state override로 재현한 결과를 원본 실행 증거라고 부르지 않습니다. Block hash·client version과 call parameters를 기록합니다.
자주 묻는 질문
Receipt에서 custom error를 바로 읽을 수 있나요?
일반 receipt에는 revert data가 없습니다. RPC 실행 오류나 historical replay·trace에서 얻어야 하며 provider 지원이 다릅니다.
Selector database가 찾은 이름은 확정인가요?
아닙니다. 4바이트 충돌과 위조가 가능하므로 해당 배포 code에 맞는 신뢰 ABI와 인수 decoding을 확인해야 합니다.
빈 revert data는 out-of-gas인가요?
가능한 원인 중 하나일 뿐입니다. Target code 유무, invalid opcode, gas와 call trace를 함께 확인해야 합니다.
더 깊이 읽기
본문에서 다룬 개념과 확인 절차를 다음 글에서 이어서 살펴보세요.



