위험 토큰 거르기: fee-on-transfer와 러그풀 방어
온체인 차익거래 봇을 돌리다 보면, 견적은 완벽했는데 실제로는 손해가 나는 거래를 만납니다. 범인은 종종 토큰 자체입니다. 겉보기엔 평범한 ERC-20이지만, 전송할 때마다 몰래 수수료를 떼거나, 아예 팔 수 없게 설계된 토큰들이죠. 신생 체인일수록 이런 지뢰가 많습니다. 이 글은 그것들을 거르는 법입니다.
조용한 저격수 — fee-on-transfer 토큰
표준 ERC-20은 100을 보내면 100이 도착합니다. 그런데 fee-on-transfer(전송 과세) 토큰은 100을 보내면 97만 도착하고 3은 어딘가로 빠집니다. 봇의 견적 로직은 100이 올 거라 계산했는데 97만 오니, 차익거래의 상환 단계에서 수량이 모자라 트랜잭션 전체가 revert됩니다. 최선의 경우 가스만 날리고, 최악의 경우 계산이 꼬여 손실이 납니다.
감지 방법은 직관적입니다. 전송 전후 잔액을 실제로 비교해, 받은 양이 보낸 양보다 적으면 과세 토큰으로 판정합니다.
// fee-on-transfer 감지: 실제 도착량 vs 명목 전송량
func isFeeOnTransfer(balanceBefore, balanceAfter, sentAmount *big.Int) bool {
received := new(big.Int).Sub(balanceAfter, balanceBefore)
// 받은 양이 보낸 양보다 적으면 전송 중 수수료가 떼인 것
return received.Cmp(sentAmount) < 0
}
이런 토큰은 시뮬레이션(eth_call) 단계에서 미리 걸러야 합니다. 실제 자금을 넣기 전에 "이 토큰으로 왕복이 되는가"를 시험 삼아 돌려 보는 거죠.
블랙리스트 — 한 번 데였으면 기억한다
위험 토큰을 만날 때마다 매번 새로 판정하는 건 비효율적이고 위험합니다. 한 번 걸러낸 토큰은 블랙리스트에 넣어 다음부터 아예 후보에서 제외합니다. 신생 체인 이식 초기에는 이 목록이 비어 있다가, 운영하며 발견하는 대로 채워 갑니다.
// 알려진 위험 토큰 — 스캔·진입 후보에서 원천 제외
var blacklistedTokens = map[string]bool{
// 주소는 운영 중 발견하는 대로 추가 (placeholder)
"0xFEE0NTRANSFER_TOKEN_ADDR": true, // 전송 과세 확인됨
"0xHONEYPOT_TOKEN_ADDR": true, // 매도 불가 허니팟
}
func isTradeable(token string) bool {
return !blacklistedTokens[strings.ToLower(token)]
}
러그풀·허니팟 — 팔 수 없는 함정
더 악질적인 건 허니팟(honeypot)입니다. 살 수는 있는데 팔 수가 없게 설계된 토큰이죠. 유동성이 있어 보이고 가격도 오르지만, 매도 트랜잭션만 골라 revert시킵니다. 러그풀은 개발자가 어느 날 유동성을 통째로 빼서 토큰을 휴지로 만드는 것이고요.
완벽한 사전 탐지는 불가능하지만, 실전에서 통하는 휴리스틱이 있습니다.
- 왕복 시뮬레이션 — 사는 것뿐 아니라 되파는 것까지
eth_call로 시험. 매도가 revert하면 허니팟 의심 - 유동성 최소 기준 — 풀 규모가 일정 이하면 제외. 러그풀은 대개 유동성이 얇다
- 유동성 잠금/보유 분산 확인 — 유동성이 잠겨 있는지, 소수 지갑이 물량을 독점하는지 점검
- 컨트랙트 검증 여부 — 소스가 공개·검증되지 않은 토큰은 더 보수적으로
기본 원칙 — 의심스러우면 건너뛴다
차익거래에서 놓친 기회는 아쉬울 뿐이지만, 지뢰를 밟으면 손실입니다. 비대칭적이죠. 그래서 판정이 애매한 토큰은 과감히 스킵하는 게 장기적으로 이깁니다. "혹시 되지 않을까"보다 "확실하지 않으면 넘긴다"가 안전합니다.
// 진입 전 최종 게이트: 하나라도 걸리면 스킵
if !isTradeable(token) { return } // 블랙리스트
if isFeeOnTransfer(before, after, amt) { return } // 전송 과세
if !passesRoundTripSim(token) { return } // 매도 불가(허니팟)
if liquidity.Cmp(minLiquidity) < 0 { return } // 유동성 부족
정리
- fee-on-transfer는 전송 전후 잔액 비교로 감지하고, 상환 실패를 막는다
- 한 번 걸러낸 토큰은 블랙리스트에 넣어 재선정에서 제외한다
- 허니팟·러그풀은 왕복 시뮬레이션·유동성 기준·보유 분산으로 방어한다
- 기본은 의심스러우면 건너뛴다 — 놓친 기회보다 밟은 지뢰가 훨씬 비싸다
신생 체인의 기회는 달콤하지만, 그만큼 검증되지 않은 토큰이 많습니다. 위험 토큰을 거르는 게이트는 화려하지 않아도, 봇의 잔고를 지키는 가장 실질적인 방어선입니다.
이 글은 교육·정보 목적이며 투자 권유가 아닙니다. DeFi 자동매매에는 원금 손실 위험이 있고, 결과에 대한 책임은 본인에게 있습니다.
댓글
댓글 쓰기