> ## 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 AMM v4

> Exemples TypeScript pour échanger contre 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.** Tous les exemples ciblent `@raydium-io/raydium-sdk-v2@0.2.42-alpha` sur Solana mainnet-beta, vérifiés 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 n'offre 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 le chemin recommandé. Les exemples ci-dessous couvrent les opérations sur pools actifs que chaque intégrateur doit connaître : 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érez 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 tous les comptes AMM v4 et OpenBook dans l'ordre attendu par le programme.

## Swap (base-in)

```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 achemine les swaps AMM v4 via les points d'entrée V2, qui ne contiennent pas les comptes OpenBook. (Après la mise à jour de 2026-07, les comptes de marché ne sont plus validés même sur le chemin v1 hérité.)

## Swap (base-out)

```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 au prorata, de sorte que le ratio de dépôt correspond aux réserves les plus récentes.

## 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 les changements d'état du pool entre votre pré-quote et le moment de l'exécution.

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

Les swaps AMM v4 sont lourds en calcul car chaque instruction valide l'état complet d'OpenBook. Un swap typique utilise 180k–250k CU selon le nombre de commandes ouvertes à régler en chemin. Passez toujours 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 depuis votre propre programme Anchor, vous devrez modéliser la liste de comptes de `SwapBaseIn` exactement. Un esquisse minimale :

```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 CPI. L'esquisse ci-dessus utilise une `Instruction` construite manuellement.

<Note>
  L'esquisse CPI ci-dessus utilise la **disposition héritée v1 `SwapBaseIn`** (tag 9, 17 comptes) pour lire/reproduire les transactions existantes. Depuis la mise à jour de 2026-07, les comptes de marché sont acceptés mais ignorés. **Pour le nouveau code, préférez `SwapBaseInV2` / `SwapBaseOutV2`** (tags 16 / 17), qui suppriment les comptes de marché (et `amm_open_orders`) entièrement — passez seulement 8 comptes : `token_program`, `amm`, `amm_authority`, les deux coffres du pool, les deux comptes de tokens utilisateur, et `user_owner`.
</Note>

## Pièges

* **Mauvais nombre de comptes sur les swaps v1.** Les anciens `SwapBaseIn` / `SwapBaseOut` nécessitent toujours la liste complète de 17 comptes (ou 18 comptes) — un *nombre* mal assorti revient avec `WrongAccountsNumber`. Le *contenu* des comptes de marché n'est plus validé, mais vous devez toujours occuper leurs emplacements. Préférez les points d'entrée V2 pour éviter cela.
* **Lecture des soldes bruts des coffres.** Les réserves sont maintenant réservées aux coffres ; soustrayez le PnL accumulé (`need_take_pnl_*`). Le devis du SDK ou `api-v3.raydium.io/pools/info/ids` gère cela pour vous.
* **Appel d'instructions supprimées.** `MonitorStep`, `MigrateToOpenBook`, `WithdrawSrm`, `SimulateInfo`, `AdminCancelOrders`, et les anciens `Initialize` / `PreInitialize` reviennent maintenant. Utilisez `Initialize2` pour la création de pools ; il n'y a pas de crank à appeler.
* **Mints Token-2022.** Non supportés. Un pool AMM v4 ne peut pas être créé contre un mint Token-2022 ; toute paire Token-2022 doit être sur CPMM ou CLMM.

## Où aller ensuite

* [`products/amm-v4/instructions`](/fr/products/amm-v4/instructions) — la surface au niveau des instructions derrière ces exemples.
* [`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)
* [Programme Raydium AMM](https://github.com/raydium-io/raydium-amm)
