استدعاءات البرامج المتقاطعة بدون موقعين PDA

ملخص

استخدم invoke لاستدعاءات البرامج المتقاطعة حيث جميع الموقعين المطلوبين قد وقعوا بالفعل على المعاملة الأصلية. لا حاجة لتوقيع PDA. تمتد صلاحيات الموقع والكتابة من المستدعي إلى المستدعى.

استدعاءات البرامج المتقاطعة بدون موقعين PDA

عندما لا يتطلب استدعاء برنامج متقاطع موقعين PDA، يتم استخدام دالة invoke. تستدعي دالة invoke دالة invoke_signed مع مصفوفة signers_seeds فارغة. تشير مصفوفة الموقعين الفارغة إلى أنه لا توجد حاجة لـ PDAs للتوقيع.

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

توضح الأمثلة أدناه كيفية إجراء استدعاء برنامج متقاطع باستخدام Anchor و Rust الأصلي. تتضمن تعليمة واحدة تنقل SOL من حساب إلى آخر.

Anchor

توضح الأمثلة التالية طريقتين لتنفيذ استدعاءات البرامج المتقاطعة في برنامج Anchor. الأمثلة متكافئة وظيفياً، لكنها توضح مستويات مختلفة من التجريد.

  • المثال 1: يستخدم CpiContext من Anchor ودالة مساعدة.
  • المثال 2: يستخدم دالة system_instruction::transfer من مكتبة solana_program.
  • المثال 3: يبني تعليمة الاستدعاء المتقاطع يدوياً. هذا النهج مفيد عندما لا توجد مكتبة للمساعدة في بناء التعليمة التي تريد استدعاءها.
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

يوضح المثال التالي كيفية إجراء استدعاء برنامج متقاطع من برنامج مكتوب بلغة 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 مؤسسة سولانا.
جميع الحقوق محفوظة.
تواصل معنا