Chuyển đến nội dung chính

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.

Trang này được dịch tự động bằng AI. Phiên bản tiếng Anh là bản chính thức.Xem bản tiếng Anh →
Mô hình tài khoản của Solana là điều quan trọng nhất cần hiểu trước khi đọc mã của Raydium. Không giống như Ethereum nơi trạng thái sống cùng với mã hợp đồng, các chương trình Solana hoàn toàn không có trạng thái: tất cả trạng thái sống trong các “tài khoản” riêng biệt mà các chương trình hoạt động trên đó. Mỗi pool, vị trí và vault của Raydium đều là một tài khoản — hiểu cách những tài khoản đó hoạt động sẽ làm cho phần còn lại của tài liệu có ý nghĩa hơn.

Sự phân chia cơ bản: chương trình so với tài khoản

Chương trình

Một chương trình trên Solana là mã thực thi — một tệp nhị phân được biên dịch, được triển khai tới một Pubkey, và có thể gọi được thông qua các giao dịch. Chương trình không có trạng thái liên quan; chúng chỉ chứa logic. Các chương trình của Raydium:
  • CPMM: CPMMoo8L3F4NbTegBCKVNunggL7H1Zpdmwpwh8KMoZ0F
  • CLMM: CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK
  • AMM v4: 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8
Mỗi chương trình là một tệp nhị phân cố định. Chương trình không “nhớ” bất cứ điều gì giữa các lần gọi.

Tài khoản

Một tài khoản là một hàng dữ liệu trên chuỗi. Mỗi tài khoản có:
  • pubkey — địa chỉ của nó.
  • owner — chương trình sở hữu nó (kiểm soát ghi).
  • data — các byte thô.
  • lamports — số dư SOL (1 SOL = 1.000.000.000 lamports).
  • rent_epoch — trường thu thập rent cũ (bị bỏ qua kể từ khi rent-exemption trở thành bắt buộc).
Khi bạn truy vấn một pool của Raydium, bạn đang đọc một hoặc nhiều tài khoản. Khi một swap chạy, chương trình CPMM đọc/ghi nhiều tài khoản — trạng thái pool, các vault, trạng thái quan sát, và các tài khoản token của người dùng.

Quyền sở hữu

Mỗi tài khoản được sở hữu bởi chính xác một chương trình. Chỉ mã của chương trình đó mới có thể sửa đổi trường data của tài khoản. Người dùng có thể sửa đổi lamports (gửi/nhận SOL) trên tài khoản mà họ có thể ký, nhưng sửa đổi data yêu cầu chương trình chủ sở hữu phải thực hiện việc này thay mặt họ. Các ví dụ:
  • Ví người dùng của bạn: được sở hữu bởi System Program. Lamports sống ở đây; bạn ký để chuyển.
  • Tài khoản token USDC của bạn: được sở hữu bởi SPL Token Program. Lệnh transfer của token program cập nhật số dư.
  • Tài khoản trạng thái pool của Raydium: được sở hữu bởi chương trình CPMM. Chỉ các lệnh của CPMM mới có thể sửa đổi dự trữ, phí, v.v.
  • PersonalPositionState của NFT vị trí của Raydium: được sở hữu bởi chương trình CLMM.
“Được sở hữu bởi” là nghiêm ngặt: nếu chương trình A ghi vào một tài khoản được sở hữu bởi chương trình B, thời gian chạy Solana sẽ từ chối giao dịch.

Rent và rent-exemption

Tạo một tài khoản tiêu tốn không gian lưu trữ. Solana tính phí rent cho không gian đó, nhưng kể từ năm 2020 tất cả các tài khoản mới phải là rent-exempt — nghĩa là chúng giữ đủ lamports để rent mà họ sẽ nợ trong 2 năm được thanh toán trước. Trong thực tế:
  • Tài khoản rent-exempt sống mãi mãi.
  • Đóng tài khoản sẽ hoàn lại lamports cho người ký đóng.
Đối với tài khoản 165 byte (ví dụ: tài khoản SPL Token), rent-exemption là khoảng 0,00204 SOL. Đối với trạng thái pool CPMM của Raydium 1.440 byte, nó là khoảng 0,011 SOL.

Chi phí rent của Raydium

Tài khoảnKích thướcRent
CPMM PoolState~1.440 B~0,011 SOL
CLMM PoolState~1.500 B~0,012 SOL
CLMM TickArray~9.000 B~0,063 SOL
CLMM PersonalPositionState~280 B~0,003 SOL
ATA165 B~0,002 SOL
Vault (Token Account)165 B~0,002 SOL
Tạo pool yêu cầu rent cho nhiều tài khoản cùng một lúc — đó là lý do tại sao tạo pool CPMM có chi phí tổng cộng ~0,15 SOL.

Tài khoản dữ liệu so với tài khoản có thể thực thi

Tài khoản có hai loại:

Tài khoản dữ liệu

Lưu trữ trạng thái (dự trữ pool, số dư token, vị trí người dùng). executable = false. Đây là phần lớn.

Tài khoản có thể thực thi

Lưu trữ bytecode chương trình. executable = true. Đây là các chương trình (CPMM, CLMM, v.v.). Chương trình không có dữ liệu ngoài bytecode của chúng.

Tài khoản dẫn xuất từ chương trình (PDA)

PDA là một tài khoản dữ liệu có địa chỉ được dẫn xuất một cách xác định từ một chương trình và một số seed — không có khóa riêng tư nào tồn tại cho địa chỉ này. Chỉ chương trình dẫn xuất mới có thể ký thay mặt PDA thông qua invoke_signed. Raydium sử dụng PDA rộng rãi:
  • PDA trạng thái pool: được dẫn xuất từ [poolTypeDiscriminator, mintA, mintB, ammConfig].
  • PDA vault: được dẫn xuất từ [pool, mint].
  • PDA trạng thái quan sát: được dẫn xuất từ [observationSeed, pool].
PDA cho phép Raydium tạo tài khoản ở các địa chỉ có thể dự đoán được mà không cần quản lý khóa. Bất kỳ ai cũng có thể tính toán địa chỉ PDA cho một pool đã biết với các seed. Xem solana-fundamentals/pdas-and-cpis.

Giao dịch và tham chiếu tài khoản

Mỗi giao dịch Solana mang theo một danh sách rõ ràng các tài khoản mà nó sẽ đọc/ghi. Thời gian chạy thực thi:
  • Các tài khoản được liệt kê có thể được đọc hoặc ghi (theo cờ is_writable của chúng).
  • Các tài khoản chưa được liệt kê không thể bị chạm vào.
Đối với swap của Raydium, danh sách tài khoản của giao dịch bao gồm:
[readonly] CPMM program
[writable] pool state
[readonly] amm config
[readonly] pool authority (PDA)
[writable] input vault
[writable] output vault
[writable] user input ATA
[writable] user output ATA
[readonly] input mint
[readonly] output mint
[readonly] input token program
[readonly] output token program
[writable] observation state
[signer,writable] user
Liệt kê rõ ràng này là lý do tại sao các giao dịch Solana nhanh và có thể song song — thời gian chạy có thể xác định các tx không xung đột trước.

Kích thước tài khoản và bố cục dữ liệu

Mỗi tài khoản của Raydium có kích thước cố định hoặc có giới hạn. Bố cục được định nghĩa trong mã (các struct Rust với #[repr(C)]) và được ghi chép trong sdk-api/anchor-idl. Các chương trình Anchor thêm một discriminator 8 byte vào mỗi tài khoản họ tạo, được dẫn xuất từ hash("account:<StructName>")[0..8]. Điều này cho phép các máy khách xác định loại tài khoản chỉ bằng cách đọc 8 byte đầu tiên — điều quan trọng đối với các quét getProgramAccounts liệt kê tất cả các tài khoản của một loại.

Đọc trạng thái pool của Raydium

Thông qua SDK:
const pool = await raydium.cpmm.getPoolInfoFromRpc({ poolId });
console.log(pool.poolInfo);
Thông qua RPC thô + bố cục:
const accountInfo = await connection.getAccountInfo(poolId);
const data = accountInfo.data;
// Bỏ qua 8 byte đầu tiên (discriminator), sau đó phân tích cú pháp theo bố cục struct.
const poolState = CpmmPoolStateLayout.decode(data.slice(8));
Bố cục nằm trong src/raydium/cpmm/layout.ts trong mã nguồn SDK.

Ví dụ thực hành: đọc tài khoản token

Hãy đọc số dư USDC của người dùng.
import { Connection, PublicKey } from "@solana/web3.js";
import { getAssociatedTokenAddressSync, AccountLayout } from "@solana/spl-token";

const connection = new Connection("https://api.mainnet-beta.solana.com");
const user       = new PublicKey("YourUserWallet...");
const usdcMint   = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");

// 1. Tính toán địa chỉ ATA (dẫn xuất kiểu PDA).
const ata = getAssociatedTokenAddressSync(usdcMint, user);

// 2. Đọc tài khoản.
const accountInfo = await connection.getAccountInfo(ata);
if (!accountInfo) {
  console.log("ATA chưa tồn tại (người dùng chưa bao giờ giữ USDC).");
  return;
}

// 3. Xác minh chủ sở hữu là SPL Token program.
console.assert(accountInfo.owner.toBase58() === "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");

// 4. Giải mã dữ liệu.
const parsed = AccountLayout.decode(accountInfo.data);
console.log("Số dư (đơn vị nhỏ nhất):", parsed.amount.toString());
console.log("Mint:",                     new PublicKey(parsed.mint).toBase58());
console.log("Chủ sở hữu:",                    new PublicKey(parsed.owner).toBase58());
Mô hình này — dẫn xuất địa chỉ, tìm nạp tài khoản, xác minh chủ sở hữu, giải mã — áp dụng cho mọi đọc trên chuỗi, bao gồm các pool của Raydium.

Tại sao điều này quan trọng đối với Raydium

Mô hình tài khoản hình thành thiết kế của Raydium:
  • Trạng thái pool là một tài khoản duy nhất — mọi thứ về một pool (mint, dự trữ, phí, admin) sống trong một tài khoản được sở hữu bởi chương trình pool.
  • Token LP là tài khoản token SPL tiêu chuẩn — Raydium ủy quyền tokenization cho SPL Token program.
  • Các mảng tick được chia thành các khúc — CLMM không thể có một mảng tick duy nhất có thể phát triển vì các tài khoản có kích thước được cấp phát cố định; thay vào đó, nó sử dụng các PDA TickArray được chia thành các khúc.
  • Position NFT là Metaplex NFT — các vị trí CLMM là NFT tiêu chuẩn theo Metaplex; trạng thái vị trí là một PDA riêng biệt.
Hiểu điều này cho phép bạn trả lời các câu hỏi “X sống ở đâu?” một cách chính xác:
  • “Dự trữ pool ở đâu?” → hai tài khoản vault (tài khoản token) được sở hữu bởi SPL Token program, với quyền hạn được ủy quyền cho một PDA của chương trình pool.
  • “Dữ liệu tick cho CLMM ở đâu?” → một loạt các PDA TickArray, mỗi cái bao gồm 60 tick liên tiếp.
  • “Cổ phần nông trại của tôi ở đâu?” → một PDA UserLedger được dẫn xuất từ [user, farmId], được sở hữu bởi chương trình nông trại.

Con trỏ

Nguồn: