이 페이지는 AI 자동 번역입니다. 모든 내용은 영문판을 기준으로 합니다.영문판 보기 →
이 페이지는
products/clmm/accounts (계정이 무엇인지)와 products/clmm/math (수학이 무엇인지)와 함께 사용됩니다. 인자와 계정 순서에 대한 권위 있는 참고자료이며, 구체적인 바이트 레이아웃은 IDL에서 나옵니다.2026-09 프로그램 업그레이드는 CLMM을 Anchor 1.0.2 / Solana 3.1.10으로 재구축했으며, 관리자 명령어 CollectExcessLamports를 추가했고, CreateAmmConfig가 owner / fund_owner에 쓰는 내용을 변경했습니다. 사용자 대면 명령어는 계정, 인자 또는 수학을 변경하지 않았습니다. 2026-09-30 변경 로그 항목을 참조하세요.2026-10-22 프로그램 업그레이드는 CreatePermissionedPool을 CreateCustomizablePoolV2로 이름을 바꾸고, 누구나 호출할 수 있도록 만들며, 두 개의 관리자 명령어가 있는 Permission 계정을 제거합니다. 2026-10-22 변경 로그 항목을 참조하세요.명령어 목록
초기화 틱 배열 명령어는 없으며 필요하지 않습니다. 틱 배열은
OpenPosition* / IncreaseLiquidity* 내에서 TickArrayState::get_or_create_tick_array에 의해 생성되며, payer가 비용을 지불합니다. (아직 초기화되지 않았을 수 있는 시스템 소유) 틱 배열 PDA를 tick_array_lower / tick_array_upper로 전달하면 프로그램이 누락된 경우 할당합니다. OpenLimitOrder는 단일 tick_array에 대해 동일한 작업을 수행합니다.CreateAmmConfig, UpdateAmmConfig, UpdatePoolStatus, CreateOperationAccount, UpdateOperationAccount, CloseProtocolPosition)는 프로그램의 하드코딩된 admin 공개 키로 제어됩니다. CreateSupportMintAssociated / CloseSupportMintAssociated는 admin 공개 키 또는 전용 지원 민트 소유자 키를 허용합니다. CollectExcessLamports는 admin 공개 키 또는 전용 수집 램포트 지갑을 허용합니다. 보상 스트림 관리자 명령어 (TransferRewardOwner, CollectRemainingRewards)는 프로그램 관리자가 아닌 보상 펀더로 제어됩니다.
V2 접미사는 “볼트 / NFT에서 Token-2022를 지원하며, 비트맵 확장 슬롯이 필요함”을 의미합니다. SDK는 새 풀에 대해 기본적으로 V2를 선택합니다.
CreatePool
인자
전제 조건
token_mint_0 < token_mint_1(바이트 순서).amm_config.disable_create_pool == false.- 민트는 Token-2022 확장 허용 목록에 의해 거부되지 않습니다.
pool_state.sqrt_price_x64 = sqrt_price_x64,tick_current = floor(log_{1.0001}(price)).pool_state.liquidity = 0(아직 포지션 없음).pool_state.fee_on = FromInput(레거시 기본값).pool_state.dynamic_fee_info는 0으로 설정됨 (동적 수수료 비활성화).
CreateCustomizablePool
새 풀에 권장됩니다. CreatePool과 동일한 효과에 풀별 수수료 수집 모드와 선택적 동적 수수료 옵트인을 추가합니다.
인자
CreatePool의 정확히 13개의 선언된 계정. dynamic_fee_config는 선언된 계정이 아닙니다.
전제 조건 — CreatePool과 동일합니다. enable_dynamic_fee = false이면 remaining_account가 필요하지 않으며, 전달된 모든 것은 지원 민트 레코드만 스캔됩니다.
사후 조건
pool_state.fee_on이 선택된CollectFeeOn변형으로 설정됨.- 동적 수수료가 활성화된 경우:
pool_state.dynamic_fee_info는 제공된DynamicFeeConfig에서 초기화됨 (5개의 보정 매개변수 복사됨; 상태 필드는 0으로 설정됨). - 그렇지 않으면:
pool_state.dynamic_fee_info는 0으로 설정됨 (= 이 풀에 대해 동적 수수료는 영구적으로 비활성화됨).
fee_on과 동적 수수료 활성화 비트는 풀 생성 시에만 설정됩니다. 제자리 업그레이드는 없습니다. 레거시 CreatePool을 통해 생성된 풀은 동적 수수료 또는 단측 수수료를 소급하여 얻을 수 없습니다. 새 배포는 이 명령어를 기본값으로 사용해야 합니다.
CreateCustomizablePoolV2
CreatePool과 CreateCustomizablePool은 모두 ["pool", amm_config, token_mint_0, token_mint_1]에서 풀 PDA를 유도하므로, (config, mint0, mint1) 조합당 정확히 하나의 정규 풀 주소가 존재합니다. 같은 시드로 두 번째 init을 시도하면 실패합니다. CreateCustomizablePoolV2는 클라이언트가 제공하는 seed_index: u16을 풀 PDA 시드에 포함시켜 이 제한을 해제하므로, 같은 페어와 수수료 계층에 대해 여러 풀을 만들 수 있습니다 — 각각 고유한 주소에 위치합니다. 누구나 호출할 수 있습니다.
풀의 다른 모든 사항은 CreateCustomizablePool과 동일합니다. 같은 CreateCustomizableParams를 사용하며 단측 수수료와 동적 수수료 옵트인을 지원합니다.
2026-10-22 업그레이드까지 이 명령어는
CreatePermissionedPool이라고 불렸으며 지불자가 관리자가 발급한 Permission PDA를 보유해야 했습니다. 업그레이드로 이름이 변경되었고, permission 계정이 제거되었으며 권한 메커니즘이 삭제되었습니다. 판별자가 이름과 함께 변경되었으므로 CreatePermissionedPool에 대해 빌드된 클라이언트는 다시 빌드해야 합니다.remaining_accounts: Token-2022 민트가 필요할 때 지원 민트 레지스트리 PDA, 그리고 enable_dynamic_fee = true일 때 DynamicFeeConfig 마지막 — CreateCustomizablePool과 동일합니다.
전제 조건
seed_index != 0.seed_index가0이면 레거시 풀을 위해 예약되어 있으며 여기서 거부됩니다.[0, 0]시드 컴포넌트가 레거시 풀 주소를 클래식 4시드 형식으로 축소하게 합니다.- 유도된 주소에 풀이 이미 존재하지 않습니다.
CreatePool과 동일한 민트/허용 목록 규칙.
- 새로운
pool_state가seed_index유도 주소에 존재하며,pool_state.seed_index = seed_index. - 다른 모든 사후 상태는
CreateCustomizablePool과 일치합니다 (수수료 모드, 선택적 동적 수수료).
OpenPositionV2 / OpenPositionWithToken22Nft
기존 풀 내에 새로운 포지션을 만듭니다.
인자
OpenPositionV2는 22개를 선언합니다. OpenPositionWithToken22Nft는 20개를 선언합니다.
OpenPositionV2, 순서대로:
OpenPositionWithToken22Nft는 metadata_account (5)와 metadata_program (19)이 제거된 동일한 목록입니다 — NFT 민트의 Token-2022 메타데이터 확장을 통해 포지션의 메타데이터를 작성하므로 20개 계정을 제공합니다. 이 변형의 position_nft_mint는 단순 Signer이고 position_nft_account는 UncheckedAccount입니다.
수학 — products/clmm/math 참조. base_flag가 주어지면, 프로그램은 liquidity 또는 (amount_0_max, amount_1_max) 중 하나를 실제 L과 소비된 실제 토큰 금액으로 해석합니다.
전제 조건
tick_lower < tick_upper, 모두pool.tick_spacing의 배수,[MIN_TICK, MAX_TICK]범위 내.- 두 틱 배열 PDA가 전달됩니다. 이미 존재할 필요는 없습니다 —
get_or_create_tick_array는 이 명령어 내에서payer의 비용으로 누락된 것을 할당합니다. 별도의 초기화 틱 배열 명령어는 없습니다. - 사용자는 소스 ATA에 최소
amount_0_max와amount_1_max를 보유합니다.
personal_position이 존재하고,liquidity가 설정되며,fee_growth_inside_last가 스냅샷됩니다.tick_lower와tick_upper의 틱 배열 항목이 업데이트됩니다 (liquidity_gross += L,liquidity_net ± L, 수수료 성장 스냅샷 유지).- 포지션이 범위 내에 있으면 (
tick_lower ≤ tick_current < tick_upper)pool_state.liquidity += L. - 포지션 NFT 민트는
pool_state를 동결 권한으로 기록합니다. 단일 NFT가 민트된 후 민트 권한이 제거됩니다. 동결 권한을 기록하는 것은 NFT 토큰 계정의 상태를 변경하지 않습니다. - NFT 토큰 계정은 명령어가
OpenPositionV2또는OpenPositionWithToken22Nft이고 어느 금고 민트의 동결 권한이 CLMM의 제한된 발급자 목록과 일치하지 않으면 동결되지 않습니다. 오직 그 일치하는 V2 경로만 계정을 동결합니다.OpenPositionV1은 동결하지 않습니다.
TickInvalidOrder (tick_lower >= tick_upper), TickAndSpacingNotMatch (끝점이 tick_spacing의 배수가 아님), InvalidTickIndex ([MIN_TICK, MAX_TICK] 범위 밖), MissingTickArrayBitmapExtensionAccount (범위가 인라인 비트맵 밖이고 확장이 추가되지 않음), NotApproved (pool_state.status가 열기를 차단), ZeroAmountSpecified.
포지션 동결은 선언된 명령어 계정이나 인자를 추가하지 않습니다. 클라이언트는 기존 V2 레이아웃으로 이러한 포지션을 열 수 있습니다. 동작은 온체인에서
vault_0_mint와 vault_1_mint로부터 선택됩니다.IncreaseLiquidityV2
이미 열려 있는 포지션에 유동성을 추가합니다.
인자
OpenPosition에서 유도할 수 없습니다. rent, system_program, associated_token_program, 메타데이터 계정이 없습니다.
포지션의 범위가 인라인 비트맵 밖에 있을 때
TickArrayBitmapExtension PDA를 remaining_accounts[0]으로 앞에 추가합니다.
효과
- 사용자 → 금고에서
amount_0_actual/amount_1_actual을 전송합니다. personal_position.liquidity와pool_state.liquidity(범위 내인 경우)를 증가시키고, 끝점 틱의liquidity_gross/liquidity_net을 그에 따라 증가시킵니다.- 마지막 터치 이후 발생한 수수료와 보상을 수집하고
token_fees_owed_{0,1}/reward_amount_owed에 적립합니다. 이들은DecreaseLiquidity/DecreaseLiquidityV2에서만 지급되며, 증가 시에는 지급되지 않습니다 — 독립형 수집 명령어는 없습니다.
DecreaseLiquidityV2
포지션에서 유동성을 제거합니다.
인자
IncreaseLiquidityV2와 동일한 형태나 순서가 아닙니다: personal_position과 pool_state가 바뀌고, 금고가 틱 배열 앞에 오며, 사용자 측 계정이 recipient_token_account_*로 명명되고, 추가 memo_program이 있습니다.
남은 계정 — 수집 중인 활성 보상당 3개씩, 순서대로
reward_token_vault(W), recipient_token_account(W), reward_vault_mint. 포지션의 범위가 인라인 비트맵 밖에 있을 때 TickArrayBitmapExtension PDA를 앞에 추가합니다.
이것은 또한 수수료와 보상을 수집하는 유일한 방법입니다. 포지션을 변경하지 않고 수집하려면
liquidity = 0, amount_0_min = 0, amount_1_min = 0으로 호출합니다.- 현재
sqrt_price_x64가 주어진 제거된L에 대해(amount_0, amount_1)을 계산합니다. - 마지막 터치 이후 발생한 수수료/보상을 정산하며,
IncreaseLiquidity와 동일합니다. amount_0 + fees_owed_0과amount_1 + fees_owed_1을 금고에서 사용자에게 전송합니다.- 유동성 카운터를 감소시킵니다. 새로운
personal_position.liquidity == 0이면, 포지션은ClosePosition에 적격입니다.
amount_0_min과 amount_1_min은 출력 측의 Token-2022 전송 수수료를 차감한 사용자가 수락하는 최소값입니다.
ClosePosition
포지션 NFT를 소각하고 PersonalPositionState를 종료합니다.
선언된 계정
남은 계정
- 동결되지 않은 NFT: 필요 없음; 추가 풀 계정은 핸들러가 읽지 않으므로 무해합니다.
- 동결된 NFT: 첫 번째 남은 계정으로
personal_position.pool_id를 추가합니다. 프로그램은 이를PoolState로 로드하고 PDA 시드를 사용하여 동결 해제에 서명합니다.
personal_position.liquidity == 0.tokens_fees_owed_{0,1} == 0.- 모든 보상 카운터
reward_amount_owed == 0.
- NFT 토큰 계정이 동결된 경우, 첫 번째 남은 계정이
personal_position.pool_id와 같은지 확인한 후 풀 PDA로 동결을 해제합니다. - NFT를 소각합니다.
- NFT 토큰 계정과
personal_position을 종료하여nft_owner에게 렌트를 환불합니다. 포지션 NFT가 Token-2022를 사용하는 경우, NFT 민트도 종료합니다. 클래식 SPL Token 민트는 종료할 수 없으며 공급량이 0으로 유지됩니다.
AccountLack으로 실패합니다. 모든 종료에 대해 풀을 전달하는 것이 가장 간단한 호환 전략입니다.
SwapV2
유동성 곡선을 따라 이동합니다. is_base_input에 따라 정확한 입력 또는 정확한 출력입니다.
인수
호출자는 예상 스왑 이동을 포함하는 순위가 지정된 틱 배열 목록을 전달합니다. 프로그램은 필요한 만큼 사용합니다. SDK는
PoolUtils.computeAmountOutFormat 또는 API의 견적 엔드포인트를 통해 이 목록을 계산합니다.
전제 조건
pool_state.status가 스왑을 허용합니다.now >= open_time.sqrt_price_limit_x64는 방향에 대해sqrt_price_x64의 올바른 쪽에 있습니다.
TooLittleOutputReceived (정확한 입력 슬리피지), TooMuchInputPaid (정확한 출력 슬리피지), SqrtPriceLimitOverflow, NotEnoughTickArrayAccount, InvalidFirstTickArrayAccount, MissingTickArrayBitmapExtensionAccount, LiquidityInsufficient, NotApproved (스왑 비트가 pool_state.status에 설정됨). CLMM에는 ExceededSlippage 변형이 없습니다 — 그 이름은 CPMM의 것입니다 — 그리고 TickArrayNotFound도 없습니다.
호출자가 알아야 할 SwapV2가 내부적으로 수행하는 작업 (2025년 이후 릴리스):
- 동적 수수료 할증 —
pool.dynamic_fee_info가 0이 아닌 경우, 프로그램은 마지막 스왑 이후 순회한 틱 거리를 사용하여 변동성 누적기를 업데이트하고 (필터/감소 규칙은products/clmm/fees참조)AmmConfig.trade_fee_rate위에dynamic_fee_component를 추가합니다. 총 수수료는 10% (MAX_FEE_RATE_NUMERATOR / 1_000_000)로 제한됩니다. - 리미트 오더 매칭 — 가격 이동이 열린 리미트 오더를 보유한 틱을 교차할 때, 프로그램은 먼저 해당 틱에서 사용 가능한 리미트 오더 유동성을 채우고 (
order_phase로 FIFO), 그 다음 LP 유동성 곡선을 따라 진행합니다. 채워진 금액은 나중의 정산을 위해tick.unfilled_ratio_x64및tick.part_filled_orders_remaining을 업데이트합니다. 오더 자체는 소유자가SettleLimitOrder를 호출할 때까지 미사용 상태로 유지됩니다. - 편측 수수료 라우팅 —
pool.fee_on = Token0Only또는Token1Only일 때, 스왑 단계는 여전히 동일한 입력-출력 거래를 계산합니다. 그 다음 수수료는 구성된 쪽으로 라우팅됩니다. 구성된 수수료 쪽이 출력인 방향의 경우, 수수료는 스왑 출력에서 공제됩니다 (사용자는out − fee를 받음). 입력인 방향의 경우, 동작은FromInput과 일치합니다.PoolState의is_fee_on_input(zero_for_one)및is_fee_on_token0(zero_for_one)을 참조하세요.
Swap (V1)은 SwapV2와 동일한 동적 수수료, 편측 수수료 라우팅, 리미트 오더 매칭을 구현합니다. 유일하게 부족한 기능은 Token-2022 지원입니다 — 두 금고 모두 클래식 SPL Token이어야 합니다. Token-2022 민트가 있는 풀은 SwapV2를 통해 스왑해야 합니다. 애그리게이터와 SDK는 이미 모든 CLMM 레그에 대해 V2를 선호하므로 호출자는 민트 유형에 따라 분기할 필요가 없습니다.
OpenLimitOrder
특정 틱에서 판매 오더를 배치합니다. 오더는 틱별 FIFO 코호트에 앉아 있으며 가격이 지나갈 때 채워집니다.
인수
남은 계정 —
[0] tick_array_bitmap_extension, 시작 인덱스가 풀의 인라인 비트맵 외부에 있는 틱 배열을 초기화할 때만 필요합니다. 그 외에는 아무것도 전달하지 마세요.
계정 목록 변경 (2026-07 릴리스).
OpenLimitOrder는 이제 입력 쪽 외에도 출력 쪽 계정 — output_token_account, output_vault, output_vault_mint — 도 사용합니다. 이들은 검증에만 사용됩니다: 프로그램은 소유자의 입력 또는 출력 토큰 계정이 동결된 경우 오더를 거부합니다. 이는 채우기를 실제로 소유자의 출력 ATA로 정산할 수 있음을 보장하며, 이는 허용 목록 / 기본 동결 Token-2022 민트 (예: 허가된 토큰)에 중요합니다. 여기서 계정이 아직 동결 해제되지 않았을 수 있습니다. 이전의 편측 계정 목록에 대해 빌드된 클라이언트는 세 개의 출력 계정을 추가해야 합니다.input_token_account와output_token_account모두 동결되지 않음 (그렇지 않으면NotApproved).pool_state.status가 스왑 (비트 4)과 리미트 오더 (비트 5) 작업을 모두 허용함 (그렇지 않으면NotApproved).tick_index % pool.tick_spacing == 0이고[MIN_TICK, MAX_TICK]범위 내.tick_index는 선택한 방향에 대해pool.tick_current의 올바른 쪽에 있음 (token0 판매 → 틱은 현재보다 위에 있어야 하고, 그 반대도 마찬가지). 이미 교차한 틱에서 판매하면 즉시 매칭되며 거부됩니다.
limit_order가 존재하며, 열 때tick.order_phase및tick.unfilled_ratio_x64를 스냅샷합니다.tick.orders_amount += amount(현재 코호트에서).limit_order_nonce.order_nonce += 1.OpenLimitOrderEvent발행됨.
NotApproved (입력 또는 출력 토큰 계정 동결, 또는 풀에 스왑 / 리미트 오더 비활성화), ZeroAmountSpecified (입력 쪽 이전 수수료 후 amount == 0), InvalidLimitOrderAmount (금액이 해당 틱에서 1 기본 단위 미만의 출력을 생성하거나 u64 오버플로우), InvalidTickIndex ([MIN_TICK, MAX_TICK] 범위 밖, 또는 선택한 방향에 대해 tick_current의 잘못된 쪽), TickAndSpacingNotMatch (tick_index % pool.tick_spacing != 0), OrderPhaseSaturated.
IncreaseLimitOrder
기존 열린 오더에 추가합니다. 오더의 owner만 호출할 수 있습니다.
인수
system_program을 제거합니다.
전제 조건
limit_order.owner == signer.- 오더는 여전히 동일한 코호트에 있음 (
tick.order_phase == limit_order.order_phase). 코호트가 이미 채우기를 시작한 경우, 오더는 부분적으로 정산됨 — 호출자는 먼저DecreaseLimitOrder또는SettleLimitOrder를 호출하여 앞으로 이동해야 합니다.
- 소유자 ATA에서
input_vault로amount를 전송합니다. limit_order.total_amount += amount;tick.orders_amount += amount.
DecreaseLimitOrder
열린 오더를 줄이거나 완전히 취소합니다. 미채워진 나머지를 소유자에게 돌려주고, 과거 부분 채우기로 이미 정산된 출력도 함께 돌려줍니다.
인수
효과
- 열 때 이후 코호트의
unfilled_ratio_x64에서 오더의 채워진 금액을 재계산합니다. - 채워진 출력을
output_token_account로 전송합니다. - 미채워진 입력
amount를input_token_account로 돌려줍니다. limit_order를 그에 따라 업데이트합니다. 새로운 미채워진 나머지가 0이면, 프로그램은 계정을 종료하고owner에게 렌트를 환불합니다.
SettleLimitOrder
채워진 출력 토큰을 주문의 미충전 잔액을 변경하지 않고 소유자에게 전달합니다. auto_withdraw 키퍼가 장기 실행 부분 채우기를 점진적으로 지급하려는 경우에 유용합니다.
호출자 — 주문의 owner 또는 프로그램의 limit_order_admin (자동화된 키퍼 루프를 실행하는 오프체인 운영 핫 지갑). 키퍼는 다른 권한이 없습니다. 주문의 owner ATA로 채워진 출력을 전달하는 것 외에는 사용자 자금을 이동할 수 없습니다.
계정
효과
(limit_order.unfilled_ratio_x64, tick.unfilled_ratio_x64)를 사용하여 누적 출력 채무를 계산합니다.- 델타를
output_token_account로 전송합니다. limit_order.settled_output을 업데이트합니다.- 주문을 닫지 않습니다. 남은 입력에 대해 여전히 열려 있습니다.
CloseLimitOrder
완전히 소비된 주문 계정을 닫습니다. 누가 서명하든 관계없이 렌트는 항상 limit_order.owner로 반환됩니다.
호출자 — owner 또는 limit_order_admin.
전제 조건
- 주문에 미충전 잔액이 0입니다 (
amount == total_amount가 채워지고 정산되었거나, 소유자가 이전에 주문을 0으로 감소시키고 닫기를 잊었습니다).
limit_order를 닫습니다. 렌트는limit_order.owner로 전송됩니다.
CreateDynamicFeeConfig (관리자)
u16 인덱스 아래에 재사용 가능한 매개변수 집합을 만듭니다.
인수
일반적인 오류 —
decay_period <= filter_period이거나 0 값 필드가 범위를 벗어나면 InvalidDynamicFeeConfigParams.
UpdateDynamicFeeConfig (관리자)
기존 DynamicFeeConfig를 수정합니다. 생성 시 이미 구성을 스냅샷한 풀은 소급하여 업데이트되지 않습니다. 이 구성을 참조하는 새로 생성된 풀만 새 값을 선택합니다.
인수 — CreateDynamicFeeConfig와 동일한 5개 보정 필드 (filter_period, decay_period, reduction_factor, dynamic_fee_control, max_volatility_accumulator). index는 생성 시 고정되며 여기서 다시 전달되지 않습니다.
CollectProtocolFee / CollectFundFee
풀의 금고에서 누적된 프로토콜/펀드 수수료를 수신자에게 스윕하고, 해당 PoolState.protocol_fees_* / fund_fees_* 필드를 0으로 설정합니다. 이것은 CPMM의 레이아웃이 아닙니다 — CLMM에는 authority 계정이 없으며, 수신자 필드는 recipient_token_{0,1}_account 대신 recipient_token_account_{0,1}로 명명됩니다.
인수 — amount_0_requested: u64, amount_1_requested: u64.
2026-09에서 변경됨: 새 구성은 더 이상 서명자로부터 수수료 소유자를 가져오지 않습니다.
create_amm_config는 이제 프로그램의 하드코딩된 protocol_fee_owner::ID를 owner에, fund_fee_owner::ID를 fund_owner에 씁니다. 이전에는 관리자 서명자의 키를 둘 다에 복사했습니다. 메인넷에서는 이미 모든 21개의 기존 구성에 저장된 동일한 키입니다. 주소는 reference/program-addresses에 있습니다.위의 허용된 서명자는 변경되지 않습니다. 관리자는 여전히 모든 구성에서 수집할 수 있으며, 기존 AmmConfig 계정은 다시 쓰지 않습니다. 값을 가정하는 대신 계정에서 owner / fund_owner를 읽습니다. UpdateAmmConfig 매개변수 3과 4는 여전히 이를 회전합니다.CollectExcessLamports
CLMM이 제어하는 계정의 렌트 면제 최소값 이상의 램포트에 대한 관리자 스윕. SIMD-0437 렌트 감소 이후 각 단계 전에 생성된 계정에 남겨진 과다 자금을 회수하기 위해 2026-09 업그레이드에서 추가되었습니다.
초과분만 이동합니다. 토큰 잔액, 계정 데이터, 소유자, 풀 상태 및 가격 곡선은 변경되지 않습니다. 이미 최소값에 있는 계정은 그대로 두므로, 각 롤아웃 단계 후에 명령을 안전하게 다시 실행할 수 있습니다.
인수: 없음.
계정
범위: 호출당 하나의 풀. CLMM에는 프로그램 전체 금고 권한이 없습니다. 각 풀의 금고는 자체
PoolState에 의해 소유됩니다. 따라서 모든 토큰 프로그램 소스는 슬롯 2의 pool_state를 권한으로 가져야 합니다: token_vault_0, token_vault_1, 또는 해당 풀의 보상 금고 중 하나. 다른 풀의 금고나 사용자의 토큰 계정을 전달하면 토큰 프로그램의 소유자 확인이 실패하고 전체 명령이 되돌려집니다. 건너뛰지 않습니다. 포지션 NFT 민트는 스윕할 수 없습니다. 포지션이 열릴 때 민트 권한이 취소되기 때문입니다.
각 소스 계정이 처리되는 방식
프로그램은 remaining_accounts에 대해 두 번 통과합니다: 먼저 모든 토큰 프로그램 CPI, 그 다음 직접 차변. 두 가지를 인터리빙하면 런타임의 UnbalancedInstruction 오류로 중단되므로, 순서는 프로그램에서 고정되며 목록을 직접 정렬할 필요가 없습니다.
트랜잭션 크기는 한 호출에 맞는 소스 수의 실제 제한입니다. 이는
solana-fundamentals/rent-and-reclaimable-rent에 설명된 지갑 측 스윕과 동일한 제약입니다.
일반적인 오류:
NotApproved(6000): 잘못된 서명자.LamportsCalculateError(6052): wSOL 왕복이 0으로 정산되지 않았습니다.- 토큰 프로그램 소유자 불일치 오류: 토큰 소스가
pool_state에 의해 소유되지 않습니다. InsufficientFunds: 프로그램 소유 계정이 자체 렌트 최소값보다 적게 보유합니다.
@raydium-io/raydium-sdk-v2는 이 관리자 경로에 대한 빌더를 제공하지 않습니다. IDL에서 직접 인코딩합니다.
InitializeReward
풀에 새로운 보상 스트림을 추가합니다. 최대 3개의 스트림이 한 번에 활성화될 수 있습니다.
인수 — 단일 구조체, param: InitializeRewardParam:
param 객체를 전달해야 합니다.
계정
전제 조건
- 풀에서 현재 3개 미만의 스트림이 활성화되어 있습니다.
- 펀더는 이 명령의 일부로
total_emission = emissions_per_second × (end_time − open_time)상당의 보상 토큰을 금고에 예치합니다. operation_state에 따라 화이트리스트된 보상 민트.
SetRewardParams
기존 보상 스트림을 연장, 충전 또는 배출 속도 변경합니다. 일반적으로 풀 생성자 또는 Raydium 멀티시그에 의해 호출됩니다. 제약은 온체인에 있습니다: 일반적으로 end_time을 연장하거나 배출을 증가시킬 수 있지만, 소급하여 축소할 수는 없습니다. operation_state의 소유자 목록을 확인합니다.
UpdateRewardInfos
순수 기록 유지 — reward_growth_global_x64를 현재 시간으로 정산하고 emissions_per_second × Δt / liquidity를 곱합니다. 모든 유동성 터치 명령에 의해 내부적으로 호출됩니다. 외부 행위자 (UI, 크랭크)가 때때로 이를 트리거하려고 하기 때문에 독립 실행형 명령으로 노출됩니다.
보상 수집
포지션에 대한 보상은DecreaseLiquidity / DecreaseLiquidityV2에 의해 지급됩니다. 포지션을 변경하지 않고 수집하려면 liquidity = 0, amount_0_min = 0, amount_1_min = 0으로 호출합니다. 보상 금고와 수신자 계정은 활성 보상당 3개 그룹으로 remaining_accounts에 들어갑니다: reward_token_vault(W), recipient_token_account(W), reward_vault_mint.
CollectRemainingRewards는 다른 것입니다: 스트림의 end_time 이후 보상 펀더가 어떤 포지션에도 할당되지 않은 토큰을 스윕할 수 있게 합니다.
상태 변경 매트릭스
다음 단계
products/clmm/code-demos— 실행 가능한 TypeScript 샘플입니다.products/clmm/fees— 수수료 및 보상 적립에 대한 세부 정보입니다.reference/error-codes— 완전한 CLMM Anchor 오류 테이블입니다.
raydium-io/raydium-clmm—programs/amm/src/instructions- Raydium SDK v2 —
@raydium-io/raydium-sdk-v2

