Documentation Index
Fetch the complete documentation index at: https://docs.raydium.io/llms.txt
Use this file to discover all available pages before exploring further.
本頁內容由 AI 自動翻譯,所有內容以英文版本為準。查看英文版 →
PDAs(程式衍生位址)和 CPIs(跨程式調用)是構成 Raydium 基礎的兩個基元。PDA 讓程式能「擁有」確定性位址,而不需要私鑰 — 這就是池授權人和金庫的運作方式。CPI 允許一個程式呼叫另一個程式 — Raydium 透過 SPL Token 程式交換代幣,整合者也透過 CPI 將 Raydium 整合到自己的流程中。在閱讀 Raydium 原始碼前,理解這兩個概念非常重要。
PDAs:無金鑰的位址
程式衍生位址(Program-Derived Address)是一個公鑰,具有以下特點:- 不在 ed25519 曲線上(不存在其對應的私鑰)。
- 由程式 ID 和一組 seeds 確定性衍生而來。
- 只能由衍生程式透過
invoke_signed來簽署。
衍生方式
PDA 透過將程式 ID 與 seeds 進行雜湊運算,然後找到一個「bump」位元組使結果離開曲線而計算得出。第一個產生離線曲線位址的 bump(通常從 255 開始遞減)就是正規 bump。u64 值。Raydium 的慣例是使用易讀的前綴後跟唯一識別符。
Raydium PDA 模式
Raydium 程式中常見的 PDAs:| PDA | Seeds | 程式 |
|---|---|---|
| AMM 授權人(AMM v4) | [b"amm authority"] + bump | AMM v4 |
| 池狀態(CPMM) | [b"pool", amm_config, mint_a, mint_b] | CPMM |
| 池金庫(CPMM) | [b"pool_vault", pool, mint] | CPMM |
| 授權人(CPMM) | [b"vault_and_lp_mint_auth_seed"] | CPMM |
| 池狀態(CLMM) | [b"pool", amm_config, mint_0, mint_1] | CLMM |
| Tick 陣列(CLMM) | [b"tick_array", pool, start_tick_index] | CLMM |
| 觀察(CLMM) | [b"observation", pool] | CLMM |
| 個人頭寸(CLMM) | [b"position", position_nft_mint] | CLMM |
| 農場狀態(Farm v6) | [b"pool_farm_state", farm_id] | Farm v6 |
| 使用者帳冊(Farm v6) | [b"user_ledger", farm, user] | Farm v6 |
正規 bump
雖然原則上可能有多個 bump 產生離線曲線位址,但 Raydium 的程式總是使用正規 bump(透過從 255 開始遞減找到)。這個值儲存在 PDA 的帳戶資料中,以便後續交易可以傳遞它,並跳過昂貴的衍生迴圈:CPIs:呼叫其他程式
跨程式調用允許程式在單一交易中內聯調用另一個程式的指令。Raydium 大量使用 CPIs:- 交換指令呼叫 SPL Token 程式移動代幣。
- CLMM 呼叫 Metaplex 鑄造頭寸 NFT。
- 池建立呼叫 System Program 分配帳戶。
- Farm v6 呼叫 SPL Token 轉移獎勵。
integration-guides/cpi-integration。
invoke 與 invoke_signed
Solana 執行時提供了兩個 CPI 基元:invoke:呼叫另一個程式;被呼叫程式繼承外層交易的簽署者。invoke_signed:代表 PDA 呼叫另一個程式;執行時驗證 PDA 的 seeds 並授權簽署。
invoke_signed 是讓程式掌握帳戶授權而無需管理私鑰的魔法。
示例:Raydium 從池金庫轉移
池金庫是一個代幣帳戶,其授權人是池程式的 PDA。為了在交換期間轉移代幣,池程式必須以該 PDA 的身份簽署:invoke_signed,驗證了 vault_and_lp_mint_auth_seed + bump 使用 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 交換跨越未知數量的 tick 陣列),額外帳戶被傳遞為剩餘帳戶 — 附加到固定帳戶列表,按位置解釋。 CPMM 的SwapV2 使用剩餘帳戶來處理轉移鉤子程式的額外必需帳戶。客戶端獲取所需帳戶並附加它們:
PDA 陷阱
錯誤的 seeds → 錯誤的位址
Seeds 順序錯誤、編碼錯誤或包含/排除額外位元組的錯誤會無聲地產生不同的 PDA。交易會模糊地失敗(程式試圖讀取不存在的帳戶)。始終針對已知的黃金值單元測試 seed 衍生。未儲存 bump
如果你在每筆交易上重新衍生 bump,你將為衍生迴圈支付計算成本。將正規 bump 儲存在 PDA 的資料中並從那裡讀取它。混淆正規 vs 非正規 bump
非正規 bumps(如果有人找到產生離線曲線的)被invoke_signed 允許但被 Raydium 程式透過 assert_eq!(bump, canonical_bump) 拒絕。如果有人試圖以非正規 bump 聲稱一個 PDA,交易會失敗。
在你不是擁有程式時將 PDA 作為簽署者傳遞
只有 PDA 衍生中程式 ID 的程式才能以其 seeds 使用invoke_signed。如果你嘗試,執行時會拒絕。
CPI 陷阱
忘記轉發 remaining_accounts
如果你的外層指令在 remaining_accounts 中傳遞轉移鉤子帳戶,但 CPI 到 Raydium 沒有轉發它們,Raydium 會失敗,因為它找不到鉤子帳戶。始終在需要它們的 CPIs 中包含 with_remaining_accounts。
可寫標誌不匹配
外層指令標記為可寫的帳戶,如果被呼叫程式打算寫入,在 CPI 呼叫中也必須是可寫的。不匹配 → 執行時拒絕。未計入租金
CPI 到建立帳戶的程式(例如,ATA 建立)需要支付者有足夠的 SOL 用於租金。失敗的租金檢查會顯示為模糊的錯誤。實際示例:計算 Raydium CPMM PDAs
getPoolInfoFromRpc({ poolId }) 時在幕後所做的 — 它衍生關聯的 PDAs,不需要往返。
參考資源
solana-fundamentals/account-model— PDA 如何適應帳戶模型。solana-fundamentals/programs-and-anchor— Anchor 宣告 PDAs 的輔助工具。integration-guides/cpi-integration— 構建呼叫 Raydium 的 CPIs 的整合。sdk-api/rust-cpi— Raydium 的 Rust CPI 類型。


