本頁內容由 AI 自動翻譯,所有內容以英文版本為準。查看英文版 →
PDA(程式衍生位址)與 CPI(跨程式調用)是讓 Raydium 得以運作的兩個基本原語。PDA 讓程式無需私鑰即可「擁有」確定性位址——這就是池權限與金庫的運作方式。CPI 讓一個程式呼叫另一個程式——這就是 Raydium 透過 SPL Token 程式交換代幣,以及整合者將 Raydium 組合到自己流程中的方式。在閱讀 Raydium 原始碼之前,值得理解這兩者。
PDA:無需金鑰的位址
程式衍生位址是一個公鑰,具有以下特性:- 不在 ed25519 曲線上(不存在其私鑰)。
- 由程式 ID 與一組種子確定性衍生。
- 只能由衍生程式透過
invoke_signed簽署。
衍生
PDA 是透過用程式 ID 與種子進行雜湊運算,然後找到一個「碰撞」位元組將結果推離曲線而計算的。第一個產生離曲線位址的碰撞值(通常從 255 開始遞減)就是規範碰撞值。u64 值。Raydium 的慣例是人類可讀的前綴後跟唯一識別符。
Raydium PDA 模式
Raydium 程式中的常見 PDA:
使用者與整合者無需取得任何資料即可計算這些位址——給定公開輸入(池 ID、農場 ID、使用者金鑰),PDA 是確定性的。
規範碰撞值
雖然原則上可能存在多個碰撞值產生離曲線位址,Raydium 的程式總是使用規範碰撞值(透過從 255 遞減找到)。這儲存在 PDA 的帳戶資料中,以便後續交易可以傳入它並跳過(昂貴的)衍生迴圈:PoolState 改為儲存 bump: [u8; 1],所以請檢查特定程式的結構而不是假設一種形狀。)
在後續交易中,碰撞值從池狀態讀取而不是重新計算。
CPI:呼叫其他程式
跨程式調用讓一個程式在單一交易內內聯調用另一個程式的指令。Raydium 廣泛使用 CPI:- 交換指令呼叫 SPL Token 程式移動代幣。
- CLMM 呼叫 Metaplex 鑄造頭寸 NFT。
- 池建立呼叫系統程式分配帳戶。
- Farm v6 呼叫 SPL Token 轉移獎勵。
integration-guides/cpi-integration。
invoke 與 invoke_signed
Solana 執行時提供兩個 CPI 原語:invoke:呼叫另一個程式;被呼叫的程式繼承外部交易的簽署者。invoke_signed:代表 PDA 呼叫另一個程式;執行時驗證 PDA 的種子並授權簽名。
invoke_signed 是讓程式無需管理私鑰即可持有帳戶權限的魔法。
範例:Raydium 從池金庫轉移
池金庫是一個代幣帳戶,其權限是池程式的 PDA。要在交換期間轉移代幣,池程式必須以該 PDA 簽署:invoke_signed,驗證 vault_and_lp_mint_auth_seed + 碰撞值 在用 CPMM 程式 ID 進行雜湊時衍生到 pool_authority 的位址,並允許代幣轉移上的權限簽名。不涉及私鑰。
範例:整合者呼叫 Raydium CPMM
整合者程式(例如,託管)可以透過 CPI 調用 Raydium 的swap_base_input:
integration-guides/cpi-integration 以取得完整託管範例。
CPI 深度限制
Solana 將 CPI 深度上限設為 4 層。交易的頂層指令計為深度 0;每次 CPI 調用遞增深度。 實際含義:Raydium 自己的交換已經使用 1-2 層 CPI(Raydium → SPL Token)。整合者呼叫 Raydium 使用 2 層。如果該整合者被另一個整合者呼叫,則為 3 層。第 4 層是限制。 大多數組合輕鬆保持在此以下,但深層嵌套(聚合器 → 路由器 → Raydium → 鉤子)可能會達到限制。設計應平坦而非深層。剩餘帳戶
當 Raydium 指令需要可變數量的帳戶時(例如,CLMM 交換跨越未知數量的刻度陣列),額外帳戶作為剩餘帳戶傳遞——附加到固定帳戶列表,按位置解釋。 CPMM 的SwapV2 使用剩餘帳戶來處理轉移鉤子程式的額外必需帳戶。客戶端取得所需帳戶並附加它們:
PDA 陷阱
錯誤的種子 → 錯誤的位址
種子順序錯誤、編碼錯誤或包含/排除額外位元組的錯誤會無聲地產生不同的 PDA。交易失敗且含糊不清(程式嘗試讀取不存在的帳戶)。始終針對已知的黃金值對種子衍生進行單元測試。未儲存碰撞值
如果你在每筆交易上重新衍生碰撞值,你需要為衍生迴圈支付計算成本。在 PDA 的資料中儲存規範碰撞值並從那裡讀取它。混淆規範與非規範碰撞值
非規範碰撞值(如果有人找到產生離曲線的碰撞值)由invoke_signed 允許但被 Raydium 的程式透過 assert_eq!(bump, canonical_bump) 拒絕。如果有人試圖以非規範碰撞值聲稱 PDA,交易失敗。
當你不是擁有程式時將 PDA 作為簽署者傳遞
只有 PDA 衍生中的程式 ID 所屬的程式可以使用其種子進行invoke_signed。如果你嘗試,執行時會拒絕。
CPI 陷阱
忘記轉發 remaining_accounts
如果你的外部指令在 remaining_accounts 中傳遞轉移鉤子帳戶,但進入 Raydium 的 CPI 不轉發它們,Raydium 失敗因為它找不到鉤子帳戶。始終在需要它們的 CPI 中包含 with_remaining_accounts。
可寫標誌不匹配
外部指令標記為可寫的帳戶如果被呼叫的程式打算寫入,在 CPI 呼叫中也必須是可寫的。不匹配 → 執行時拒絕。未考慮租金
CPI 到建立帳戶的程式(例如,ATA 建立)要求支付者有足夠的 SOL 用於租金。失敗的租金檢查顯示為模糊的錯誤。實際範例:計算 Raydium CPMM PDA
getPoolInfoFromRpc({ poolId }) 時在幕後所做的——它衍生相關 PDA 而無需往返。
指標
solana-fundamentals/account-model— PDA 如何適應帳戶模型。solana-fundamentals/programs-and-anchor— Anchor 用於宣告 PDA 的輔助工具。integration-guides/cpi-integration— 建立呼叫進入 Raydium 的整合。sdk-api/rust-cpi— Raydium 的 Rust CPI 型別。
- Solana PDA 文件。
- Solana CPI 文件。
- Anchor PDA 文件與 Anchor CPI 文件 — Anchor 沒有組合頁面。

