CPI không có PDA Signers

Tóm tắt

Sử dụng invoke cho các CPI khi tất cả signers cần thiết đã ký giao dịch ban đầu. Không cần PDA signing. Các đặc quyền signer và writable được mở rộng từ caller đến callee.

CPI không có PDA signers

Khi một CPI không yêu cầu PDA signers, hàm invoke được sử dụng. Hàm invoke gọi hàm invoke_signed với một mảng signers_seeds rỗng. Mảng signers rỗng cho biết rằng không có PDA nào cần thiết để ký.

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

Các ví dụ dưới đây thực hiện CPI bằng Anchor và Native Rust. Nó bao gồm một instruction duy nhất chuyển SOL từ tài khoản này sang tài khoản khác.

Anchor

Các ví dụ sau đây cho thấy hai cách tiếp cận để triển khai CPI trong một chương trình Anchor. Các ví dụ này tương đương về mặt chức năng, nhưng thể hiện các mức độ trừu tượng khác nhau.

  • Ví dụ 1: Sử dụng CpiContext và hàm helper của Anchor.
  • Ví dụ 2: Sử dụng hàm system_instruction::transfer từ crate solana_program.
  • Ví dụ 3: Xây dựng instruction CPI thủ công. Cách tiếp cận này hữu ích khi không có crate nào giúp xây dựng instruction bạn muốn invoke.
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

Ví dụ sau đây cho thấy cách thực hiện CPI từ một chương trình được viết bằng Native Rust. Nó bao gồm một instruction duy nhất chuyển SOL từ tài khoản này sang tài khoản khác. (File test sử dụng LiteSVM để test chương trình.)

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?

Mục lục

Chỉnh sửa trang

Quản lý bởi

© 2026 Solana Foundation.
Đã đăng ký bản quyền.
Kết nối