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.
Banner versi. Semua demo menargetkan @raydium-io/raydium-sdk-v2@0.2.42-alpha terhadap Solana mainnet-beta, diverifikasi 2026-04. SDK mengirimkan v3 / v5 / v6 secara internal berdasarkan pemilik program farm; contoh di bawah mengasumsikan farm v6. Lihat reference/program-addresses untuk ketiga ID program.
Setup
Demo di sini mencerminkan file di raydium-sdk-V2-demo/src/farm. Bootstrap mengikuti config.ts.template repo 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;
Ambil farm berdasarkan 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 mengambil FarmState off-chain, melakukan decode sesuai versi program, dan menormalisasi laju emisi fixed-point menjadi Decimal biasa per detik.
Stake token LP
Sumber: src/farm/stake.ts
const amount = new BN(1_000_000_000); // 1 LP (anggap 9 desimal)
const { execute } = await raydium.farm.deposit({
farmInfo: farm,
amount,
txVersion: TxVersion.V0,
});
const { txId } = await execute({ sendAndConfirm: true });
console.log("Deposit tx:", txId);
SDK menangani pre-settle dari reward yang tertunda, sehingga jika wallet ini sudah memiliki stake di farm ini, instruksi akan membayarkan reward yang terkumpul ke ATA pengguna dalam transaksi yang sama.
Claim saja (harvest)
Sumber: src/farm/harvest.ts
const { execute } = await raydium.farm.harvestAllRewards({
farmInfoList: [farm],
txVersion: TxVersion.V0,
});
await execute({ sendAndConfirm: true });
harvestAllRewards menerima daftar — untuk UI yang menampilkan tampilan portfolio, batch panggilan ini. Setiap farm diklaim dalam instruksi terpisah dalam satu transaksi (tunduk pada batas ukuran 1232 byte; untuk >~6 farm, bagi menjadi beberapa transaksi).
Untuk satu farm di v6, Anda juga bisa menggunakan jalur Harvest eksplisit:
const { execute } = await raydium.farm.withdraw({
farmInfo: farm,
amount: new BN(0), // 0 = jalur harvest-only, bahkan di v6
txVersion: TxVersion.V0,
});
await execute({ sendAndConfirm: true });
Di v3 dan v5 idiom amount: 0 diperlukan; SDK mengirimnya dengan benar.
Unstake
Sumber: 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 });
Buat farm v6
Sumber: src/farm/createAmmFarm.ts dan editAmmFarm.ts
import { CurveCalculator } from "@raydium-io/raydium-sdk-v2"; // opsional, untuk perencanaan APR
const stakingMint = new PublicKey("<LP_MINT>"); // misal mint LP CPMM
const rewardMint = new PublicKey("<REWARD_MINT>"); // misal token proyek Anda
const now = Math.floor(Date.now() / 1000);
const openTime = now + 60 * 60; // mulai dalam 1j
const duration = 60 * 60 * 24 * 30; // 30 hari
const endTime = openTime + duration;
const totalBudget = new BN(1_000_000).mul(new BN(10).pow(new BN(9))); // 1M token reward (9 des)
const perSecond = totalBudget.div(new BN(duration)); // integer, SDK naikkan ke Q64.64
const { execute, extInfo } = await raydium.farm.create({
programId: /* ID program v6, dari 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, // siapa yang membayar anggaran awal
mintProgramId: /* SPL Token atau Token-2022 */,
},
],
txVersion: TxVersion.V0,
});
const { txId } = await execute({ sendAndConfirm: true });
console.log("Farm:", extInfo.farmId.toBase58(), "createTx:", txId);
Poin penting:
perSecond adalah laju emisi integer per detik. SDK mengemas ke Q64.64 sebelum mengirim. Untuk laju pecahan, skala dan sesuaikan durasi.
- Anggaran penuh (
perSecond × duration) harus hadir di ATA reward Anda — create memindahkannya ke vault reward secara atom.
- Anda dapat menambahkan hingga 5 reward dalam satu panggilan
create. Daftar akun tumbuh sebesar (reward_mint, reward_vault, sender_ata, token_program) per aliran ekstra; sadari batas ukuran transaksi 1232 byte. Untuk 4+ reward, buat dengan 1–2 dan gunakan AddReward dalam transaksi lanjutan.
Topup aliran reward yang sudah ada
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, // pertahankan laju yang sama
payer: owner.publicKey,
},
],
txVersion: TxVersion.V0,
});
await execute({ sendAndConfirm: true });
setRewards memperpanjang end_time dan mentransfer anggaran delta. Instruksi tidak dapat mempersingkat aliran, tidak dapat menurunkan per_second pada aliran aktif, dan tidak dapat mengubah mint reward. Untuk menukar mint, tunggu end_time dan gunakan AddReward di slot yang dibebaskan (jika ada), atau buat farm baru.
Mulai ulang aliran yang selesai
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 });
Valid hanya jika reward_state == 2 slot target (selesai). Pemanggil harus reward_sender slot (v6) atau pemilik farm (v5).
Rust CPI
Tidak seperti AMM v4, program farm v6 dilengkapi dengan crate Anchor (raydium_farm_v6) yang dipublikasikan bersama sumber frontend dan SDK. Sketsa Deposit minimal:
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>,
// Diikuti di remaining_accounts oleh pasangan (reward_vault_i, user_reward_ata_i)
// untuk setiap aliran reward aktif di 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)
}
Slice remaining_accounts harus cocok dengan slot reward aktif farm 1-untuk-1 (pasangan reward_vault_i, user_reward_ata_i dalam urutan indeks). Menghilangkan atau salah urutan ini menghasilkan mis-accounting senyap — program akan mentransfer jumlah yang salah.
Jebakan
- Lupa claim sebelum withdraw. Tidak berbahaya —
Withdraw menyelesaikan reward yang tertunda lebih dulu. Tetapi jika UI Anda menampilkan “claim” terpisah dari “withdraw”, pengguna mungkin berpikir masih ada sesuatu untuk diklaim setelah Withdraw. Tidak ada; semuanya yang terkumpul hingga titik itu sudah dibayarkan.
total_staked = 0 selama emisi. Emisi yang terkumpul saat tidak ada yang distake hilang (formula pembaruan reward_per_share membagi dengan 0 dan program melewati pembaruan). Untuk program dengan open_time terjadwal, jalankan “seed stake” pada open_time untuk menghindari ini.
- Biaya transfer Token-2022. Di farm v6 dengan mint reward Token-2022, biaya transfer berlaku saat emit (vault → pengguna). Faktorkan ini ke dalam kutipan APR.
per_second kecil di v5. u64 v5 berarti per_second < 1 unit token per detik (pada mint dengan ≥9 desimal ini sering kali laju yang diinginkan) tidak dapat diekspresikan — laju aliran dibulatkan ke 0 dan farm memancarkan tidak ada apa-apa. Gunakan v6.
Ke mana selanjutnya
Sumber: