Skip to main content
هذه الصفحة مُترجَمة آليًا بواسطة الذكاء الاصطناعي. النسخة الإنجليزية هي المرجع المعتمد.عرض النسخة الإنجليزية →
تصف هذه الصفحة تخطيط ودور كل حساب. البذور (Seeds) موثّقة بشكل قانوني في reference/program-addresses. يحتوي مجمع CLMM على حسابات أكثر من مجمع CPMM، إذ يُخزَّن السيولة بشكل متفرق عبر نطاق التدرجات (tick range)؛ وفهم هذا التفرق هو جوهر هذه الصفحة.

فهرس الحسابات

يتكون مجمع CLMM النشط من عائلات الحسابات التالية. جميعها مملوكة لبرنامج CLMM ما عدا الـ mint الخاصتين بالعملتين ومخازنهما.

PoolState

الحالة الحية للمجمع، تُقرأ عند كل عملية swap وكل تغيير في المراكز.
الحقول التي ستتعامل معها فعلياً:
  • sqrt_price_x64 و**tick_current** هما حالة سعر المجمع. يُحدَّثان معاً عند كل عملية swap. tick_current هو الجزء الصحيح الأدنى لـ log_{1.0001}(price).
  • liquidity هي السيولة النشطة — مجموع قيم L لجميع المراكز التي تحتوي tick_current ضمن نطاقها. تتغير في كل مرة يعبر فيها swap تدرجاً، وفي كل مرة يُفتح أو يُغلق أو يُعاد تحديد حجم مركز.
  • fee_growth_global_{0,1}_x64 هي الرسوم التراكمية المكتسبة لكل وحدة سيولة عبر تاريخ المجمع بأكمله. تقرأ المراكز هذه القيم لحساب ما يستحقانه.
  • tick_spacing مقيّد بـ AmmConfig عند التهيئة ولا يتغير أبداً. يحدد أي مؤشرات تدرجات مسموح بها كنقاط نهاية للمراكز.
  • tick_array_bitmap هي خريطة بت مضمّنة تغطي نطاق التدرجات الأكثر استخداماً حول السعر الفوري. بالنسبة للمجمعات التي تمتد مراكزها بعيداً، يقع تتبع الفائض في حساب TickArrayBitmapExtension المنفصل.
  • fee_on ثابت عند إنشاء المجمع. القيمة 0 (FromInput) تعيد إنتاج سلوك Uniswap-V3 الكلاسيكي. القيمتان 1 و2 توجّهان رسوم الـ swap إلى جانب واحد من الدفتر — راجع products/clmm/fees للاطلاع على المقايضات.
  • dynamic_fee_info يحمل حالة التقلب لرسوم الرسوم الديناميكية الإضافية. عند التفعيل، تُعيد كل عملية swap حساب dynamic_fee_component فوق AmmConfig.trade_fee_rate. التخطيط موثّق ضمن DynamicFeeInfo أدناه؛ المجمعات بدون رسوم ديناميكية تترك البنية كلها بقيمة صفر.

AmmConfig

مجموعة نموذجية منشورة من طبقات رسوم CLMM (تحقق من GET https://api-v3.raydium.io/main/clmm-config): protocol_fee_rate وfund_fee_rate هما كسور من رسوم التداول؛ بنفس الاتفاقية المستخدمة في CPMM. راجع products/clmm/fees.

TickArrayState

لا يُخزّن CLMM سجلاً واحداً لكل تدرج، إذ سيعني ذلك مليارات الحسابات. بدلاً من ذلك، يجمع TICK_ARRAY_SIZE تدرجات متجاورة مُهيَّأة أو غير مُهيَّأة (عادةً 60 أو 88 حسب إصدار البرنامج) في TickArrayState يُنشأ عند أول استخدام.
حقول أوامر الحد الأربعة تساوي صفراً لأي تدرج لم يُستخدم قط لأمر حد. عند فتح أوامر على تدرج ما، يتتبع البرنامج تسلسلاً من الدُفعات (cohorts):
  • order_phase هو معرّف الدُفعة. يزداد في كل مرة تنتقل دُفعة من “غير مملوءة كلياً” إلى “ممتلئة جزئياً”.
  • orders_amount هو إجمالي رمز الإدخال للدُفعة الحالية (الأحدث).
  • part_filled_orders_remaining يتتبع الدُفعة السابقة التي تملؤها عمليات الـ swap الجارية حالياً.
  • unfilled_ratio_x64 هو مضاعف Q64.64 يُحمل على الدُفعة: عندما تملأ عملية swap نسبة X% من الدُفعة، يُضرب المعامل في (1 − X). يُخزّن كل أمر مفتوح لقطته الخاصة (order_phase, unfilled_ratio_x64) عند وقت الفتح، مما يختزل حساب التسوية في مقارنة اللقطات.
القواعد:
  • تدرج نقطة نهاية المركز t يجب أن يحقق t % tick_spacing == 0. يرفض البرنامج المراكز غير المتوافقة مع التباعد.
  • مصفوفة التدرج تقع عند floor(t / (TICK_ARRAY_SIZE * tick_spacing)) * (TICK_ARRAY_SIZE * tick_spacing).
  • تُهيَّأ مصفوفة التدرجات بشكل كسول: أول مركز أو swap يلمس مصفوفة غير مُهيَّأة يُنشئها، مدفوعاً تكلفة الإيجار.
  • لا يُغلق البرنامج مصفوفة التدرجات أبداً. بمجرد تخصيصها تظل موجودة طوال عمر المجمع، حتى بعد أن تعود كل التدرجات فيها إلى liquidity_gross == 0. تُعاد استخدام المراكز والـ swaps اللاحقة للحساب الموجود بدون إيجار إضافي. لا توجد مسار تنظيف لمصفوفات التدرجات مرتبط بـ ClosePosition.

TickArrayBitmapExtension

يغطي PoolState.tick_array_bitmap (المضمّن) النطاق “القريب من السعر الفوري” — ±1,024 مصفوفة تدرجات. خارج هذا النطاق (لقيم التدرجات الشديدة)، يحتفظ البرنامج بحساب امتداد:
إذا كان نطاق مركزك “عادياً”، فلن تحتاج أبداً للتفكير في حساب الامتداد. المراكز ذات النطاق الكامل (مثل (MIN_TICK, MAX_TICK)) تستلزمه؛ يحله SDK تلقائياً.

المراكز

مركز CLMM هو حزمة من ثلاثة حسابات بالإضافة إلى mint:

Position NFT mint

Mint لتوكن SPL بإمداد 1. عنوان الـ mint هو PDA محدد؛ الـ NFT الخاص بالمركز في محفظة المالك ليس سوى ATA يحتفظ بذلك التوكن الواحد. نقل الـ NFT هو طريقة تغيير ملكية المركز — يربط البرنامج التفويض بـحامل رصيد ATA الخاص بـ NFT في الوقت الحالي، وليس بـ Pubkey مخزّن في الحالة.

PersonalPositionState

حساب واحد لكل مركز مفتوح. مفتاحه مشتق من NFT mint.

ProtocolPositionState (مهجور)

كانت الإصدارات القديمة من CLMM تخزّن حسابات (pool, tick_lower, tick_upper) التجميعية في PDA من نوع ProtocolPositionState. الإصدارات الأحدث لا تنشئ هذا الحساب ولا تقرأه بعد الآن. لا يزال الفتحة تظهر في قوائم حسابات OpenPosition / IncreaseLiquidity / DecreaseLiquidity بوصفها UncheckedAccount للتوافق مع ABI، لكن البرنامج لا يكتب فيه. الحسابات الموجودة على السلسلة متبقية؛ يمكن للمشرف استدعاء CloseProtocolPosition لاسترداد الإيجار منها.يُشتق الآن حساب النطاق التجميعي مباشرةً من تدرجي نقطة النهاية (liquidity_gross، liquidity_net، وfee_growth_outside_* / reward_growths_outside_x64 لكل تدرج) في TickArrayState. تستمر صيغة نمو الرسوم الداخلية fee_growth_inside = global − outside_lower − outside_upper في العمل بدون حساب مركز تجميعي.

الملاحظات (Observation)

يُخزّن مخزن الملاحظات في CLMM تدرجاً تراكمياً، لا سعراً تراكمياً. يحسب المستهلكون الخارجيون السعر ذي الوسط الهندسي عبر فترة زمنية من (tick_cumulative[t1] − tick_cumulative[t0]) / (t1 − t0) ثم price = 1.0001 ** tick. راجع algorithms/clmm-math.

DynamicFeeConfig وDynamicFeeInfo

تقع معاملات الرسوم الديناميكية في مكانين. القالب القابل لإعادة الاستخدام — DynamicFeeConfig — يديره المشرف ويُشارَك بين المجمعات المشتركة. حالة التشغيل لكل مجمع — DynamicFeeInfo — مضمّنة في PoolState وتُحدَّث عند كل عملية swap.

DynamicFeeConfig

بذرة PDA: ["dynamic_fee_config", index.to_be_bytes()]. يُنشأ عبر create_dynamic_fee_config (مقيّد بصلاحيات المشرف) ويُعدَّل عبر update_dynamic_fee_config. تُنشئ المجمعات التي تُنشأ بـ enable_dynamic_fee = true لقطة من المعاملات الخمسة للضبط (filter_period، decay_period، reduction_factor، dynamic_fee_control، max_volatility_accumulator) في DynamicFeeInfo الخاص بها عند الإنشاء؛ التعديلات اللاحقة على DynamicFeeConfig لا تؤثر بأثر رجعي على المجمعات الموجودة.

DynamicFeeInfo (مضمّن في PoolState)

الحقول الأربعة السفلية هي حالة؛ الخمسة العليا هي معاملات ضبط منسوخة من DynamicFeeConfig. رياضيات الرسوم وقواعد الاضمحلال موثّقة في products/clmm/math وproducts/clmm/fees. الثوابت المستخدمة في الصيغة:

LimitOrderState

حساب واحد لكل أمر حد مفتوح.
دورة الحياة:
  1. الفتح — يستدعي المستخدم open_limit_order، يودع total_amount من رمز الإدخال، ويُربط الأمر بدُفعة TickState.
  2. (اختياري) الزيادة / التخفيض — يضيف increase_limit_order إلى total_amount؛ يُعيد decrease_limit_order الرموز غير المملوءة (وأي مخرجات مسوّاة حتى تلك النقطة).
  3. التسوية — عند ملء الدُفعة كلياً أو جزئياً، يستدعي المالك أو حارس العمليات settle_limit_order لدفع رموز المخرجات إلى ATA المالك.
  4. الإغلاق — بمجرد أن يصبح unfilled_amount == 0، يمكن إغلاق الحساب. يعود الإيجار دائماً إلى owner.
بذرة PDA: [owner.as_ref(), limit_order_nonce.key().as_ref(), limit_order_nonce.order_nonce.to_be_bytes().as_ref()]. وبذلك يكون PDA الأمر فريداً لكل (owner, nonce_index, order_nonce).

LimitOrderNonce

عداد لكل (wallet, nonce_index) يتيح لمستخدم واحد تشغيل خطوط متوازية متعددة من أوامر الحد دون تعارض في PDAs.
بذرة PDA: [user_wallet.as_ref(), &[nonce_index]]. معظم العملاء يستخدمون nonce_index = 0 ويتركون order_nonce يحمل العدد الكلي.

اشتقاق الحسابات الرئيسية

يجب دائماً التحقق المزدوج من سلاسل البذور مقابل IDL على السلسلة وreference/program-addresses.

مرجع سريع لدورة الحياة

حسابات TickArrayState لا يُغلقها البرنامج أبداً — تظل موجودة طوال عمر المجمع. بمجرد تهيئة مصفوفة تدرجات تبقى على السلسلة حتى عندما تعود كل التدرجات فيها إلى liquidity_gross == 0. إعادة استخدام مصفوفة موجودة مجانية؛ فقط أول مركز يلمس مصفوفة لم تُهيَّأ من قبل يدفع إيجارها.

ما تجده في كل صفحة

المصادر: