本頁內容由 AI 自動翻譯,所有內容以英文版本為準。查看英文版 →
本頁與
products/clmm/accounts(帳戶說明)和 products/clmm/math(數學說明)配套。本頁對參數和帳戶順序具有權威性;具體的位元組佈局來自 IDL。指令清單
大多數管理員專用指令(
CreateAmmConfig、UpdateAmmConfig、UpdatePoolStatus、CreateSupportMintAssociated、CreateOperationAccount、UpdateOperationAccount、CloseProtocolPosition)由程序的硬編碼 admin 公鑰控制。CreatePermissionPda / ClosePermissionPda 接受 admin 公鑰或專用的 permission_pda_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被清零(動態費用禁用)。
CreateCustomizablePool
推薦用於新池。與 CreatePool 效果相同,加上每池費用收集模式和可選的動態費用選擇加入。
參數
CreatePool 相同,加上當 enable_dynamic_fee = true 時:
前置條件 — 與
CreatePool 相同。如果 enable_dynamic_fee = false,dynamic_fee_config 被忽略。
後置條件
pool_state.fee_on設置為選定的CollectFeeOn變體。- 如果啟用了動態費用:
pool_state.dynamic_fee_info從提供的DynamicFeeConfig初始化(複製五個校準參數;狀態欄位清零)。 - 否則:
pool_state.dynamic_fee_info被清零(= 此池永遠不會啟用動態費用)。
fee_on 和動態費用啟用位僅在池創建時設置。沒有就地升級 — 通過舊版 CreatePool 創建的池無法追溯地獲得動態費用或單邊費用。新部署應預設為此指令。
CreatePermissionedPool
CreatePool 和 CreateCustomizablePool 都從 ["pool", amm_config, token_mint_0, token_mint_1] 派生池 PDA,因此每個 (config, mint0, mint1) 三元組恰好有一個規範池地址 — 在相同種子處的第二個 init 失敗。CreatePermissionedPool 通過將客戶端提供的 seed_index: u16 折疊到池 PDA 種子中來解除此限制,允許同一交易對和費用等級的多個池 — 每個在其自己的地址。因為任意池地址是特權功能,支付者必須持有授權它的 Permission PDA。
關於池的其他一切與 CreateCustomizablePool 相同:它採用相同的 CreateCustomizableParams 並支持單邊費用和動態費用選擇加入。
參數
CreateCustomizablePool 相同,加上前面的:
pool_state PDA 派生自 ["pool", amm_config, token_mint_0, token_mint_1, seed_index.to_le_bytes()]。
前置條件
seed_index != 0。seed_index為0保留給舊版池並在此被拒絕;[0, 0]種子分量是使舊版池地址折疊為經典四種子形式的原因。payer的permissionPDA 存在(由管理員通過CreatePermissionPda創建)。- 與
CreatePool相同的鑄幣/允許列表規則。
- 新的
pool_state存在於seed_index派生的地址,pool_state.seed_index = seed_index。 - 所有其他後狀態與
CreateCustomizablePool匹配(費用模式、可選動態費用)。
此指令不擴大一般池創建訪問 — 無權限創建繼續通過
CreatePool / CreateCustomizablePool,每對仍為一個池。CreatePermissionedPool 存在於白名單操作者需要同一交易對的多個池(例如不同的初始價格或啟動隊列)並持有由管理員授予的 Permission PDA 的特定情況。OpenPositionV2 / OpenPositionWithToken22Nft
在現有池內創建新頭寸。
參數
數學 — 見
products/clmm/math。給定 base_flag,程序將 liquidity 或 (amount_0_max, amount_1_max) 解析為實際 L 和消耗的實際代幣金額。
前置條件
tick_lower < tick_upper,都是pool.tick_spacing的倍數,在[MIN_TICK, MAX_TICK]內。- 所需 tick 陣列已傳遞並初始化(或在交易中通過
InitTickArrayCPI 創建)。 - 用戶在源 ATA 中至少有
amount_0_max和amount_1_max。
personal_position存在,liquidity設置,fee_growth_inside_last快照。- Tick 陣列條目在
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 不凍結。
InvalidTickIndex、NotApproved、ZeroAmountSpecified、TransactionTooLarge(如果 tick 陣列過多)。
頭寸凍結不添加聲明的指令帳戶或參數。客戶端可以使用現有的 V2 佈局打開這些頭寸。行為在鏈上從
vault_0_mint 和 vault_1_mint 選擇。IncreaseLiquidityV2
向已開放的頭寸添加流動性。
參數
OpenPosition 減去 NFT 鑄幣(頭寸已存在;NFT 作為持有 1 個代幣的所有者 ATA 傳遞)。
效果
- 從用戶轉移
amount_0_actual/amount_1_actual→ 保管庫。 - 增加
personal_position.liquidity和pool_state.liquidity(如果在範圍內),以及端點 tick 的liquidity_gross/liquidity_net。 - 收集自上次觸及以來應付的費用和獎勵並將其記入
tokens_fees_owed_{0,1}/reward_amount_owed。這些僅在DecreaseLiquidity或CollectReward時支付,而不是在增加時。
DecreaseLiquidityV2
從頭寸移除流動性。
參數
IncreaseLiquidity 相同的形狀。
效果
- 給定當前
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 鑄幣無法關閉,供應量保持為零。
AccountLack。為每次關閉傳遞池是最簡單的兼容策略。
SwapV2
沿流動性曲線行走;精確輸入或精確輸出取決於 is_base_input。
參數
調用者傳遞覆蓋預期交換行走的排序 tick 陣列列表;程序使用所需的數量。SDK 通過
PoolUtils.computeAmountOutFormat 或 API 的報價端點計算此列表。
前置條件
pool_state.status允許交換。now >= open_time。sqrt_price_limit_x64在sqrt_price_x64的正確一側用於方向。
ExceededSlippage、SqrtPriceLimitOverflow、TickArrayNotFound、LiquidityInsufficient。
SwapV2 在內部執行的調用者應該知道的內容(2025 年後發布):
- 動態費用附加費 — 如果
pool.dynamic_fee_info非零,程序使用自上次交換以來遍歷的 tick 距離更新波動率累加器(使用products/clmm/fees中的過濾/衰減規則),並在AmmConfig.trade_fee_rate之上添加dynamic_fee_component。總費用上限為 10%(MAX_FEE_RATE_NUMERATOR / 1_000_000)。 - 限價單匹配 — 當價格行走穿過持有開放限價單的 tick 時,程序首先填充該 tick 處可用的限價單流動性(按
order_phase的 FIFO),然後沿著 LP 流動性曲線進行。已成交金額更新tick.unfilled_ratio_x64和tick.part_filled_orders_remaining以供稍後結算;訂單本身保持未花費,直到其所有者調用SettleLimitOrder。 - 單邊費用路由 — 當
pool.fee_on = Token0Only或Token1Only時,交換步驟仍計算相同的輸入輸出交易;費用隨後被路由到配置的一側。對於配置費用側是輸出的方向,費用從交換輸出中扣除(用戶收到out − fee);對於配置費用側是輸入的方向,行為與FromInput匹配。見pool_state上的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
在特定 tick 處下達賣單。訂單位於每 tick FIFO 隊列中,並在價格穿過時填充。
參數
帳戶列表變更(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 → tick 必須在當前上方,反之亦然)。在已穿過的 tick 處出售會立即匹配並被拒絕。
limit_order存在,快照打開時的tick.order_phase和tick.unfilled_ratio_x64。tick.orders_amount += amount(在當前隊列中)。limit_order_nonce.order_nonce += 1。- 發出
OpenLimitOrderEvent。
NotApproved(輸入或輸出代幣帳戶被凍結,或池禁用交換/限價單)、InvalidLimitOrderAmount(零或低於池的最小值)、InvalidTickIndex(超出 [MIN_TICK, MAX_TICK],或在所選方向的 tick_current 的錯誤一側)、TickAndSpacingNotMatch(tick_index % pool.tick_spacing != 0)、OrderPhaseSaturated。
IncreaseLimitOrder
添加到現有開放訂單。僅由訂單的 owner 調用。
參數
OpenLimitOrder 減去 nonce 帳戶;limit_order PDA 直接傳遞。
前置條件
limit_order.owner == signer。- 訂單仍在同一隊列中(
tick.order_phase == limit_order.order_phase)。如果隊列已開始填充,訂單已部分結算 — 調用者應首先調用DecreaseLimitOrder或SettleLimitOrder以向前推進。
- 從所有者 ATA 轉移
amount到input_vault。 limit_order.total_amount += amount;tick.orders_amount += amount。
DecreaseLimitOrder
減少或完全取消開放訂單。將未成交的剩餘部分支付回所有者,加上過去部分成交已結算的任何輸出。
參數
效果
- 從打開以來隊列的
unfilled_ratio_x64重新計算訂單的已成交金額。 - 將已成交輸出發送到
output_token_account。 - 將
amount的未成交輸入發送回input_token_account。 - 相應地更新
limit_order。如果新的未成交剩餘為零,程序關閉帳戶並將租金退款給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。
前置條件
- 訂單的未成交剩餘為零(
amount == total_amount已成交並結算,或所有者之前將訂單減少到零並忘記關閉)。
- 關閉
limit_order;租金發送到limit_order.owner。
CreateDynamicFeeConfig(管理員)
在 u16 索引下創建可重用的參數集。
參數
常見錯誤 — 如果
decay_period <= filter_period 或任何 0 值欄位超出邊界,則 InvalidDynamicFeeConfigParams。
UpdateDynamicFeeConfig(管理員)
修改現有 DynamicFeeConfig。在創建時已快照配置的池不被追溯更新;只有引用此配置的新創建池才會選擇新值。
參數 — 與 CreateDynamicFeeConfig 相同的五個校準欄位(filter_period、decay_period、reduction_factor、dynamic_fee_control、max_volatility_accumulator);index 在創建時固定,此處不重新傳遞。
CollectProtocolFee / CollectFundFee
與 CPMM 的 CollectProtocolFee / CollectFundFee 相同的形狀。簽署者必須與 AmmConfig.owner / AmmConfig.fund_owner 匹配。從池的保管庫掃描累積的協議/基金費用到收件人,將相應的 PoolState.protocol_fees_* / fund_fees_* 欄位清零。
InitializeReward
向池添加新的獎勵流。最多 3 個流可同時活躍。
參數
前置條件
- 池上當前活躍的流少於 3 個。
- 資金提供者作為此指令的一部分將
total_emission = emissions_per_second × (end_time − open_time)價值的獎勵代幣存入保管庫。 - 根據
operation_state白名單獎勵鑄幣。
SetRewardParams
延長、充值或更改現有獎勵流的發放速率。通常由池創建者或 Raydium 多簽調用。約束在鏈上:你通常可以延長 end_time 或增加發放,而不是追溯縮減。檢查 operation_state 的所有者列表。
UpdateRewardInfos
純粹的簿記 — 通過將 emissions_per_second × Δt / liquidity 相乘將 reward_growth_global_x64 結算到當前時間。由每個流動性觸及指令在內部調用。作為獨立指令公開,因為外部參與者(UI、cranks)有時想觸發它。
CollectReward
頭寸所有者聲稱應付的獎勵代幣。
帳戶
效果
- 結算獎勵增長(與費用相同的模式)。
- 將應付金額轉移到收件人 ATA,將
reward_amount_owed[i]清零。
狀態變更矩陣
後續步驟
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

