> ## 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.

# Démonstrations de code pour Farm / Staking

> Exemples TypeScript pour créer une farm, staker des LP, récolter les récompenses et augmenter les budgets de récompenses sur le programme farm v6 de Raydium.

<Info>
  **Cette page est traduite automatiquement par IA. La version anglaise fait foi.**

  [Voir la version anglaise →](/products/farm-staking/code-demos)
</Info>

<Info>
  **Banneau de version.** Tous les exemples ciblent `@raydium-io/raydium-sdk-v2@0.2.64-alpha` sur Solana mainnet-beta, **vérifié le 2026-09-09** — chaque nom de builder, nom de paramètre et type de paramètre ci-dessous a été vérifié par rapport au `src/raydium/farm/` de cette version et par rapport à [`raydium-sdk-V2-demo/src/farm`](https://github.com/raydium-io/raydium-sdk-V2-demo/tree/master/src/farm). Le SDK dispatche en interne v3 / v5 / v6 selon le propriétaire du programme de la farm ; les exemples ci-dessous supposent une farm v6. Consultez [`reference/program-addresses`](/fr/reference/program-addresses) pour les trois ID de programme.

  Les noms des méthodes du module farm ne sont pas ce que vous pourriez deviner : il n'y a **pas** de `getFarmById` et **pas** de `setRewards`. La récupération se fait via `raydium.api.fetchFarmInfoById`, et les builders d'édition des récompenses sont `addNewRewardToken` / `addNewRewardsToken` et `restartReward` / `restartRewards`.
</Info>

## Configuration

Les exemples ici reflètent les fichiers dans [`raydium-sdk-V2-demo/src/farm`](https://github.com/raydium-io/raydium-sdk-V2-demo/tree/master/src/farm). L'amorçage suit le [`config.ts.template`](https://github.com/raydium-io/raydium-sdk-V2-demo/blob/master/src/config.ts.template) du dépôt de démonstration :

```ts theme={null}
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;
```

## Récupérer une farm par ID

Il n'existe pas de `raydium.farm.getFarmById`. Chaque démonstration de farm commence par le module API, qui retourne la forme normalisée `FormatFarmInfoOut` que `deposit` / `withdraw` / `harvestAllRewards` acceptent tous :

```ts theme={null}
const farmId = "CHYrUBX2RKX8iBg7gYTkccoGNBzP44LdaazMHCLcdEgS"; // RAY-USDC farm

const farmInfo = (await raydium.api.fetchFarmInfoById({ ids: farmId }))[0];
if (!farmInfo) throw new Error("farm not found");

console.log("LP mint:", farmInfo.lpMint.address);
console.log("TVL:", farmInfo.tvl);
for (const r of farmInfo.rewardInfos) {
  console.log("  -", r.mint.address, r.mint.symbol);
}
```

`fetchFarmInfoById` prend une **chaîne d'ID séparée par des virgules** et retourne un tableau, donc un seul appel peut hydrater un portefeuille entier. Si vous avez besoin des clés de compte brutes plutôt que des informations d'affichage, `raydium.api.fetchFarmKeysById({ ids })` retourne les vaults et les PDAs d'autorité ; le SDK l'appelle en interne pour vous dans chaque builder ci-dessous.

## Staker des tokens LP

Source : [`src/farm/stake.ts`](https://github.com/raydium-io/raydium-sdk-V2-demo/blob/master/src/farm/stake.ts)

```ts theme={null}
// La démo stake le solde LP entier du portefeuille ; tout BN en unités brutes fonctionne.
const amount = raydium.account.tokenAccountRawInfos.find(
  (a) => a.accountInfo.mint.toBase58() === farmInfo.lpMint.address,
)?.accountInfo.amount;

if (!amount || amount.isZero()) throw new Error("user does not have an LP balance");

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

const { txId } = await execute({ sendAndConfirm: true });
console.log("Deposit tx:", txId);
```

Le SDK gère le pré-règlement de toute récompense en attente, donc si ce portefeuille a déjà un stake dans cette farm, l'instruction paiera les récompenses accumulées aux ATA de l'utilisateur dans la même transaction.

## Récolte uniquement (harvest)

Source : [`src/farm/harvest.ts`](https://github.com/raydium-io/raydium-sdk-V2-demo/blob/master/src/farm/harvest.ts)

`farmInfoList` est un **`Record` indexé par ID de farm**, pas un tableau, et le builder retourne **plusieurs** transactions — donc `execute` doit recevoir `sequentially: true` :

```ts theme={null}
const farmIds = [farmId, "<ANOTHER_FARM_ID>"];
const farmInfos = await raydium.api.fetchFarmInfoById({ ids: farmIds.join(",") });

const { execute } = await raydium.farm.harvestAllRewards({
  farmInfoList: Object.fromEntries(farmInfos.map((f) => [f.id, f])),
  txVersion: TxVersion.V0,
});

const { txIds } = await execute({ sequentially: true });
console.log("harvest txs:", txIds);
```

Le builder empile autant de farms par transaction que la limite de 1232 octets le permet et divise le reste en transactions de suivi, c'est pourquoi il retourne `txIds` plutôt qu'un seul `txId`.

Pour une seule farm, récoltez avec l'idiome `amount: 0` — c'est ce que fait [`src/farm/harvest.ts`](https://github.com/raydium-io/raydium-sdk-V2-demo/blob/master/src/farm/harvest.ts), sur chaque version y compris v6 :

```ts theme={null}
const { execute } = await raydium.farm.withdraw({
  farmInfo,
  amount: new BN(0),        // 0 = harvest-only path
  txVersion: TxVersion.V0,
});
await execute({ sendAndConfirm: true });
```

## Unstake

Source : [`src/farm/unstake.ts`](https://github.com/raydium-io/raydium-sdk-V2-demo/blob/master/src/farm/unstake.ts)

```ts theme={null}
const amount = new BN(500_000_000);   // 0.5 LP, raw units

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

await execute({ sendAndConfirm: true });
```

## Créer une farm v6

Source : [`src/farm/createAmmFarm.ts`](https://github.com/raydium-io/raydium-sdk-V2-demo/blob/master/src/farm/createAmmFarm.ts) et [`editAmmFarm.ts`](https://github.com/raydium-io/raydium-sdk-V2-demo/blob/master/src/farm/editAmmFarm.ts)

`create` prend l'**objet d'informations du pool** pour le pool dont le mint LP est staké (pas un mint nu), et chaque entrée de `rewardInfos` est un `FarmRewardInfo` : `{ mint: PublicKey, perSecond: string, openTime: number, endTime: number, rewardType: "Standard SPL" | "Option tokens" }`. Les temps sont en **secondes simples**, et `perSecond` est une **chaîne**, pas un `BN`. `programId` par défaut au programme v6, donc vous le passez rarement.

```ts theme={null}
import type { ApiV3PoolInfoStandardItem, FarmRewardInfo } from "@raydium-io/raydium-sdk-v2";
import { RAYMint } from "@raydium-io/raydium-sdk-v2";

// Le pool que vous possédez dont le mint LP sera le mint de staking.
const poolInfo = (
  await raydium.api.fetchPoolById({ ids: "<POOL_ID>" })
)[0] as ApiV3PoolInfoStandardItem;
if (!poolInfo) throw new Error("pool not found");

const rewardMint = await raydium.token.getTokenInfo(RAYMint);

// Utilisez l'heure de la chaîne, pas l'heure murale — le programme valide par rapport à la première.
const openTime = Math.floor((await raydium.currentBlockChainTime()) / 1000);
const endTime  = openTime + 60 * 60 * 24 * 7; // 7 days

const rewardInfos: FarmRewardInfo[] = [
  {
    mint:       new PublicKey(rewardMint.address),
    perSecond:  "1",              // string, in raw units per second
    openTime,                      // seconds, not BN
    endTime,
    rewardType: "Standard SPL",   // "Option tokens" is the only other value
  },
];

const { execute, extInfo } = await raydium.farm.create({
  poolInfo,
  rewardInfos,
  txVersion: TxVersion.V0,
});

const { txId } = await execute({ sendAndConfirm: true });
console.log("Farm:", extInfo.farmId.toBase58(), "createTx:", txId);
```

Points clés :

* `perSecond` est le taux d'émission par seconde en unités **brutes** du mint de récompense, passé en tant que chaîne décimale. Le SDK le compacte dans la représentation en virgule fixe on-chain avant d'envoyer.
* Le budget complet (`perSecond × (endTime − openTime)`) doit être présent dans votre ATA de récompense — `create` le déplace dans le vault de récompense de manière atomique.
* **Les mints de récompense Token-2022 ne sont pas supportés par les builders de farm du SDK** à cette version du SDK ; utilisez un mint SPL simple pour les récompenses.
* Vous pouvez amorcer jusqu'à 5 récompenses en un seul appel `create`. La liste des comptes augmente de `(reward_mint, reward_vault, sender_ata, token_program)` par flux supplémentaire ; restez conscient de la limite de taille de transaction de 1232 octets. Pour 4+ récompenses, créez avec 1–2 et utilisez `addNewRewardsToken` dans les transactions de suivi.

## Ajouter un nouveau flux de récompense

Il n'existe pas de `raydium.farm.setRewards`. Les deux builders qui modifient les récompenses d'une farm sont `addNewRewardToken` / `addNewRewardsToken` (occupent un slot libre avec un mint **nouveau**) et `restartReward` / `restartRewards` (réarment un slot dont le flux a pris fin). Les deux prennent des objets `FarmRewardInfo` exactement dans la forme que `create` utilise.

```ts theme={null}
import { USDCMint } from "@raydium-io/raydium-sdk-v2";

const added = await raydium.token.getTokenInfo(USDCMint);
const openTime = Math.floor((await raydium.currentBlockChainTime()) / 1000);

const { execute } = await raydium.farm.addNewRewardsToken({
  farmInfo,
  newRewardInfos: [
    {
      mint:       new PublicKey(added.address),
      perSecond:  "1",
      openTime,
      endTime:    openTime + 60 * 60 * 24 * 7,
      rewardType: "Standard SPL",
    },
  ],
  txVersion: TxVersion.V0,
});

await execute({ sendAndConfirm: true });
```

Le budget delta (`perSecond × duration`) est prélevé sur l'ATA du payeur dans le cadre de la transaction. L'instruction sous-jacente ne peut pas raccourcir un flux, ne peut pas abaisser `per_second` sur un flux actif, et ne peut pas changer le mint de récompense d'un slot — pour échanger les mints, attendez `end_time` et utilisez `addNewRewardsToken` sur un slot libéré, ou créez une nouvelle farm.

<Tip>
  `restartRewards` et `addNewRewardsToken` retournent chacun un builder, donc une seule transaction peut faire les deux. [`src/farm/editAmmFarm.ts`](https://github.com/raydium-io/raydium-sdk-V2-demo/blob/master/src/farm/editAmmFarm.ts) montre le motif : `editFarmBuilder.builder.addInstruction(addNewRewardBuildData.builder.AllTxData)`, puis un `versionBuild({ txVersion })`.
</Tip>

## Redémarrer un flux terminé

Source : [`src/farm/editAmmFarm.ts`](https://github.com/raydium-io/raydium-sdk-V2-demo/blob/master/src/farm/editAmmFarm.ts)

`restartRewards` prend **`newRewardInfos`** (pluriel, un tableau) ; `restartReward` est la forme à un seul élément et prend `newRewardInfo`. Le champ mint est `mint`, pas `rewardMint`, et il doit correspondre à un slot qui existe déjà sur la farm — le builder recherche le slot par mint et génère une erreur s'il est absent.

```ts theme={null}
import type { FarmRewardInfo } from "@raydium-io/raydium-sdk-v2";

// Réarmez le slot de récompense existant en premier de la farm.
const existing = await raydium.token.getTokenInfo(farmInfo.rewardInfos[0].mint.address);
const openTime = Math.floor((await raydium.currentBlockChainTime()) / 1000);

const newRewardInfos: FarmRewardInfo[] = [
  {
    mint:       new PublicKey(existing.address),
    perSecond:  "1",
    openTime,
    endTime:    openTime + 60 * 60 * 24 * 14,
    rewardType: "Standard SPL",
  },
];

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

await execute({ sendAndConfirm: true });
```

`restartRewards` est **v6 uniquement** — le builder lit l'ID du programme de la farm et génère une erreur pour les farms v3 / v5. Valide uniquement quand `reward_state == 2` du slot cible (terminé) ; l'appelant doit être le `reward_sender` du slot. Notez que `openTime >= endTime` est rejeté côté client avant tout RPC.

## CPI Rust

<Warning>
  **Il n'existe pas de crate Anchor `raydium_farm_v6`.** Aucune crate portant ce nom n'existe sur crates.io, le programme Farm v6 ne publie pas d'IDL on-chain (ni un compte `anchor:idl` hérité ni une entrée dans le programme Program Metadata), et aucun dépôt source public pour celui-ci n'existe. Une révision antérieure de cette page montrait un exemple `raydium_farm_v6::cpi::deposit` ; il ne compilait contre rien et a été supprimé.
</Warning>

Farm v6 a été déployée pour la dernière fois le 2024-05-13 et n'est pas un programme Anchor du point de vue d'un intégrateur. Si vous avez besoin de composer avec celui-ci à partir de votre propre programme on-chain, construisez l'`Instruction` à la main — dérivez la liste des comptes et les discriminateurs d'instruction indépendamment (à partir des mises en page TypeScript du SDK sous `raydium-sdk-V2/src/raydium/farm/`, ou en décodant des transactions réelles), et `invoke_signed` le. Consultez [`sdk-api/rust-cpi`](/fr/sdk-api/rust-cpi#farm-v6) pour cette procédure.

Quelle que soit la route que vous empruntez, la queue `remaining_accounts` doit correspondre 1-pour-1 aux slots de récompense actifs de la farm (paires de `reward_vault_i`, `user_reward_ata_i` dans l'ordre des index). Omettre ou mal ordonner ces éléments produit une comptabilité silencieuse erronée — le programme transférera le mauvais montant.

## Pièges

* **Oublier de réclamer avant de retirer.** Inoffensif — `Withdraw` règle d'abord les récompenses en attente. Mais si votre interface utilisateur affiche « réclamer » séparément de « retirer », l'utilisateur peut penser qu'il y a encore quelque chose à réclamer après un `Withdraw`. Il n'y a rien ; tout ce qui s'est accumulé jusqu'à ce point a été payé.
* **`total_staked = 0` pendant les émissions.** Les émissions accumulées alors que rien n'était staké sont perdues (la formule de mise à jour `reward_per_share` divise par 0 et le programme saute la mise à jour). Pour les programmes avec `open_time` programmé, exécutez un « seed stake » à open\_time pour éviter cela.
* **Frais de transfert Token-2022.** Sur les farms v6 avec des mints de récompense Token-2022, le frais de transfert s'applique à l'émission (vault → utilisateur). Tenez compte de cela dans vos devis d'APR.
* **Petit `per_second` sur v5.** Le taux `u64` de v5 signifie que tout `per_second < 1` unité de token par seconde (sur les mints avec ≥9 décimales, c'est souvent le taux souhaité) ne peut pas être exprimé — le taux du flux s'arrondit à 0 et la farm n'émet rien. Utilisez v6.

## Où aller ensuite

* [`products/farm-staking/instructions`](/fr/products/farm-staking/instructions) — référence d'instruction sous-jacente.
* [`products/clmm/fees`](/fr/products/clmm/fees) — comparez aux flux de récompense natifs de CLMM.
* [`user-flows/migrate-amm-v4-to-cpmm`](/fr/user-flows/migrate-amm-v4-to-cpmm) — souvent associé au lancement d'une nouvelle farm CPMM.

Sources :

* [Raydium SDK v2](https://github.com/raydium-io/raydium-sdk-V2)
* IDL Farm v6 fourni dans [`raydium-io/raydium-sdk-V2`](https://github.com/raydium-io/raydium-sdk-V2) sous `src/raydium/farm/`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.