SwiftHTML & CSSSolidityDesenvolvimento de JogosSolana/Rust
18.11.2024

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

  1. Endereços de Programas: Todo programa implantado possui um endereço único na Solana.
  2. Contas: Os programas podem ler e gravar em contas que possuem ou que são passadas como argumentos.
  3. 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.

  1. Implemente o programa receptor e obtenha o ID do programa.
  2. Implemente o programa remetente e obtenha o ID do programa.
  3. Crie uma conta para armazenar dados do programa receptor:
solana create-account <RECEIVER_PROGRAM_ID> --lamports <quantidade>
  1. 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!

Did you like this article? Rate it from 1 to 5:

Thank you for voting!