Aula 068: Desenvolvendo Interações Entre Programas
No ecossistema Solana, aplicativos descentralizados frequentemente exigem que programas (contratos inteligentes) interajam entre si. Essa interação é conhecida como invocação entre programas (CPI, do inglês Cross-Program Invocation). Nesta aula, vamos explorar como criar e utilizar CPIs em Solana, juntamente com exemplos práticos para ilustrar o conceito.
Compreendendo a Invocação Entre Programas (CPI)
A invocação entre programas permite que um programa Solana chame outro, fornecendo um mecanismo para comunicação inter-programas. Esse recurso é particularmente útil para compor funcionalidades oferecidas por múltiplos programas, habilitando aplicações DeFi complexas, trocas de tokens e muito mais.
Conceitos Chave
- Endereços de Programas: Todo programa implantado possui um endereço único na Solana.
- Contas: Os programas podem ler e gravar em contas que possuem ou que são passadas como argumentos.
- Dados de Instrução: Os programas podem enviar e receber dados de instrução, que é um formato serializado que especifica o que o programa chamado deve fazer.
Exemplo: Invocação Básica Entre Programas
Neste exemplo, vamos criar dois programas simples na Solana: um programa remetente que chama um programa receptor e atualiza um determinado estado.
Passo 1: Criar o Programa Receptor
Primeiro, vamos criar um programa receptor que armazena um número inteiro e permite a recuperação e atualização desse número.
// receiver/src/lib.rs
use solana_program::{
account_info::{next_account_info, AccountInfo},
entrypoint::{ProgramResult, Entrypoint},
entrypoint,
msg,
program_error::ProgramError,
pubkey::Pubkey,
};
#[entrypoint]
pub fn process_instruction(
_program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
let accounts_iter = &mut accounts.iter();
let account = next_account_info(accounts_iter)?;
// Verificar se os dados de instrução estão corretos
if instruction_data.len() != 4 {
return Err(ProgramError::InvalidInstructionData);
}
let num = u32::from_le_bytes(instruction_data.try_into().unwrap());
// Armazenar o número nos dados da conta
let mut data = account.try_borrow_mut_data()?;
data[..4].copy_from_slice(&num.to_le_bytes());
msg!("Receptor: Armazenado {}", num);
Ok(())
}
Passo 2: Criar o Programa Remetente
A seguir, vamos criar um programa remetente que invoca o programa receptor, passando o número inteiro a ser armazenado.
// sender/src/lib.rs
use solana_program::{
account_info::{next_account_info, AccountInfo},
entrypoint::{ProgramResult, Entrypoint},
entrypoint,
msg,
program::{invoke_signed, invoke},
pubkey::Pubkey,
system_instruction,
program_error::ProgramError,
};
#[entrypoint]
pub fn process_instruction(
_program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
let accounts_iter = &mut accounts.iter();
let sender_account = next_account_info(accounts_iter)?;
let receiver_program_account = next_account_info(accounts_iter)?;
let data_account = next_account_info(accounts_iter)?;
// Chamar o programa receptor
invoke(
&solana_program::instruction::Instruction {
program_id: *receiver_program_account.key,
accounts: vec![data_account.clone()],
data: instruction_data.to_vec(),
},
&[
sender_account.clone(),
receiver_program_account.clone(),
data_account.clone(),
],
)?;
msg!("Remetente: Invocou o programa receptor com dados {:?}", instruction_data);
Ok(())
}
Passo 3: Implantar e Interagir
Após escrever e compilar ambos os programas, implante-os usando a CLI do Solana ou uma ferramenta de implantação semelhante. Para garantir que eles interajam corretamente, você precisará criar uma conta que será usada como armazenamento de dados para o programa receptor.
- Implemente o programa receptor e obtenha o ID do programa.
- Implemente o programa remetente e obtenha o ID do programa.
- Crie uma conta para armazenar dados do programa receptor:
solana create-account <RECEIVER_PROGRAM_ID> --lamports <quantidade>
- Invocar o programa remetente com os dados do número inteiro desejado:
solana invoke <SENDER_PROGRAM_ID> --data <seu_inteiro_como_bytes>
Conclusão
A invocação entre programas é um recurso poderoso na Solana que permite que múltiplos contratos trabalhem juntos, aprimorando a funcionalidade de aplicativos descentralizados. Nesta aula, criamos dois programas simples, demonstrando como invocar um a partir do outro.
Isso é apenas o começo do que você pode realizar com CPIs na Solana. À medida que você se sentir mais confortável com os conceitos, considere explorar casos de uso e padrões mais complexos, como transferências de tokens, trocas e construção sobre protocolos DeFi existentes. Boa codificação!