Skip to main content
이 페이지는 AI 자동 번역입니다. 모든 내용은 영문판을 기준으로 합니다.영문판 보기 →
버전 안내. 모든 예제는 Solana mainnet-beta 환경에서 @raydium-io/raydium-sdk-v2@0.2.42-alpha를 대상으로 하며, 2026년 4월에 검증되었습니다. Program ID는 SDK를 통해 reference/program-addresses에서 가져옵니다.

설정

이 페이지의 모든 예제는 raydium-sdk-V2-demo/src/clmm의 파일과 대응됩니다. 각 섹션 옆에 GitHub 링크가 있습니다. 부트스트랩은 데모 저장소의 config.ts.template(소스)을 따르며, 실질적인 통합에는 disableFeatureCheck: true 설정을 권장합니다.

CLMM 풀 생성

소스: src/clmm/createPool.ts
SDK 동작 방식:
  • 파생 전에 바이트 순서 기준으로 mint1/mint2를 정렬합니다.
  • sqrt_price_x64 = floor(sqrt(initialPrice × 10^(dB−dA)) × 2^64)를 계산합니다.
  • observationtick_array_bitmap_extension 계정을 생성합니다.
  • ammConfig에 정의된 풀 생성 수수료를 지불합니다.

원하는 범위에서 포지션 열기

소스: src/clmm/createPosition.ts
SDK는 범위가 걸치는 틱 배열을 자동으로 계산하며, 초기화되지 않은 틱 배열이 있으면 InitTickArray 인스트럭션을 함께 묶어서 처리합니다.

기존 포지션의 유동성 증가

소스: src/clmm/increaseLiquidity.ts

유동성 감소 (수수료 동시 수집)

소스: src/clmm/decreaseLiquidity.tssrc/clmm/closePosition.ts
수수료만 수집하려면 liquidity = new BN(0)으로 decreaseLiquidity를 호출하세요. 이 인스트럭션의 부수 효과로 tokens_fees_owed_{0,1}이 정산되고 출금됩니다. 유동성과 수수료를 모두 0으로 만든 후 포지션을 완전히 닫으려면, 마지막 decreaseLiquidity 호출에 closePosition: true를 전달하세요. SDK가 ClosePosition을 추가하고 NFT를 소각합니다.

보상 수집

소스: src/clmm/harvestAllRewards.ts
harvestAllRewards는 전달된 모든 풀의 모든 포지션을 순회하며, CollectReward(및 필요한 UpdateRewardInfos) 인스트럭션을 일괄 처리합니다. 필요한 경우 여러 트랜잭션으로 자동 분할됩니다.

스왑

소스: src/clmm/swap.ts
computeAmountOutFormat은 온체인 프로그램과 동일한 로직으로 오프체인에서 틱 맵을 순회하며 다음을 반환합니다:
  • 예상 출력 수량
  • 슬리피지 적용 후 최소 출력 수량
  • 실제 스왑이 접근할 틱 배열 계정 목록 (remainingAccounts)
시뮬레이션이 반환한 remainingAccounts를 반드시 전달하세요. 너무 적게 전달하면 스왑이 TickArrayNotFound로 중간에 실패하고, 오래된 값을 전달하면 컴퓨팅 파워가 낭비됩니다.

커스터마이징 가능한 CLMM 풀 생성

createCustomizablePool은 풀 생성 시점에 동적 수수료 및 단일 측면 수수료 토글을 노출하는 새로운 진입점입니다. createPool과 동일한 형태에 세 가지 항목이 추가됩니다:
기본 수수료, 지정가 주문 없음, 동적 수수료 없음 경로에는 createPool을 계속 사용할 수 있습니다. 세 가지 새로운 옵션 중 하나라도 필요한 경우에는 createCustomizablePool을 사용하세요. 온체인 계정 목록은 products/clmm/instructions를 참고하세요.

지정가 주문 (Limit Orders)

지정가 주문은 사용자의 입력을 단일 틱에 예치하고, 스왑이 해당 틱을 지날 때 FIFO 방식으로 체결됩니다. 출력은 정산 시점에 소유자의 ATA로 전송되며, 체결을 위해 소유자가 온라인 상태일 필요는 없습니다.

지정가 주문 열기

SDK는 (pool, owner, tick, nonce)로부터 LimitOrderState PDA를 파생하고, (pool, owner) 단위의 LimitOrderNonce를 증가시키며, 해당 틱의 FIFO 코호트에 주문을 삽입합니다.

열린 주문의 수량 증감

decreaseLimitOrder는 주문의 미체결 부분에서만 제거할 수 있으며, 체결된 부분은 정산 전까지 잠겨 있습니다. 주문이 이미 완전히 체결된 경우 두 인스트럭션 모두 InvalidOrderPhase로 되돌아갑니다.

체결된 주문 정산

settleLimitOrder는 코호트 트래커를 기준으로 주문의 unfilled_ratio_x64를 읽고, 체결된 출력을 계산하여 소유자의 ATA로 전송합니다. 소유자가 직접 호출할 수도 있고, 오프체인 운영 키퍼인 limit_order_admin이 소유자를 대신해 호출할 수도 있습니다. 단, 출력은 항상 소유자에게 전송됩니다. 완전히 정산된 주문을 닫아 렌트를 회수하려면 closeLimitOrder(단건) 또는 closeAllLimitOrder(일괄)를 사용하세요. 여러 주문을 한 번에 정산하려면 settleAllLimitOrder가 v0 트랜잭션에 가능한 한 많은 SettleLimitOrder 호출을 묶어 처리합니다.

지갑의 활성 주문 조회 (오프체인)

활성 주문 엔드포인트는 미체결 주문과 부분 체결 주문을 하나의 페이로드로 반환합니다(totalAmount / filledAmount / pendingSettle로 각 상태를 구분합니다). 종료된 주문 이력은 /limit-order/history/order/list-by-user?wallet=…(지갑별, nextPageId로 페이지네이션), 특정 주문의 전체 이벤트 로그는 /limit-order/history/event/list-by-pda?pda=…를 사용하세요.

Rust CPI 스켈레톤

SwapV2의 remaining account 순서:
스왑에 extension이 필요하지 않으면 생략하고, 필요한 경우 첫 번째 remaining account로 전달합니다.

자주 발생하는 실수

  • 틱 간격에 맞지 않는 틱 엔드포인트InvalidTickIndex. 항상 TickUtils.getPriceAndTick으로 스냅하세요.
  • SwapV2에 틱 배열을 충분히 공급하지 않음TickArrayNotFound. computeAmountOutFormat으로 전체 목록을 가져오세요.
  • bitmap extension 없이 풀 레인지 포지션 열기 → extension PDA가 writable이어야 합니다. SDK가 자동으로 처리합니다.
  • sqrt_price_x64price를 혼동 → 여기서의 혼동은 특히 큰 문제를 일으킵니다. 확실하지 않으면 SDK가 사람이 읽을 수 있는 가격으로부터 계산하도록 맡기세요.
  • 보상을 너무 자주 수집 → 수집마다 트랜잭션 비용이 발생합니다. harvestAllRewards로 여러 포지션을 일괄 처리하세요.
  • 렌트가 남아 있는 상태에서 NFT 소각ClosePosition은 NFT 민트와 ATA도 함께 닫습니다. 별도로 닫으면 프로그램이 되돌아갑니다.
  • 간격에 맞지 않는 틱에서 지정가 주문 열기InvalidTickIndex. 항상 TickUtils.getPriceAndTick으로 양자화하세요.
  • 완전히 체결된 주문에 decreaseLimitOrder 호출InvalidOrderPhase. 대신 settleLimitOrdercloseLimitOrder를 사용하세요.
  • enableDynamicFee: true를 전달하면서 dynamicFeeConfigId를 누락CreateCustomizablePoolInvalidDynamicFeeConfigParams로 실패합니다. 동적 수수료를 끄거나 /main/clmm-dynamic-config에서 설정을 선택하세요.

다음 단계

참고 자료: