Solana 上每一項可交易資產(包括 Raydium 所有流動性池的基礎資產和報價資產)都是由兩個程式之一鑄造的代幣:舊版 SPL Token 程式或其後繼版本 Token-2022。它們是位於不同位址的獨立程式,具有不同的帳戶佈局和擴展語意。Raydium 兩者都支援,但不是在所有地方都支援:CPMM、CLMM 和 Farm v6 接受 Token-2022 代幣;AMM v4 則不支援。在與任何流動性池整合之前,理解這種區別至關重要。
兩個程式
| SPL Token | Token-2022 |
|---|
| 程式 ID | TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA | TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb |
| 推出時間 | 2020 | 2022 |
| 帳戶大小(代幣帳戶) | 165 B | 165 B + 擴展(可變) |
| 擴展 | 否 | 是 — 17+ 個官方擴展 |
| 舊版相容性 | 完全 | 按代幣選擇 |
兩者都由 Solana Labs 團隊(現為 Anza)維護,位於 solana-program-library 儲存庫下。
為什麼有兩個程式?
SPL Token 被凍結以實現向前相容性 — 其位元組碼實際上是不可變的,為整個生態系統提供了一個乾淨的基線。隨著用例增多(穩定幣需要轉帳費用、機構代幣需要細緻化的凍結權限、NFT 需要中繼資料指標),Solana 團隊引入了 Token-2022 作為一個獨立的、可擴展的程式,而不是升級 SPL Token。這既保留了現有整合,又讓每個代幣能夠選擇性地使用它需要的擴展。
Token-2022 在功能上是一個嚴格的超集,而不是在位址空間上:兩個程式並存,給定位址上的代幣恰好屬於其中之一。
帳戶結構
代幣帳戶
定義代幣的身份。
SPL Token 代幣帳戶(82 字節):
u32 mint_authority_option
Pubkey mint_authority
u64 supply
u8 decimals
bool is_initialized
u32 freeze_authority_option
Pubkey freeze_authority
Token-2022 代幣帳戶:相同的基礎佈局,加上零個或多個 擴展 TLV(型別-長度-值)記錄附加在基礎之後。
代幣帳戶
持有特定代幣對特定擁有者的餘額。
SPL Token 帳戶(165 字節):
Pubkey mint
Pubkey owner
u64 amount
u32 delegate_option
Pubkey delegate
u8 state // initialized, frozen
u32 is_native_option
u64 is_native
u64 delegated_amount
u32 close_authority_option
Pubkey close_authority
Token-2022 帳戶:相同的基礎,加上如有任何擴展啟用則為擴展 TLV 記錄。
Token-2022 擴展
擴展是可以連接到代幣或帳戶的模組化功能。每個擴展都是一個獨立的 TLV 記錄。對 Raydium 而言重要的擴展有:
轉帳費用
代幣可以對每次轉帳收取百分比費用。費用送到配置的提取權限。Raydium CPMM 和 CLMM 通過 SwapV2 支援此功能 — 程式在計算匯率時會計入費用,所以流動性池的數學保持一致。
let extension = TransferFeeConfig {
transfer_fee_config_authority,
withdraw_withheld_authority,
withheld_amount: 0,
older_transfer_fee: ...,
newer_transfer_fee: ...,
};
轉帳掛鉤
代幣指向一個程式,運行時在每次轉帳時調用它。掛鉤程式可以拒絕轉帳或執行副作用(更新合規狀態、記錄等)。Raydium CPMM/CLMM 通過 SwapV2 調用掛鉤 — 交易包括掛鉤程式和它需要的任何額外帳戶。
鏈上餘額按配置的費率計息。顯示用途(餘額隨時間增加)而非實際鑄造;底層供應量保持不變。
代幣關閉權限
允許在供應量達到零後關閉代幣。
永久委託人
指定的錢包可以無條件地從任何帳戶轉帳或銷毀代幣。Raydium 阻止為具有此擴展的代幣建立流動性池 — 這與流動性池儲備無法被沒收的不變量不相容。
不可轉帳
代幣無法從它們被鑄造到的帳戶移出。Raydium 阻止建立流動性池 — 無法交易的資產不能作為 LP 流動性池的基礎資產或報價資產。
預設帳戶狀態
此代幣的新代幣帳戶預設為凍結,必須由凍結權限解凍。可用但罕見。
機密轉帳
餘額和轉帳金額已加密。Raydium 不支援機密轉帳代幣(流動性池數學需要明文餘額)。
中繼資料指標 + 代幣中繼資料
取代 Token-2022 代幣的 Metaplex 中繼資料。Raydium 流動性池列表支援此功能。
組 / 成員指標
將代幣聲明為屬於一個組(例如 NFT 集合)。資訊性的;Raydium 用此作為顯示。
完整清單見官方 Token-2022 擴展頁面。
Raydium 哪些產品支援什麼
| 產品 | SPL Token | Token-2022 | 備註 |
|---|
| AMM v4 | 是 | 否 | OpenBook 整合需要 SPL Token |
| CPMM | 是 | 是 | Token-2022 流動性池需要 SwapV2 |
| CLMM | 是 | 是 | Token-2022 流動性池需要 SwapV2 |
| Farm v6 | 是 | 是 | 支援質押代幣和獎勵代幣 |
| LaunchLab | 是 | 是 | 已畢業的 CPMM 流動性池繼承 Token-2022 支援 |
Raydium 流動性池的代幣合格性 — 除非列出,所有擴展都允許:
- 被阻止:不可轉帳、永久委託人、機密轉帳、預設帳戶狀態(在被拒絕的配置中)。
- 允許但有注意事項(LP 必須接受風險):轉帳費用、轉帳掛鉤、凍結權限啟用。
- 完全允許:計息、中繼資料指標、組指標、代幣關閉權限。
getPoolInfoFromRpc 回應包括代幣的擴展標誌 — 用戶端應在成為 LP 之前檢查。
代幣帳戶標準
關聯代幣帳戶 (ATA)
兩個程式都共享關聯代幣帳戶慣例:通過關聯代幣程式 (ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL) 由 [owner, programId, mint] 衍生的 PDA。Solana 上幾乎所有使用者代幣帳戶都是 ATA。
import { getAssociatedTokenAddressSync } from "@solana/spl-token";
// SPL Token
const ata = getAssociatedTokenAddressSync(mint, owner);
// Token-2022
const ata22 = getAssociatedTokenAddressSync(
mint,
owner,
false, // allowOwnerOffCurve
TOKEN_2022_PROGRAM_ID,
);
ATA 程式根據擁有代幣的程式建立由相應代幣程式擁有的帳戶。
非 ATA 代幣帳戶
錢包可以為單個代幣擁有多個代幣帳戶;ATA 只是慣例。例如,流動性池金庫不是 ATA — 它們是流動性池程式的 PDA,持有流動性池的儲備。
檢測代幣屬於哪個程式
每個代幣帳戶都有一個 owner 欄位,指向 SPL Token 或 Token-2022:
const mintInfo = await connection.getAccountInfo(mintPubkey);
if (mintInfo.owner.equals(TOKEN_PROGRAM_ID)) {
console.log("SPL Token mint");
} else if (mintInfo.owner.equals(TOKEN_2022_PROGRAM_ID)) {
console.log("Token-2022 mint");
}
Raydium SDK 自動處理此檢測 — getPoolInfoFromRpc 返回每個代幣的相應 programId,以便用戶端可以構造正確的 ATA。
按程式分類的交換指令
Raydium 的 CPMM 和 CLMM 各有兩個交換指令:
| 指令 | 支援的代幣 |
|---|
Swap / SwapBaseInput(舊版) | 僅 SPL Token |
SwapV2 / SwapBaseInputV2 | SPL Token 和 Token-2022 |
SwapV2 接受額外帳戶:兩邊的代幣帳戶、每邊的代幣程式(因為它們可能不同),以及 — 對於轉帳掛鉤代幣 — 掛鉤程式及其必需帳戶。
當至少一邊是 Token-2022 時,用戶端應始終使用 SwapV2;SwapV2 也適用於僅 SPL 的流動性池,但舊版 Swap 計算成本更低。
SDK 會自動選擇正確的變體。
將 SPL Token 專案遷移到 Token-2022
Token-2022 在代幣級別不是即插即用的替換 — 位址 X 上的代幣要麼是 SPL,要麼是 Token-2022,這在建立時就固定了。要「遷移」你必須:
- 在 Token-2022 下建立新代幣,使用你想要的擴展。
- 為舊 SPL 代幣持有者提供交換/包裝機制以交換新代幣。
- 更新所有 LP 流動性池、農場和整合以引用新代幣。
這很繁重。大多數在 SPL 下推出的專案保持在 SPL,除非特定的擴展需求迫使它們轉移。
實作範例:建立帶轉帳費用的 Token-2022 代幣
import {
Connection, Keypair, SystemProgram, Transaction, sendAndConfirmTransaction,
} from "@solana/web3.js";
import {
TOKEN_2022_PROGRAM_ID, ExtensionType, createInitializeMintInstruction,
getMintLen, createInitializeTransferFeeConfigInstruction,
} from "@solana/spl-token";
const connection = new Connection("https://api.mainnet-beta.solana.com");
const payer = Keypair.generate();
const mint = Keypair.generate();
const extensions = [ExtensionType.TransferFeeConfig];
const mintLen = getMintLen(extensions);
const rentLamports = await connection.getMinimumBalanceForRentExemption(mintLen);
const tx = new Transaction().add(
SystemProgram.createAccount({
fromPubkey: payer.publicKey,
newAccountPubkey: mint.publicKey,
space: mintLen,
lamports: rentLamports,
programId: TOKEN_2022_PROGRAM_ID,
}),
createInitializeTransferFeeConfigInstruction(
mint.publicKey,
payer.publicKey, // transfer fee authority
payer.publicKey, // withdraw-withheld authority
50, // 50 bps = 0.5%
BigInt(1_000_000), // max fee per transfer (smallest units)
TOKEN_2022_PROGRAM_ID,
),
createInitializeMintInstruction(
mint.publicKey,
9, // decimals
payer.publicKey, // mint authority
null, // freeze authority
TOKEN_2022_PROGRAM_ID,
),
);
await sendAndConfirmTransaction(connection, tx, [payer, mint]);
此代幣可以進入 Raydium CPMM 流動性池;交換者除了流動性池的交換費外,還要支付 0.5% 的轉帳費。
安全考量
在進入或通過 Token-2022 代幣交換之前:
- 檢查
freeze_authority。如果非空且由中心化方持有,他們可以凍結你的 ATA(也可能凍結流動性池金庫)。
- 檢查
transfer_hook。掛鉤程式可以任意阻止轉帳 — 對掛鉤的來源進行自己的研究。
- 檢查
transfer_fee。將費用計入預期交換輸出。
- 檢查
permanent_delegate 和 non_transferable。Raydium 程式拒絕這些,但在建立自訂整合時驗證。
見security/oracle-and-token-risks了解完整的風險接受框架。
來源: