الانتقال إلى المحتوى الرئيسي

Documentation Index

Fetch the complete documentation index at: https://docs.raydium.io/llms.txt

Use this file to discover all available pages before exploring further.

هذه الصفحة مُترجَمة آليًا بواسطة الذكاء الاصطناعي. النسخة الإنجليزية هي المرجع المعتمد.عرض النسخة الإنجليزية →

لماذا توجد التدرجات (Ticks)؟

تتركز سيولة CLMM في نطاقات سعرية محددة. ولجعل هذه النطاقات قابلةً للمعالجة على السلسلة، تُكمَّم الأسعار إلى تدرجات (ticks) صحيحة، بحيث يمثّل كل تدرج مضاعفًا ثابتًا للتدرج السابق: price(i)=1.0001i\text{price}(i) = 1.0001^{\,i} يقابل كل تدرج حركةً سعريةً بنسبة 0.01%، أي ما يعادل نقطة أساس واحدة تقريبًا. وفيما يلي جدول التعيين:
مؤشر التدرج iمضاعف السعر
01.0000
1001.0100 (≈ +1.00%)
-1000.9900 (≈ −0.99%)
100002.7181 (≈ e)
MAX_TICK = 4436361.84e19
MIN_TICK = -4436365.42e-20
اختيار MIN_TICK وMAX_TICK مدروس لضمان أن قيمة sqrt_price_x64 تتسع في نوع البيانات u128 عند طرفي النطاق. يفرض كل pool شرطَي: tick_lower >= MIN_TICK وtick_upper <= MAX_TICK. من الناحية العملية، تُقيّد واجهة الويب النطاق إلى قيم أضيق بكثير لمنع المستخدمين من تجميد سيولتهم في تدرجات لا يمكن الوصول إليها.

التباعد بين التدرجات (Tick Spacing)

يُحدد AmmConfig الخاص بكل pool قيمةَ التباعد بين التدرجات (tick spacing)، وهي التدرجات الوحيدة المسموح باستخدامها كنقاط نهاية للمراكز. فإن كان tick_spacing = 60، لم تكن التدرجات الصالحة إلا: …, −120, −60, 0, 60, 120, …. أي محاولة لفتح مركز بنقطة نهاية 31 ستؤدي إلى إلغاء العملية برسالة InvalidTickIndex. القيم الشائعة للتباعد المنشورة:
مستوى الرسومtrade_fee_rateالتباعد بين التدرجاتأضخم خطوة سعرية لكل موضع تدرج
0.01%10010.01%
0.05%500100.10%
0.25%2500600.60%
1.00%100001201.21%
كلما اتسع التباعد، قلّت مصفوفات التدرجات اللازمة للتهيئة، وانخفضت تكلفة فتح مركز واسع، وأصبح الحد السعري أقل دقةً. تعيش أزواج التداول المتقلبة عادةً في مستويات التباعد 120، بينما تستقر الأزواج المستقرة (stables) في مستويات التباعد 1.

مصفوفات التدرجات (Tick Arrays)

لا يخزّن الـ pool حالة كل تدرج في حسابات منفصلة. عوضًا عن ذلك، تُحزم TICK_ARRAY_SIZE تدرجات متجاورة (60 في Raydium CLMM الحالي) في حساب TickArrayState واحد. يُحدّد أول تدرج في المصفوفة قيمة start_tick_index، وتغطي المصفوفة تمامًا TICK_ARRAY_SIZE * tick_spacing وحدةً من وحدات التدرج الصحيحة. عند tick_spacing = 60 وTICK_ARRAY_SIZE = 60:
  • تمتد كل مصفوفة تدرجات 60 × 60 = 3600 تدرجًا صحيحًا.
  • قيمة start_tick_index مضاعف لـ 3600: …, -7200, -3600, 0, 3600, 7200, ….
نقطة نهاية المركز t = 2040 عند tick_spacing = 60 تقع في مصفوفة التدرجات ذات start_tick_index = 0، في حين تقع t = 4200 في المصفوفة ذات start_tick_index = 3600.

متى تُنشأ المصفوفة؟

إنشاء مصفوفات التدرجات مؤجَّل (lazy)؛ إذ يُهيّئ المصفوفةَ أول مركز يُشير إلى أي تدرج داخلها، ويدفع هو أيضًا رسوم الإيجار (rent). عمليات الـ swap لا تُهيّئ مصفوفات التدرجات، بل تتخطى المصفوفات غير المُهيَّأة باستخدام الخريطة النقطية (bitmap). يفحص تدفق فتح المركز في SDK النطاق المختار، ويحسب قائمة مصفوفات التدرجات التي يلمسها، ثم يُضيف تعليمات init_tick_array في نفس العملية مع OpenPosition إن وُجدت مصفوفات مفقودة.

مصفوفات التدرجات لا تُغلق

بمجرد تهيئة مصفوفة تدرجات، تبقى قائمةً طوال عمر الـ pool. لا يكشف البرنامج عن أي مسار لإغلاق مصفوفة تدرجات، حتى حين يعود initialized_tick_count إلى الصفر. لا استرداد للإيجار من مصفوفات التدرجات؛ فالإيجار الذي دفعه أول مركز لمسَ المصفوفةَ يصبح محجوزًا في ذلك الحساب إلى الأبد. هذا مقايضة مقصودة: إعادة استخدام مصفوفة تدرجات موجودة مجانية لكل مركز لاحق، فبالتالي لا يدفع الـ pool النشط تكلفة الإيجار إلا مرةً واحدة لكل فتحة (pool, start_tick_index) بصرف النظر عن معدل الدوران.

الخريطة النقطية (Bitmap)

يجب أن يكون البحث عن “أقرب تدرج مُهيَّأ على يسار/يمين التدرج الحالي” سريعًا، إذ قد تتجاوز عملية swap تدرجاتٍ كثيرة. يخزّن الـ pool خريطةً نقطيةً بمقدار bit لكل مصفوفة تدرجات، مُضمَّنةً مباشرةً في PoolState، تغطي نطاق ±1,024 مصفوفة حول التدرج 0. خارج هذا النطاق (المراكز ذات النطاق الكامل والإعدادات الخاصة)، تتولى TickArrayBitmapExtension التعامل مع الفائض. تسير عملية swap عبر الخريطة النقطية: lowest_set_bit_above(tick_current_array_index) يُعطي المصفوفة التالية التي تحوي تدرجًا مُهيَّأً في الاتجاه الذي تتجه نحوه. داخل تلك المصفوفة، يُحدّد فحص بِتِّي مشابه التدرجَ المُهيَّأ التالي.

liquidity_gross وliquidity_net

يخزّن كل تدرج مُهيَّأ قيمتَين للسيولة:
  • liquidity_gross — مجموع L لجميع المراكز التي تُشير إلى هذا التدرج كنقطة نهاية (سواء أكانت حدًا أدنى أم أعلى). حين تصل liquidity_gross إلى الصفر، يصبح التدرج غير مُهيَّأ ويمكن حذفه من الخريطة النقطية.
  • liquidity_net — التغيُّر الموقَّع في liquidity على مستوى الـ pool عندما يتجاوز السعر هذا التدرج في الاتجاه التصاعدي (من اليسار إلى اليمين في فضاء التدرجات). إن كان هذا التدرج حدًا أدنى لمركز بحجم L، فإنه يُضيف +L؛ وإن كان حدًا أعلى لذلك المركز، فإنه يُضيف −L.
مثال توضيحي: مركزان على نفس الـ pool.
  • المركز A: tick_lower = -120، tick_upper = 0، سيولة L_A = 100.
  • المركز B: tick_lower = -60، tick_upper = 60، سيولة L_B = 50.
حالة التدرجات تفصيليًا:
التدرجيمسّهliquidity_grossliquidity_net
-120الحد الأدنى لـ A100+100
-60الحد الأدنى لـ B50+50
0الحد الأعلى لـ A100−100
60الحد الأعلى لـ B50−50
قيمة liquidity على مستوى الـ pool لمختلف قيم tick_current:
  • tick_current = -180: liquidity = 0 (قبل أي مركز)
  • tick_current = -90: liquidity = 100 (داخل A فقط)
  • tick_current = -30: liquidity = 150 (داخل A و B معًا)
  • tick_current = 30: liquidity = 50 (داخل B فقط)
  • tick_current = 90: liquidity = 0 (بعد كلا المركزين)
عند كل تجاوز لتدرج أثناء عملية swap، يُضيف البرنامج liquidity_net (التي قد تكون سالبة) إلى PoolState.liquidity. هذه هي الآلية ذاتها المستخدمة في Uniswap v3.

المراكز بوصفها NFTs

مركز Raydium CLMM هو NFT. عند فتح مركز، يُصكّ mint جديد كليًا بمعروض 1 في محفظة المُنشئ، وتكون صلاحية mint بيد برنامج CLMM. يربط البرنامج ملكية المركز بـ من يملك رصيدًا في ATA لذلك الـ mint وقت استدعاء CPI. التبعات:
  • المراكز قابلة للنقل. يمكن لأي محفظة بيع مركز أو توزيعه بنقل الـ NFT، ويصبح الحائز الجديد قادرًا على استدعاء CollectRewards وIncreaseLiquidity وغيرها.
  • المراكز قابلة للعنونة خارج CLMM. تعرض المنصات والمحافظ المراكز كسائر الـ NFTs. يضبط SDK اسمًا name ورمزًا symbol مناسبَين في بيانات الـ mint الوصفية.
  • عنوان PDA للمركز مُشتق من mint الـ NFT. يمكنك العثور على PersonalPositionState دون معرفة من يحتفظ به حاليًا.

مراكز Token-2022

يمكن لـ pools CLMM الأحدث أن تُصكّ المراكز عبر Token-2022 بدلًا من SPL Token الكلاسيكي. يوفر البرنامج تعليمتَي فتح متوازيتَين — OpenPosition وOpenPositionWithToken22Nft — بدلالات متطابقة تمامًا، باستثناء برنامج الرمز المالك لـ mint الـ NFT. يتباين التوافق بين المحافظ والمنصات؛ وتتابع واجهة Raydium كلا النوعين.

قواعد النطاق المسموح به

يفرض البرنامج عند OpenPosition الشروط التالية:
  1. tick_lower < tick_upper.
  2. tick_lower % tick_spacing == 0 وtick_upper % tick_spacing == 0.
  3. MIN_TICK <= tick_lower وtick_upper <= MAX_TICK.
  4. قدّم المُنشئ مصفوفات التدرجات التي تحوي tick_lower وtick_upper — إما مُهيَّأةً مسبقًا أو عبر init_tick_array في نفس العملية.
  5. حساب امتداد الخريطة النقطية، إن امتد هذا المركز إلى نطاق الامتداد.
إن فشل أيٌّ من هذه الشروط، تُلغى التعليمة برسالة InvalidTickIndex أو NotApproved أو InsufficientLiquidity بحسب القيد المنتهَك. راجع reference/error-codes.

”ضمن النطاق” مقابل “خارج النطاق”

يكون المركز ضمن النطاق (in range) حين يتحقق الشرط: tick_lower <= tick_current < tick_upper. المراكز ضمن النطاق فقط هي التي تُساهم في PoolState.liquidity، وبالتالي هي وحدها التي تكسب رسوم الـ swap. المركز الخارج عن النطاق:
  • يحتوي 100% من رمز واحد (الرمز الذي مرّ السعر بنطاقه). تحديدًا، إن كان tick_current < tick_lower، يحتوي المركز على token1 فقط (إذ “بِيع” إليه بتحرك السعر بعيدًا)؛ وإن كان tick_current >= tick_upper، يحتوي على token0 فقط.
  • لا يكسب رسوم الـ swap.
  • يواصل تراكم المكافآت إن كانت تدفقات مكافآت الـ pool تُصدر للسيولة خارج النطاق — غير أن السلوك الافتراضي في Raydium هو “الإصدار للسيولة ضمن النطاق فقط”، توافقًا مع اصطلاح Uniswap v3. راجع products/clmm/fees.
يُمضي مزودو السيولة في CLMM معظم اهتمامهم في إبقاء مراكزهم ضمن النطاق مع تحرك السعر.

أخطاء التكامل الشائعة

  • نقاط نهاية لا تتوافق مع التباعد. الكود الذي يحسب تدرجًا من سعر مستهدف يجب أن يُدوّره إلى أقرب مضاعف لـ tick_spacing قبل تمريره إلى OpenPosition. أدوات SDK (TickUtils.getTickWithPriceAndTickspacing) تتكفل بذلك؛ أما الحسابات المكتوبة يدويًا فغالبًا لا تفعل.
  • مصفوفات تدرجات مفقودة. قد يستلزم فتح مركز واسع تهيئة عدة مصفوفات تدرجات؛ فنسيان تمريرها كحسابات قابلة للكتابة يُلغي العملية. تُعيد دالة openPositionFromBase في SDK القائمة المطلوبة تلقائيًا.
  • تدرج قديم بعد عملية swap. قد يتجاوز tick_current تدرجاتٍ كثيرة في swap واحدة. إن كانت واجهتك تعرض “التدرج الحالي” من استدعاء RPC سابق ثم تفتح مركزًا في استدعاء لاحق، فقد يكون الموضع النسبي مقارنةً بالسعر الحي منحرفًا بعشرات التدرجات. أعد الجلب مباشرةً قبل التوقيع.
  • NFTs المراكز ذات البيانات الوصفية الإضافية. إن كنت تبني محفظة تتعرف على مراكز Raydium، فاكتشفها من خلال صلاحية الـ mint (= PDA برنامج CLMM)، لا من خلال حقل بيانات وصفية ثابت.

ما التالي؟

  • الرياضيات — خطوات حساب الـ swap واشتقاق نمو الرسوم التي تشارك فيها حدود التدرجات.
  • الحسابات — تخطيط TickArrayState وPositionState.
  • الرسوم والمكافآت — كيف يتحكم كون المركز ضمن النطاق في تراكم الرسوم.
  • algorithms/clmm-math — الاشتقاق المشترك لصيغ السيولة المركّزة.
المصادر: