이 페이지는 AI 자동 번역입니다. 모든 내용은 영문판을 기준으로 합니다.영문판 보기 →
버전 안내. 모든 TypeScript 데모는
@raydium-io/raydium-sdk-v2@0.2.64-alpha를 기준으로 작성되었습니다. 마지막으로 0.2.42-alpha(2026-04)에서 Solana mainnet-beta를 대상으로 실행했고, 2026-09-09에 호출 시그니처를 0.2.64-alpha 소스와 대조해 다시 확인했습니다. 끝부분의 Rust CPI 골격은 master 브랜치의 raydium-clmm과 Anchor 1.0.2를 대상으로 합니다. CPMM 페이지와 같은 버전 고정이라 두 코드를 하나의 crate에 함께 둘 수 있습니다. 프로그램 ID는 SDK를 통해 reference/program-addresses에서 가져옵니다.설정
raydium-sdk-V2-demo/src/clmm의 파일과 대응합니다. 각 섹션 옆에 GitHub 링크가 있습니다. 초기 설정은 데모 저장소의 config.ts.template (소스)을 따릅니다. 규모가 있는 통합이라면 disableFeatureCheck: true를 설정하는 것을 권장합니다.
CLMM 풀 생성
출처:src/clmm/createPool.ts
- 주소를 유도하기 전에
mint1과mint2를 바이트 순서로 정렬합니다. sqrt_price_x64 = floor(sqrt(initialPrice × 10^(dB−dA)) × 2^64)를 계산합니다.observation계정과tick_array_bitmap_extension계정을 생성합니다.ammConfig에 정의된 풀 생성 수수료를 지불합니다.
원하는 범위에 포지션 열기
출처:src/clmm/createPosition.ts
OpenPosition*이 없는 tick array를 호출자(payer)의 비용으로 직접 할당합니다.
기존 포지션의 유동성 늘리기
출처:src/clmm/increaseLiquidity.ts
유동성 줄이기 (수수료 동시 수령)
출처:src/clmm/decreaseLiquidity.ts 및 src/clmm/closePosition.ts
liquidity = new BN(0)으로 decreaseLiquidity를 호출합니다. 이 명령은 token_fees_owed_{0,1}과 reward_amount_owed를 정산하고 그 금액을 밖으로 전송합니다. 두 항목을 수령하는 방법은 이것이 유일합니다.
유동성과 수수료를 모두 0으로 만든 뒤 포지션을 완전히 닫으려면 마지막 decreaseLiquidity 호출에 ownerInfo: { closePosition: true }를 전달합니다. SDK가 ClosePosition을 추가하고 NFT를 소각합니다.
Anchor 클라이언트를 직접 사용한다면 선언된 계정은 그대로 두고 풀 계정을 추가합니다.
poolId를 전달해도 됩니다. CLMM은 positionNftAccount가 동결된 경우에만 이 값을 읽습니다. 따라서 하나의 클라이언트 경로로 기존 포지션과 새 포지션을 모두 처리할 수 있습니다.
보상 수령
출처:src/clmm/harvestAllRewards.ts
harvestAllRewards는 전달된 모든 풀의 모든 포지션을 순회합니다. 수수료와 보상을 정산하는 유동성 0짜리 DecreaseLiquidity 호출(필요하면 UpdateRewardInfos도 포함)을 묶고, 필요에 따라 여러 트랜잭션으로 나눕니다.
스왑
출처:src/clmm/swap.ts
이 예제는 src/clmm/swap.ts와 같은 방식으로 작성되었으며, PoolUtils.computeAmountOutFormat 대신 swapInternal로 시뮬레이션합니다.
amountCalculated)과 스왑이 접근할 정확한 계정 목록(accounts)을 반환합니다.
시뮬레이션이 반환한 remainingAccounts는 반드시 그대로 전달하세요. 개수가 부족하면 순회 도중 NotEnoughTickArrayAccount 오류로 스왑이 되돌아가고, 오래된 계정을 전달하면 컴퓨트만 낭비됩니다.
PoolUtils.computeAmountOutFormat도 여전히 존재하지만, ComputeClmmPoolInfo가 필요합니다. 즉 API 풀 객체가 아니라 getPoolInfoFromRpc에서 얻은 computePoolInfo를 넘겨야 하며, 추가로 필수 인자 두 개(tickarrayBitmapExtension, blockTimestamp)가 더 필요합니다. 또한 raydium.clmm.fetchTickArrays 메서드는 없습니다. fetchTickArrays는 독립 함수이고, 모듈 수준 헬퍼는 PoolUtils.fetchMultiplePoolTickArrays와 getPoolInfoFromRpc가 반환하는 tickData / tickArrays입니다.커스터마이즈 가능한 CLMM 풀 생성
createCustomizablePool은 풀 생성 시점에 동적 수수료와 단일 자산 수수료 설정을 노출하는 진입점입니다. 인자 구조는 createPool과 같고, 여기에 두 가지 항목이 추가됩니다.
createPool을 계속 사용할 수 있습니다. 두 가지 설정 중 하나라도 필요하다면 createCustomizablePool을 사용하세요. 온체인 계정 목록은 products/clmm/instructions에서 확인할 수 있습니다.
지정가 주문
지정가 주문은 사용자의 입력 자산을 특정 틱 하나에 예치해 두고, 스왑이 해당 틱을 통과할 때 선입선출(FIFO) 순서로 체결합니다. 출력 자산은 정산 시점에 주문자의 ATA로 전송되므로, 체결을 위해 주문자가 온라인 상태일 필요는 없습니다.지정가 주문 열기
풀마다 지정가 주문 설정 계정이 따로 있지 않으며,getClmmLimitOrderConfigs() 헬퍼도 없습니다. 주문은 틱 단위로 구분됩니다.
(owner, nonce PDA, order nonce)로부터 LimitOrderState PDA를 도출하고, 지갑별 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 순서는 다음과 같습니다.
자주 하는 실수
- Tick 끝점이 간격에 맞지 않음 →
TickAndSpacingNotMatch. 항상TickUtil.getPriceAndTick으로 스냅하세요 (단수형TickUtil입니다). SwapV2에 tick array를 충분히 전달하지 않음 →NotEnoughTickArrayAccount. 목록은swapInternal(...).accounts에서 가져오세요.- 비트맵 확장 없이 전체 범위 포지션을 만듦 → 확장 PDA는 쓰기 가능(writable)해야 합니다. SDK가 이 부분을 자동으로 처리합니다.
sqrt_price_x64를price로 착각함 → 여기서 2배 차이를 혼동하면 특히 골치 아픕니다. 확신이 없다면 사람이 읽을 수 있는 가격을 넘겨서 SDK가 계산하도록 하세요.- 보상을 너무 자주 수령함 → 수령할 때마다 유동성이 0인
DecreaseLiquidity가 실행되어 트랜잭션이 하나씩 추가됩니다. 여러 포지션의 보상은harvestAllRewards로 한꺼번에 묶어서 처리하세요. 이때execute에는{ sequentially: true }가 필요하다는 점을 기억하세요. - NFT 계정을 직접 닫음 →
ClosePosition은 NFT를 소각하고 해당 ATA도 닫습니다. Token-2022 NFT 민트도 함께 닫히지만, 기존 SPL Token 민트는 해당 프로그램이 민트를 닫을 수 없으므로 공급량 0 상태로 남습니다. 지원되는 계정을 따로 닫지 마세요. 그렇게 하면 명령이 실패(revert)합니다. - 간격에 맞지 않는 tick에 지정가 주문을 엶 →
TickAndSpacingNotMatch. 내보내진(exported)getOrderTick헬퍼로 항상 tick을 맞추세요. - 이미 완전히 체결된 주문에
decreaseLimitOrder를 호출함 →InvalidOrderPhase. 대신settleLimitOrder를 호출한 뒤closeLimitOrder를 사용하세요. enableDynamicFee플래그가 있다고 기대함 → 그런 플래그는 없습니다.dynamicFeeConfig를 생략하면 오류 없이 조용히 고정 수수료 풀이 만들어집니다. 동적 수수료를 사용하려면/main/clmm-dynamic-config에서 고른 설정 계정의PublicKey를 전달하세요.
다음 단계
sdk-api/typescript-sdk— SDK 전체 인터페이스를 다룹니다.sdk-api/rest-api— 견적 및 풀 메타데이터 엔드포인트를 다룹니다.user-flows/create-clmm-pool— 코드 없이 따라 할 수 있는 안내입니다.integration-guides/aggregator— 경로의 일부로 CLMM을 라우팅하는 방법입니다.

