CPI sans signataires PDA

Résumé

Utilisez invoke pour les CPI où tous les signataires requis ont déjà signé la transaction d'origine. Aucune signature PDA n'est nécessaire. Les privilèges de signataire et d'écriture s'étendent de l'appelant à l'appelé.

CPI sans signataires PDA

Lorsqu'une CPI ne nécessite pas de signataires PDA, la fonction invoke est utilisée. La fonction invoke appelle la fonction invoke_signed avec un tableau signers_seeds vide. Le tableau de signataires vide indique qu'aucun PDA n'est requis pour la signature.

Invoke function
pub fn invoke(instruction: &Instruction, account_infos: &[AccountInfo]) -> ProgramResult {
invoke_signed(instruction, account_infos, &[])
}

Les exemples ci-dessous effectuent une CPI en utilisant Anchor et Rust natif. Ils incluent une seule instruction qui transfère des SOL d'un compte à un autre.

Anchor

Les exemples suivants montrent deux approches pour implémenter des CPI dans un programme Anchor. Les exemples sont fonctionnellement équivalents, mais démontrent différents niveaux d'abstraction.

  • Exemple 1 : utilise le CpiContext d'Anchor et une fonction auxiliaire.
  • Exemple 2 : utilise la fonction system_instruction::transfer de la crate solana_program.
  • Exemple 3 : construit l'instruction CPI manuellement. Cette approche est utile lorsqu'aucune crate n'existe pour aider à construire l'instruction que vous souhaitez invoquer.
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

L'exemple suivant montre comment effectuer une CPI depuis un programme écrit en Rust natif. Il inclut une seule instruction qui transfère des SOL d'un compte à un autre. (Le fichier de test utilise LiteSVM pour tester le programme.)

use borsh::BorshDeserialize;
use solana_program::{
account_info::AccountInfo,
entrypoint,
entrypoint::ProgramResult,
program::invoke,
program_error::ProgramError,
pubkey::Pubkey,
system_instruction,
};
// Declare program entrypoint
entrypoint!(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 data
let instruction = ProgramInstruction::unpack(instruction_data)?;
// Process instruction
match instruction {
ProgramInstruction::SolTransfer { amount } => {
// Parse accounts
let [sender_info, recipient_info, system_program_info] = accounts else {
return Err(ProgramError::NotEnoughAccountKeys);
};
// Verify the sender is a signer
if !sender_info.is_signer {
return Err(ProgramError::MissingRequiredSignature);
}
// Create and invoke the transfer instruction
let 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?

Table des matières

Modifier la page

Géré par

© 2026 Fondation Solana.
Tous droits réservés.
Restez connecté