Invocación entre programas

En esta sección, el programa CRUD de la sección anterior de PDA se actualiza añadiendo Invocaciones entre programas (CPIs), una característica que permite a los programas de Solana invocarse entre sí.

Este tutorial también muestra cómo los programas pueden "firmar" por Program Derived Addresses (PDAs) cuando realizan Invocaciones entre programas.

Las instrucciones update y delete necesitan modificación para manejar transferencias de SOL entre cuentas invocando el System Program.

El propósito de esta sección incluye recorrer el proceso de implementación de CPIs en un programa de Solana usando el framework Anchor, basándose en los conceptos de PDA explorados en la sección anterior. Para más detalles, consulta la página Invocación entre programas.

Como referencia, este enlace incluye el código final después de completar tanto la sección de PDA como la de CPI.

El código inicial para esta sección incluye solo la sección de PDA completada.

Actualizar la instrucción de actualización

Primero, el programa necesita un mecanismo simple de "pago por actualización" cambiando la estructura Update y la función update.

Comienza actualizando el archivo lib.rs para incluir elementos del módulo system_program.

lib.rs
use anchor_lang::system_program::{transfer, Transfer};

A continuación, actualiza la estructura Update para incluir una nueva cuenta llamada vault_account. Esta cuenta, controlada por el programa, recibe SOL de un usuario cuando actualizan su cuenta de mensaje.

lib.rs
#[account(
mut,
seeds = [b"vault", user.key().as_ref()],
bump,
)]
pub vault_account: SystemAccount<'info>,

A continuación, añade la lógica CPI en la instrucción update para transferir 0.001 SOL desde la cuenta del usuario a la cuenta de la bóveda.

lib.rs
let transfer_accounts = Transfer {
from: ctx.accounts.user.to_account_info(),
to: ctx.accounts.vault_account.to_account_info(),
};
let cpi_context = CpiContext::new(
ctx.accounts.system_program.to_account_info(),
transfer_accounts,
);
transfer(cpi_context, 1_000_000)?;

Reconstruye el programa.

Terminal
$
build

Actualiza la instrucción Delete

Ahora añade un mecanismo de "reembolso al eliminar" cambiando la estructura Delete y la función delete.

Primero, actualiza la estructura Delete para incluir el vault_account. Esto permite transferir cualquier SOL en el vault de vuelta al usuario cuando cierran su cuenta de mensaje.

lib.rs
#[account(
mut,
seeds = [b"vault", user.key().as_ref()],
bump,
)]
pub vault_account: SystemAccount<'info>,

También añade el system_program ya que el CPI para la transferencia requiere invocar el System Program.

lib.rs
pub system_program: Program<'info, System>,

A continuación, añade la lógica CPI en la instrucción delete para transferir SOL desde la cuenta vault de vuelta a la cuenta del usuario.

lib.rs
let user_key = ctx.accounts.user.key();
let signer_seeds: &[&[&[u8]]] =
&[&[b"vault", user_key.as_ref(), &[ctx.bumps.vault_account]]];
let transfer_accounts = Transfer {
from: ctx.accounts.vault_account.to_account_info(),
to: ctx.accounts.user.to_account_info(),
};
let cpi_context = CpiContext::new(
ctx.accounts.system_program.to_account_info(),
transfer_accounts,
).with_signer(signer_seeds);
transfer(cpi_context, ctx.accounts.vault_account.lamports())?;

Ten en cuenta que _ctx: Context<Delete> cambia a ctx: Context<Delete> para usar el contexto en el cuerpo de la función.

Reconstruye el programa.

Terminal
$
build

Redesplegar el programa

Después de hacer estos cambios, redespliegua el programa actualizado. Esto asegura que el programa modificado esté disponible para pruebas. En Solana, actualizar un programa simplemente requiere desplegar el programa con el mismo ID de programa.

Asegúrate de que tu cartera de Playground tenga SOL de devnet. Obtén SOL de devnet desde el Faucet de Solana.

Terminal
$
deploy

Actualizar archivo de prueba

A continuación, actualiza el archivo anchor.test.ts para incluir la nueva cuenta vault en las instrucciones. Esto requiere derivación de la PDA del vault e incluirla en las llamadas de instrucción de actualización y eliminación.

Derivar PDA de la bóveda

Primero, añade la derivación PDA de la bóveda:

anchor.test.ts
const [vaultPda, vaultBump] = PublicKey.findProgramAddressSync(
[Buffer.from("vault"), wallet.publicKey.toBuffer()],
program.programId
);

Cambiar prueba de actualización

Luego, actualiza la instrucción de actualización para incluir el vaultAccount

anchor.test.ts
const transactionSignature = await program.methods
.update(message)
.accounts({
messageAccount: messagePda,
vaultAccount: vaultPda
})
.rpc({ commitment: "confirmed" });

Cambiar prueba de eliminación

Luego, actualiza la instrucción de eliminación para incluir el vaultAccount

anchor.test.ts
const transactionSignature = await program.methods
.delete()
.accounts({
messageAccount: messagePda,
vaultAccount: vaultPda
})
.rpc({ commitment: "confirmed" });

Volver a ejecutar la prueba

Después de hacer estos cambios, ejecuta las pruebas para asegurarte de que todo funciona como se espera:

Terminal
$
test

Luego puedes inspeccionar los enlaces de SolanaFM para ver los detalles de la transacción, donde encontrarás los CPIs para las instrucciones de transferencia dentro de las instrucciones de actualización y eliminación.

CPI de actualizaciónCPI de actualización

CPI de eliminaciónCPI de eliminación

Si encuentras algún error, puedes consultar el código final.

Próximos pasos

Felicidades por completar la guía de inicio rápido de Solana. Has adquirido experiencia práctica con conceptos clave de Solana, incluyendo:

  • Obtener y leer datos de cuentas
  • Construir y enviar transacciones
  • Desplegar y actualizar programas de Solana
  • Trabajar con Program Derived Addresses (PDAs)
  • Realizar Cross-Program Invocations (CPIs)

Para profundizar tu comprensión de estos conceptos, consulta la documentación de Conceptos fundamentales que proporciona explicaciones detalladas de los temas cubiertos en esta guía.

Explora más ejemplos

Si prefieres aprender con ejemplos, consulta el Repositorio de ejemplos de programas para ver una variedad de programas de ejemplo.

Solana Playground ofrece una función conveniente que te permite importar o ver proyectos usando sus enlaces de GitHub. Por ejemplo, abre este enlace de Solana Playground para ver el proyecto Anchor de este repositorio de Github.

Haz clic en el botón Import e introduce un nombre de proyecto para añadirlo a tu lista de proyectos en Solana Playground. Una vez que un proyecto se importa, todos los cambios se guardan y persisten automáticamente.

Is this page helpful?

Tabla de Contenidos

Editar Página