Skip to main content
هذه الصفحة مُترجَمة آليًا بواسطة الذكاء الاصطناعي. النسخة الإنجليزية هي المرجع المعتمد.عرض النسخة الإنجليزية →
CPI (“cross-program invocation” أو استدعاء البرنامج المتقاطع) هي الآلية التي يستدعي بها برنامج Solana واحد برنامجًا آخر. تشحن معظم برامج Raydium مع crate غلاف CPI قائم على Anchor يجعل موقع الاستدعاء يبدو مثل استدعاء دالة مكتوبة بشكل صحيح، مع هياكل حسابات لها أسماء حقول تم التحقق منها ومساعدات cpi::<ix>(). توثق هذه الصفحة النمط العام مرة واحدة، ثم الاختلافات لكل برنامج. للحصول على TypeScript قابل للتشغيل، انظر صفحة code-demos في فصل كل منتج.

أي نمط ينطبق على أي برنامج

إذا كنت تدمج CPMM أو CLMM أو LaunchLab، اقرأ النمط العام أولاً، ثم انتقل إلى قسم برنامجك للحصول على قائمة الحسابات وأي اختلافات. Farm v6 و AMM v4 مختلفان بما يكفي لضمان قراءة أقسامهما بشكل مستقل.

تبعيات Cargo

يجب أن يطابق مفتاح التبعية اسم [package] في المستودع المستهدف بالضبط، بما في ذلك الواصلات. لا يعامل Cargo raydium_cp_swap كمكافئ لـ raydium-cp-swap عند حل تبعية git.
branch = "master" يتتبع أحدث مصدر منشور؛ ثبّت على rev = "<commit>" محدد إذا كنت بحاجة إلى بناء قابل للتكرار. يُنصح بهذا بمجرد الانتهاء من النماذج الأولية، لأن تغيير تخطيط الحساب في master سيكسر بناءك بدون تحذير. علم الميزة cpi يجعل crates تجميع السطح فقط من CPI (هياكل الحسابات + المستدعيات) بدلاً من البرنامج الكامل، لذا يبقى ملفك الثنائي صغيراً. يجب أن يطابق anchor-lang / anchor-spl ما يثبته crate المستهدف:
خذ كلا crate من نفس سطر Anchor. كلا فرع master يثبتان =1.0.2، لذا يمكن لبرنامج واحد أن يستدعي CPI إلى CPMM و CLMM من crate واحد. خلط الأسطر يكسر البناء: على سبيل المثال، raydium-cp-swap على master مع raydium-clmm مثبت على rev من قبل ترقية Anchor 1.0. سيضطر Cargo إلى ربط نسختين غير متوافقتين من سمات Anchor في ملف ثنائي واحد. إذا كنت عالقًا في زوج مختلط، قسّم البرنامج إلى اثنين، أو أسقط crate CPI المكتوب للجانب الآخر وقم بترميز هذا التعليمات يدويًا (النمط الموضح لـ AMM v4 يعمل مع أي برنامج).
غيّر Anchor 1.0 شيئين يلمسهما كل موقع استدعاء CPI. إذا كنت تنقل تكاملاً عاملاً من 0.3x:
  • CpiContext::new يأخذ Pubkey، وليس AccountInfo. CpiContext::new(ctx.accounts.cpmm_program.to_account_info(), accts) يصبح CpiContext::new(*ctx.accounts.cpmm_program.key, accts). نفس الشيء لـ new_with_signer. حقل الهيكل الآن program_id: Pubkey.
  • Context له عمر واحد، وليس أربعة. Context<'_, '_, 'info, 'info, MyProxySwap<'info>> يصبح Context<'info, MyProxySwap<'info>>.
على جانب العميل، RequestBuilder::instructions() من anchor-client يعيد الآن Vec<Instruction> بدلاً من Result<Vec<Instruction>> (أسقط ?)، و CommitmentConfig انتقل من solana-sdk — خذه من anchor_client بدلاً من ذلك. spl-associated-token-account 8.0 يعيد تصدير مساعداته من crate spl-associated-token-account-interface الجديد. get_associated_token_address و ID لا تزال قابلة للوصول في جذر crate (spl_associated_token_account::{get_associated_token_address, ID})، لكن مساعدات العنوان مهملة هناك — فضّل الاعتماد على spl-associated-token-account-interface مباشرة واستيراد spl_associated_token_account_interface::address::get_associated_token_address و spl_associated_token_account_interface::program::ID. لاحظ أن ::address و ::program هي وحدات من crate الواجهة؛ spl_associated_token_account::address::… لا تحل.
للحصول على أمثلة CPI عاملة تربط هياكل الحسابات من البداية إلى النهاية، انظر raydium-io/raydium-cpi-example (يغطي AMM v4 و CPMM و CLMM). أحدث فرع لها هو anchor-0.31.0 — لا يوجد فرع Anchor 1.x حتى الآن، لذا تعامل مع هذا المستودع كمرجع لـ ربط هيكل الحسابات، وليس لتثبيتات الإصدار التي تفرضها هذه الصفحة.

نمط Anchor CPI العام

يشرح هذا القسم CPMM من البداية إلى النهاية كمثال عملي: هيكل Accounts، CpiContext، cpi::<ix>(). يتبع CLMM الشكل المطابق تماماً، مع قائمة حسابات مختلفة ومتطلب remaining-accounts. يتبع LaunchLab نفس الآليات لكن قائمة حساباته تحتوي على عدة حسابات بلا مكافئ في CPMM/CLMM (global_config، platform_config، event_authority، program)، لذا تعامل معها كنفس النمط، وليس نفس الشكل. راجع قسم كل برنامج بدلاً من افتراض أن قائمة الحسابات في هذا الشرح تنطبق مباشرة.

بناء قائمة الحسابات

كل CPI من Raydium يتطلب هيكل Accounts في البرنامج الذي يستدعيه. حقوله هي أي حسابات تحتاجها تعليماتك، مع محققات على مستوى الحقل؛ ترتيب إعلانها لا يجب أن يطابق ترتيب حسابات تعليمات Raydium الخاصة، لأن عميل IDL الذي تم إنشاؤه يعالجها بالاسم وليس بالموضع:
معظم حسابات جانب Raydium هي UncheckedAccount لأن المستدعى (Raydium) يمتلك التحقق. برنامجك الذي يستدعي يتحقق بصرامة فقط من الحسابات التي تمتلكها، مثل ATAs المستخدم و PDAs الخاصة بك. تعليق /// CHECK: يقمع تحذير Anchor حول الفحوصات المفقودة. الاستثناء الوحيد من جانب Raydium هو cpmm_program نفسه: إنه البرنامج الذي يتم استدعاؤه وليس حساب بيانات يتحقق منه Raydium داخلياً، لذا يتم كتابته كـ Program<T> ويحصل على فحص العنوان التلقائي من Anchor بدلاً من فحص /// CHECK: يدوي. هذا الشكل الذي يحتوي على UncheckedAccount في الغالب، حيث يتحقق Raydium من حساباته الخاصة، هو نفسه بالنسبة لـ CLMM و LaunchLab. يفترض هذا المثال أن كلا الـ mints كلاسيكي SPL Token؛ إذا كان أي جانب يمكن أن يكون Token-2022 mint، أضف حقل token_program_2022: Program<'info, anchor_spl::token_2022::Token2022> وأمرره كـ input_token_program/output_token_program لذلك الجانب في استدعاء CPI أدناه بدلاً من token_program.

بناء استدعاء CPI

ينشئ Anchor مساعداً واحداً لكل تعليمة، مع هيكل حسابات CPI (cpi::accounts::Swap، مستعار كـ CpmmSwap أدناه). بخلاف هيكل MyProxySwap الخاص بك أعلاه، أسماء الحقول والترتيب في هذا الهيكل ثابتة بواسطة IDL الخاص بـ raydium-cp-swap ويجب أن تطابق بالضبط:
cpi::swap_base_input يتم إنشاؤه من IDL؛ قائمة حجته تعكس قائمة حجج تعليمات Anchor. كل برنامج Raydium مؤكد قائم على Anchor (CPMM، CLMM، LaunchLab) ينشئ مساعدات cpi::<ix>() بنفس الطريقة، مع تطابق اسم الدالة مع اسم التعليمة بصيغة snake_case. ما إذا كان هذا يمتد إلى Farm v6 غير مؤكد؛ راجع قسمه.

بذور الموقّع (CPI موقّع بـ PDA)

عندما يوقّع برنامجك على CPI نيابة عن PDA (شائع للخزائن والضمانات، إلخ)، استخدم CpiContext::new_with_signer:
يجب أن تطابق بذور الموقّع اشتقاق PDA. لأي حساب يتم تمريره كـ authority (أو دور موقّع مشابه)، يتحقق وقت تشغيل Solana من أن PDA يوقّع عبر هذه البذور.

الحسابات المتبقية

بعض تعليمات Raydium تأخذ حسابات متبقية، قائمة بطول متغير مُلحقة بعد الحسابات الثابتة. مساعدات CPI الخاصة بـ Anchor لا تفحص نوع الحسابات المتبقية؛ مررها عبر .with_remaining_accounts(...):
الترتيب مهم دائماً، لأن برنامج المستقبل يكرر الحسابات المتبقية بالترتيب الذي تمررها به. ترتيبان مؤكدان:
  • CLMM SwapV2: مصفوفات التجزئة، مرتبة اتجاهياً.
  • Farm v6: أزواج (reward_vault, user_reward_ata)، لكن فقط من تدفق المكافأة الثاني فما بعده؛ راجع Farm v6 لمعرفة ما يظهره فك تشفير معاملة حقيقية.

تطبيق النمط: CLMM

يتبع SwapV2 النمط العام أعلاه مع قائمة حسابات مختلفة ومتطلب remaining-accounts لمصفوفات التجزئة. وحدة #[program] الخاصة بـ crate مسماة raydium_clmm، وهي أيضاً مسار Rust use الخاص بها.
هيكل حسابات CPI مسمى SwapSingleV2، وليس SwapV2. SwapV2 هو اسم التعليمة على السلسلة.
احسب قائمة مصفوفة التجزئة بنفس الطريقة التي يفعلها SDK، عبر اقتباس ضد حالة المجموعة الحالية، بدلاً من تخمين عدد ثابت؛ مبادلة تتجاوز المصفوفات التي مررتها تعود مع TickArrayNotFound (راجع products/clmm/instructions للحصول على جدول الحسابات الكامل وقائمة الأخطاء). مررها في اتجاه المشي السعري: أول مصفوفة في اتجاه المبادلة أولاً.

تطبيق النمط: LaunchLab

LaunchLab مبني على Anchor ومنشور عبر IDL: raydium_launchpad/raydium_launchpad.json في مستودع raydium-idl العام. معرّف البيانات الوصفية الداخلي لهذا IDL هو raydium_launchpad، وهو اسم تقني للبرنامج الأساسي وليس اسماً بديلاً للمنتج. بخلاف CPMM و CLMM، الكود المصدري للبرنامج نفسه غير متاح للعموم (انظر reference/program-addresses). لا توجد تبعية git = "..." لتوجيه Cargo إليها، ولا يوجد مصدر للتحقق من مسار Rust use الفعلي للـ crate. أنشئ الربطات من IDL المنشور باستخدام ماكرو Anchor declare_program!. احفظ ملف JSON الخاص بـ IDL باسم idls/raydium_launchpad.json في crate الخاص بك (يبحث Cargo عن مجلد idls/ نسبة إلى CARGO_MANIFEST_DIR)، ثم declare_program!(raydium_launchpad); ينشئ هياكل raydium_launchpad::cpi::accounts::<Ix> ودوال cpi::<ix>() مباشرة من IDL، بدون الحاجة إلى مصدر البرنامج. اسم هيكل الحسابات المُنشأ هو دائماً اسم التعليمة بصيغة PascalCase (buy_exact_in → BuyExactIn)، وأسماء الحقول تطابق أسماء الحسابات في IDL بالضبط، نفس قائمة الحسابات المستخدمة بالفعل في MyProxyBuy أدناه. شكل CPI يتبع النمط العام. قائمة الحسابات والمعاملات أدناه تأتي من تعليمة buy_exact_in في IDL على السلسلة، وليس من products/launchlab/instructions.mdx:
بعد التخرج، البرنامج المستهدف هو CPMM أو AMM v4 حسب pool_state.migrate_type، والذي تقول products/launchlab/accounts.mdx أنه يُعيّن في وقت Initialize. قائمة حسابات CPI الخاصة بك يجب أن تكون مُعدّة لأي منهما، أو تحتاج إلى قراءة migrate_type من PoolState أولاً والتفرع.

نشر الأخطاء

كل برنامج Raydium مبني على Anchor يُرجع enum أخطاء خاص به؛ Anchor يلفّه، لذا برنامجك الذي يستدعي يرى الأخطاء كـ Err(ProgramError::Custom(code)). للتعامل مع أخطاء محددة:
استبدل نوع الخطأ ذا الصلة للبرنامج الذي تستدعيه (raydium_clmm::error::ErrorCode لـ CLMM، وهكذا). أرقام رموز الأخطاء مستقرة وفقاً لسياسة IDL (sdk-api/anchor-idl)، لذا يمكنك الاختبار مقابل رموز محددة بمقارنة القيمة الرقمية. جداول الأخطاء الكاملة: CPMM، CLMM، AMM v4، Farm v6، و LaunchLab.

ميزانية الحساب في CPIs المركبة

لكل إطار CPI تكلفة عامة، واستهلاك CU الخاص بالمستدعى يتراكم فوق استهلاكك، لذا معاملة تستدعي Raydium من داخل برنامجك تحتاج إلى ميزانية حساب صريحة بدلاً من الاعتماد على الحد الافتراضي 200k CU.
مقاس، وليس مقدّر. swap_base_input في CPMM على mainnet يستهلك ~23,000 CU في برنامج CPMM نفسه — تم أخذ عينات في 2026-09-09 عبر ثماني مبادلات مباشرة على مجموعة عالية الحجم (22,721–23,052)، مقروءة من سطر السجل Program CPMMoo8… consumed N of M compute units. للمقارنة: AMM v4 swap ~26,000؛ CLMM swap ~41,000؛ CLMM swap_v2 ~48,000 (43,838–52,887)، يرتفع مع كل عبور tick.نسخة سابقة من هذه الصفحة أبلغت عن ~47,700 CU لـ proxy-swap CPI. كان هذا الرقم المعاملة بأكملها (computeUnitsConsumed)، والذي يشمل برنامجك الخاص، إطار CPI وأي إعداد ATA — وليس تكلفة المستدعى. كلاهما مفيد، لكنهما ليسا نفس الرقم، لذا قارن مثل مع مثل. قس معاملتك الخاصة بدلاً من وضع ميزانية من أي من الرقمين.
CPIs في CLMM و LaunchLab تكلف أكثر (CLMM بشكل خاص يمشي عبر مصفوفات tick إضافية عبر remaining_accounts، مضيفاً CU لكل مصفوفة)، لكن فقط الرقم CPMM أعلاه هو قيمة مقاسة. اضبط دائماً تعليمة ComputeBudgetProgram::set_compute_unit_limit(...) صريحة بحجم من قياسك الخاص، وليس رقماً منسوخاً من التوثيق، لأن حد 200k CU الافتراضي سيستنزف بصمت وتكاليف كل تعليمة تتغير مع ترقية البرامج.

AMM v4: بناء Instruction يدوي

AMM v4 يسبق Anchor وليس لديه crate CPI، مما يجعله البرنامج الوحيد في هذا المستند الذي لا يتبع النمط العام أعلاه. بناء Instruction يدويًا:
انظر products/amm-v4/code-demos للحصول على قائمة الحسابات الكاملة.

Farm v6

استخدم TS SDK إذا كان هذا خياراً لتكاملك. raydium.farm.deposit(...) (انظر products/farm-staking/code-demos) يتم ممارسته من خلال عروض توضيحية حقيقية ولا يعتمد على ما إذا كان crate Anchor موجود لهذا البرنامج.
Farm v6 لا يوفر مسار Anchor CPI. لا يوجد crate raydium_farm_v6 على crates.io، لا توجد مستودع مصدر عام، ولا يوجد IDL على السلسلة — البرنامج لا يملك حساب anchor:idl قديم ولا إدخال في برنامج Program Metadata (انظر sdk-api/anchor-idl). تعامل معه كبرنامج غير Anchor وبناء تعليماته يدويًا، كما هو موضح أدناه.
إذا كنت بحاجة إلى Rust CPI بغض النظر، على سبيل المثال التركيب من برنامج آخر على السلسلة، بناء Instruction يدويًا، بنفس الطريقة كما في AMM v4: اشتق قائمة الحسابات الحقيقية ومميزات التعليمات بشكل مستقل، على سبيل المثال بفك تشفير تخطيطات TypeScript الخاصة بـ SDK (raydium-sdk-V2’s farm module)، فك تشفير المعاملات الحقيقية مباشرة (انظر أدناه)، أو تفريغ وفك تجميع البرنامج المنشور. لشكل التعليمة بدون معاملات متسق مع استدعاء harvest أو claim، ترتيب الحساب الحقيقي هو بادئة ثابتة (token_program، حساب حالة المزرعة، PDA سلطة الخزن، أول خزن مكافآت PDA، ثاني PDA، المستدعي، و ATA المستدعي لأول mint مكافآت)، متبوعاً بأزواج (reward_vault_i, user_reward_ata_i) في remaining_accounts لكل تدفق مكافآت بعد الأول. اتفاقية الاقتران حقيقية، لكنها تبدأ فقط عند تدفق المكافآت الثاني: خزن وATA تدفق المكافآت الأول حسابات ثابتة، وليست مجاورة لبعضها البعض، وليست جزءاً من remaining_accounts على الإطلاق.

اختبار تدفق CPI

يتطلب التطوير المحلي توفر برامج Raydium في مدقق الاختبار المحلي لديك. ثلاث خيارات:
  1. anchor test مع استنساخ البرنامج. يسحب bytecode المنشور من mainnet إلى مدقق الاختبار المحلي؛ انظر استنساخ البرامج إلى مدقق محلي أدناه للحصول على إعدادات Anchor.toml وشيئين يسبّبان مشاكل في اختبارات إنشاء المجمع تحديداً.
  2. Devnet. تنشر Raydium معظم البرامج على devnet، لكن بـ معرفات برامج مختلفة عن mainnet لكل برنامج (CPMM و CLMM و AMM v4 و Stable AMM و LaunchLab لكل منها عنوان devnet مختلف؛ انظر جدول Devnet في reference/program-addresses). لا يتم نشر Farm v3/v5/v6 بشكل موثوق على devnet؛ واجهة برمجية حية (https://api-v3-devnet.raydium.io/main/info) توضح الصورة الحالية. إذا استخدمت ثوابت DEVNET_PROGRAM_ID المضمنة في raydium_clmm (أو ما يعادلها في صناديق أخرى)، فلا تفترض أن معرف mainnet يعمل أيضاً على devnet. شغّل anchor test --provider.cluster devnet للوصول إلى الكود الحي بمجرد حصولك على العناوين الصحيحة.
  3. نشر محلي. استنسخ مستودعات Raydium (CPMM و CLMM؛ مصدر LaunchLab غير متاح لهذا الخيار) و anchor deploy إلى مدقق محلي. يضيف تكلفة دورة اختبار لكن يتيح لك تعديل المستدعى للتصحيح.
شغّل باستخدام anchor test، أو anchor build أولاً ثم anchor test --skip-build بعده إذا كنت تكرر على ملف الاختبار دون تغيير البرنامج.

استنساخ البرامج إلى مدقق محلي

يعمل هذا بواسطة معرف البرنامج بغض النظر عما إذا كان مصدر البرنامج عاماً أم لا، لذا يستنسخ LaunchLab بنفس الطريقة التي يستنسخ بها CPMM و CLMM حتى وإن لم يكن مصدره متاحاً. reference/program-addresses هو مصدر الحقيقة لكل عنوان هنا.
استنساخ البرنامج وحده غير كافٍ إذا كان اختبارك أيضاً ينشئ مجمعاً (بدلاً من المبادلة مقابل واحد موجود بالفعل). تتحقق تعليمة initialize الخاصة بـ CPMM من حسابات amm_config و create_pool_fee مقابل بيانات حقيقية على السلسلة، لذا تحتاج إلى استنساخ تلك أيضاً، وإلا فإن initialize يفشل تماماً. بالنسبة إلى CPMM تحديداً: استنسخ AmmConfig لفئة الرسوم التي تريدها (احصل على عنوانها من GET https://api-v3.raydium.io/main/cpmm-config، الفهرس 0 هو فئة 0.25%) وحساب رمز استقبال الرسوم، يتم التحقق منه بالعنوان الدقيق، وليس إنشاؤه على الطاير، لذا يجب أن يكون موجوداً بالفعل.
المجمع الذي أنشأه اختبارك للتو ليس قابلاً للمبادلة في نفس اللحظة. تتجاوز تعليمة initialize الخاصة بـ CPMM بصمت open_time مطلوب ليس بدقة في المستقبل (if open_time <= block_timestamp { open_time = block_timestamp + 1 })، لذا حتى startTime: 0 (“افتح فوراً،” وفقاً لـ SDK) يترك فجوة حقيقية ≥1 ثانية قبل أن يقبل المجمع المبادلات. سيؤدي الاختبار الذي ينشئ مجمعاً ويتبادل معه بدون تأخير إلى NotApproved. انتظار قصير (1–2 ثانية) بين إنشاء المجمع والمبادلة الأولى كافٍ. هذا خاص بالاختبار؛ الشخص الذي يشغل أمرين منفصلين يدويين عادة لن يلاحظ، لأن الكتابة وبدء العملية يستهلكان بالفعل أكثر من ثانية.

مؤشرات

المصادر: