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.
Informações de versão. Todos os exemplos visam @raydium-io/raydium-sdk-v2@0.2.42-alpha contra Solana mainnet-beta, verificado em 2026-04. O SDK despacha v3 / v5 / v6 internamente com base no proprietário do programa do farm; os exemplos abaixo assumem um farm v6. Consulte reference/program-addresses para os três IDs de programa.
Setup
Os exemplos aqui espelham arquivos em raydium-sdk-V2-demo/src/farm. O bootstrap segue o config.ts.template do repositório de demonstração:
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;
Buscar um farm por 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 obtém FarmState fora da cadeia, decodifica por versão de programa e normaliza a taxa de emissão de ponto fixo para um simples Decimal por segundo.
Fazer stake de tokens LP
Fonte: src/farm/stake.ts
const amount = new BN(1_000_000_000); // 1 LP (assumindo 9 decimais)
const { execute } = await raydium.farm.deposit({
farmInfo: farm,
amount,
txVersion: TxVersion.V0,
});
const { txId } = await execute({ sendAndConfirm: true });
console.log("Deposit tx:", txId);
O SDK lida com a pré-liquidação de qualquer recompensa pendente, então se esta carteira já tiver stake neste farm, a instrução pagará recompensas acumuladas aos ATAs do usuário na mesma transação.
Apenas coleta (harvest)
Fonte: src/farm/harvest.ts
const { execute } = await raydium.farm.harvestAllRewards({
farmInfoList: [farm],
txVersion: TxVersion.V0,
});
await execute({ sendAndConfirm: true });
harvestAllRewards aceita uma lista — para UIs mostrando uma visão de portfólio, agrupe a chamada. Cada farm é coletado em uma instrução separada em uma transação (sujeito ao limite de tamanho de 1232 bytes; para >~6 farms, divida em múltiplas transações).
Para um único farm em v6, você também pode usar o caminho Harvest explícito:
const { execute } = await raydium.farm.withdraw({
farmInfo: farm,
amount: new BN(0), // 0 = caminho harvest-only, mesmo em v6
txVersion: TxVersion.V0,
});
await execute({ sendAndConfirm: true });
Em v3 e v5 o idioma amount: 0 é necessário; o SDK o despacha corretamente.
Unstake
Fonte: 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 });
Criar um farm v6
Fonte: src/farm/createAmmFarm.ts e editAmmFarm.ts
import { CurveCalculator } from "@raydium-io/raydium-sdk-v2"; // opcional, para planejamento de APR
const stakingMint = new PublicKey("<LP_MINT>"); // ex: um mint LP CPMM
const rewardMint = new PublicKey("<REWARD_MINT>"); // ex: token do seu projeto
const now = Math.floor(Date.now() / 1000);
const openTime = now + 60 * 60; // começar em 1h
const duration = 60 * 60 * 24 * 30; // 30 dias
const endTime = openTime + duration;
const totalBudget = new BN(1_000_000).mul(new BN(10).pow(new BN(9))); // 1M tokens de recompensa (9 dec)
const perSecond = totalBudget.div(new BN(duration)); // inteiro, SDK levanta para Q64.64
const { execute, extInfo } = await raydium.farm.create({
programId: /* ID do programa v6, de 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, // quem paga o orçamento inicial
mintProgramId: /* SPL Token ou Token-2022 */,
},
],
txVersion: TxVersion.V0,
});
const { txId } = await execute({ sendAndConfirm: true });
console.log("Farm:", extInfo.farmId.toBase58(), "createTx:", txId);
Pontos-chave:
perSecond é a taxa de emissão inteira por segundo. O SDK a empacota em Q64.64 antes de enviar. Para uma taxa fracionária, escale e ajuste a duração.
- O orçamento completo (
perSecond × duration) deve estar presente em seu ATA de recompensa — create o move para o vault de recompensa atomicamente.
- Você pode semear até 5 recompensas em uma chamada
create. A lista de contas cresce por (reward_mint, reward_vault, sender_ata, token_program) por fluxo extra; esteja atento ao limite de tamanho de transação de 1232 bytes. Para 4+ recompensas, crie com 1–2 e use AddReward em transações subsequentes.
Adicionar orçamento a um fluxo de recompensa existente
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, // manter mesma taxa
payer: owner.publicKey,
},
],
txVersion: TxVersion.V0,
});
await execute({ sendAndConfirm: true });
setRewards estende end_time e transfere o orçamento delta. A instrução não pode encurtar um fluxo, não pode baixar per_second em um fluxo ativo e não pode alterar o mint de recompensa. Para trocar mints, aguarde end_time e use AddReward em um slot liberado (se houver), ou crie um novo farm.
Reiniciar um fluxo terminado
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 });
Válido apenas quando o reward_state == 2 (terminado) do slot alvo. O chamador deve ser o reward_sender do slot (v6) ou o proprietário do farm (v5).
Rust CPI
Diferentemente do AMM v4, o programa farm v6 vem com um crate Anchor (raydium_farm_v6) publicado junto com as fontes do frontend e SDK. Um esboço Deposit mínimo:
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>,
// Seguido em remaining_accounts por pares (reward_vault_i, user_reward_ata_i)
// para cada fluxo de recompensa ativo no 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)
}
A fatia remaining_accounts deve corresponder 1 para 1 aos slots de recompensa ativos do farm (pares de reward_vault_i, user_reward_ata_i em ordem de índice). Omitir ou desordenar esses produz uma contabilização silenciosamente incorreta — o programa transferirá o valor incorreto.
Armadilhas comuns
- Esquecer de coletar antes de sacar. Inofensivo —
Withdraw liquida recompensas pendentes primeiro. Mas se sua UI mostrar “coletar” separadamente de “sacar”, o usuário pode pensar que ainda há algo a coletar após um Withdraw. Não há; tudo acumulado até aquele ponto foi pago.
total_staked = 0 durante emissões. Emissões acumuladas enquanto nada estava em stake são perdidas (a fórmula de atualização reward_per_share divide por 0 e o programa pula a atualização). Para programas com open_time agendado, execute um “seed stake” no open_time para evitar isso.
- Taxas de transferência Token-2022. Em farms v6 com mints de recompensa Token-2022, a taxa de transferência se aplica na emissão (vault → usuário). Fatore isso em citações de APR.
- Pequeno
per_second em v5. A taxa u64 do v5 significa que qualquer per_second < 1 unidade de token por segundo (em mints com ≥9 decimais esta é frequentemente a taxa desejada) não pode ser expressa — a taxa do fluxo arredonda para 0 e o farm não emite nada. Use v6.
Próximos passos
Fontes: