온체인 가스 최적화 — EIP-1559로 순이익을 지키는 법
온체인 봇에서 가스는 두 얼굴을 가집니다. 하나는 반드시 내야 하는 비용, 다른 하나는 남보다 먼저 실행되기 위한 경쟁 도구. 가스를 무시하면 겉보기 이익이 나는 거래마다 실제로는 손해를 보고, 가스를 무작정 높이면 이익을 채굴자에게 다 헌납합니다. 핵심은 정확히 추정하고, 순이익에 반영하는 것입니다.
가스 비용 = 가스량 × 가스 단가
트랜잭션 하나의 비용은 두 값의 곱입니다. 가스량(gas used) — 그 연산이 얼마나 무거운가, 그리고 가스 단가(gas price) — 가스 한 단위에 얼마를 낼 것인가. 스왑 한 번은 대략 정해진 가스량을 쓰고, 삼각 경로처럼 여러 홉을 한 트랜잭션에 묶으면 그만큼 늘어납니다.
// 가스량은 EstimateGas로 실제 시뮬레이션해 얻는 게 가장 정확하다
gasLimit, err := client.EstimateGas(ctx, ethereum.CallMsg{
From: botAddr,
To: &routerAddr,
Data: calldata,
})
if err != nil {
return fmt.Errorf("가스 추정 실패(revert 가능성): %w", err)
}
// 추정치에 여유를 둔다 (상태 변화로 실제가 조금 더 들 수 있음)
gasLimit = gasLimit * 12 / 10 // +20% 버퍼
EstimateGas가 에러를 내면, 그 트랜잭션은 지금 실행하면 revert 될 확률이 높다는 신호입니다. 기회가 이미 사라졌거나 경로가 막힌 것이죠. 이때는 보내지 않고 스킵하는 게 맞습니다 — revert 돼도 가스는 나가니까요.
EIP-1559 — maxFee와 priorityFee
요즘 대부분의 체인은 EIP-1559 방식을 씁니다. 여기서 가스 단가는 두 조각으로 나뉩니다. base fee(프로토콜이 정하고 소각됨)와 priority fee(tip)(채굴자/검증자에게 주는 팁). 봇은 두 값을 지정합니다.
- maxPriorityFeePerGas (tip) — 검증자에게 줄 팁. 이걸 올리면 내 트랜잭션이 우선 처리될 가능성이 커집니다(경쟁 도구).
- maxFeePerGas — 내가 감내할 총 단가 상한. base fee가 튀어도 이 위로는 안 냅니다. 실제로는
base fee + tip만큼만 지불되고 나머지는 환불됩니다.
// 최신 base fee와 팁 제안값을 받아 1559 트랜잭션 파라미터를 만든다
head, _ := client.HeaderByNumber(ctx, nil)
baseFee := head.BaseFee
tip, _ := client.SuggestGasTipCap(ctx) // 네트워크가 제안하는 적정 팁
// maxFee = base fee 여유분(2배) + 팁. base fee가 튀어도 견디게
maxFee := new(big.Int).Add(
new(big.Int).Mul(baseFee, big.NewInt(2)),
tip,
)
tx := types.NewTx(&types.DynamicFeeTx{
GasTipCap: tip, // 검증자 팁 (우선순위)
GasFeeCap: maxFee, // 총 단가 상한
Gas: gasLimit,
To: &routerAddr,
Data: calldata,
})
base fee에 2배 여유를 두는 이유는, 트랜잭션이 블록에 담기기까지 몇 블록 사이 base fee가 오를 수 있기 때문입니다. 상한을 너무 빡빡하게 잡으면 base fee가 살짝만 올라도 트랜잭션이 멈춰 버립니다.
가스를 순이익에 반드시 반영하라
가장 중요한 부분입니다. 봇의 실행 판단은 겉보기 이익이 아니라 가스를 뺀 순이익으로 해야 합니다. 예상 가스 비용을 시작 토큰 기준으로 환산해, 이익에서 빼고도 문턱을 넘는지 봅니다.
// 가스 비용(wei) = gasLimit × (baseFee + tip)
gasCostWei := new(big.Int).Mul(
big.NewInt(int64(gasLimit)),
new(big.Int).Add(baseFee, tip),
)
// 겉보기 이익에서 가스 비용을 빼고도 최소 문턱을 넘어야 실행
netProfit := new(big.Int).Sub(grossProfitWei, gasCostWei)
if netProfit.Cmp(minProfitWei) < 0 {
log.Printf("스킵: 순이익 부족 (gross=%s, gas=%s)", grossProfitWei, gasCostWei)
return
}
실전 팁
- 팁은 상황에 맞게 동적으로. 한산할 땐 낮은 팁으로 충분하고, 같은 기회를 노리는 경쟁이 치열할 땐 팁을 올려야 합니다. 다만 팁이 이익을 넘어서면 그 거래는 포기하는 게 맞습니다.
- base fee 급등에 대비하라. 큰 이벤트가 있으면 base fee가 몇 배로 튑니다. maxFee 상한과 순이익 계산이 이걸 흡수해야 합니다.
- revert는 조용한 출혈이다. 실패한 트랜잭션도 가스를 소모합니다. 보내기 전
EstimateGas로 걸러 revert를 줄이세요. - 가스 토큰과 이익 토큰을 같은 단위로. 이익은 USDT인데 가스는 네이티브 코인으로 낸다면, 순이익 비교 전에 같은 기준으로 환산해야 합니다.
가스는 봇의 손익을 조용히 갉아먹는 요소입니다. 하지만 정확히 추정하고, EIP-1559의 두 손잡이를 이해하고, 순이익 계산에 빠짐없이 반영하면 — 가스는 비용이 아니라 통제 가능한 변수가 됩니다.
이 글은 교육·정보 목적이며 투자 권유가 아닙니다. 온체인 자동매매에는 원금 손실과 트랜잭션 실패 비용 위험이 있고, 결과에 대한 책임은 본인에게 있습니다.
댓글
댓글 쓰기