> For the complete documentation index, see [llms.txt](https://docs.rome.builders/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.rome.builders/ar/almfahym-alasasyh/token-interop.md).

# التشغيل البيني للرموز

كيف يكون ERC-20 وSPL token هما نفس الحساب الأساسي على Rome.

تُمثّل Rome رمز ERC-20 ورمز SPL الأساسي الخاص به كحساب مشترك واحد. تشرح هذه الصفحة كيف تعمل الرموز عبر EVM وSolana.

## نموذج الحالة المشتركة

بالنسبة إلى محفظة عادية، فإن رمز ERC-20 على Rome هو **غلاف شفاف** فوق حساب رمز SPL على Solana. رصيد ERC-20 للمحفظة هو رصيد SPL الخاص بها. يملك عنوان مشتق من البرنامج لعنوان EVM حساب الرمز. هذا هو **عنوان PDA للسلطة الخارجية**.

<figure><img src="https://1717205515-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F671PKS8ZQSNqtoC8PGvz%2Fuploads%2Fgit-blob-552c639322c2d0e90b312def5db39d06c1871d18%2Ftoken-interop.svg?alt=media" alt="An EVM address and its Solana token account, owned by its external-authority PDA. Multiple wrappers read the same token account. The wrapper escrow account and Solana pool vaults hold tokens of the same Solana mint."><figcaption></figcaption></figure>

* لا يوجد تأخير في الجسر: رصيد ERC-20 للمحفظة هو رصيد SPL الخاص بها.
* المحافظ العادية، بما في ذلك محافظ MetaMask والعناوين الاصطناعية، لا تعاني من تجزؤ السيولة. كل غلاف فوق أصل mint يُظهر رصيد المحفظة نفسه. إن `balanceOf` تقرأ هذه الطريقة ذلك الرصيد من حساب رموز المحفظة. الرموز المحتفظ بها داخل عقود EVM تُحتفَظ بها لكل غلاف على حدة (انظر [عقد الغلاف](#the-wrapper-contract)).
* بالنسبة إلى رموز المحفظة، لا يُقفل شيء على جانب ويُسكّ على الجانب الآخر. الرموز المحتفظ بها في العقود تقبع في حساب الضمان الرمزي الخاص بالغلاف على Solana. يتتبع كل غلاف تلك الرموز بشكل منفصل.

**لماذا لا يؤدي غلاف ثانٍ إلى تقسيم الرصيد**

غلافان فوق أصل mint نفسه يُظهران رصيد المحفظة نفسه. تقرأ الأغلفة `totalSupply` من أصل mint على Solana. على Hadrian (شبكة الاختبار)، أعادت ثلاثة أغلفة wUSDC أرصدة متطابقة للمحفظة. أعادت جميع أغلفة wUSDC الثلاثة (9.0.0 و8.0.0 وMay 2026) معروض أصل mint على Solana.

يتيح كل مصنع غلافًا واحدًا لكل mint. يمكن لإصدار جديد من المصنع نشر غلاف آخر لذلك mint. يسمي السجل الغلافَ المرجعي لكل سلسلة.

محفظة Solana التي تحتفظ بـ USDC مباشرةً وعنوان EVM يحتفظان برموز من أصل mint نفسه. تستخدم مجمعات Solana الخزائن والاحتياطيات نفسها لكليهما.

جدول الحائزين في [عبر المستكشف](/ar/alttbyqat-ala-rome/via.md) مبني من `أحداث` Transfer `ActivateAta`، والتحويلات عبر غلاف آخر لا تظهر في أحداث ذلك الغلاف.

> مسارات الاستيراد أدناه تستخدم `@rome-protocol/rome-solidity`. الحزمة ليست على npm؛ ثبّتها من [`rome-solidity`](https://github.com/rome-protocol/rome-solidity) المستودع العام باستخدام `npm install github:rome-protocol/rome-solidity`، أو `forge install rome-protocol/rome-solidity` مع remapping؛ كما تحتاج عقود الغلاف والمصنع أيضًا إلى OpenZeppelin ضمن Foundry (انظر [نشر عقود Solidity](/ar/adlh-almtw-ryn/deploy-solidity.md#using-the-rome-solidity-sdk)). توجد واجهات precompile في [`contracts/interface.sol`](https://github.com/rome-protocol/rome-solidity/blob/master/contracts/interface.sol).

## عقد الغلاف

`SPL_ERC20` (وبنسختها المخزنة مؤقتًا `SPL_ERC20_cached`، والتي ينشرها المصنع لكل mint باستثناء واحد ذي transfer hook مُسلَّح؛ انظر [أصول Token-2022](#token-2022-mints)) تُوفّر واجهة ERC-20 كاملة فوق أصل SPL mint:

* `balanceOf()` — يقرأ رصيد ATA الخاص بالمستخدم من Solana (أما بالنسبة إلى عنوان عقد فيقرأ دفتر حسابات الغلاف نفسه، انظر أدناه)
* `transfer()` / `transferFrom()` — نقل الرموز على Solana
* `approve()` / `allowance()` — مخصصات ERC-20 لكل جهة إنفاق محفوظة في تخزين EVM (حساب رمز SPL لا يملك مخصصات على نمط EVM). وهي منفصلة عن المنحة لمرة واحدة أدناه: لتحريك رموز المستخدم أصلًا، يعمل الغلاف بوصفه مفوّض SPL لذلك المستخدم، ويمنحه المستخدم هذا الحق مرة واحدة لكل محفظة
* `totalSupply()` — يقرأ معروض أصل SPL mint

لا يمكن للعقد إرسال المنحة لمرة واحدة، لذا تُحتفَظ رموز العقد في حساب الرمز الخاص بالغلاف نفسه ويُتتبَّع في دفتر حسابات الغلاف. `balanceOf(contract)` يقرأ ذلك الدفتر.

## المصنع

`ERC20SPLFactory` ينشر غلافًا لأي أصل SPL mint:

```solidity
import {ERC20SPLFactory} from "@rome-protocol/rome-solidity/contracts/erc20spl/erc20spl_factory.sol";

// نشر غلاف، مع تحميل الاسم/الرمز من بيانات Token-2022 الوصفية الخاصة بالـ mint أو من Metaplex
address wrapper = factory.add_spl_token_with_metadata(splMint);

// أو حدّد الاسم/الرمز يدويًا
address wrapper = factory.add_spl_token_no_metadata(splMint, "USD Coin", "USDC");
```

عنوان المصنع الحي، من `نشطًا` مدخلات السجل (v0.2.0): Hadrian `0x37c13e4ff21fb914eb24014dcbd0f8dbeaa31078`. كانت المصانع الأقدم ما تزال على السلسلة لكنها موسومة بـ `مُهملة` أو `مُتقاعدة` الخاصة بالسلسلة). إن [السجل](https://github.com/rome-protocol/rome-registry/tree/main/chains)؛ لا تستخدمها. السجل هو مصدر الحقيقة، لذا اقرأ العنوان الحي منه (انظر [قراءة قائمة العقود](/ar/almrja/contract-addresses.md#reading-the-contracts-list)) بدلًا من نسخه إلى شيفرتك.

## أصول mint المرجعية

لا يوجد عقد سجل رموز على السلسلة. الأغطية المرجعية ورموز الغاز/الجسر مُنتقاة في السجل غير المتصل بالسلسلة [`rome-protocol/registry`](https://github.com/rome-protocol/rome-registry)؛ وتُكتشَف الأغطية غير المصرح بها المنشأة عبر `add_spl_token_no_metadata` من حدث `TokenCreated` على السلسلة. يسمي السجل الغلافَ المرجعي لكل mint على كل سلسلة. أرصدة المحافظ مشتركة عبر الأغطية. يتتبع كل غلاف بشكل منفصل الأرصدة المحتفظ بها بواسطة عقود EVM.

## عمليات SPL من Solidity

بالنسبة إلى بدائيات SPL الموقعة بواسطة PDA للمستخدم، استخدم **HelperProgram** precompile (`0xFF…09`) — إنشاء ATA، وتحويلات SPL، والتحويل بين gas وlamports:

```solidity
import {IHelperProgram} from "@rome-protocol/rome-solidity/contracts/interface.sol";

IHelperProgram helper = IHelperProgram(0xFF00000000000000000000000000000000000009);

helper.create_ata(user, mint);              // إنشاء ATA الخاص بالمستخدم لأصل mint
helper.transfer_spl(to, tokens, mint);      // نقل SPL من PDA الخاص بالمستدعي
```

`transfer_spl` يملك عدة تغايرات (بما في ذلك نسخة المفوض لـ `transferFrom` تدفقات)؛ انظر `interface.sol` للاطلاع على التواقيع الدقيقة. في المسار المخزن مؤقتًا، توجد العمليات المكافئة على `ISplCached` (`0xFF…05`، و `IAssociatedSplCached` (`0xFF…06`). يستخدم العقد مسارًا واحدًا باستمرار.

## منح لمرة واحدة لكل محفظة

ينقل الغلاف رموز المستخدم بوصفه **مفوّض SPL** لحساب الرمز الخاص بذلك المستخدم. لذلك على المحفظة أن تمنحه هذا الحق مرة واحدة لكل غلاف، قبل أن يتمكن الغلاف من تحريك أي شيء نيابة عنها. والمنحة هي استدعاء واحد إلى precompile المساعد (`0xff00000000000000000000000000000000000009`):

```solidity
helper.approve_spl(wrapper, type(uint64).max, mint);   // approve_spl(wrapper, 2^64-1, mint)
```

`approve_spl` موقَّع من حساب المستخدم نفسه، لذا يرسله المستخدم، لا الغلاف ولا عقدك. الـ mint هو `mint_id()` على الغلاف.

* **من يحتاجه.** كل محفظة EVM، وكل العنوان الاصطناعي لمستخدم Solana، لكل غلاف يرغب في تحريك رموزه. العقد الذي يسحب الرموز باستخدام `transferFrom` لا يعمل إلا للمستخدمين الذين منحوا الغلاف.
* **كيفية التحقق.** استدعِ `isEnabled(user)` على الغلاف. سيُرجِع `true` بمجرد أن تكون المنحة في مكانها.
* **كيف يبدو الأمر عندما تكون مفقودة.** تفشل عملية النقل بخطأ SPL `0x4` (عدم تطابق المالك).
* **مفوّض واحد لكل حساب رمز.** يملك حساب رمز SPL مفوضًا واحدًا. إن منح برنامج آخر منحة على حساب الرمز نفسه، مثل جسر أو موجه، يستبدل منحة الغلاف، ويتوقف الغلاف عن العمل لذلك المستخدم حتى يمنحه مرة أخرى. تحقّق من `isEnabled` قبل عملية نقل بدلًا من افتراض أن منحة سابقة ما تزال موجودة.

عندما يستبدل إصدار جديد من المصنع غلافًا، يمنح كل wallet الغلاف الجديد الإذن باستخدام `approve_spl`. يمكن للغلاف القديم تحريك رموز تلك المحفظة فقط ما دام لا يزال مفوض حساب الرمز. يمنح الغلاف الجديد يستبدل ذلك المفوض.

الـ [دليل التطبيق ثنائي المسار](/ar/adlh-almtw-ryn/dual-lane-app.md#one-time-grant-the-wrapper) يحتوي على الشيفرة الكاملة لكلا المسارين.

## الإيداع والسحب

* **إلى EVM** — يضيف جانب SPL رصيدًا إلى ATA المملوك لـ PDA الخاص بالمستخدم؛ ويعكس غلاف ERC-20 الرصيد فورًا. تتم التسويات العابرة للسلاسل الواردة من دون ثقة عبر تفويض موقَّع من المستخدم على الجسر.
* **لفّ الغاز إلى رمز الغاز** — استدعِ `سحب` precompile (`0x42…16`). `withdraw_to_ata(wei)` يحرق الغاز الأصلي ويقيّد المبلغ المكافئ، بوحدات المنازل العشرية نفسها لرمز الغاز، إلى حساب الرمز الخاص بالمستدعي، والذي يعرضه غلاف رمز الغاز (مثل wUSDC) بعد ذلك كرصد. `withdraw_to_pda(wei)` يدفع lamports إلى PDA الخاص بالمستدعي وينطبق فقط على سلسلة غازها SOL؛ ويفشل على Hadrian وRubicon، اللتين تستخدمان USDC كغاز، لذا استخدم `withdraw_to_ata` هناك. المبلغ بوحدات الغاز ذات 18 منزلة عشرية ويجب أن يكون عددًا صحيحًا من وحدات رمز الغاز: على سلسلة غازها USDC يجب أن يكون مضاعفًا لـ 10^12 (وحدة واحدة ذات 6 منازل عشرية)، وإلا تفشل الدعوة. `HelperProgram.deposit_from_ata(wei)` تسير في الاتجاه المعاكس وتحول رمز الغاز في حساب الرمز الخاص بالمستدعي مرة أخرى إلى الغاز الأصلي، مع نفس قاعدة المضاعف. هذه تحويلات لرمز الغاز، وليست مخرجًا لرموز أخرى.
* **إلى Solana، أي رمز آخر** — رصيد الغلاف نفسه هو بالفعل رصيد SPL، لذا فإن إخراجه هو تحويل SPL:
  * `HelperProgram.transfer_spl_to_signer(amount, mint)` يرسل رموز المستدعي إلى حساب الرمز الخاص بمحفظة Solana التي وقّعت على المعاملة. يصل مسار العودة هذا إلى محفظة المستخدم نفسها فقط على مسار Solana الموقّع من المحفظة. إذا استُدعي من MetaMask أو عبر المرحّل، يكون الموقّع هو دافع Rome الوكيل، لذا تفشل الدعوة أو تذهب الرموز إلى Rome. استخدم `transfer_spl` أو `RomeBridgeWithdraw.bridgeOutToSolana` هناك بدلًا من ذلك.
  * `RomeBridgeWithdraw.bridgeOutToSolana(solanaRecipient, amount, mint)` يرسلها إلى أي محفظة Solana. وهو يحتاج إلى منحة المستخدم لعقد الجسر (`approve_spl(bridge, …)`، انظر الملاحظة أعلاه حول المفوض الواحد)، ويجب أن يكون حساب الرمز الخاص بالمستلم موجودًا؛ `ensureRecipientAta(solanaRecipient, mint)` ينشئه.
  * `RomeBridgeWithdraw` كما يحرق USDC إلى سلسلة أخرى عبر CCTP (`burnUSDC`) ويرسل الأصول الأخرى عبر Wormhole (`burnETH`, `burnToWormhole`).

خذ العنوان الحي `RomeBridgeWithdraw` من السجل.

## رمز الغاز

لكل سلسلة رمز غاز خاص بها: SOL أو رمز SPL. يمكن لمصدر سعر Rome Proxy أن يكون تغذية Hermes API، أو تجمع Meteora DAMM v1، أو تجمع Meteora DAMM v2، أو سعرًا ثابتًا. تستخدم Hadrian (شبكة الاختبار) وRubicon (الشبكة الرئيسية) USDC. تستخدم Hadrian USDC للاختبار. وتستخدم Rubicon USDC الحقيقي. لا يوجد رمز غاز افتراضي عالمي.

## أصول Token-2022

كما يلف المصنع أصول Token-2022. ويسأل precompile المساعد عمّا هو mint، باستخدام `mint_info(mint)` (المُحدِّد `0xe24bf5d4`)، ويختار الغلاف من الإجابة. `mint_info` يُرجع خمس قيم:

| القيمة         | المعنى                                                                          |
| -------------- | ------------------------------------------------------------------------------- |
| `tokenProgram` | برنامج الرمز الذي يملك الـ mint (برنامج SPL Token الكلاسيكي أو Token-2022)      |
| `decimals`     | عدد المنازل العشرية للـ mint                                                    |
| `hookProgram`  | برنامج transfer-hook، أو صفر عندما لا يوجد hook أو يكون موجودًا لكنه غير مسلّح  |
| `feeBps`       | رسوم التحويل بالنقاط الأساسية، أو صفر عندما لا توجد رسوم أو تكون مضبوطة على صفر |
| `extensions`   | خريطة بتّات للامتدادات Token-2022 التي يحملها الـ mint، البت N لنوع الامتداد N  |

ما الذي يحصل عليه mint:

| mint                                                                    | الغلاف                                                                                        | `wrapper_kind_by_mint` |
| ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | ---------------------- |
| Mint عادي، أو mint من Token-2022 بلا hook، أو hook موجود لكنه غير مسلّح | الغلاف المخزَّن مؤقتًا (`SPL_ERC20_cached`)                                                   | `1`                    |
| Mint من Token-2022 مع transfer hook مسلّح                               | الغلاف المزوّد بالhook (`SPL_ERC20_Token2022Hooked`)، المنشور عبر `hooked_wrapper_deployer()` | `2`                    |

mint الذي لديه رسوم تحويل يحصل على الغلاف المخزن مؤقتًا، و `أحداث` حدثه يبلّغ عن المبلغ الذي وصل بعد الرسوم، لا المبلغ المُرسَل. يمكنك قراءة نوع الغلاف الذي حصل عليه mint من المصنع باستخدام `wrapper_kind_by_mint(mint)`؛ وعلى مصنع Hadrian الحي تُرجع أغلفة USDC وETH وSOL جميعها `1`.

ما الذي يُرفَض:

* mint ذو transfer hook مسلّح لا يمكنه الحصول على أحد الأغطية العادية. نشر `SPL_ERC20` أو `SPL_ERC20_cached` عليه مباشرةً يفشل بـ `ArmedTransferHookUnsupported(mint, hookProgram)`. عبر المصنع تذهب هذه الحالة إلى الغلاف المزوّد بالhook بدلًا من ذلك.
* عنوان ليس mint SPL يجعل `mint_info` يفشل بـ `Invalid SPL mint account: <address>`.
* mint الذي لديه غلاف بالفعل يفشل بـ `Token exists`، ورمز مستخدم بالفعل يفشل بـ `Token with symbol exists`.
* `add_spl_token_with_metadata` يقرأ الاسم والرمز أولًا من بيانات Token-2022 الوصفية الخاصة بالـ mint نفسه ثم من Metaplex ثانيًا. إذا لم يكن لدى الـ mint أي منهما يفشل بـ `Mint asserts no name: use add_spl_token_no_metadata`.

كيف يتصرف الغلاف المزوّد بالhook:

* يشغّل Token-2022 hook في كل عملية نقل، ويحتاج hook إلى حسابات تعتمد على عملية النقل. لا يستطيع الغلاف استنتاجها، لذا يحلّ المستدعي قائمة الحسابات الكاملة من قائمة extra-account-metas الخاصة بالـ mint ويمررها. ويتحقق الغلاف من الجزء الثابت من تلك القائمة (برنامج hook وحساب التحقق الخاص به) ويمررها دون تغيير.
* الـ `transfer`, `transferFrom` و `bridgeOutToSolana` يفشل بـ `HookAccountPlanRequired`. استخدم `transferWithHookAccounts`, `transferFromWithHookAccounts` و `bridgeOutToSolanaWithHookAccounts`، والتي تأخذ قائمة الحسابات كوسيط إضافي.
* إذا تغيّر برنامج hook الخاص بالـ mint بعد نشر الغلاف، تفشل التحويلات بـ `HookConfigurationChanged`.
* ينقل الرموز عبر استدعاء مباشر عبر البرامج، وهو المسار القديم، ولا يستخدم المسار المخزن مؤقتًا. يستخدم العقد مسارًا واحدًا باستمرار، وتعمل الاستدعاءات على المسار القديم فقط في تنفيذ ذري، لذا يجب أن يلائم الاستدعاء الذي يستخدم الغلاف المزوّد بالhook معاملة ذرية واحدة.
* لا يحتفظ بدفتر حسابات لأرصدة العقود. الرموز المُرسلة إلى عقد تصل إلى حساب الرمز الخاص بذلك العقد، ولا يمكن للعقد إرسالها إلا بعد أن يكون قد منح `approve_spl` منحة إلى الغلاف نفسه.
* يحتاج إلى نفس [المنحة لمرة واحدة](#one-time-grant-per-wallet) مثل أي غلاف آخر.

## القيود

* مبالغ رموز SPL هي `uint64` (الحد الأقصى 18,446,744,073,709,551,615)
* مخصصات ERC-20 (`approve` / `allowance`) هي تخزين EVM. ينقل الغلاف الرموز بوصفه مفوض SPL الخاص بالمستخدم، والذي يمنحه المستخدم مرة واحدة لكل غلاف (انظر [منح لمرة واحدة لكل محفظة](#one-time-grant-per-wallet))
* يجب أن تكون رموز غلاف ERC-20 فريدة لكل مصنع

## ما التالي

* [عناوين العقود](/ar/almrja/contract-addresses.md) — precompiles والعناوين الخاصة بكل سلسلة
* [استدعِ Solana من EVM](/ar/adlh-almtw-ryn/call-solana-from-evm.md) — CPI وعمليات SPL من Solidity
* [كيف يلتقي Solana وEVM على Rome](/ar/almfahym-alasasyh/how-solana-and-evm-meet.md)
* [دمج برنامج سولانا](/ar/adlh-almtw-ryn/integrate-solana-program.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.rome.builders/ar/almfahym-alasasyh/token-interop.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
