Skip to main content
本頁內容由 AI 自動翻譯,所有內容以英文版本為準。查看英文版 →
sdk-api/rust-cpi 涵蓋了呼叫各個 Raydium 程式的低階機制。本頁是更高層級的補充:為什麼你會將 Raydium 組合到自己的程式中、哪種模式適合你的使用案例,以及端到端所需的完整膠水程式碼。

CPI 何時是正確的工具

當交易需要與只有你的程式才能進行的其他鏈上狀態變更原子性地發生時,自訂程式就很有意義。常見的情況:
  • 託管 / 限價單程式 — 使用者將一個 mint 存入你的託管,你的程式監視價格條件,當觸發時,你的程式原子性地透過 Raydium 交換並將結果記入使用者帳戶。
  • 聚合器代理 — 單一指令將交換路由透過 Raydium 加上一個或多個其他 DEX,所有跳轉都在由你的程式擁有的單一滑點檢查下。
  • 自動複利金庫 — 將 LP 或農場質押存入你的金庫,金庫按計畫收穫獎勵、重新供應流動性、發行份額代幣。
  • 策略金庫 — 槓桿 LP 頭寸透過 CLMM 交換進行再平衡;清算人在一筆交易中關閉頭寸並交換抵押品。
  • 具有自訂解鎖的代幣發行平台 — 你的程式持有解鎖代幣並按計畫釋放到 Raydium 池中。
如果你只想從鏈下程式碼發送交換,CPI 就太複雜了 — 使用 SDK。只有當與你自己的狀態的原子性是要求時,CPI 才值得這種複雜性。

組合模式

模式 1:薄代理

你的程式公開單一指令,驗證某些政策(例如白名單 mint 對、驗證使用者的費用折扣),然後轉發到 Raydium。
狀態存在於使用者的 ATA 中。你的程式不擁有任何代幣。最小信任足跡。

模式 2:託管

你的程式擁有一個 PDA,持有使用者的輸入 mint。觸發時,PDA 簽署一個 CPI 到 Raydium 以交換其自己的餘額。
關鍵細節:PDA 透過 CpiContext::new_with_signer 簽署。見 簽署者種子。

模式 3:組合多跳

你的程式在一個指令中發出多個 CPI,在所有 CPI 中強制執行單一滑點界限。Raydium 交換指令各自有自己的 minimum_amount_out,但你將其設定為 0(或非常寬鬆的下限),並在最後一跳後自己強制執行嚴格的最終最小值。
這為整個路由提供了單一的還原門。只有在你信任每個跳轉都是滑點安全的情況下才使用此模式;否則,讓每個跳轉強制執行自己的最小值。

模式 4:金庫 / 策略

你的程式在 PDA 中持有 LP 代幣或農場質押。保管人(或使用者)呼叫 compound(),其中:
  1. 從農場收穫獎勵。
  2. 將獎勵交換為池代幣(CPI 進入 CPMM 或 CLMM)。
  3. 將收益存回 LP(另一個 CPI)。
  4. 質押新 LP(另一個 CPI)。
全部在一筆交易中進行,以便金庫的 NAV 原子性地移動。計算預算通常為 600k–1M CU;地址查詢表是必需的。

帳戶列表構造

呼叫程式的 Accounts 結構鏡像 Raydium 程式的帳戶順序,但大多數 Raydium 端帳戶是 UncheckedAccount,因為 Raydium 自己驗證它們。你只在你擁有的帳戶上新增約束:
不對稱性 — 對你的帳戶進行嚴格驗證,對 Raydium 的帳戶進行 UncheckedAccount — 不是懶惰。接收者驗證自己的;在呼叫者處雙重驗證只會燃燒 CU,並在 Raydium 發布新結構佈局欄位時冒著不同步的風險。

CPI 呼叫本身

PDA 簽署者種子

CPI 只有在作為 authority 傳遞的 PDA 與呼叫者聲稱的推導相符時才會成功。兩者必須同意:
  1. 種子位元組序列(此處 [b"escrow", user.key().as_ref()])。
  2. bump。
  3. 呼叫程式 ID(你的程式,不是 Raydium 的)。
請注意 PDA 必須與什麼相符。CPMM 的 authority 槽位是它自己的金庫 PDA — 一個固定的、程式範圍的帳戶,由它自己推導並簽署,你的程式既不控制它也無法替換它。你的 PDA 種子必須對齊的帳戶是 payer:檢查發生在 CPMM 自己的 transfer_from_user_to_pool_vault 輔助函式中,它要求作為 payer 傳入的帳戶必須是 input_token_account 的擁有者。 常見錯誤:將 user 作為 payer 傳遞,而 escrow_input_ata 卻由託管 PDA 擁有。SPL Token 程式以 owner mismatch 拒絕。始終讓 payer 成為 ATA 的擁有者 — 當該擁有者是 PDA 時,用 new_with_signer 為其簽名。

剩餘帳戶

幾個 Raydium 指令在固定帳戶之後採用可變長度的帳戶列表 — 剩餘帳戶。
  • CLMM SwapV2:1–8 個 TickArrayState 帳戶,用於交換可能遍歷的 tick 陣列,按交換方向。
  • Farm v6 Deposit / Harvest / Withdraw:(reward_vault, user_reward_ata) 對,每個活躍獎勵槽一對。
  • Token-2022 轉帳掛鉤 mint:轉帳掛鉤程式加上掛鉤需要的任何帳戶。
Anchor CPI 幫助程式不對剩餘帳戶進行型別檢查。將其傳遞:
順序很重要。 對於 CLMM:
對於 farm v6 收穫:
你的呼叫程式必須將從客戶端接收的剩餘帳戶原封不動地傳遞。不要嘗試篩選或重新排序它們。

組合呼叫的計算預算

CPI 本身的呼叫框架成本約 1,500 CU;被呼叫者自己的 CU 使用堆疊在上面。 下面的被呼叫者數字是在 2026-09-09 從高交易量流動性池的主網實際交易中測得的,取自 Raydium 程式自身呼叫的 Program <id> consumed N of M compute units 日誌行(因此已包含其內部的代幣程式 CPI): 在此之上,為每個 CPI 框架新增約 1,500,再加上你自己程式的開銷。CLMM 交換成本會隨 tick 穿越次數增加,因此把它的數字當作下限。Token-2022 代幣會增加轉帳本身處理擴展的成本;請針對你自己的 mint 實測,而不是套用一個固定倍數。
本頁較早的版本給出的估算高出 5–7 倍(CPMM 交換約 150,000 CU,CLMM 約 180,000)。那些數字從未經過實測。 請根據你自己讀到的 computeUnitsConsumed 來編列預算,而不是根據文件中的數字 — 並且請注意,一旦計入 ATA 建立、wSOL 包裝和 compute-budget 指令,完整交易的成本會高於單獨的 Raydium 指令。
始終設定明確的 ComputeBudgetProgram::set_compute_unit_limit:
預設的 200k CU 上限將在組合呼叫完成之前很久就無聲地耗盡。

錯誤傳播

Raydium 的程式返回具有穩定錯誤代碼的 Anchor 錯誤。你的呼叫程式將其視為 Err(ProgramError::Custom(code))。預設情況下冒泡:
或攔截特定代碼:
注意 ERROR_CODE_OFFSET 這一項:#[error_code] 變體從 6000 開始產生,因此與裸列舉判別值比較永遠不會相符。(anchor-lang 和 raydium_cp_swap 中都沒有 is_err 輔助函數——本頁的早期版本用過一個並不存在的函數。) 錯誤代碼到含義的對應根據 IDL 政策是穩定的(sdk-api/anchor-idl);新代碼在末尾附加,現有代碼的含義永遠不會改變。

完整實作範例:限價單託管

流程:
  1. open_order — 使用者將 amount_in 的 input_mint 存入託管 PDA;記錄目標 min_amount_out 和到期時間。
  2. execute_order — 任何人(保管人)使用當前池帳戶呼叫。程式檢查當前報價 ≥ min_amount_out,然後 CPI Raydium 交換並將輸出保留在託管中。
  3. claim — 使用者從託管中提取輸出 mint。
保管人支付交易費(他們在其他地方獲得保管人費 — 未顯示)。order PDA 以 payer 的身分簽署 CPI,因為它擁有託管的輸入 ATA;因此 ExecuteOrder 也需要一個 pool_authority: UncheckedAccount<'info> 欄位,用於 CPMM 自己的金庫 PDA。Raydium 端滑點檢查和託管自己的 delta 檢查都強制執行下限 — 雙重保險。

測試

將 Raydium 程式拉入本地驗證器進行整合測試(來自 Anchor.toml):
也複製池狀態帳戶,以便你的測試可以實際執行交換;anchor test 在啟動時從主網獲取它們。見 sdk-api/rust-cpi。

組合特有的陷阱

重入

Solana 沒有真正的重入 — CPI 不能在同一呼叫中回呼到發起程式。但你仍然可以將自己構建成邏輯重入:CPI 讀取你的狀態,然後你的程式再次讀取它,假設 CPI 沒有改變它。對於 Raydium,CPI 不會觸及你的狀態,所以這不如例如閃電貸上下文那樣令人擔憂。但如果你將 Raydium 與借貸協議組合,請注意。

帳戶可變性漂移

如果你的程式將帳戶作為 mut 傳遞,但 Raydium 期望它唯讀(或反之),執行時以 InvalidAccountData 拒絕呼叫。始終在 IDL 中檢查 Raydium 指令的預期可變性;raydium_cp_swap::cpi::accounts::Swap 會依據 CPMM 自己的 Swap 結構上的 #[account(mut)] 標記,為你設定每個帳戶的可變性 — 產生的欄位全都是普通的 AccountInfo<'info>,因此攜帶這些旗標的是衍生的 ToAccountMetas 實作,而不是欄位型別。

Token-2022 程式欄位

輸入和輸出 mint 可能在不同的代幣程式下 — 一個 SPL Token,一個 Token-2022。CPI 有單獨的 input_token_program 和 output_token_program 欄位是有原因的。始終檢查每個 mint 的 owner 欄位並將正確的程式路由到每個槽中。

版本化交易

執行 2+ 個 Raydium CPI 加上 ATA 建立的組合 tx 很少適合舊版(v0-without-LUT)交易。使用 V0 與地址查詢表;透過 raydium.getRaydiumLutAddresses() 拉取 Raydium 的公開 LUT。

指標

來源: