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 →
Banner phiên bản. Tất cả các demo hướng tới @raydium-io/raydium-sdk-v2@0.2.42-alpha trên Solana mainnet-beta, được xác minh vào tháng 4 năm 2026. SDK điều phối v3 / v5 / v6 nội bộ dựa trên chủ sở hữu chương trình của farm; các ví dụ dưới đây giả định farm v6. Xem reference/program-addresses để tìm ba ID chương trình.

Cài đặt

Các demo ở đây phản ánh các tập tin trong raydium-sdk-V2-demo/src/farm. Bootstrap theo config.ts.template của kho demo:
import { Connection, Keypair, clusterApiUrl, PublicKey } from "@solana/web3.js";
import { Raydium, TxVersion } from "@raydium-io/raydium-sdk-v2";
import BN from "bn.js";
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",
  disableFeatureCheck: true,
  blockhashCommitment: "finalized",
});
export const txVersion = TxVersion.V0;

Tìm nạp farm theo ID

const farmId = new PublicKey("<FARM_ID>");

const farm = await raydium.farm.getFarmById({ farmId });
console.log("Staking mint:", farm.symbolMint.toBase58());
console.log("Total staked:", farm.totalStaked.toString());
console.log("Rewards:");
for (const r of farm.rewardInfos) {
  console.log(
    "  -", r.mint.toBase58(),
    "rate(1e-" + r.decimals + "/s):", r.perSecond.toString(),
    "open:", new Date(r.openTime * 1000).toISOString(),
    "end: ", new Date(r.endTime * 1000).toISOString(),
  );
}
getFarmById tải FarmState ngoài chuỗi, giải mã theo phiên bản chương trình và chuẩn hóa tỷ lệ phát hành điểm cố định thành Decimal đơn giản trên mỗi giây.

Staking token LP

Nguồn: src/farm/stake.ts
const amount = new BN(1_000_000_000);   // 1 LP (assuming 9 decimals)

const { execute } = await raydium.farm.deposit({
  farmInfo: farm,
  amount,
  txVersion: TxVersion.V0,
});

const { txId } = await execute({ sendAndConfirm: true });
console.log("Deposit tx:", txId);
SDK xử lý việc giải quyết trước bất kỳ phần thưởng nào đang chờ xử lý, vì vậy nếu ví này đã có cổ phần trong farm này, hướng dẫn sẽ trả các phần thưởng tích lũy cho ATA của người dùng trong cùng một giao dịch.

Chỉ yêu cầu (thu hoạch)

Nguồn: src/farm/harvest.ts
const { execute } = await raydium.farm.harvestAllRewards({
  farmInfoList: [farm],
  txVersion: TxVersion.V0,
});

await execute({ sendAndConfirm: true });
harvestAllRewards chấp nhận một danh sách — đối với UI hiển thị dạng xem danh mục đầu tư, hãy ghép lại cuộc gọi. Mỗi farm được yêu cầu trong một hướng dẫn riêng biệt trong một giao dịch (tùy thuộc vào giới hạn kích thước 1232 byte; đối với >~6 farm, hãy chia thành nhiều giao dịch). Đối với một farm duy nhất trên v6, bạn cũng có thể sử dụng đường dẫn Harvest rõ ràng:
const { execute } = await raydium.farm.withdraw({
  farmInfo: farm,
  amount: new BN(0),        // 0 = harvest-only path, even on v6
  txVersion: TxVersion.V0,
});
await execute({ sendAndConfirm: true });
Trên v3 và v5 thành ngữ amount: 0 là bắt buộc; SDK điều phối nó một cách chính xác.

Rút cọc

Nguồn: src/farm/unstake.ts
const amount = new BN(500_000_000);   // 0.5 LP

const { execute } = await raydium.farm.withdraw({
  farmInfo: farm,
  amount,
  txVersion: TxVersion.V0,
});

await execute({ sendAndConfirm: true });

Tạo farm v6

Nguồn: src/farm/createAmmFarm.tseditAmmFarm.ts
import { CurveCalculator } from "@raydium-io/raydium-sdk-v2"; // optional, for APR planning

const stakingMint = new PublicKey("<LP_MINT>");       // e.g. a CPMM LP mint
const rewardMint  = new PublicKey("<REWARD_MINT>");   // e.g. your project's token

const now      = Math.floor(Date.now() / 1000);
const openTime = now + 60 * 60;                       // start in 1h
const duration = 60 * 60 * 24 * 30;                   // 30 days
const endTime  = openTime + duration;

const totalBudget = new BN(1_000_000).mul(new BN(10).pow(new BN(9))); // 1M reward tokens (9 dec)
const perSecond   = totalBudget.div(new BN(duration));                // integer, SDK lifts to Q64.64

const { execute, extInfo } = await raydium.farm.create({
  programId: /* v6 program ID, from reference/program-addresses */,
  poolInfo: { lpMint: { address: stakingMint, decimals: 9, programId: /* SPL Token */ } as any },
  rewardInfos: [
    {
      mint:           rewardMint,
      openTime:       new BN(openTime),
      endTime:        new BN(endTime),
      perSecond,
      rewardSender:   owner.publicKey,    // who pays the initial budget
      mintProgramId:  /* SPL Token or Token-2022 */,
    },
  ],
  txVersion: TxVersion.V0,
});

const { txId } = await execute({ sendAndConfirm: true });
console.log("Farm:", extInfo.farmId.toBase58(), "createTx:", txId);
Những điểm chính:
  • perSecond là tỷ lệ phát hành nguyên số mỗi giây. SDK đóng gói nó thành Q64.64 trước khi gửi. Đối với tỷ lệ phân số, hãy chia tỷ lệ và điều chỉnh khoảng thời gian.
  • Ngân sách đầy đủ (perSecond × duration) phải có trong ATA phần thưởng của bạn — create di chuyển nó vào kho phần thưởng một cách nguyên tử.
  • Bạn có thể tạo hạt giống tối đa 5 phần thưởng trong một cuộc gọi create. Danh sách tài khoản tăng thêm (reward_mint, reward_vault, sender_ata, token_program) cho mỗi luồng bổ sung; hãy nhận thức được giới hạn kích thước giao dịch 1232 byte. Đối với 4 hoặc nhiều phần thưởng, hãy tạo với 1–2 và sử dụng AddReward trong các giao dịch tiếp theo.

Nạp thêm luồng phần thưởng hiện có

const additionalDays = 30;
const extraSeconds   = 60 * 60 * 24 * additionalDays;
const extraBudget    = perSecond.mul(new BN(extraSeconds));

const { execute } = await raydium.farm.setRewards({
  farmInfo: farm,
  rewardInfos: [
    {
      rewardMint:  rewardMint,
      newEndTime:  new BN(farm.rewardInfos[0].endTime + extraSeconds),
      newPerSecond: perSecond,                   // keep same rate
      payer:        owner.publicKey,
    },
  ],
  txVersion: TxVersion.V0,
});

await execute({ sendAndConfirm: true });
setRewards mở rộng end_time và chuyển ngân sách delta. Hướng dẫn không thể rút ngắn luồng, không thể hạ thấp per_second trên luồng hoạt động và không thể thay đổi mint phần thưởng. Để hoán đổi mint, hãy đợi end_time và sử dụng AddReward trên một slot được giải phóng (nếu có), hoặc tạo farm mới.

Khởi động lại luồng hoàn thành

const { execute } = await raydium.farm.restartRewards({
  farmInfo: farm,
  newRewardInfo: {
    rewardMint:   rewardMint,
    openTime:     new BN(Math.floor(Date.now() / 1000) + 60 * 60),
    endTime:      new BN(Math.floor(Date.now() / 1000) + 60 * 60 + 60 * 60 * 24 * 14),
    perSecond:    new BN("1000000000"),
    payer:        owner.publicKey,
  },
  txVersion: TxVersion.V0,
});

await execute({ sendAndConfirm: true });
Chỉ có giá trị khi reward_state == 2 của slot mục tiêu (kết thúc). Người gọi phải là reward_sender (v6) hoặc chủ sở hữu farm (v5) của slot.

CPI Rust

Không giống như AMM v4, chương trình farm v6 được cung cấp với crate Anchor (raydium_farm_v6) được xuất bản cùng với nguồn SDK và frontend. Một bản phác họa Deposit tối thiểu:
use anchor_lang::prelude::*;
use raydium_farm_v6::{self, cpi::accounts::Deposit as RaydiumDeposit};

#[derive(Accounts)]
pub struct ProxyFarmDeposit<'info> {
    /// CHECK:
    pub farm_program: UncheckedAccount<'info>,
    #[account(mut)] pub user: Signer<'info>,
    #[account(mut)] /// CHECK:
    pub user_ledger: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub farm_state: UncheckedAccount<'info>,
    /// CHECK:
    pub farm_authority: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub staking_vault: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub user_staking_ata: UncheckedAccount<'info>,
    // Followed in remaining_accounts by (reward_vault_i, user_reward_ata_i) pairs
    // for each live reward stream on the farm.
    pub token_program: UncheckedAccount<'info>,
    pub system_program: Program<'info, System>,
}

pub fn proxy_deposit<'info>(
    ctx: Context<'_, '_, '_, 'info, ProxyFarmDeposit<'info>>,
    amount: u64,
) -> Result<()> {
    let cpi_ctx = CpiContext::new(
        ctx.accounts.farm_program.to_account_info(),
        RaydiumDeposit {
            user:             ctx.accounts.user.to_account_info(),
            user_ledger:      ctx.accounts.user_ledger.to_account_info(),
            farm_state:       ctx.accounts.farm_state.to_account_info(),
            farm_authority:   ctx.accounts.farm_authority.to_account_info(),
            staking_vault:    ctx.accounts.staking_vault.to_account_info(),
            user_staking_ata: ctx.accounts.user_staking_ata.to_account_info(),
            token_program:    ctx.accounts.token_program.to_account_info(),
            system_program:   ctx.accounts.system_program.to_account_info(),
        },
    ).with_remaining_accounts(ctx.remaining_accounts.to_vec());

    raydium_farm_v6::cpi::deposit(cpi_ctx, amount)
}
Lát remaining_accounts phải khớp các slot phần thưởng hoạt động của farm 1-cho-1 (cặp reward_vault_i, user_reward_ata_i theo thứ tự chỉ số). Bỏ qua hoặc sắp xếp sai các thành phần này sẽ tạo ra kỹ toán sai lệch im lặng — chương trình sẽ chuyển số tiền sai.

Những cạm bẫy

  • Quên yêu cầu trước khi rút cọc. Vô hại — Withdraw giải quyết phần thưởng chờ xử lý trước. Nhưng nếu UI của bạn hiển thị “yêu cầu” riêng biệt với “rút cọc”, người dùng có thể nghĩ rằng vẫn còn gì đó để yêu cầu sau Withdraw. Không có; mọi thứ tích lũy cho đến thời điểm đó đã được thanh toán.
  • total_staked = 0 trong quá trình phát hành. Phát hành tích lũy khi không có gì được staking bị mất (công thức cập nhật reward_per_share chia cho 0 và chương trình bỏ qua cập nhật). Đối với các chương trình có open_time theo lịch trình, chạy “seed stake” tại open_time để tránh điều này.
  • Phí chuyển Token-2022. Trên farm v6 với mint phần thưởng Token-2022, phí chuyển được áp dụng khi phát hành (vault → người dùng). Tính toán điều này vào báo giá APR.
  • Nhỏ per_second trên v5. u64 rate của v5 có nghĩa là bất kỳ per_second < 1 đơn vị token trên mỗi giây (trên mint có ≥9 decimals đây thường là tỷ lệ mong muốn) không thể được biểu thị — tỷ lệ luồng làm tròn thành 0 và farm không phát hành gì. Sử dụng v6.

Bước tiếp theo

Nguồn: