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.
版本說明。 所有示例針對 @raydium-io/raydium-sdk-v2@0.2.42-alpha 運行於 Solana mainnet-beta,已於 2026 年 4 月驗證。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.ts 和 editAmmFarm.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,也無法變更獎勵代幣。若要交換代幣,請等待 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 crate(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_i、user_reward_ata_i 對)。遺漏或排列錯誤會導致無聲的誤算 — 程式會轉移錯誤的金額。
常見陷阱
- 提現前忘記領取。 無害 —
Withdraw 會先結算未決獎勵。但如果你的 UI 將「領取」與「提現」分開顯示,用戶可能認為 Withdraw 後還有東西要領取。沒有;所有累積到那時的獎勵都已支出。
- 發行期間
total_staked = 0。 在沒有質押時累積的發行會被沒收(reward_per_share 更新公式除以 0,程式跳過更新)。對於有計畫 open_time 的程式,在 open_time 進行「種子質押」以避免此問題。
- Token-2022 轉帳費用。 在帶有 Token-2022 獎勵代幣的 v6 農場上,轉帳費用在發行時適用(金庫 → 用戶)。將其納入 APR 引用。
- v5 上的小
per_second。 v5 的 u64 率意味著任何 per_second < 1 代幣單位/秒(對於小數點≥9 位的代幣,這通常是期望的率)無法表示 — 流率四捨五入到 0,農場發行無效。使用 v6。
接下來的方向
來源: