CPIs ohne PDA-Signer

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.

Invoke function
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 CpiContext und Hilfsfunktion.
  • Beispiel 2: Verwendet die system_instruction::transfer Funktion aus der solana_program Crate.
  • 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 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?

Inhaltsverzeichnis

Seite bearbeiten

Verwaltet von

© 2026 Solana Foundation.
Alle Rechte vorbehalten.
Verbinden Sie sich