Zusammenfassung
Verwenden Sie invoke für CPIs, bei denen alle erforderlichen Signer
bereits die ursprüngliche Transaktion signiert haben. Es ist keine
PDA-Signierung erforderlich. Signer- und Schreibrechte werden vom Aufrufer auf
den Aufgerufenen übertragen.
CPIs ohne PDA-Signer
Wenn ein CPI keine PDA-Signer erfordert, wird die
invoke
Funktion verwendet. Die invoke Funktion ruft die invoke_signed
Funktion mit einem leeren signers_seeds Array auf. Das leere Signer-Array
zeigt an, dass keine PDAs für die Signierung erforderlich sind.
pub fn invoke(instruction: &Instruction, account_infos: &[AccountInfo]) -> ProgramResult {invoke_signed(instruction, account_infos, &[])}
Die folgenden Beispiele führen einen CPI mit Anchor und Native Rust durch. Es enthält eine einzelne Instruction, die SOL von einem Konto auf ein anderes überträgt.
Anchor
Die folgenden Beispiele zeigen zwei Ansätze zur Implementierung von CPIs in einem Anchor Programm. Die Beispiele sind funktional gleichwertig, demonstrieren aber unterschiedliche Abstraktionsebenen.
- Beispiel 1: Verwendet Anchors
CpiContextund Hilfsfunktion. - Beispiel 2: Verwendet die
system_instruction::transferFunktion aus dersolana_programCrate. - Beispiel 3: Konstruiert die CPI-Instruction manuell. Dieser Ansatz ist nützlich, wenn keine Crate existiert, die beim Erstellen der Instruction hilft, die Sie aufrufen möchten.
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
Das folgende Beispiel zeigt, wie man einen CPI aus einem in Native Rust geschriebenen Programm durchführt. Es enthält eine einzelne Instruction, die SOL von einem Konto auf ein anderes überträgt. (Die Testdatei verwendet LiteSVM zum Testen des Programms.)
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?