온체인 가스 최적화 — EIP-1559로 순이익을 지키는 법

🌐 English

온체인 봇에서 가스는 두 얼굴을 가집니다. 하나는 반드시 내야 하는 비용, 다른 하나는 남보다 먼저 실행되기 위한 경쟁 도구. 가스를 무시하면 겉보기 이익이 나는 거래마다 실제로는 손해를 보고, 가스를 무작정 높이면 이익을 채굴자에게 다 헌납합니다. 핵심은 정확히 추정하고, 순이익에 반영하는 것입니다.

가스 비용 = 가스량 × 가스 단가

트랜잭션 하나의 비용은 두 값의 곱입니다. 가스량(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의 두 손잡이를 이해하고, 순이익 계산에 빠짐없이 반영하면 — 가스는 비용이 아니라 통제 가능한 변수가 됩니다.

이 글은 교육·정보 목적이며 투자 권유가 아닙니다. 온체인 자동매매에는 원금 손실과 트랜잭션 실패 비용 위험이 있고, 결과에 대한 책임은 본인에게 있습니다.

댓글

이 블로그의 인기 게시물

한국투자증권 KIS API로 실시간 시세 받기 (WebSocket 실전)

파이썬으로 업비트 API 연동하기 — 시세 조회부터 주문까지 기초

Go로 자동매매 신호봇 프레임워크 설계하기