For the complete documentation index, see llms.txt. This page is also available as Markdown.

أنشئ تطبيقًا ثنائي المسار

شرح خطوة بخطوة لتطبيق ثنائي المسار — عقد Solidity واحد يستخدمه كلٌّ من مستخدم MetaMask ومستخدم Phantom (Solana)، مع ما يحدث بالضبط في كل خطوة.

أحد تطبيق ثنائي المسار هو عقد Solidity واحد يستخدمه كلٌّ من MetaMask (EVM) المستخدم و Phantom (Solana) يستخدمانه مباشرة — العقد نفسه، والحالة نفسها، وكلٌّ بالمحفظة التي لديه بالفعل. تشرح هذه الصفحة بالضبط ما يحدث في كل خطوة، على كل جانب.

المثال عبارة عن خزنة: أنت تودع USDC ثم لاحقًا تسحب إياه. "Stake / unstake" و"supply / redeem" و"tip / claim" لها البنية نفسها.

ما تكتبه — خزنة ERC-20 قياسية

على Rome، يظهر USDC الخاص بمستخدم Solana على جانب EVM كـ رمز ERC-20 — غلاف SPL لذلك الإصدار (مثلًا wUSDC). لذا فإن عقدك خزنة رمزية عادية: يسحب الرموز باستخدام transferFrom ويعيدها باستخدام transfer. لا شيء خاص بـRome:

interface IERC20 {
    function transfer(address to, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

contract Vault {
    IERC20 public immutable token;                 // غلاف wUSDC
    mapping(address => uint256) public balanceOf;
    constructor(IERC20 _token) { token = _token; }

    function deposit(uint256 amount) external {
        require(token.transferFrom(msg.sender, address(this), amount));
        balanceOf[msg.sender] += amount;
    }
    function withdraw(uint256 amount) external {
        balanceOf[msg.sender] -= amount;
        require(token.transfer(msg.sender, amount));
    }
}

لماذا ERC-20 وليس قابلاً للدفع / msg.value? الرصيد القابل للإنفاق لدى مستخدم Solana هو حساب رمز SPL في محفظته، ويظهر واحدًا لواحد على هيئة غلاف ERC-20 هذا — وليس الرصيد الأصلي على EVM. لذا يمكن لمستخدم Solana دائمًا تمويل transferFrom، لكن deposit() payable سيتطلب قيمة أصلية لا يمتلكونها ساكنة. ابنِ حول الرمز، وسيعمل المساران بالطريقة نفسها.

انشره باستخدام Foundry أو Hardhat، مع توجيه المُنشئ إلى عنوان الغلاف لرمزك (من السجل). على Rome، رمز الغاز هو USDC، لذا تحتاج إلى رصيد USDC صغير للغاز كي تنشر.

المساران

المسار
المحفظة
كيف يستدعيه التطبيق

EVM

MetaMask (مفتاح EVM)

submitRomeTx — عملية الكتابة القياسية في Rome

Solana

Phantom (مفتاح Solana)

submitRomeTxSolanaLane — لا حاجة إلى مفتاح EVM

مسار EVM عادي. بقية هذه الصفحة هي مسار Solana — النصف المثير للاهتمام.

الفكرة الأساسية: الهوية الاصطناعية مجرد وسيط تمرير

هوية EVM لمستخدم Solana هي العنوان الاصطناعيkeccak256(solana_pubkey)[12:]. إنه msg.sender في العقد، لكنه لا يحتفظ بأي شيء أثناء السكون. أموال المستخدم موجودة في محفظة Solana (بصفتها SPL USDC)، وعلى جانب EVM فإن الرصيد نفسه هو ما wUSDC.balanceOf(synthetic) يقرأه. تتدفق القيمة عبر الهوية الاصطناعية:

  • للداخل (الإيداع): حساب الرمز في المحفظة → حساب الرمز الاصطناعي → العقد (عبر transferFrom).

  • للخارج (السحب): العقد → حساب الرمز الاصطناعي → حساب الرمز في المحفظة.

تعود الهوية الاصطناعية إلى الصفر بعد كل دورة ذهاب وعودة.

مرة واحدة: التفعيل (تهيئة الهوية الاصطناعية)

الحساب على السلسلة لهوية اصطناعية جديدة لا يوجد حتى تنشئه. عند أول مرة يتصرف فيها مستخدم Solana، تكون هويته الاصطناعية مُهيأة بـ create_pda استدعاء — وبعد ذلك، يمكن استدعاءات نقل القيمة (ERC-20 transferFrom، وعمليّة الكنس) أن توقّعها.

submitRomeTxSolanaLane يفعل هذا تلقائيًا عند أول استخدام (autoProvision مفعّل افتراضيًا). إذا كنت تفضل عرض شاشة "التفعيل" صراحةً (إعداد حساب لمرة واحدة)، فافعل ذلك بنفسك:

ما يحتاجه كل جانب

المتطلبات
السبب

مستخدم Solana (Phantom)

SOL (قليلًا)

يدفع رسوم معاملة Solana في كل معاملة على المسار

USDC كرمز SPL في محفظته

القيمة التي يودعونها (وتظهر على جانب EVM كـ wUSDC)

مستخدم EVM (MetaMask)

USDC كـرصيد الغاز في Rome

غاز + قيمة؛ ويزيدونه عبر جسر USDC إلى Rome (لا يوجد صنبور)

أنت (الباني)

محفظة فيها USDC غاز على Rome

لنشر العقد

القيمة الداخلة — الإيداع (خطوة بخطوة)

لدى مستخدم Solana ‏SOL + USDC في محفظة Phantom الخاصة به. كل معاملة على المسار تكون موقعة بواسطة Phantom — المحفظة توقعها وترسلها إلى Solana RPC (يُستخدم الوكيل فقط لاكتشاف الحسابات):

  1. مرحلة التمويلbuildFundLeg(...)submitSolanaInstructions(...). ينشئ حساب رمز USDC الخاص بالهوية الاصطناعية (إن لزم) ويشغّل ActivateAta، ناقلًا amount من USDC من حساب الرمز في المحفظة إلى حساب الرمز الخاص بالهوية الاصطناعية. الآن wUSDC.balanceOf(synthetic) يظهر ذلك الرصيد.

  2. الموافقةsubmitRomeTxSolanaLane({ to: wUSDC, data: approve(vault, amount) }). يتيح للخزنة سحب الرموز. (عادةً هذا هو أول استدعاء على المسار، لذا تُهيَّأ الهوية الاصطناعية تلقائيًا هنا.)

  3. إيداعsubmitRomeTxSolanaLane({ to: vault, data: deposit(amount) }). تنفذ الخزنة transferFrom(synthetic, vault, amount) — ينتقل USDC من الهوية الاصطناعية إلى الخزنة، ويُقيد على عنوان الهوية الاصطناعية.

الأثر الصافي: انتقل USDC محفظة Phantom → (الهوية الاصطناعية) → الخزنة.

القيمة الخارجة — السحب (خطوة بخطوة)

الآن يسحب المستخدم. وهي أيضًا موقعة بواسطة Phantom:

  1. سحبsubmitRomeTxSolanaLane({ to: vault, data: withdraw(amount) }). vault.withdraw تنفذ transfer(synthetic, amount) — ينتقل USDC من الخزنة عائدًا إلى الخاص بالهوية الاصطناعية حساب الرمز.

  2. مرحلة الكنسbuildSweepLeg(...) يعطيك HelperProgram.transfer_spl الاستدعاء + الحسابات؛ شغِّله (أنشئ حساب الرمز في المحفظة إن لزم، ثم DoTxUnsigned إلى precompile الخاص بـ Helper) لنقل USDC من الهوية الاصطناعية إلى محفظة Solana الخاصة بالمستخدم. وتعود الهوية الاصطناعية إلى الصفر.

الأثر الصافي: انتقل USDC الخزنة → (الهوية الاصطناعية) → محفظة Phantom الخاصة بالمستخدم. لا يبقى شيء عالقًا.

المآخذ — كلها يعالجها SDK

هذه هي الأشياء التي تخطئ فيها معاملة مسار Solana المبنية يدويًا؛ submitRomeTxSolanaLane ويقوم بها نيابةً عنك:

  • التهيئة. يجب إنشاء حساب هوية اصطناعية جديدة (create_pda) قبل أي استدعاء ينقل قيمة، وإلا فلن تستطيع توقيع النقل. مفعّل تلقائيًا عند أول استخدام؛ أوقفه باستخدام autoProvision: false + provisionSynthetic.

  • استخدم الغلاف، لا msg.value. رصيد مستخدم Solana هو حساب الرمز SPL الخاص به، ويظهر على هيئة غلاف ERC-20 — انقله باستخدام transfer / transferFrom، وليس بالقيمة الأصلية أبدًا.

  • ComputeBudget. يحتاج EVM الخاص بـRome إلى حد CU مرتفع (~1.35M) وإطار heap كبير (~250 KB). أما القيم الافتراضية لـSolana عند 200K-CU / 32-KB فتفشل.

  • محفظة الخزانة. تدفع عملية التنفيذ رسمًا صغيرًا إلى حساب الخزانة لكل سلسلة؛ ويغفله اكتشاف الحسابات، لذا يضيفه SDK.

  • إلى أين يُرسل. المحفظة توقّع معاملة Solana وترسلها إلى Solana RPC — وليس إلى الوكيل. يُستخدم الوكيل فقط لاكتشاف الحسابات. على السلسلة، يستنتج البرنامج msg.sender انطلاقًا من موقِّع Solana.

  • الغاز هو USDC. لا يوجد صنبور — جسّر USDC إلى الداخل (انظر الحصول على التمويل).

التطبيق نفسه من MetaMask

يستدعي مستخدم EVM العقد نفسه مع submitRomeTx — أدوات EVM قياسية، والغاز بعملة USDC. وما يزالون يوافقون ثم تودع (ERC-20 كالمعتاد)، من دون مرحلتي التمويل/الكنس (رموزهم موجودة بالفعل على عنوان EVM الخاص بهم). يشترك المستخدمان في نفس balanceOf الحالة.

ما التالي

آخر تحديث

هل كان هذا مفيدا؟