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

# Demostraciones de código AMM v4

> Ejemplos en TypeScript para realizar swaps contra un pool AMM v4 existente y proporcionar liquidez. La creación de nuevos pools está fuera del alcance — utiliza CPMM en su lugar.

<Info>
  **Esta página fue traducida automáticamente por IA. La versión en inglés es la fuente autorizada.**

  [Ver versión en inglés →](/products/amm-v4/code-demos)
</Info>

<Info>
  **Banner de versión.** Todas las demostraciones se orientan a `@raydium-io/raydium-sdk-v2@0.2.42-alpha` contra la red principal de Solana (mainnet-beta), verificado 2026-04. ID del programa: `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8` (ver [`reference/program-addresses`](/es/reference/program-addresses)).
</Info>

<Info>
  **La creación de nuevos pools no se muestra aquí.** La interfaz de Raydium ya no ofrece creación de pools AMM v4 — los nuevos pares por defecto van a [CPMM](/es/products/cpmm/code-demos). El programa AMM v4 en sí todavía acepta `Initialize2` en cadena; simplemente no es la ruta recomendada. Las demostraciones a continuación cubren las operaciones de pool activo que todo integrador necesita: swap, depósito, retiro.
</Info>

## Configuración

```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" });
```

## Obtener un pool por ID

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

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

// Extrae el objeto del pool normalizado por el SDK. Para AMM v4, esto incluye las cuentas
// de OpenBook que los constructores de instrucciones necesitarán.
const data = await raydium.liquidity.getPoolInfoFromRpc({ poolId });
const { poolInfo, poolKeys, poolRpcData } = data;

console.log("Par:", poolInfo.mintA.symbol, "/", poolInfo.mintB.symbol);
console.log("Versión:", poolInfo.version);       // 4 para AMM v4
console.log("Mercado:", poolKeys.marketId.toBase58());
```

`poolKeys` es la estructura que consumen los constructores de instrucciones. Contiene todas las cuentas AMM v4 y OpenBook en el orden que el programa espera.

## Swap (entrada en base)

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

const amountIn = new BN(1_000_000);            // 1 USDC (cotización de 6 decimales)
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("Tx de swap:", txId);
```

El SDK añade automáticamente cada cuenta de OpenBook. No intentes sustituirlas manualmente — el programa valida cada posición.

## Swap (salida en base)

```ts theme={null}
const amountOut = new BN(1_000_000_000);       // 1 SOL (base de 9 decimales)
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 });
```

## Agregar liquidez

```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"` le indica al SDK que suministraste el `amountInA` exacto y que `amountInB` debe ser como máximo `maxAnotherAmount`. La liquidez en libro del pool se liquida antes del cálculo prorrateado para que la ratio de depósito coincida con las reservas más recientes.

## Retirar liquidez

```ts theme={null}
const lpAmount = new BN(50_000);               // LP a quemar

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

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

Los mínimos de slippage protegen contra cambios en el estado del pool entre tu precotización y el momento de la ejecución.

## Sintonización de unidad de cálculo / tarifa de prioridad

Los swaps de AMM v4 son intensivos en cálculo porque cada instrucción valida el estado completo de OpenBook. Un swap típico usa 180k–250k CU dependiendo de cuántas órdenes abiertas necesiten liquidarse en el camino. Siempre especifica un límite de unidad de cálculo:

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

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

Si omites `computeBudgetConfig`, el SDK aún puede usar su propio valor por defecto; inspecciona `innerTransactions` para confirmar. Ver [`integration-guides/priority-fee-tuning`](/es/integration-guides/priority-fee-tuning).

## CPI directo de Rust

Si debes hacer CPI en AMM v4 desde tu propio programa Anchor, necesitarás modelar la lista de cuentas de `SwapBaseIn` exactamente. Un boceto mínimo:

```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<()> {
    // El discriminador de instrucción para SwapBaseIn es 9 en 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 no incluye una caja Anchor para CPI. El boceto anterior utiliza una `Instruction` construida manualmente.

## Trampas comunes

* **Falta una cuenta de OpenBook.** Las 8 cuentas del lado de OpenBook son obligatorias en cada swap, depósito y retiro; el SDK se encarga de esto, pero las instrucciones construidas manualmente a menudo no.
* **Leer saldos brutos de bóvedas.** No refleja montos en custodia en libro o PnL acumulado. Usa la cotización del SDK o `api-v3.raydium.io/pools/info/ids`.
* **Cola de eventos de OpenBook llena.** Un pool puede revertir swaps con `SerumOrderError` cuando la cola de eventos de su mercado necesita ser procesada. El procesamiento es permissionless (`MonitorStep` en las cuentas OpenBook del mercado).
* **Mints de Token-2022.** No soportados. Un pool AMM v4 no puede crearse contra un mint de Token-2022; cualquier par de Token-2022 debe estar en CPMM o CLMM.

## Por dónde continuar

* [`products/amm-v4/instructions`](/es/products/amm-v4/instructions) — la superficie a nivel de instrucción detrás de estas demostraciones.
* [`user-flows/migrate-amm-v4-to-cpmm`](/es/user-flows/migrate-amm-v4-to-cpmm) — si eres un LP considerando migración.
* [`integration-guides/priority-fee-tuning`](/es/integration-guides/priority-fee-tuning) — dimensionamiento de tarifa de prioridad para swaps pesados de AMM v4.

Fuentes:

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