> ## 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émos de code AMM v4

> Exemples TypeScript pour effectuer des swaps et fournir de la liquidité à un pool AMM v4 existant. La création de nouveaux pools n'est pas couverte — utilisez CPMM à la place.

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

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

<Info>
  **Banneau de version.** Toutes les démos ciblent `@raydium-io/raydium-sdk-v2@0.2.42-alpha` sur Solana mainnet-beta, vérifiées en 2026-04. ID du programme : `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8` (voir [`reference/program-addresses`](/fr/reference/program-addresses)).
</Info>

<Info>
  **La création de nouveaux pools n'est pas montrée ici.** L'interface Raydium ne propose plus la création de pools AMM v4 — les nouvelles paires utilisent par défaut [CPMM](/fr/products/cpmm/code-demos). Le programme AMM v4 lui-même accepte toujours `Initialize2` on-chain ; ce n'est simplement pas la voie recommandée. Les démos ci-dessous couvrent les opérations sur pools actifs que tout intégrateur doit maîtriser : swap, dépôt, retrait.
</Info>

## Configuration

```ts theme={null}
import { Connection, Keypair, clusterApiUrl } from "@solana/web3.js";
import { Raydium, TxVersion } from "@raydium-io/raydium-sdk-v2";
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" });
```

## Récupérer un pool par ID

```ts theme={null}
import { PublicKey } from "@solana/web3.js";

const poolId = new PublicKey("<AMM_V4_POOL_ID>");

// Récupère l'objet pool normalisé par le SDK. Pour AMM v4, cela inclut les
// comptes OpenBook que les constructeurs d'instructions utiliseront.
const data = await raydium.liquidity.getPoolInfoFromRpc({ poolId });
const { poolInfo, poolKeys, poolRpcData } = data;

console.log("Pair:", poolInfo.mintA.symbol, "/", poolInfo.mintB.symbol);
console.log("Version:", poolInfo.version);       // 4 pour AMM v4
console.log("Market:", poolKeys.marketId.toBase58());
```

`poolKeys` est la structure que les constructeurs d'instructions consomment. Elle contient chaque compte AMM v4 et OpenBook dans l'ordre attendu par le programme.

## Swap (base entrante)

```ts theme={null}
import BN from "bn.js";

const amountIn = new BN(1_000_000);            // 1 USDC (quote à 6 décimales)
const inputMint = new PublicKey(poolInfo.mintB.address);  // USDC
const slippage  = 0.005;

const computed = raydium.liquidity.computeAmountOut({
  poolInfo,
  amountIn,
  mintIn: inputMint,
  mintOut: new PublicKey(poolInfo.mintA.address),
  slippage,
});

const { execute } = await raydium.liquidity.swap({
  poolInfo,
  poolKeys,
  amountIn,
  amountOut: computed.minAmountOut,
  fixedSide: "in",
  inputMint,
  txVersion: TxVersion.V0,
});

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

Le SDK ajoute automatiquement chaque compte OpenBook. N'essayez pas de les substituer à la main — le programme valide chaque emplacement.

## Swap (base sortante)

```ts theme={null}
const amountOut = new BN(1_000_000_000);       // 1 SOL (base à 9 décimales)
const slippage  = 0.005;

const computed = raydium.liquidity.computeAmountIn({
  poolInfo,
  amountOut,
  mintOut: new PublicKey(poolInfo.mintA.address),
  mintIn: new PublicKey(poolInfo.mintB.address),
  slippage,
});

const { execute } = await raydium.liquidity.swap({
  poolInfo,
  poolKeys,
  amountIn: computed.maxAmountIn,
  amountOut,
  fixedSide: "out",
  inputMint: new PublicKey(poolInfo.mintB.address),
  txVersion: TxVersion.V0,
});

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

## Ajouter de la liquidité

```ts theme={null}
const amountA = new BN(100_000_000);           // 0,1 SOL

const { anotherAmount, maxAnotherAmount } = raydium.liquidity.computePairAmount({
  poolInfo,
  amount: amountA,
  baseIn: true,
  slippage: 0.01,
});

const { execute } = await raydium.liquidity.addLiquidity({
  poolInfo,
  poolKeys,
  amountInA: amountA,
  amountInB: maxAnotherAmount,
  fixedSide: "a",
  txVersion: TxVersion.V0,
});

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

`fixedSide: "a"` indique au SDK que vous avez fourni l'`amountInA` exact et que `amountInB` doit être au maximum `maxAnotherAmount`. La liquidité on-book du pool est réglée avant le calcul pro-rata, de sorte que le ratio de dépôt correspond aux réserves les plus fraîches.

## Retirer de la liquidité

```ts theme={null}
const lpAmount = new BN(50_000);               // LP à brûler

const { execute } = await raydium.liquidity.removeLiquidity({
  poolInfo,
  poolKeys,
  lpAmount,
  baseAmountMin: new BN(0),
  quoteAmountMin: new BN(0),
  txVersion: TxVersion.V0,
});

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

Les minimums de slippage protègent contre le changement d'état du pool entre votre pré-citation et le temps d'atterrissage.

## Ajustement des frais de priorité et des unités de calcul

Les swaps AMM v4 sont gourmands en calcul car chaque instruction valide l'état complet d'OpenBook. Un swap typique utilise 180 k–250 k CU selon le nombre de commandes ouvertes à régler en cours de route. Toujours fournir une limite d'unités de calcul :

```ts theme={null}
import { ComputeBudgetProgram } from "@solana/web3.js";

const { execute, innerTransactions } = await raydium.liquidity.swap({
  /* ...params... */
  computeBudgetConfig: {
    units: 400_000,
    microLamports: 50_000,       // frais de priorité
  },
});
```

Si vous omettez `computeBudgetConfig`, le SDK peut toujours utiliser sa propre valeur par défaut ; inspectez `innerTransactions` pour confirmer. Voir [`integration-guides/priority-fee-tuning`](/fr/integration-guides/priority-fee-tuning).

## CPI Rust direct

Si vous devez faire un CPI dans AMM v4 à partir de votre propre programme Anchor, vous devrez modéliser la liste de comptes de `SwapBaseIn` verbatim. Un esquisse minimal :

```rust theme={null}
use anchor_lang::prelude::*;
use anchor_lang::solana_program::program::invoke_signed;
use anchor_lang::solana_program::instruction::Instruction;

const AMM_V4_PROGRAM_ID: Pubkey = pubkey!("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8");

#[derive(Accounts)]
pub struct ProxyAmmV4Swap<'info> {
    /// CHECK:
    pub token_program: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub amm:          UncheckedAccount<'info>,
    /// CHECK:
    pub amm_authority: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub amm_open_orders: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub amm_target_orders: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub pool_coin_token_account: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub pool_pc_token_account: UncheckedAccount<'info>,
    /// CHECK:
    pub market_program: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market_bids: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market_asks: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market_event_queue: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market_coin_vault: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market_pc_vault: UncheckedAccount<'info>,
    /// CHECK:
    pub market_vault_signer: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub user_source: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub user_dest: UncheckedAccount<'info>,
    pub user_owner: Signer<'info>,
}

pub fn proxy_swap(
    ctx: Context<ProxyAmmV4Swap>,
    amount_in: u64,
    minimum_amount_out: u64,
) -> Result<()> {
    // Le discriminateur d'instruction pour SwapBaseIn est 9 sur AMM v4.
    let mut data = vec![9u8];
    data.extend_from_slice(&amount_in.to_le_bytes());
    data.extend_from_slice(&minimum_amount_out.to_le_bytes());

    let ix = Instruction {
        program_id: AMM_V4_PROGRAM_ID,
        accounts: vec![
            AccountMeta::new_readonly(ctx.accounts.token_program.key(), false),
            AccountMeta::new(ctx.accounts.amm.key(), false),
            AccountMeta::new_readonly(ctx.accounts.amm_authority.key(), false),
            AccountMeta::new(ctx.accounts.amm_open_orders.key(), false),
            AccountMeta::new(ctx.accounts.amm_target_orders.key(), false),
            AccountMeta::new(ctx.accounts.pool_coin_token_account.key(), false),
            AccountMeta::new(ctx.accounts.pool_pc_token_account.key(), false),
            AccountMeta::new_readonly(ctx.accounts.market_program.key(), false),
            AccountMeta::new(ctx.accounts.market.key(), false),
            AccountMeta::new(ctx.accounts.market_bids.key(), false),
            AccountMeta::new(ctx.accounts.market_asks.key(), false),
            AccountMeta::new(ctx.accounts.market_event_queue.key(), false),
            AccountMeta::new(ctx.accounts.market_coin_vault.key(), false),
            AccountMeta::new(ctx.accounts.market_pc_vault.key(), false),
            AccountMeta::new_readonly(ctx.accounts.market_vault_signer.key(), false),
            AccountMeta::new(ctx.accounts.user_source.key(), false),
            AccountMeta::new(ctx.accounts.user_dest.key(), false),
            AccountMeta::new_readonly(ctx.accounts.user_owner.key(), true),
        ],
        data,
    };
    invoke_signed(&ix, &ctx.accounts.to_account_infos(), &[])?;
    Ok(())
}
```

AMM v4 ne fournit pas de caisse Anchor pour le CPI. L'esquisse ci-dessus utilise une `Instruction` construite manuellement.

## Pièges

* **Compte OpenBook manquant.** Les 8 comptes du côté OpenBook sont requis sur chaque swap, dépôt et retrait ; le SDK gère cela, les instructions construites à la main souvent non.
* **Lecture des soldes bruts des coffres.** Ne reflète pas les montants séquestré on-book ni les pertes et profits accumulés. Utilisez la citation du SDK ou `api-v3.raydium.io/pools/info/ids`.
* **File d'attente des événements OpenBook pleine.** Un pool peut rejeter les swaps avec `SerumOrderError` quand la file d'attente des événements de son marché a besoin d'être remontée. Remonter est permissionless (`MonitorStep` sur les comptes OpenBook du marché).
* **Mints Token-2022.** Non pris en charge. Un pool AMM v4 ne peut pas être créé par rapport à un mint Token-2022 ; toute paire Token-2022 doit être sur CPMM ou CLMM.

## Prochaines étapes

* [`products/amm-v4/instructions`](/fr/products/amm-v4/instructions) — la surface au niveau des instructions derrière ces démos.
* [`user-flows/migrate-amm-v4-to-cpmm`](/fr/user-flows/migrate-amm-v4-to-cpmm) — si vous êtes un LP envisageant une migration.
* [`integration-guides/priority-fee-tuning`](/fr/integration-guides/priority-fee-tuning) — dimensionnement des frais de priorité pour les swaps AMM v4 lourds.

Sources :

* [Raydium SDK v2](https://github.com/raydium-io/raydium-sdk-V2)
* [Raydium AMM program](https://github.com/raydium-io/raydium-amm)
