Resumo
Use invoke para CPIs onde todos os signatários necessários já assinaram
a transação original. Não é necessária assinatura PDA. Os privilégios de
signatário e escrita estendem-se do chamador para o chamado.
CPIs sem signatários PDA
Quando uma CPI não requer signatários PDA, a função
invoke
é usada. A função invoke chama a função invoke_signed com um array
signers_seeds vazio. O array de signatários vazio indica que não são
necessários PDAs para assinatura.
pub fn invoke(instruction: &Instruction, account_infos: &[AccountInfo]) -> ProgramResult {invoke_signed(instruction, account_infos, &[])}
Os exemplos abaixo fazem uma CPI usando Anchor e Rust nativo. Inclui uma única instrução que transfere SOL de uma conta para outra.
Anchor
Os exemplos seguintes mostram duas abordagens para implementar CPIs num programa Anchor. Os exemplos são funcionalmente equivalentes, mas demonstram diferentes níveis de abstração.
- Exemplo 1: Usa
CpiContexte função auxiliar do Anchor. - Exemplo 2: Usa a função
system_instruction::transferda cratesolana_program. - Exemplo 3: Constrói a instrução CPI manualmente. Esta abordagem é útil quando não existe uma crate para ajudar a construir a instrução que deseja invocar.
use anchor_lang::prelude::*;use anchor_lang::system_program::{transfer, Transfer};declare_id!("9AvUNHjxscdkiKQ8tUn12QCMXtcnbR9BVGq3ULNzFMRi");#[program]pub mod cpi {use super::*;pub fn sol_transfer(ctx: Context<SolTransfer>, amount: u64) -> Result<()> {let from_pubkey = ctx.accounts.sender.to_account_info();let to_pubkey = ctx.accounts.recipient.to_account_info();let program_id = ctx.accounts.system_program.to_account_info();let cpi_context = CpiContext::new(program_id,Transfer {from: from_pubkey,to: to_pubkey,},);transfer(cpi_context, amount)?;Ok(())}}#[derive(Accounts)]pub struct SolTransfer<'info> {#[account(mut)]sender: Signer<'info>,#[account(mut)]recipient: SystemAccount<'info>,system_program: Program<'info, System>,}
Rust
O exemplo seguinte mostra como fazer uma CPI a partir de um programa escrito em Rust nativo. Inclui uma única instrução que transfere SOL de uma conta para outra. (O ficheiro de teste usa LiteSVM para testar o programa.)
use borsh::BorshDeserialize;use solana_program::{account_info::AccountInfo,entrypoint,entrypoint::ProgramResult,program::invoke,program_error::ProgramError,pubkey::Pubkey,system_instruction,};// Declare program entrypointentrypoint!(process_instruction);// Define program instructions#[derive(BorshDeserialize)]enum ProgramInstruction {SolTransfer { amount: u64 },}impl ProgramInstruction {fn unpack(input: &[u8]) -> Result<Self, ProgramError> {Self::try_from_slice(input).map_err(|_| ProgramError::InvalidInstructionData)}}pub fn process_instruction(_program_id: &Pubkey,accounts: &[AccountInfo],instruction_data: &[u8],) -> ProgramResult {// Deserialize instruction datalet instruction = ProgramInstruction::unpack(instruction_data)?;// Process instructionmatch instruction {ProgramInstruction::SolTransfer { amount } => {// Parse accountslet [sender_info, recipient_info, system_program_info] = accounts else {return Err(ProgramError::NotEnoughAccountKeys);};// Verify the sender is a signerif !sender_info.is_signer {return Err(ProgramError::MissingRequiredSignature);}// Create and invoke the transfer instructionlet transfer_ix = system_instruction::transfer(sender_info.key,recipient_info.key,amount,);invoke(&transfer_ix,&[sender_info.clone(),recipient_info.clone(),system_program_info.clone(),],)?;Ok(())}}}
Is this page helpful?