메인 콘텐츠로 건너뛰기

Documentation Index

Fetch the complete documentation index at: https://docs.raydium.io/llms.txt

Use this file to discover all available pages before exploring further.

이 페이지는 AI 자동 번역입니다. 모든 내용은 영문판을 기준으로 합니다.영문판 보기 →
모든 Solana 트랜잭션은 두 가지 파라미터를 설정합니다 (명시적 또는 암시적): 컴퓨팅 유닛 한계 (트랜잭션이 소비할 수 있는 최대 CU; 기본값은 명령어 수 × 200,000이지만 트랜잭션별 한계 있음) 와 우선순위 수수료 (CU당 마이크로랍포트). 두 설정 중 하나를 너무 작게 설정하면 트랜잭션이 실패합니다 — CU 한계가 너무 낮으면 ProgramFailedToComplete 오류 발생, 우선순위 수수료가 너무 낮으면 트랜잭션이 만료될 때까지 미확인 상태로 남습니다.

두 가지 설정

import { ComputeBudgetProgram } from "@solana/web3.js";

const tx = new Transaction()
  .add(ComputeBudgetProgram.setComputeUnitLimit({ units: 250_000 }))
  .add(ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 50_000 }))
  .add(yourRaydiumSwapIx);
  • setComputeUnitLimit(units) — 컴퓨팅을 제한합니다. 트랜잭션은 최대 units CU에 대해서만 비용을 지불합니다.
  • setComputeUnitPrice(microLamports) — CU당 마이크로랍포트 단위의 우선순위 수수료 입찰. 총 우선순위 수수료 = units × microLamports × 1e-6 랍포트.
비용 계산: 250k CU 한계에서 50k 마이크로랍포트/CU는 250_000 × 50_000 / 1e6 = 12,500 랍포트 ≈ 0.0000125 SOL ≈ $200 SOL 기준 $0.003입니다. 이 규모의 우선순위 수수료는 대부분의 사용자 스왑에서는 무시할 수준이지만 하루에 1000개의 트랜잭션을 실행하는 봇에는 의미 있는 비용입니다.

명령어별 CU 벤치마크

메인넷 실행 로그에서 수집한 벤치마크로, 최근 실행들의 평균값입니다. 숫자는 근사값입니다 (±15%); 특정 흐름에 맞게 재측정하세요.
명령어SPL TokenToken-2022 (기본)Token-2022 (전송 수수료)
CPMM initialize_pool180,000200,000
CPMM swap_base_input140,000180,000200,000
CPMM swap_base_output150,000185,000205,000
CPMM deposit130,000160,000180,000
CPMM withdraw120,000150,000170,000
CLMM create_pool70,00085,000
CLMM open_position_v2120,000140,000160,000
CLMM increase_liquidity_v2150,000175,000195,000
CLMM decrease_liquidity_v2140,000165,000185,000
CLMM swap_v2 (0 틱 교차)170,000205,000225,000
CLMM swap_v2 (1 틱 교차)220,000255,000275,000
CLMM swap_v2 (3 틱 교차)320,000355,000375,000
CLMM collect_fee80,00095,000105,000
AMM v4 swap_base_in140,000
AMM v4 deposit120,000
AMM v4 withdraw110,000
Farm v6 create_farm70,00085,000
Farm v6 deposit (1 보상 슬롯)130,000155,000175,000
Farm v6 deposit (3 보상 슬롯)220,000255,000275,000
Farm v6 withdrawdeposit과 동일
Farm v6 harvestdeposit과 동일
Farm v3/v5 deposit100,000
LaunchLab initialize100,000
LaunchLab buy_exact_in140,000
LaunchLab graduate250,000
CLMM의 “틱 교차” 행은 가장 큰 CU 변수입니다. 스왑이 몇 개의 틱을 교차할지 모르는 경우 최악의 시나리오를 예산하세요 — 8 교차가 하드 캡입니다 (프로그램은 최대 8개의 틱 배열을 로드합니다).

구성된 트랜잭션

개별 예산을 합산하고 다음을 추가합니다:
  • CPI 프레임당 +1,500 CU — 각 크로스 프로그램 호출에 대한 런타임의 고정 오버헤드.
  • ATA 생성당 +20,000 CUcreate_associated_token_account는 무료가 아닙니다.
  • setComputeUnitLimit / setComputeUnitPrice당 +5,000 CU.
예: 출력 ATA를 생성하고 네이티브 SOL을 래핑하는 사용자 스왑:
wrap_sol (create_ata + system transfer + sync_native)   ≈ 30,000
CPMM swap_base_input (SPL)                              ≈ 140,000
close_account (unwrap)                                  ≈ 5,000
ComputeBudget instructions                              ≈ 10,000
────────────────────────────────────────────────────────
합계                                                   ≈ 185,000 → 250,000으로 예산
패딩: CU 한계를 예상 사용량의 약 25% 위로 설정합니다. 저평가하면 전체 트랜잭션이 실패하고, 과평가하면 우선순위 수수료 비용이 비례적으로 증가합니다 (우선순위 수수료는 units × microLamports이므로 ~25% 과다 예산은 우선순위 수수료에서 25% 추가 비용입니다).

우선순위 수수료 예상

Solana의 로컬 수수료 시장은 우선순위 수수료가 쓰기 가능 계정별임을 의미합니다. 핫 계정 (인기 있는 풀 상태)에 쓰는 트랜잭션이 콜드 계정에 쓰는 트랜잭션보다 더 많이 지불합니다. 글로벌 수수료 수준은 Raydium 스왑의 올바른 지표가 아닙니다. 터치하는 특정 풀의 수수료가 필요합니다.

전략 1: RPC 제공업체 추정 도구

각 주요 RPC 제공업체는 특정 계정의 최근 수수료를 쿼리하는 우선순위 수수료 추정 도구를 발행합니다:
// Helius
const response = await fetch(`https://mainnet.helius-rpc.com/?api-key=${apiKey}`, {
  method: "POST",
  body: JSON.stringify({
    jsonrpc: "2.0",
    id:      "fee-estimate",
    method:  "getPriorityFeeEstimate",
    params: [{
      accountKeys: [poolStatePubkey.toBase58()],
      options:     { priorityLevel: "High" },
    }],
  }),
});
const { result } = await response.json();
const microLamports = result.priorityFeeEstimate;
대부분의 제공업체 우선순위 수준: Min / Low / Medium / High / VeryHigh / UnsafeMax. 백분위수에 매핑합니다:
수준백분위수사용 사례
Min25th백그라운드, 긴급하지 않은 봇 트래픽
Low50th일반 사용자 스왑
Medium60th지갑 UI의 기본값
High75th시간 민감한 중재
VeryHigh95th청산, 마지막 기회 출구
제공업체: Helius (getPriorityFeeEstimate), Triton (getRecentPrioritizationFees 계정 목록 포함), QuickNode (유사).

전략 2: 직접 RPC 쿼리

표준 getRecentPrioritizationFees RPC를 사용합니다:
const fees = await connection.getRecentPrioritizationFees({
  lockedWritableAccounts: [poolStatePubkey],
});

// fees: Array<{ slot, prioritizationFee }>
// 최근 N개 슬롯; 기본값 ~150 슬롯.

const median = percentile(fees.map(f => f.prioritizationFee), 0.5);
이것은 바닐라 Solana RPC 메서드입니다. 모든 제공업체에서 작동합니다. 단점: 샘플이 작습니다 (150 슬롯 ≈ 60초) 그리고 노이즈가 많습니다. 더 부드러운 추정을 위해 제공업체의 집계를 사용합니다.

전략 3: 역사적 자체 조정

상수 흐름을 실행하는 봇의 경우 착지한 것과 만료된 비율을 추적합니다:
풀별 목표: <30s에서 80% 착지율
if current_land_rate < 80%: priorityFee += 10%
if current_land_rate > 95%: priorityFee -= 5%
이것은 공개 추정 도구보다 빠르게 자체 수정하고 공개 추정 도구가 항상 볼 수 없는 풀별 구조를 캡처합니다.

CU 부족 실패 처리

증상: 트랜잭션이 exceeded maximum number of instructions allowed (200000) 또는 ProgramFailedToComplete로 실패합니다. 진단:
solana confirm <tx-sig> -v
# "consumed N of M compute units"를 찾고 어떤 명령어가 CU를 소진했는지 확인합니다.
해결방법:
  1. CU 한계를 올립니다. 트랜잭션이 200k 예산 중 195k를 사용하고 있다면 300k로 올립니다.
  2. 트랜잭션을 분할합니다. 1.4M 트랜잭션당 한계에 도달했다면 두 개의 트랜잭션으로 나눕니다. Farm harvest then stake는 보상이 많을 때 분할하기에 전형적입니다.
  3. 계정을 정리합니다. 각 추가 쓰기 가능 계정은 약 2,000 CU를 추가합니다. 사용하지 않는 계정을 제거하면 한계 경우에 도움이 됩니다.
  4. 조회 테이블을 사용합니다. LUT 조회는 해석된 주소당 약 50 CU이며, 항목당 전체 계정 참조의 5,000 CU를 절약합니다.

정체된 트랜잭션 처리

증상: 트랜잭션을 제출했는데 확인되지 않고 결국 BlockhashNotFound로 만료됩니다. 진단:
  • getSignatureStatuses([sig])null을 반환합니다 → 리더가 볼 수 없습니다.
  • { confirmationStatus: null }을 반환합니다 → 리더가 봤지만 포함하지 않았습니다.
해결방법:
  1. 우선순위 수수료를 올립니다. 현재 수수료의 2배로 다시 제출합니다.
  2. 신선한 블록해시로 다시 구성합니다. 블록해시 수명은 약 60초이며, 그 이상이면 수수료에 관계없이 트랜잭션이 무효입니다.
  3. 다중 RPC 브로드캐스트합니다. 일부 RPC는 다른 RPC보다 리더 연결이 더 좋습니다. 3~5개를 병렬로 제출합니다.
  4. Jito 번들로 전환합니다. integration-guides/routing-and-mev를 참조하세요. 번들은 공개 패킷 큐를 우회합니다.
재시도 로직 스켈레톤:
async function submitWithRetry(buildTx, maxAttempts = 5) {
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    const tx = await buildTx({
      priorityFee: basePriorityFee * Math.pow(1.5, attempt),
      blockhash:   (await connection.getLatestBlockhash()).blockhash,
    });

    try {
      const sig = await connection.sendRawTransaction(tx.serialize(), {
        skipPreflight: attempt > 0,  // 첫 시도 후 건너뛰어 지연 절감
      });

      const result = await connection.confirmTransaction(sig, "confirmed");
      if (result.value.err) {
        // 논리 오류; 재시도하지 않습니다.
        throw result.value.err;
      }
      return sig;

    } catch (e) {
      if (isExpiredError(e)) continue;  // 재시도
      if (isRevertError(e)) throw e;    // 재시도하지 않음; 결정적 실패
      throw e;
    }
  }
  throw new Error("submit: exhausted retries");
}

혼잡 시

네트워크가 혼잡할 때 (Jupiter / Jito 번들 대시보드가 백로그를 표시, RPC 지연이 스파이크, 트랜잭션 만료율이 상승), 다음을 조정합니다:
파라미터정상 조건혼잡 조건
CU 한계예상의 +25%예상의 +25% (변경 없음)
우선순위 수수료 백분위수50th75th–95th
재시도 횟수35–7
재시도 백오프500ms1000ms
Jito 번들 사용선택사항강력 권장
재시도 시 블록해시 새로고침예, 필수
혼잡 신호 감시:
  • 우선순위 수수료 75th 백분위수 > 500k 마이크로랍포트: 혼잡.
  • Jito 50th 백분위수 팁 > 0.001 SOL: 혼잡.
  • RPC 응답 p99 > 2초: RPC 특정 문제 또는 혼잡.

봇을 위한 수수료 예산

하루에 약 1000개의 트랜잭션을 실행하는 거래 봇은 우선순위 수수료 예산이 필요합니다. 대략적인 계산:
트랜잭션당 평균 CU:          ~250,000
50th 백분위수 수수료:        ~20,000 마이크로랍포트/CU
트랜잭션당 비용:            250_000 × 20_000 × 1e-6 = 5_000 랍포트 = 5e-6 SOL
일일 비용 (1000 txs):       5e-3 SOL ≈ $200 SOL 기준 $1
월간 비용:                   ~$30
이것이 최소입니다. 혼잡 시에는 510배를 곱합니다. 안정적인 흐름 봇의 경우 월간 우선순위 수수료 약 $150300을 계획합니다. 특정 슬롯에 착지해야 하는 봇 (청산, 중재)은 지속적으로 95th 백분위수를 지불하며 약 10배 더 많이 씁니다. Jito 번들 팁이 해당 규모에서 지배적입니다 — 종종 월간 $1000 이상 — 하지만 대안 (프론트 런되거나 만료됨)이 더 나쁩니다.

함정

1. CU 한계 잊음

기본값은 200k CU × (트랜잭션의 명령어). 단일 명령어 스왑의 기본값은 200k입니다. SPL Token에서 CPMM에는 충분하지만 틱 교차가 있는 CLMM 또는 Token-2022는 부족합니다. 항상 명시적으로 설정하세요.

2. 잘못된 계정의 우선순위 수수료

토큰 민트에 대해 우선순위 수수료를 예상하지만 핫 계정이 풀 상태인 경우 예상이 너무 낮습니다. 풀 상태가 Raydium의 올바른 쓰기 가능 계정입니다.

3. 수수료는 CU 한계로 확장

total_priority_fee = units × microLamports. units를 200k에서 1M으로 올리되 50k 마이크로랍포트/CU는 우선순위 수수료를 5배로 곱합니다. 혹시 모를 상황에 대비해 CU를 과다 예산하지 마세요. 측정하세요.

4. 기본 트랜잭션 버전

레거시 트랜잭션은 더 낮은 계정 제한이 있으며, V0 트랜잭션은 주소 조회 테이블로 더 큰 경로를 잠금 해제합니다. SDK는 txVersion: TxVersion.V0에서 기본값으로 V0을 사용합니다. 지갑 호환성이 필요하지 않으면 레거시로 드롭하지 마세요.

5. skipPreflight는 CU 오류를 숨김

skipPreflight: true는 로컬 시뮬레이션 없이 트랜잭션을 보냅니다. 약 100ms를 절약하지만 CU 부족에 대한 조기 피드백을 잃습니다. 첫 시도가 아닌 재시도에만 사용합니다.

참고 자료

출처: