ERC-20 표준은 transfer와 transferFrom이 bool success를 반환하도록 정의하며 호출자는 false를 반드시 처리해야 합니다. 그러나 배포된 일부 토큰은 성공 시 반환 데이터가 없거나 비표준 동작을 하므로 통합 계약은 안전한 래퍼를 사용합니다. 거래 status, 호출 반환, Transfer 이벤트와 송수신 balanceOf 변화를 함께 봐야 실제 전송 결과를 판단할 수 있습니다.
전송 결과에는 여러 층의 성공 신호가 있다
사용자가 토큰을 보내면 외부 계정의 트랜잭션, 토큰 계약 함수 호출, 계약 내부 상태 변경이 이어집니다. 영수증 status가 1이면 최상위 실행이 revert 없이 끝났다는 뜻입니다. 그러나 호출한 함수가 false를 반환했는데 상위 계약이 이를 무시했다면 전체 거래는 성공 상태로 남아도 기대한 전송은 이뤄지지 않을 수 있습니다.
ERC-20 표준은 transfer와 transferFrom이 bool success를 반환하도록 정의하고 호출자가 false를 처리해야 한다고 강조합니다. 반환값은 블록 탐색기의 거래 status와 같은 값이 아닙니다. 직접 지갑 전송, 라우터를 거친 전송, 다른 계약의 low-level call에 따라 사용자가 볼 수 있는 신호도 달라집니다.
| 신호 | 뜻 | 단독 판단의 한계 |
|---|---|---|
| 영수증 status 1 | 최상위 실행이 revert되지 않음 | 내부 false 무시 가능 |
| 함수 true | 구현이 성공을 반환 | 비표준 부수 효과 가능 |
| Transfer 이벤트 | 계약이 이동 이벤트 기록 | 악성 구현은 상태와 불일치 가능 |
| balanceOf 변화 | 조회 시점의 실제 장부 값 | 리베이스·후속 거래 영향 가능 |
false와 revert는 호출자에게 다르게 전달된다
토큰이 잔액 부족이나 정책 조건에서 revert하면 해당 호출과 상위 호출의 상태 변경이 되돌아갑니다. 상위 계약이 low-level call 실패를 잡아 별도 처리하지 않는 일반 흐름에서는 전체 거래도 실패합니다. 반면 토큰이 단순히 false를 반환하면 EVM 호출 자체는 성공할 수 있고 상위 계약이 값을 검사해야 실패를 인식합니다.
표준 문서가 false를 절대 나오지 않는다고 가정하지 말라고 한 이유가 여기에 있습니다. 디파이 계약이 transferFrom 결과를 무시한 채 사용자의 예치 지분을 발행하면 실제 토큰을 받지 않고 부채를 만들 수 있습니다. 반환값 검사는 회계 불변식을 지키는 입력 검증입니다.
호출이 끝났다는 사실과 자산이 이동했다는 사실을 분리해 확인해야 한다.
JOBCOIN 해설
일부 레거시 토큰은 반환 데이터를 주지 않는다
현실의 토큰 생태계에는 transfer가 성공해도 bool 값을 ABI대로 반환하지 않는 구현이 있습니다. 엄격하게 bool 디코딩하는 계약은 이런 토큰 호출에서 되돌아갈 수 있어 실제 통합성이 깨집니다. 그렇다고 모든 빈 반환 데이터를 무조건 성공으로 취급하면 존재하지 않는 함수나 악성 계약의 동작을 놓칠 수 있습니다.
OpenZeppelin의 SafeERC20은 선택적 반환 데이터를 다루는 래퍼를 제공합니다. 호출이 revert되면 실패시키고, 반환 데이터가 있다면 false인지 검사합니다. 코드가 없는 주소를 성공으로 오인하지 않도록 대상 계약 여부도 고려합니다. 라이브러리 버전과 토큰별 예외를 테스트에서 고정해야 합니다.
- 토큰 계약 주소에 코드가 존재하는지 확인한다.
- low-level call 성공과 디코딩된 bool을 각각 검사한다.
- 반환 데이터가 없는 토큰을 테스트 케이스에 포함한다.
- 전후 잔액 차이가 회계 가정과 맞는지 검증한다.
Transfer 이벤트는 표준 단서지만 잔액과 대조한다
ERC-20은 성공한 전송에서 Transfer 이벤트를 발생시키도록 요구합니다. 인덱서와 지갑은 from, to, value를 이용해 활동을 보여 줍니다. 그러나 이벤트는 계약이 기록하는 로그이므로 비표준 또는 악성 계약이 실제 장부와 다른 값을 낼 가능성을 통합 코드가 배제할 수는 없습니다.
민감한 회계에서는 호출 전후 balanceOf 차이를 측정합니다. 전송 수수료를 떼는 토큰은 발신 amount와 수취 증가량이 다를 수 있고, 리베이스 토큰은 보유량이 다른 규칙으로 변할 수 있습니다. 정확히 amount만큼 도착한다는 가정을 함수 이름만 보고 두지 않습니다.
승인과 transferFrom 실패 지점을 나눠 본다
transferFrom은 owner 잔액뿐 아니라 caller에게 허용된 allowance가 충분해야 합니다. approve 거래가 확정되지 않았거나 spender 주소가 실제 호출자와 다르면 실패합니다. permit 서명을 썼다면 nonce, deadline, domain이 맞지 않아 승인 단계에서 먼저 되돌아갈 수 있습니다.
문제를 진단할 때 owner balance, allowance(owner, spender), 실제 msg.sender, transferFrom 반환 또는 revert data를 순서대로 확인합니다. 프록시 라우터에서는 사용자가 승인한 주소와 최종 토큰 호출자가 다른 구조가 있을 수 있습니다. 공식 배포 주소와 호출 trace로 관계를 검증합니다.
테스트는 성공 사례보다 이상 구현을 포함한다
통합 테스트에 정상 true 토큰만 사용하면 반환값 누락, false, fee-on-transfer, blacklist, pause 같은 운영 조건을 놓칩니다. 각각을 모의한 토큰으로 예치·교환·인출의 회계 불변식을 확인합니다. 호출 실패 뒤 내부 크레딧이나 지분이 남지 않는지도 검사합니다.
사용자 화면은 거래 제출과 자산 수령을 구분해 표시해야 합니다. 해시 생성은 네트워크 접수 전일 수 있고 status 1도 목표 수량 수령과 같지 않습니다. 확정 블록의 receipt, 이벤트, 최종 잔액을 조회한 뒤 완료로 표시하고 예상보다 적은 수령은 구체적인 토큰 규칙과 함께 알립니다.
자주 묻는 질문
거래 status가 성공이면 토큰 전송도 무조건 성공인가요?
아닙니다. 상위 계약이 false 반환을 무시했거나 토큰이 비표준 동작을 할 수 있습니다. 이벤트와 전후 잔액을 함께 확인하세요.
Transfer 이벤트가 있으면 충분한가요?
표준적인 강한 단서지만 민감한 회계에서는 balanceOf 변화와 대조합니다. 수수료형·리베이스형 토큰은 표시 수량과 다를 수 있습니다.
SafeERC20은 모든 토큰을 안전하게 만드나요?
흔한 반환값 차이를 처리하지만 악성 계약과 경제적 규칙까지 검증하지는 않습니다. 대상 코드와 잔액 불변식 테스트가 필요합니다.



