本頁內容由 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 變更日誌條目。指令摘要
狀態位元遮罩:每個池的
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 池。
參數
* pool_state 僅在隨機金鑰對路徑上簽署;規範 PDA 路徑在沒有 pool_state 簽署的情況下執行。
前置條件
- 鑄幣廠已排序(
token_0_mint < token_1_mint按位元組順序)。 - 兩個鑄幣廠都不使用 CPMM 允許清單外的擴展(
TransferFeeConfig、MetadataPointer、TokenMetadata、InterestBearingConfig、ScaledUiAmount)— 參閱products/cpmm/accounts。其SupportMintAssociatedPDA(種子[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_feelamports 從建立者轉移到接收者並同步為原生 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 仍然可呼叫,所以想要為自己的收集簽署的建立者仍然可以。
參數 — 無。
帳戶
效果 — 與上面的
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_feeparam = 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 中的錢包側清掃對代幣程式指令所做的那樣。
狀態變更矩陣
下一步去哪裡
products/cpmm/code-demos— 上述的可執行 TypeScript 範例。reference/error-codes— 完整的 Anchor 錯誤表。products/cpmm/fees—Collect*Fee指令排出的費用累積模型。

