Skip to main content
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 →
sdk-api/rust-cpi cubre la mecánica de bajo nivel para invocar cada programa de Raydium. Esta página es la acompañante de nivel superior: por qué compondrías Raydium en tu propio programa, qué patrón se ajusta a tu caso de uso, y el código de integración completo que necesitas de principio a fin.

Cuándo CPI es la herramienta correcta

Un programa personalizado tiene sentido cuando el intercambio debe ocurrir de forma atómica con otros cambios de estado on-chain que solo tu programa puede hacer. Casos comunes:
  • Programas de depósito en garantía / órdenes limitadas — el usuario deposita un mint en tu depósito en garantía, tu programa observa una condición de precio, y cuando se activa, tu programa intercambia atómicamente a través de Raydium y acredita la cuenta del usuario.
  • Proxies agregadores — una única instrucción que enruta un intercambio a través de Raydium + uno o más DEXes adicionales, con todos los saltos bajo una única verificación de slippage propiedad de tu programa.
  • Bóvedas de auto-compounding — deposita LP o participación en granja en tu bóveda, la bóveda cosecha recompensas en un cronograma, re-suministra liquidez, emite tokens de participación.
  • Bóvedas de estrategia — posiciones LP apalancadas que se reequilibran intercambiando a través de CLMM; liquidadores que cierran posiciones e intercambian garantía en una transacción.
  • Plataformas de lanzamiento de tokens con vesting personalizado — tu programa mantiene tokens de vesting y los libera en un pool de Raydium en un cronograma.
Si solo quieres enviar un intercambio desde código off-chain, CPI es excesivo — usa el SDK. CPI justifica su complejidad solo cuando la atomicidad con tu propio estado es el requisito.

Patrones de composición

Patrón 1: Proxy delgado

Tu programa expone una única instrucción que valida alguna política (p. ej. pares de mint en lista blanca, descuento de tarifa para usuarios verificados) y luego reenvía a Raydium.
El estado vive en los ATAs del usuario. Tu programa no posee tokens. Huella de confianza mínima.

Patrón 2: Depósito en garantía

Tu programa posee un PDA que mantiene el mint de entrada del usuario. Al activarse, el PDA firma un CPI a Raydium para intercambiar su propio saldo.
Detalle crítico: el PDA firma a través de CpiContext::new_with_signer. Ver Semillas de firmante PDA.

Patrón 3: Multi-salto compuesto

Tu programa emite múltiples CPIs en una instrucción, aplicando un único límite de slippage en todos ellos. Las instrucciones de intercambio de Raydium tienen cada una su propio minimum_amount_out, pero estableces esos en 0 (o un piso muy flexible) y aplicas un mínimo final estricto después del último salto.
Esto te da una única puerta de reversión para toda la ruta. Solo usa este patrón cuando confíes en que cada salto sea seguro en slippage; de lo contrario, deja que cada salto aplique su propio mínimo.

Patrón 4: Bóveda / estrategia

Tu programa mantiene tokens LP o participación en granja en un PDA. Un guardián (o el usuario) llama a compound(), que:
  1. Cosecha recompensas de la granja.
  2. Intercambia recompensas por tokens de pool (CPI en CPMM o CLMM).
  3. Deposita los ingresos de vuelta en el LP (otro CPI).
  4. Participa en el nuevo LP (otro CPI).
Todo en una transacción para que el NAV de la bóveda se mueva atómicamente. El presupuesto de cómputo es típicamente 600k–1M CU; las tablas de búsqueda de direcciones son obligatorias.

Construcción de lista de cuentas

La estructura Accounts del programa que llama refleja el orden de cuentas del programa de Raydium, pero la mayoría de las cuentas del lado de Raydium son UncheckedAccount porque Raydium las valida a sí mismo. Solo añades restricciones en cuentas que tú posees:
La asimetría — validación estricta en tus cuentas, UncheckedAccount en las de Raydium — no es pereza. El receptor valida las suyas; validar dos veces en el llamador solo quema CU y arriesga desincronización cuando Raydium envía un nuevo campo de diseño de struct.

La llamada CPI en sí

Semillas de firmante PDA

El CPI solo tiene éxito si el PDA pasado como authority coincide con la derivación que el llamador afirma. Los dos deben estar de acuerdo en:
  1. La secuencia de bytes de semilla (aquí [b"escrow", user.key().as_ref()]).
  2. El bump.
  3. El ID del programa que llama (tu programa, no el de Raydium).
Ten en cuenta qué debe coincidir el PDA. La ranura authority de CPMM es su propio PDA de bóveda — una cuenta fija de todo el programa que deriva y firma a sí mismo, y que tu programa ni controla ni sustituye. La cuenta con la que tus semillas PDA tienen que alinearse es payer: la verificación ocurre dentro del ayudante transfer_from_user_to_pool_vault propio de CPMM, que requiere que la cuenta pasada como payer sea la propietaria de input_token_account. Error común: pasar user como payer mientras escrow_input_ata es propiedad del PDA de depósito en garantía. El programa SPL Token rechaza con owner mismatch. Siempre haz que payer sea el propietario del ATA — y firma por él con new_with_signer cuando ese propietario es un PDA.

Cuentas restantes

Varias instrucciones de Raydium toman una lista de longitud variable de cuentas añadidas después de las fijas — cuentas restantes.
  • CLMM SwapV2: 1–8 cuentas TickArrayState para los arrays de tick que el intercambio puede atravesar, en dirección de intercambio.
  • Farm v6 Deposit / Harvest / Withdraw: pares (reward_vault, user_reward_ata), un par por ranura de recompensa activa.
  • Mints de transfer-hook de Token-2022: el programa de transfer-hook más cualquier cuenta que el hook necesite.
Los ayudantes CPI de Anchor no verifican tipos en cuentas restantes. Pásalas a través:
El orden importa. Para CLMM:
Para cosecha de farm v6:
Tu programa que llama debe pasar las cuentas restantes que recibe del cliente sin cambios. No intentes filtrarlas o reordenarlas.

Presupuesto de cómputo para llamadas compuestas

Un CPI cuesta ~1,500 CU por el marco de llamada en sí; el uso de CU propio del llamado se apila encima. Las figuras del llamado abajo se midieron de transacciones mainnet en vivo en pools de alto volumen el 2026-09-09, leídas de la línea de log Program <id> consumed N of M compute units para la propia invocación del programa de Raydium (así que incluyen sus CPIs internos de programa de token): Añade ~1,500 por cada marco CPI y la sobrecarga de tu propio programa encima. El costo de intercambio CLMM se escala con cruces de tick, así que trata su figura como un piso. Los mints de Token-2022 añaden el costo de manejo de extensión de la transferencia en sí; mídelo para tus propios mints en lugar de aplicar un multiplicador plano.
Revisiones anteriores de esta página llevaban estimaciones 5–7× más altas (un intercambio CPMM de ~150,000 CU, ~180,000 para CLMM). Esos nunca fueron medidos. Presupuesta desde tu propia lectura de computeUnitsConsumed, no desde un número documentado — y ten en cuenta que una transacción completa cuesta más que la instrucción de Raydium sola una vez que se cuentan creación de ATA, envoltura de wSOL e instrucciones de presupuesto de cómputo.
Siempre establece un ComputeBudgetProgram::set_compute_unit_limit explícito:
El techo de 200k CU predeterminado se agotará silenciosamente mucho antes de que una llamada compuesta se complete.

Propagación de errores

Los programas de Raydium devuelven errores de Anchor con códigos de error estables. Tu programa que llama los ve como Err(ProgramError::Custom(code)). Propágalos por defecto:
O intercepta códigos específicos:
Ten en cuenta el término ERROR_CODE_OFFSET: las variantes #[error_code] se emiten comenzando en 6000, así que comparar contra el discriminante de enum desnudo nunca coincide. (No hay ayudante is_err en anchor-lang o en raydium_cp_swap — revisiones anteriores de esta página usaban uno que no existe.) La asignación de código de error a significado es estable según la política de IDL (sdk-api/anchor-idl); nuevos códigos se añaden al final, códigos existentes nunca cambian de significado.

Ejemplo completo trabajado: escrow de orden limitada

Flujo:
  1. open_order — el usuario deposita amount_in de input_mint en el PDA de depósito en garantía; registra min_amount_out objetivo y vencimiento.
  2. execute_order — cualquiera (guardián) llama con las cuentas de pool actuales. El programa verifica que la cotización actual ≥ min_amount_out, luego CPI intercambia Raydium y mantiene la salida en depósito en garantía.
  3. claim — el usuario retira el mint de salida del depósito en garantía.
El guardián paga la tarifa de transacción (obtiene una tarifa de guardián en otro lugar — no se muestra). El PDA order firma el CPI como payer, porque posee el ATA de entrada del depósito en garantía; ExecuteOrder por lo tanto también necesita un campo pool_authority: UncheckedAccount<'info> para el PDA de bóveda propio de CPMM. Tanto la verificación de slippage del lado de Raydium como la verificación de delta del propio depósito en garantía aplican el piso — doble seguridad.

Pruebas

Extrayendo programas de Raydium en un validador local para pruebas de integración (desde Anchor.toml):
Clona también las cuentas de estado del pool para que tus pruebas puedan ejecutar realmente intercambios; anchor test las obtiene de mainnet al inicio. Ver sdk-api/rust-cpi.

Trampas específicas de composición

Reentrancia

Solana no tiene verdadera reentrancia — un CPI no puede llamar de vuelta al programa originador en la misma invocación. Pero aún puedes construirte en una reentrancia lógica: un CPI que lee tu estado, luego tu código lo lee de nuevo asumiendo que el CPI no lo cambió. Para Raydium, los CPIs no tocan tu estado, así que esto es menos una preocupación que p. ej. contextos de flash-loan. Pero si compones Raydium con un protocolo de préstamo, ten cuidado.

Deriva de mutabilidad de cuenta

Si tu programa pasa una cuenta como mut pero Raydium la espera de solo lectura (o viceversa), el tiempo de ejecución rechaza la invocación con InvalidAccountData. Siempre verifica la mutabilidad esperada de la instrucción de Raydium en el IDL; raydium_cp_swap::cpi::accounts::Swap establece la mutabilidad de cada cuenta para ti, desde los marcadores #[account(mut)] en la estructura Swap propia de CPMM — los campos derivados son todos AccountInfo<'info> simples, así que es la implementación ToAccountMetas derivada, no los tipos de campo, la que lleva las banderas.

Campo de programa Token-2022

Los mints de entrada y salida pueden estar bajo diferentes programas de token — uno SPL Token, uno Token-2022. El CPI tiene campos input_token_program y output_token_program separados por esta razón. Siempre verifica el campo owner de cada mint y enruta el programa correcto en cada ranura.

Transacciones versionadas

Una tx compuesta que hace 2+ CPIs de Raydium más una creación de ATA raramente cabe en una transacción heredada (v0-sin-LUT). Usa V0 con tablas de búsqueda de direcciones; extrae los LUTs públicos de Raydium a través de raydium.getRaydiumLutAddresses().

Punteros

Fuentes: