Skip to main content
本頁內容由 AI 自動翻譯,所有內容以英文版本為準。查看英文版 →
本頁是權威的指令參考。如需實際組成這些指令的程式碼,請參閱 products/cpmm/code-demos。如需錯誤代碼含義,請參閱 reference/error-codes。2026-09 程式升級在 Anchor 1.0.2 / Solana 3.1.10 上重建了 CPMM,新增了管理員指令 CollectExcessLamports,移除了硬編碼的 Token-2022 鑄幣廠白名單,並改變了 CreateAmmConfig 寫入 protocol_owner / fund_owner 的內容。沒有使用者面向的指令改變其帳戶、參數或數學。請參閱 2026-09-09 變更日誌條目。
兩個建立者費用收集指令在 2026-09-19 改變了其帳戶列表。 CollectCreatorFee 新增 creator_fee_share;CollectCreatorFeePermissionless 新增 amm_config 和 creator_fee_share。兩者都附加在 system_program 之後,因此現有用戶端已傳遞的每個帳戶都保持其索引 — 但新帳戶是強制性的,所以針對舊版配置構建的交易帳戶數量不足,會被 Anchor 的 AccountNotEnoughKeys(3005)拒絕。新增了兩個管理員指令 — CreateCreatorFeeShare 和 CloseCreatorFeeShare — 並且 UpdateAmmConfig 採用新的 param = 8。請參閱 2026-09-19 變更日誌條目。

指令摘要

狀態位元遮罩:每個池的 status 是一個 u8,其中位 0 = 禁用存款,位 1 = 禁用提取,位 2 = 禁用交換(程式中的 PoolStatusBitIndex { Deposit, Withdraw, Swap })。清除位表示允許操作;設定位表示暫停。UpdatePoolStatus 採用原始 u8 並覆蓋現有值。 下一節詳細介紹每一個。帳戶順序遵循 CPMM IDL;SDK 和 raydium-cp-swap/programs/cp-swap/src/instructions 中的 Rust 用戶端符合此順序。

Initialize

建立新的 CPMM 池。 參數
帳戶(W = 可寫,S = 簽署者) * pool_state 僅在隨機金鑰對路徑上簽署;規範 PDA 路徑在沒有 pool_state 簽署的情況下執行。 前置條件
  • 鑄幣廠已排序(token_0_mint < token_1_mint 按位元組順序)。
  • 兩個鑄幣廠都不使用 CPMM 允許清單外的擴展(TransferFeeConfig、MetadataPointer、TokenMetadata、InterestBearingConfig、ScaledUiAmount)— 參閱 products/cpmm/accounts。其 SupportMintAssociated PDA(種子 [b"support_mint", mint])存在的鑄幣廠跳過擴展檢查 — 但你必須將該 PDA 附加到 remaining_accounts。程式只掃描你傳遞的帳戶,從不自己載入 PDA,所以依賴登記而不提供帳戶仍然會失敗,出現 NotSupportMint(6007)。順序無關緊要(按鑰匙匹配);為每個需要繞過的鑄幣廠傳遞一個條目。該登記是自 2026-09 升級移除硬編碼四鑄幣廠白名單以來唯一的繞過。
  • creator 在各自的 ATA 中至少有 init_amount_0 和 init_amount_1。
  • amm_config.disable_create_pool == false。
後置條件
  • pool_state.lp_supply = sqrt(init_amount_0 * init_amount_1) — 完整平方根。建立者被鑄造 lp_supply − 100;100 個鎖定的基礎單位被計入 lp_supply 但從不鑄造。
  • 因此 lp_mint.supply == pool_state.lp_supply − 100 在池的整個生命週期內。所有 LP 份額數學(存款、提取)除以 lp_supply,所以使用該欄位,不要替換鑄幣廠的鏈上供應。如果 sqrt(...) < 100 則回退 InitLpAmountTooLess。
  • observation_state 已初始化;observation_index = 0 和 pool_id = pool_state.key()。
  • create_pool_fee lamports 從建立者轉移到接收者並同步為原生 SOL(它是 wSOL ATA)。
  • 池的狀態位元遮罩是 0(存款/提取/交換全部啟用)。
  • enable_creator_fee = false 和 creator_fee_on = BothToken。Initialize 不支援啟用建立者費用 — 該路徑是 InitializeWithPermission。
  • 如果呼叫者傳遞的值 <= block_timestamp,open_time 被提升到 block_timestamp + 1。交換在 open_time 之前被拒絕;存款和提取立即工作。
常見錯誤(完整清單在 reference/error-codes)
  • InvalidInput — 鑄幣廠未排序或相同鑄幣廠。
  • NotSupportMint — 被阻止的 Token-2022 擴展。
  • ExceededSlippage — 很少;如果 init_amount_0/1 由於小數位數不匹配導致零 LP。

Deposit

按池的比例在兩個代幣中新增流動性。 參數
帳戶 數學
兩個值得釘住的細節:按比例基礎是費用排除保管庫總額(vault_amount_without_fee,即原始餘額減去累積的協議、基金和建立者計數器),而不是原始保管庫餘額;滑點上限針對支付者實際轉移的內容進行檢查,在 Token-2022 轉移費用被新增後,而不是針對總保管庫移動。 k 的比例沒有變化 — 兩個總額和 lp_supply 按相同因子縮放。 後置條件
  • lp_supply += lp_token_amount。
  • vault_0 += needed_token_0(扣除輸入上任何 Token-2022 轉移費用)。
  • vault_1 += needed_token_1(扣除輸入上任何 Token-2022 轉移費用)。
常見錯誤 — ExceededSlippage、ZeroTradingTokens、InvalidStatus(如果存款被暫停)。

Withdraw

燒毀 LP 代幣並按比例接收兩個基礎代幣。 參數
帳戶 前 13 個帳戶與 Deposit 相同,lp_mint 是可寫的,因為 LP 代幣被燒毀。Withdraw 另外採用第 14 個帳戶 memo_program(受限 address = memo::ID)— Deposit 不採用。13 帳戶 Withdraw 失敗 Anchor 反序列化,所以 LP 無法退出。 數學
後置條件
  • lp_supply -= lp_token_amount。
  • 保管庫發送 out_token_0 / out_token_1(總額;使用者接收扣除任何 Token-2022 轉移費用的淨額)。

SwapBaseInput

精確輸入交換。 參數
帳戶 順序輸入 → 輸出是按使用者的方向,而不是按池的規範 token_0 / token_1。程式通過匹配鑄幣廠來確定哪個保管庫是哪個。 數學 — 參閱 products/cpmm/math。 前置條件
  • open_time <= now。
  • pool_status 允許交換。
  • 對於此授權,兩個鑄幣廠都未暫停或凍結。
  • amount_in > 0。
常見錯誤
  • ExceededSlippage — amount_out < minimum_amount_out。
  • ZeroTradingTokens — 交易四捨五入為零。
  • NotApproved — 池通過 UpdatePoolStatus 暫停交換。
  • InvalidInput — 鑄幣廠與池的任一保管庫鑄幣廠不匹配。

SwapBaseOutput

精確輸出交換。 參數
帳戶 — 與 SwapBaseInput 相同。 數學 — 反向曲線與上限,參閱 products/cpmm/math。 常見錯誤 — ExceededSlippage(gross_in > max_amount_in)、ZeroTradingTokens、InvalidInput、NotApproved。

CollectProtocolFee

從保管庫清掃累積的協議費用到協議目標。 參數 — 無。 帳戶 效果
曲線有效餘額沒有變化(累積費用已被排除)。 常見錯誤 — InvalidOwner(6001)如果簽署者既不是 amm_config.protocol_owner 也不是程式管理員。(此路徑上沒有 NotApproved。)

CollectFundFee

與 CollectProtocolFee 相同的形狀,但由 amm_config.fund_owner 簽署 — 或再次由程式管理員簽署 — 並將 fund_fees_* 計數器歸零。錯誤簽署者上相同的 InvalidOwner。

CollectCreatorFee

由 pool_state.pool_creator 簽署。它結算累積的建立者費用並將建立者的部分轉移到建立者的代幣帳戶。 參數 — 無。 帳戶 效果
協議的份額在此處從不離開保管庫 — 它被重新標記為協議費用並等待 CollectProtocolFee。兩個計數器已被排除在曲線對保管庫的看法之外,所以池的價格不會移動。完整推導在 products/cpmm/fees。 常見錯誤 — 當兩個建立者計數器都為零時 NoFeeCollect(在分割前檢查),InvalidInput(6003)如果解析的 share_rate 超過 1_000_000,MathOverflow(6011)如果預訂份額會溢出 protocol_fees_token_*,以及 Anchor 的 ConstraintSeeds 錯誤如果 creator_fee_share 不是規範 PDA。

CollectCreatorFeePermissionless

任何人都可以觸發建立者費用收集。指令始終將建立者的部分發送到由 pool_state.pool_creator 擁有的規範關聯代幣帳戶;呼叫者無法選擇另一個建立者或目標。如果任一 ATA 缺失,支付者為其建立提供資金。 原始 CollectCreatorFee 仍然可呼叫,所以想要為自己的收集簽署的建立者仍然可以。 參數 — 無。 帳戶
兩個新帳戶附加在 system_program 之後,而非插入。從 payer 到 system_program 的每個帳戶都保持升級前的位置,所以這個破壞是乾淨的:針對升級前十四帳戶配置構建的交易不會誤讀保管庫為設定帳戶 — 它只是傳遞的帳戶太少,Anchor 在任何約束執行之前就以 AccountNotEnoughKeys(3005)拒絕它。這些帳戶仍然是強制性的,所以請附加兩者並刷新 IDL;舊版配置沒有相容路徑。
效果 — 與上面的 CollectCreatorFee 相同:份額從 creator_fee_share 或 amm_config 解析,協議的部分被記入 protocol_fees_token_{0,1},建立者的部分被轉移到建立者 ATA,兩個建立者計數器被歸零,recent_epoch 被更新。當兩個計數器都為零時返回 NoFeeCollect。

UpdatePoolStatus

暫停或恢復池上的個別操作。status 欄位是一個位元遮罩: 參數
帳戶 管理員鑰匙是編譯到程式中的公鑰(crate::admin::ID),而不是 BPF 升級授權 — 改變它需要程式升級。參閱 reference/program-addresses 以獲取值,以及 security/admin-and-multisig 以了解誰持有它。

CreateAmmConfig

建立新的費用層級。 參數
帳戶 前置條件
  • 沒有具有相同 index 的現有 AmmConfig。
  • protocol_fee_rate + fund_fee_rate <= FEE_RATE_DENOMINATOR_VALUE。
在 2026-09 中改變:新設定的費用所有者不再來自簽署者。 create_amm_config 現在將程式的硬編碼 protocol_fee_owner::ID 寫入 protocol_owner 和 fund_fee_owner::ID 寫入 fund_owner,而不是將管理員簽署者的鑰匙複製到兩者。地址在 reference/program-addresses。後果:新建立的 AmmConfig 上的費用落入專用費用錢包,而不是管理員的。管理員確實仍然是收集的接受簽署者 — CollectProtocolFee / CollectFundFee 接受 amm_config.protocol_owner / fund_owner 或 crate::admin::ID — 所以沒有什麼必須旋轉來清掃;改變的只是預設情況下收益去向的位置。現有 AmmConfig 帳戶不被重寫 — 無論在它們上儲存什麼仍然管理,所以始終從帳戶讀取 protocol_owner / fund_owner 而不是假設任一值。UpdateAmmConfig 參數 3 和 4 仍然旋轉它們。

UpdateAmmConfig

改變現有 AmmConfig 上的費率或所有權。採用 param: u8(要更新的欄位)和 value: u64。完整分派表:
  • param = 0 → trade_fee_rate(斷言 trade_fee_rate + creator_fee_rate < 1_000_000)
  • param = 1 → protocol_fee_rate(斷言 ≤ 1_000_000 和 + fund_fee_rate ≤ 1_000_000)
  • param = 2 → fund_fee_rate(斷言 ≤ 1_000_000 和 + protocol_fee_rate ≤ 1_000_000)
  • param = 3 → protocol_owner。新鑰匙不在 value 中:將其附加為 remaining_accounts[0](唯讀沒問題)。它不能是預設公鑰,省略帳戶會在 unwrap() 上恐慌。
  • param = 4 → fund_owner。與 3 相同的機制。
  • param = 5 → create_pool_fee
  • param = 6 → disable_create_pool(任何非零 value 禁用)
  • param = 7 → creator_fee_rate(斷言 creator_fee_rate + trade_fee_rate < 1_000_000)
  • param = 8 → creator_fee_share_rate(斷言 ≤ 1_000_000)。新增於 2026-09-19。協議在此層級上建立者費用的預設份額;參閱 products/cpmm/fees。它與 protocol_fee_rate 無關,後者分割交易費用。
任何其他 param 返回 InvalidInput。 變更由管理員簽署並影響綁定到此 AmmConfig 的每個池在下一次交換時。沒有遷移;池簡單地讀取新值。

CreateCreatorFeeShare

為一個 (creator, amm_config) 對設定自訂協議份額的建立者費用,覆蓋 AmmConfig.creator_fee_share_rate 用於該費用層級上該建立者擁有的每個池。新增於 2026-09-19 建立者費用份額升級。 參數
帳戶 前置條件
  • share_rate <= 1_000_000,否則 InvalidInput(6003)。
  • PDA 不能已存在 — Anchor 的 init 在同一對的第二次呼叫時失敗。要改變費率,關閉帳戶並重新建立。
後置條件
  • creator_fee_share 儲存 bump、creator、amm_config 和 share_rate。
  • 在該費用層級上由 creator 建立的池上的每個後續 CollectCreatorFee / CollectCreatorFeePermissionless 從此帳戶解析份額,而不是設定。
池建立者不是此指令的一方,也不簽署它。費率在收集時讀取,所以在費用已經累積後建立的覆蓋也適用於該累積餘額。

CloseCreatorFeeShare

移除覆蓋。該對回退到 AmmConfig.creator_fee_share_rate。 參數 — 無。 帳戶 後置條件
  • 帳戶被關閉,其 lamports 去往 owner。
  • 該對的收集再次從 amm_config.creator_fee_share_rate 解析份額 — 除非管理員已設定 UpdateAmmConfig 參數 8,否則為 0。

CollectExcessLamports

管理員清掃 CPMM 控制的帳戶上超過租金豁免最低額的 lamports。新增於 2026-09 升級,以便協議可以回收 SIMD-0437 租金減少 在每個步驟之前建立的帳戶上留下的過度資金。 只有超額移動。代幣餘額、帳戶資料、所有者、池狀態和曲線保持不變,指令對已在其最低值的帳戶是無操作 — 所以在每個推出步驟後重新執行是安全的。 參數 — 無。 帳戶
排序修復,2026-09-19。 程式現在對 remaining_accounts 進行兩次傳遞 — 每個代幣程式 CPI 首先,然後是 CPMM 擁有的 PDA 的直接借記。當 PDA 在 CPI 之前被借記時,它們會中止,出現執行時的 UnbalancedInstruction(「指令前後帳戶餘額總和不匹配」),因為呼叫者的待處理 lamport 變更只在 CPI 實際執行時才被刷新到帳戶。呼叫者不必自己對清單進行分組或排序。
每個來源帳戶的處理方式 程式根據來源帳戶的 owner 進行分派: 因為它採用無界 remaining_accounts 清單,交易大小是真正的限制 — 與 solana-fundamentals/rent-and-reclaimable-rent 中描述的錢包側清掃相同的約束。 常見錯誤 — InvalidOwner(6001,錯誤簽署者)、LamportsCalculateError(6015,wSOL 往返沒有淨為零)和 InsufficientFunds 來自程式擁有的路徑,當帳戶持有少於其自己的租金最低額時。 沒有 SDK 構建器。 @raydium-io/raydium-sdk-v2 不提供此指令的構建器,raydium-sdk-V2-demo 儲存庫也不提供 — 它是管理員路徑。手動編碼,就像 solana-fundamentals/rent-and-reclaimable-rent 中的錢包側清掃對代幣程式指令所做的那樣。

狀態變更矩陣

下一步去哪裡

來源: