CPI без підписувачів PDA

Підсумок

Використовуйте invoke для CPI, де всі необхідні підписувачі вже підписали оригінальну транзакцію. Підпис PDA не потрібен. Привілеї підписувача та запису поширюються від викликача до викликаного.

CPI без підписувачів PDA

Коли CPI не потребує підписувачів PDA, використовується функція invoke. Функція invoke викликає функцію invoke_signed з порожнім масивом signers_seeds. Порожній масив підписувачів вказує на те, що PDA для підпису не потрібні.

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

Наведені нижче приклади виконують CPI за допомогою Anchor та Native Rust. Вони включають одну інструкцію, яка переказує SOL з одного акаунта на інший.

Anchor

Наступні приклади демонструють два підходи до реалізації CPI у програмі Anchor. Приклади функціонально еквівалентні, але демонструють різні рівні абстракції.

  • Приклад 1: використовує CpiContext та допоміжну функцію Anchor.
  • Приклад 2: використовує функцію system_instruction::transfer з крейта solana_program.
  • Приклад 3: конструює інструкцію CPI вручну. Цей підхід корисний, коли не існує крейта для побудови інструкції, яку ви хочете викликати.
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

Наступний приклад показує, як виконати CPI з програми, написаної на Native Rust. Він включає одну інструкцію, яка переказує SOL з одного акаунта на інший. (Тестовий файл використовує LiteSVM для тестування програми.)

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?

Зміст

Редагувати сторінку

Керується

© 2026 Фонд Solana.
Всі права захищені.
Залишайтеся на зв'язку