跳转到主要内容

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.

本页内容由 AI 自动翻译,所有内容以英文版本为准。查看英文版 →
版本说明。 所有示例针对 @raydium-io/raydium-sdk-v2@0.2.42-alpha,在 Solana mainnet-beta 上验证,时间为 2026-04。SDK 根据农场的程序所有者在内部分发 v3 / v5 / v6;下面的示例假定为 v6 农场。参见 reference/program-addresses 了解三个程序 ID。

设置

此处的示例镜像自 raydium-sdk-V2-demo/src/farm。初始化步骤遵循示例仓库的 config.ts.template
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;

按 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 从链外拉取 FarmState,根据程序版本进行解码,并将固定点发放速率标准化为普通的每秒 Decimal

质押 LP 代币

来源: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 会处理任何待处理奖励的提前结算,所以如果该钱包已在此农场中有质押,该指令将在同一笔交易中把累积的奖励支付到用户的 ATA。

仅领取(收获)

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

await execute({ sendAndConfirm: true });
harvestAllRewards 接受一个列表——对于显示投资组合视图的 UI,将调用进行批处理。每个农场在一笔交易内的单独指令中被领取(受 1232 字节大小限制;超过约 6 个农场时,拆分为多个交易)。 对于 v6 上的单个农场,你也可以使用显式的 Harvest 路径:
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 });
在 v3 和 v5 上,amount: 0 习用法是必需的;SDK 会正确地分发它。

解除质押

来源: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 });

创建 v6 农场

来源: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);
关键点:
  • perSecond 是每秒的整数发放速率。SDK 在发送前将其打包为 Q64.64。对于分数速率,按比例调整并调整持续时间。
  • 完整的预算(perSecond × duration)必须存在于你的奖励 ATA 中——create 原子地将其移入奖励金库。
  • 你最多可以在一个 create 调用中设置 5 个奖励。账户列表按每个额外流程增加 (reward_mint, reward_vault, sender_ata, token_program);注意 1232 字节交易大小限制。对于 4 个或更多奖励,先用 1–2 个创建,然后在后续交易中使用 AddReward

追加现有奖励流

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 扩展 end_time 并转移增量预算。该指令无法缩短流、无法在活跃流上降低 per_second、无法改变奖励 mint。要交换 mint,请等待 end_time 并在已释放的槽位(如果有)使用 AddReward,或创建新农场。

重启已完成的流

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 });
仅当目标槽位的 reward_state == 2(已结束)时有效。调用者必须是该槽位的 reward_sender(v6)或农场所有者(v5)。

Rust CPI

与 AMM v4 不同,v6 农场程序附带一个 Anchor 箱(raydium_farm_v6),与前端和 SDK 源代码一起发布。一个最小的 Deposit 示例:
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)
}
remaining_accounts 切片必须与农场的活跃奖励槽位 1 对 1 匹配(按索引顺序成对的 reward_vault_iuser_reward_ata_i)。省略或错误排序这些会导致静默的错误会计——程序将转移错误的金额。

常见陷阱

  • 提款前忘记领取。 无害的——Withdraw 会先结算待处理的奖励。但如果你的 UI 将”领取”与”提款”分开显示,用户可能会在 Withdraw 后认为仍有内容可以领取。实际上没有;到那一点为止累积的所有内容都已支付。
  • 发放期间 total_staked = 0 当没有任何质押时累积的发放被没收(reward_per_share 更新公式除以 0,程序跳过更新)。对于有计划的 open_time 的程序,在 open_time 运行”种子质押”以避免这种情况。
  • Token-2022 转账费。 在具有 Token-2022 奖励 mint 的 v6 农场上,转账费在发放时适用(金库 → 用户)。在 APR 报价中考虑这一点。
  • v5 上的小 per_second v5 的 u64 速率意味着任何 per_second < 1 代币单位/秒(在 ≥9 小数位的 mint 上这通常是所需速率)无法表示——流速率舍入为 0,农场不发放任何东西。使用 v6。

下一步

来源: