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 →
Thông báo phiên bản. Tất cả bản demo nhắm mục tiêu @raydium-io/raydium-sdk-v2@0.2.42-alpha trên Solana mainnet-beta, được xác minh vào tháng 04 năm 2026. ID chương trình: 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 (xem reference/program-addresses).
Tạo pool mới không được hiển thị ở đây. Giao diện Raydium không còn cung cấp khả năng tạo pool AMM v4 — các cặp mới mặc định sử dụng CPMM. Chương trình AMM v4 vẫn chấp nhận Initialize2 trên chuỗi; nó chỉ không phải là con đường được khuyến cáo. Các bản demo dưới đây bao gồm các hoạt động pool trực tiếp mà mọi người tích hợp vẫn cần: swap, deposit, withdraw.

Thiết lập

import { Connection, Keypair, clusterApiUrl } from "@solana/web3.js";
import { Raydium, TxVersion } from "@raydium-io/raydium-sdk-v2";
import fs from "node:fs";

const connection = new Connection(process.env.RPC_URL ?? clusterApiUrl("mainnet-beta"));
const owner = Keypair.fromSecretKey(
  new Uint8Array(JSON.parse(fs.readFileSync(process.env.KEYPAIR!, "utf8"))),
);
const raydium = await Raydium.load({ owner, connection, cluster: "mainnet" });

Lấy pool theo id

import { PublicKey } from "@solana/web3.js";

const poolId = new PublicKey("<AMM_V4_POOL_ID>");

// Lấy đối tượng pool được chuẩn hóa SDK. Đối với AMM v4, điều này bao gồm các tài khoản OpenBook
// mà các trình tạo hướng dẫn sẽ cần.
const data = await raydium.liquidity.getPoolInfoFromRpc({ poolId });
const { poolInfo, poolKeys, poolRpcData } = data;

console.log("Pair:", poolInfo.mintA.symbol, "/", poolInfo.mintB.symbol);
console.log("Version:", poolInfo.version);       // 4 for AMM v4
console.log("Market:", poolKeys.marketId.toBase58());
poolKeys là struct mà các trình tạo hướng dẫn sử dụng. Nó chứa mọi tài khoản AMM v4 và OpenBook theo thứ tự mà chương trình mong đợi.

Swap (base-in)

import BN from "bn.js";

const amountIn = new BN(1_000_000);            // 1 USDC (6-decimal quote)
const inputMint = new PublicKey(poolInfo.mintB.address);  // USDC
const slippage  = 0.005;

const computed = raydium.liquidity.computeAmountOut({
  poolInfo,
  amountIn,
  mintIn: inputMint,
  mintOut: new PublicKey(poolInfo.mintA.address),
  slippage,
});

const { execute } = await raydium.liquidity.swap({
  poolInfo,
  poolKeys,
  amountIn,
  amountOut: computed.minAmountOut,
  fixedSide: "in",
  inputMint,
  txVersion: TxVersion.V0,
});

const { txId } = await execute({ sendAndConfirm: true });
console.log("Swap tx:", txId);
SDK tự động thêm mọi tài khoản OpenBook. Đừng cố gắng thay thế chúng bằng tay — chương trình xác thực mọi slot.

Swap (base-out)

const amountOut = new BN(1_000_000_000);       // 1 SOL (9-decimal base)
const slippage  = 0.005;

const computed = raydium.liquidity.computeAmountIn({
  poolInfo,
  amountOut,
  mintOut: new PublicKey(poolInfo.mintA.address),
  mintIn: new PublicKey(poolInfo.mintB.address),
  slippage,
});

const { execute } = await raydium.liquidity.swap({
  poolInfo,
  poolKeys,
  amountIn: computed.maxAmountIn,
  amountOut,
  fixedSide: "out",
  inputMint: new PublicKey(poolInfo.mintB.address),
  txVersion: TxVersion.V0,
});

await execute({ sendAndConfirm: true });

Thêm thanh khoản

const amountA = new BN(100_000_000);           // 0.1 SOL

const { anotherAmount, maxAnotherAmount } = raydium.liquidity.computePairAmount({
  poolInfo,
  amount: amountA,
  baseIn: true,
  slippage: 0.01,
});

const { execute } = await raydium.liquidity.addLiquidity({
  poolInfo,
  poolKeys,
  amountInA: amountA,
  amountInB: maxAnotherAmount,
  fixedSide: "a",
  txVersion: TxVersion.V0,
});

await execute({ sendAndConfirm: true });
fixedSide: "a" cho SDK biết rằng bạn cung cấp amountInA chính xác và amountInB không nên vượt quá maxAnotherAmount. Thanh khoản trên sách của pool được giải quyết trước khi thực hiện toán học pro-rata, do đó tỷ lệ gửi tiền phù hợp với dự trữ mới nhất.

Xóa thanh khoản

const lpAmount = new BN(50_000);               // LP to burn

const { execute } = await raydium.liquidity.removeLiquidity({
  poolInfo,
  poolKeys,
  lpAmount,
  baseAmountMin: new BN(0),
  quoteAmountMin: new BN(0),
  txVersion: TxVersion.V0,
});

await execute({ sendAndConfirm: true });
Yêu cầu tối thiểu slippage bảo vệ chống lại trạng thái pool thay đổi giữa lần báo giá trước của bạn và thời gian đặt.

Điều chỉnh compute-unit / priority fee

Swap AMM v4 nặng về compute vì mọi hướng dẫn xác thực trạng thái OpenBook đầy đủ. Một swap điển hình sử dụng 180k–250k CU tùy thuộc vào có bao nhiêu lệnh mở cần giải quyết trên đường đi qua. Luôn chuyển giới hạn compute-unit:
import { ComputeBudgetProgram } from "@solana/web3.js";

const { execute, innerTransactions } = await raydium.liquidity.swap({
  /* ...params... */
  computeBudgetConfig: {
    units: 400_000,
    microLamports: 50_000,       // priority fee
  },
});
Nếu bạn bỏ qua computeBudgetConfig, SDK có thể vẫn sử dụng mặc định của nó; kiểm tra innerTransactions để xác nhận. Xem integration-guides/priority-fee-tuning.

CPI Rust trực tiếp

Nếu bạn phải CPI vào AMM v4 từ chương trình Anchor của riêng bạn, bạn sẽ cần để mô hình danh sách tài khoản của SwapBaseIn chính xác. Một phác thảo tối thiểu:
use anchor_lang::prelude::*;
use anchor_lang::solana_program::program::invoke_signed;
use anchor_lang::solana_program::instruction::Instruction;

const AMM_V4_PROGRAM_ID: Pubkey = pubkey!("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8");

#[derive(Accounts)]
pub struct ProxyAmmV4Swap<'info> {
    /// CHECK:
    pub token_program: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub amm:          UncheckedAccount<'info>,
    /// CHECK:
    pub amm_authority: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub amm_open_orders: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub amm_target_orders: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub pool_coin_token_account: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub pool_pc_token_account: UncheckedAccount<'info>,
    /// CHECK:
    pub market_program: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market_bids: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market_asks: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market_event_queue: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market_coin_vault: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market_pc_vault: UncheckedAccount<'info>,
    /// CHECK:
    pub market_vault_signer: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub user_source: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub user_dest: UncheckedAccount<'info>,
    pub user_owner: Signer<'info>,
}

pub fn proxy_swap(
    ctx: Context<ProxyAmmV4Swap>,
    amount_in: u64,
    minimum_amount_out: u64,
) -> Result<()> {
    // Instruction discriminator for SwapBaseIn is 9 on AMM v4.
    let mut data = vec![9u8];
    data.extend_from_slice(&amount_in.to_le_bytes());
    data.extend_from_slice(&minimum_amount_out.to_le_bytes());

    let ix = Instruction {
        program_id: AMM_V4_PROGRAM_ID,
        accounts: vec![
            AccountMeta::new_readonly(ctx.accounts.token_program.key(), false),
            AccountMeta::new(ctx.accounts.amm.key(), false),
            AccountMeta::new_readonly(ctx.accounts.amm_authority.key(), false),
            AccountMeta::new(ctx.accounts.amm_open_orders.key(), false),
            AccountMeta::new(ctx.accounts.amm_target_orders.key(), false),
            AccountMeta::new(ctx.accounts.pool_coin_token_account.key(), false),
            AccountMeta::new(ctx.accounts.pool_pc_token_account.key(), false),
            AccountMeta::new_readonly(ctx.accounts.market_program.key(), false),
            AccountMeta::new(ctx.accounts.market.key(), false),
            AccountMeta::new(ctx.accounts.market_bids.key(), false),
            AccountMeta::new(ctx.accounts.market_asks.key(), false),
            AccountMeta::new(ctx.accounts.market_event_queue.key(), false),
            AccountMeta::new(ctx.accounts.market_coin_vault.key(), false),
            AccountMeta::new(ctx.accounts.market_pc_vault.key(), false),
            AccountMeta::new_readonly(ctx.accounts.market_vault_signer.key(), false),
            AccountMeta::new(ctx.accounts.user_source.key(), false),
            AccountMeta::new(ctx.accounts.user_dest.key(), false),
            AccountMeta::new_readonly(ctx.accounts.user_owner.key(), true),
        ],
        data,
    };
    invoke_signed(&ix, &ctx.accounts.to_account_infos(), &[])?;
    Ok(())
}
AMM v4 không cung cấp crate Anchor cho CPI. Phác thảo trên sử dụng một Instruction được xây dựng thủ công.

Những cạm bẫy

  • Thiếu tài khoản OpenBook. Cả 8 tài khoản phía OpenBook đều bắt buộc trên mọi swap, deposit và withdraw; SDK xử lý điều này, các hướng dẫn xây dựng tay thường không.
  • Đọc số dư kho lưu trữ thô. Không phản ánh các số tiền được ký quỹ trên sách hoặc PnL tích lũy. Sử dụng báo giá của SDK hoặc api-v3.raydium.io/pools/info/ids.
  • Hàng đợi sự kiện OpenBook đầy. Một pool có thể hoàn lại swap với SerumOrderError khi hàng đợi sự kiện thị trường của nó cần cranking. Cranking không có quyền (MonitorStep trên các tài khoản OpenBook của thị trường).
  • Token-2022 mints. Không được hỗ trợ. Không thể tạo pool AMM v4 chống lại mint Token-2022; bất kỳ cặp Token-2022 nào cũng nên được sử dụng trên CPMM hoặc CLMM.

Bước tiếp theo

Nguồn: