‘98개를 받습니다’가 틀릴 때
요즘 많은 지갑은 서명 버튼을 누르기 전에 ‘이 거래로 토큰 A 1개가 나가고 토큰 B 98개가 들어옵니다’ 같은 예상 결과를 보여줍니다. 거래를 미리 가상으로 실행해 본 결과로, 승인하려는 내용을 이해하는 데 큰 도움이 됩니다. 하지만 이 결과는 예측이지 보장이 아닙니다.
이 글은 지갑 시뮬레이션이 어떤 방식으로 결과를 계산하는지, 실제 실행 결과가 왜 달라질 수 있는지 설명합니다. 같은 스왑이 여러 상황에서 어떻게 끝나는지 가상의 표로 비교하고, 시뮬레이션이 보여주지 않는 승인 권한과 악성 계약의 위험, 서명 전에 확인할 항목을 정리합니다.
시뮬레이션이 계산하는 방식
Ethereum.org의 JSON-RPC 문서에 나오는 eth_call과 eth_estimateGas는 거래를 블록에 넣지 않고 현재 상태에서 실행해 결과와 필요한 가스를 계산합니다. 지갑 시뮬레이션은 이와 비슷하게 특정 블록 시점의 상태를 기준으로 거래를 실행해 보고, 토큰 잔액 변화와 수수료를 보여줍니다.
문제는 시뮬레이션 시점과 실제 실행 시점 사이에 시간이 흐른다는 점입니다. Ethereum.org의 트랜잭션 설명처럼 거래는 서명 후 네트워크에 전파되고, 블록에 포함될 때 그 시점의 상태로 실행됩니다. 그 사이에 다른 거래가 먼저 처리돼 가격이나 잔액이 바뀌면 결과도 달라집니다.
가상 스왑 비교
아래 표는 토큰 A 1개를 넣어 토큰 B를 받는 스왑에서, 시뮬레이션은 98개를 보여줬고 최소 수령량을 96개로 설정한 가상의 경우입니다. 실제 실행 상황에 따라 결과를 비교했습니다.
| 상황 | 시뮬레이션 결과 | 실제 수령량 | 거래 결과 | 이용자 부담 |
|---|---|---|---|---|
| 상태 변화 없음 | 98개 | 98개 | 성공 | 수수료 |
| 다른 큰 거래가 먼저 처리돼 가격 변동 | 98개 | 95개로 계산됨 | 최소 수령량 미달로 실패 | 실패 거래 수수료 |
| 앞뒤로 끼어드는 거래(샌드위치) | 98개 | 96.1개 | 성공 | 약 1.9개 불리 + 수수료 |
| 시뮬레이션 환경을 구분하는 악성 계약 | 98개 | 0개, 승인 권한 탈취 | 성공처럼 보임 | 자산 손실 위험 |
최소 수령량 조건은 불리한 체결을 막지만, 조건에 걸려 실패한 거래도 그때까지 쓴 가스 수수료는 냅니다.
결과가 달라지는 이유
Ethereum.org의 MEV 설명처럼 블록을 만드는 쪽과 검색자들은 대기 중인 거래를 보고 그 앞이나 뒤에 자신의 거래를 넣어 이익을 얻을 수 있습니다. 표의 샌드위치 사례처럼 이용자의 스왑 직전에 같은 방향으로 사고 직후에 팔면, 이용자는 최소 수령량 안에서 가장 불리한 가격에 체결될 수 있습니다.
또 계약이 외부 가격 피드, 블록 시간, 블록 번호처럼 실행 시점마다 바뀌는 값을 읽으면 시뮬레이션과 실제 결과가 달라집니다. 예를 들어 일정 시간이 지나면 보상 비율이 바뀌는 계약은, 시뮬레이션 직후 블록이 바뀌는 것만으로도 다른 결과를 낼 수 있습니다.
시뮬레이션이 보여주지 않는 것
시뮬레이션은 ‘이번 거래’의 결과만 보여줍니다. 토큰 사용 승인(approve) 거래는 당장은 자산이 움직이지 않아 시뮬레이션 결과가 깨끗해 보이지만, 승인받은 계약은 나중에 언제든 승인 한도까지 토큰을 가져갈 수 있습니다. 무제한 승인이라면 그 위험도 무제한입니다.
악성 계약 가운데는 시뮬레이션 환경과 실제 실행 환경을 구분해 다르게 동작하도록 만든 것도 있습니다. 시뮬레이션에서는 정상적인 스왑처럼 보이게 하고, 실제 실행에서는 다른 경로로 자산을 빼가는 방식입니다. 그래서 시뮬레이션 결과가 정상이라도 처음 보는 계약이나 출처가 불분명한 사이트에서는 주의해야 합니다.
서명 전 확인 순서
시뮬레이션 결과가 나와도 아래 항목을 함께 확인해 보세요.
- 상호작용하는 계약 주소가 공식 문서에 나온 주소와 같은지 확인합니다.
- 시뮬레이션에 나온 토큰 이동 방향과 수량이 의도한 거래와 맞는지 봅니다.
- 승인 거래라면 승인 대상 계약과 승인 한도를 확인하고, 필요한 만큼만 승인합니다.
- 스왑이라면 최소 수령량(슬리피지 허용 범위)이 적절한지, 실패하면 수수료가 얼마나 드는지 확인합니다.
- 지갑이 ‘시뮬레이션 실패’나 ‘결과를 알 수 없음’을 표시하면 이유를 확인하기 전에는 서명하지 않습니다.
보호 장치와 그 한계
최소 수령량 설정은 샌드위치 공격이나 가격 변동으로 인한 손해의 최대 범위를 정하는 가장 기본적인 장치입니다. 허용 범위를 너무 넓게 잡으면 불리한 체결을 허용하고, 너무 좁게 잡으면 거래가 자주 실패해 수수료만 낼 수 있습니다.
대기 중인 거래가 공개 멤풀에 노출되지 않도록 비공개 경로로 보내는 방법도 있지만, 그 경로를 운영하는 쪽을 믿어야 한다는 다른 가정이 생깁니다. 어떤 보호 장치든 무엇을 막고 무엇을 막지 못하는지 함께 이해하는 것이 좋습니다.
예측의 한계
이 글의 수량과 상황은 시뮬레이션의 한계를 보여주기 위한 가상의 예시입니다. 지갑마다 시뮬레이션 방식과 표시 내용, 경고 기준이 다르고, 사용하는 RPC 제공자의 데이터에 따라 결과가 달라질 수도 있습니다.
실제로 서명할 때는 Ethereum.org의 최신 자료와 지갑의 공식 안내를 기준 시점과 함께 확인하세요. 이 글은 특정 거래나 토큰의 매매를 권유하지 않습니다.