> ## 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.

# 程式和 Anchor

> Solana 程式如何部署和升級、Anchor 框架在原始 Solana 之上新增的功能，以及如何閱讀 Raydium 的 IDL 來生成您自己的客戶端。

<Info>
  **本頁內容由 AI 自動翻譯，所有內容以英文版本為準。**

  [查看英文版 →](/solana-fundamentals/programs-and-anchor)
</Info>

<Info>
  Raydium 的較新程式（CPMM、CLMM、Farm v6、LaunchLab）採用 **Anchor** 編寫——一個建立在 Solana 原生程式模型之上的 Rust 框架，提供帳戶驗證、錯誤處理和 IDL（介面描述）。AMM v4 和較舊的農場出現在 Anchor 之前。了解兩種範例都將幫助您閱讀程式碼、從 IDL 生成客戶端，以及調試非預期的錯誤。
</Info>

## 程式部署模型

每個 Solana 程式都在一個 `Pubkey` 上。程式的位元組碼存儲在由 **BPF 可升級加載器**（`BPFLoaderUpgradeab1e11111111111111111111111`）擁有的**可執行**帳戶中。

程式部署包含三個帳戶：

1. **程式帳戶**：程式 ID 處的小型中繼資料帳戶。擁有者：BPF 可升級加載器。
2. **程式資料帳戶**：保存實際的位元組碼。衍生為 `[program_id, "programdata"]`。
3. **緩衝區帳戶**（暫時的）：在升級期間保存新位元組碼。升級後將被丟棄。

程式資料帳戶具有**升級授權**——一個可以用新版本替換位元組碼的密鑰。Raydium 的升級授權是受 24 小時時間鎖保護的多簽；詳見 [`security/admin-and-multisig`](/zh-Hant/security/admin-and-multisig)。

### 驗證已部署的程式

確認鏈上的內容與經審計批准的源代碼相符：

```bash theme={null}
# Dump the program from mainnet
solana program dump CPMMoo8L3F4NbTegBCKVNunggL7H1Zpdmwpwh8KMoZ0F cpmm-onchain.so

# Build from known source
cargo build-bpf --manifest-path raydium-cp-swap/programs/cp-amm/Cargo.toml
cp target/deploy/raydium_cp_swap.so cpmm-source.so

# Compare
sha256sum cpmm-onchain.so cpmm-source.so
```

匹配的雜湊值證明您正在與您認為的源進行互動。Raydium 在發布說明中發佈經過驗證的構建指令。

## Anchor：構建在 Solana 之上的框架

原始 Solana 程式是具有此簽名的 Rust 函數：

```rust theme={null}
pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    instruction_data: &[u8],
) -> ProgramResult {
    // Manually parse instruction_data
    // Manually validate accounts
    // Manually deserialize account data
    // Manually check signer/writable flags
    // ... then do the actual work
}
```

Anchor 包裝所有樣板代碼並允許您編寫：

```rust theme={null}
#[program]
pub mod cpmm {
    use super::*;

    pub fn swap_base_input(
        ctx: Context<Swap>,
        amount_in: u64,
        min_out: u64,
    ) -> Result<()> {
        // Just the business logic — ctx is pre-validated
    }
}

#[derive(Accounts)]
pub struct Swap<'info> {
    pub payer: Signer<'info>,
    #[account(mut, seeds = [b"pool", config.key().as_ref(), ...], bump)]
    pub pool_state: AccountLoader<'info, PoolState>,
    #[account(mut)]
    pub input_vault: Box<Account<'info, TokenAccount>>,
    // ... more accounts
}
```

Anchor：

* 為每個指令和每個帳戶類型自動生成確定性的 8 位元組**識別符**。
* 在您的程式碼運行前驗證帳戶約束（擁有者、種子、可寫性、簽名者、mint 匹配、token 程式匹配）。
* 生成 **IDL**——客戶端用來調用程式的介面描述檔案。
* 隨附 Rust、TypeScript 和 Python 客戶端函式庫。

### 8 位元組識別符

每個 Anchor 帳戶和每個 Anchor 指令都以 8 位元組識別符開始——固定字符串的 SHA-256 的前 8 位元組：

```
Account discriminator:     sha256("account:PoolState")[0..8]
Instruction discriminator: sha256("global:swap_base_input")[0..8]
```

調用 Anchor 指令時，指令資料的前 8 位元組是此識別符；Anchor 通過查找來分派到正確的處理程序。

閱讀 Anchor 帳戶時，前 8 位元組會告訴您其類型——對於像 `getProgramAccounts` 這樣列舉某種類型所有帳戶的工具至關重要。

### 錯誤

Anchor 程式通過 `#[error_code]` 定義錯誤：

```rust theme={null}
#[error_code]
pub enum ErrorCode {
    #[msg("Slippage tolerance exceeded")]
    SlippageExceeded,
    #[msg("Pool is disabled")]
    PoolDisabled,
    // ...
}
```

Anchor 從 6000 (0x1770) 開始自動分配這些數字代碼。Raydium 的完整錯誤代碼表位於 [`reference/error-codes`](/zh-Hant/reference/error-codes)。

## IDL

Anchor **IDL**（介面描述語言）檔案是程式的 JSON 描述：其指令、帳戶、類型、錯誤和事件。它相當於以太坊的 ABI。

Raydium 為所有 Anchor 程式發佈 IDL。從鏈上即時獲取：

```bash theme={null}
anchor idl fetch CPMMoo8L3F4NbTegBCKVNunggL7H1Zpdmwpwh8KMoZ0F -o cpmm.idl.json
```

或從 SDK 源：`src/raydium/*/idl/*.json`。

### IDL 結構

```json theme={null}
{
  "version":      "0.1.0",
  "name":         "raydium_cp_swap",
  "instructions": [ { "name": "swap_base_input", "accounts": [ ... ], "args": [ ... ] }, ... ],
  "accounts":     [ { "name": "PoolState", "type": { ... } }, ... ],
  "types":        [ { "name": "AmmConfig", "type": { ... } }, ... ],
  "errors":       [ { "code": 6000, "name": "SlippageExceeded", "msg": "..." }, ... ],
  "events":       [ { "name": "SwapEvent", "fields": [ ... ] }, ... ]
}
```

### 從 IDL 生成客戶端

Anchor 的 `anchor` CLI 生成 TypeScript 和 Rust 類型：

```bash theme={null}
anchor idl build -o target/idl/cpmm.json
# TypeScript types auto-generated by Anchor's ts-client
# Raydium SDK already includes these
```

第三方工具如 [Kinobi](https://github.com/metaplex-foundation/kinobi) 可以從 IDL 生成 Rust、Python、C 或 Go 客戶端。

### 何時 IDL 是您的好幫手

如果您想構建不通過 Raydium SDK 的自訂整合：

1. 獲取 IDL（從鏈上即時或從 SDK 源）。
2. 查找您想要的指令（例如 `swap_base_input`）。
3. 構造指令資料：8 位元組識別符 + 編碼的參數。
4. 按 IDL 指定的順序傳遞帳戶。

見 [`sdk-api/anchor-idl`](/zh-Hant/sdk-api/anchor-idl) 以獲得實際操作的例子。

## Anchor 前的程式：AMM v4 和 Farm v3/v5

這些程式出現在 Anchor 之前。它們使用：

* **手動指令分派**：`instruction_data` 中帶有 `match` 語句的 `u8` 標籤。
* **手動帳戶驗證**：`if accounts[0].owner != &expected_program { ... }`。
* **Borsh 序列化的指令參數**：無識別符，只有 `instruction_data[1..]`。
* **通過 `#[repr(C, packed)]` 的佈局**：C 結構體二進位佈局。

Raydium SDK v2 為非 Anchor AMM v4 指令提供 TypeScript 佈局，以便客戶端可以無需 Anchor 進行編碼/解碼：

```ts theme={null}
import { liquidityStateV4Layout, swapInstructionData }
  from "@raydium-io/raydium-sdk-v2";

const data = swapInstructionData.encode({
  instruction: 9,   // swap
  amountIn:    1_000_000n,
  minAmountOut: 950_000n,
});
```

整合模式是相同的——您只是沒有獲得 Anchor 的 IDL 驅動的自動生成。

## 程式升級機制

只有程式資料的 `upgrade_authority` 可以升級。步驟：

1. 編譯新位元組碼。
2. 將其寫入緩衝區帳戶（`solana program write-buffer`）。
3. 提交升級指令：`BpfLoaderUpgradeable::Upgrade { buffer, program, authority }`。
4. 運行時原子性地用緩衝區的內容替換程式的位元組碼。

Raydium 在 Squads 多簽設置中實現的 **24 小時時間鎖**後面設置了此功能。升級交易在多簽批准後必須等待 24 小時才能執行。這保護了免受匆忙的 / 被脅迫的升級。

見 [`security/admin-and-multisig`](/zh-Hant/security/admin-and-multisig)。

### 使程式不可變

升級授權可以設置為 `None`，此時程式變為永久不可變。Raydium 尚未對任何產品執行此操作——團隊保留了推送安全修復的能力。折衷：用戶必須信任多簽 + 時間鎖進程。

## 程式和租金

部署程式會消耗免租 lamports：

* 50 KB 程式：約 0.35 SOL 租金。
* 200 KB 程式：約 1.4 SOL 租金。

關閉程式（通過 `solana program close`）會返回 lamports。Raydium 程式保持活躍，未計畫關閉。

## 調試 Anchor 程式

### 日誌輸出

Anchor 的 `msg!` 宏寫入交易的日誌。模擬交易以查看日誌：

```ts theme={null}
const sim = await connection.simulateTransaction(tx);
console.log(sim.value.logs);
```

日誌包括：

* 程式調用（`Program CPMMoo8... invoke [1]`）。
* 程式碼中的 `msg!` 調用。
* 計算單位消耗（`consumed 137842 of 400000 compute units`）。
* 程式成功或錯誤。

### 錯誤代碼

如果 Anchor 程式拋出，日誌顯示：

```
Program CPMMoo8... failed: custom program error: 0x1770
```

0x1770 = 6000 十進制 = 第一個 Anchor 錯誤（例如 `SlippageExceeded`）。與 IDL 的 `errors` 陣列交叉參考。

見 [`reference/error-codes`](/zh-Hant/reference/error-codes) 以了解 Raydium 的完整錯誤表。

### 帳戶佈局不匹配

如果您在錯誤的位置傳遞了錯誤的帳戶，Anchor 的帳戶驗證宏返回錯誤，如：

```
AnchorError: AccountNotInitialized. Error Number: 3012
```

低於 6000 的錯誤號是 Anchor 的內建錯誤（見 Anchor 的 `ErrorCode` 列舉）；≥6000 的錯誤是程式的自訂代碼。

## 指針

* [`solana-fundamentals/account-model`](/zh-Hant/solana-fundamentals/account-model) ——程式如何擁有帳戶。
* [`solana-fundamentals/pdas-and-cpis`](/zh-Hant/solana-fundamentals/pdas-and-cpis) ——Anchor 聲明的 PDA。
* [`sdk-api/anchor-idl`](/zh-Hant/sdk-api/anchor-idl) ——獲取和使用 Raydium 的 IDL。
* [`reference/program-addresses`](/zh-Hant/reference/program-addresses) ——程式 ID。
* [`reference/error-codes`](/zh-Hant/reference/error-codes) ——錯誤代碼參考。
* [`security/admin-and-multisig`](/zh-Hant/security/admin-and-multisig) ——升級授權控制。

來源：

* [Anchor 手冊](https://book.anchor-lang.com)。
* [Solana 程式部署](https://docs.solana.com/cli/deploy-a-program)。
* Raydium IDL（發佈在 SDK `src/raydium/*/idl/*.json` 中）。
