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ý.
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
CpiContextvà hàm helper của Anchor. - Ví dụ 2: Sử dụng hàm
system_instruction::transfertừ cratesolana_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 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?