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

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.

هذه الصفحة مُترجَمة آليًا بواسطة الذكاء الاصطناعي. النسخة الإنجليزية هي المرجع المعتمد.عرض النسخة الإنجليزية →
تجمع هذه الصفحة الاشتقاقات الرياضية وراء CLMM. لتطبيق السلسلة الذي يعمل مباشرة، انظر products/clmm/math (الذي يُشير إلى هذه الصفحة) وproducts/clmm/ticks-and-positions (الذي يُبرّر شبكة التيك).

لماذا الجذر التربيعي للسعر وليس السعر ذاته

تمثّل CLMM العائلات شبيهة Uniswap-v3 السعر كجذره التربيعي، مخزّن في Q64.64 بنقطة ثابتة:
sqrt_price_x64 = floor(sqrt(price) · 2^64)
ثلاثة أسباب:
  1. حسابيات السيولة الخطية. كمية token0 أو token1 في نطاق السعر تتبيّن أنها دالة خطية لـ sqrt_price وليس لـ price. يتيح تخزين sqrt_price لخطوة المبادلة تقييم تلك الصيغ الخطية دون حساب جذر تربيعي.
  2. التحكم في الامتلاء. sqrt_price · L يناسب u256 لجميع المعاملات المعقولة؛ price · L قد يتجاوز الحد بكثير أبكر.
  3. حسابيات التيك موحدة. لأن التيكات معرّفة كـ 1.0001^i، فإن sqrt(price) = 1.00005^i هو أيضًا سلم دقيق لقوة 1.00005. كل عبور تيك ينقل إلى ضرب صغير في فضاء sqrt_price_x64.
السعر والجذر التربيعي للسعر متطابقان؛ التحويل هو price = (sqrt_price_x64 / 2^64)^2.

شبكة التيك

يتم تحديد الأسعار على شبكة:
price(tick_i) = 1.0001^i
tick_i هو i32. النطاق النشط هو [MIN_TICK, MAX_TICK] = [−443636, 443636]، مما يعطي نطاق سعر تقريبي [2^−128, 2^128]. يتم تعيين tick_spacing لكل مجموعة من قبل طبقة الرسوم الخاصة بها: مسافات أصغر للأزواج الضيقة (مثلاً المستقرات 0.01% تستخدم المسافة 1)، مسافات أكبر للأزواج المتقلبة (طبقة 0.25% تستخدم 60، طبقة 1% تستخدم 120). يجب أن تكون المراكز محاذية لـ tick_lower وtick_upper إلى tick_spacing. التيكات النشطة للمجموعة (تلك التي لديها سيولة تبدأ أو تنتهي هناك) هي التيكات الوحيدة التي تهتم بها خطوة المبادلة.

السيولة إلى الكمية

لمركز بسيولة L ونطاق سعر [sqrt_lo, sqrt_hi] (جميع قيم sqrt_price):
حالة المجموعةكمية token0كمية token1
السعر فوق النطاق (sqrt_p ≥ sqrt_hi)0L · (sqrt_hi − sqrt_lo)
السعر في النطاقL · (sqrt_hi − sqrt_p) / (sqrt_p · sqrt_hi)L · (sqrt_p − sqrt_lo)
السعر تحت النطاق (sqrt_p ≤ sqrt_lo)L · (sqrt_hi − sqrt_lo) / (sqrt_lo · sqrt_hi)0
الاشتقاق: تفاضل متغير CPMM محليًا. داخل أي نطاق تيك واحد، يتصرف المركز كـ CPMM مع احتياطيات افتراضية (x_v, y_v) مختارة بحيث يكون (sqrt_p, L) الحالي للمجموعة متسقًا مع L = sqrt(x_v · y_v). دمج من sqrt_p إلى حدود النطاق يعطي الكميات أعلاه. الصيغ العكسية (تُستخدم عند إنشاء مركز لـ amount0 أو amount1 معين):
L_from_amount0(amount0, sqrt_lo, sqrt_hi, sqrt_p) =
    amount0 · sqrt_p · sqrt_hi / (sqrt_hi − sqrt_p)

L_from_amount1(amount1, sqrt_lo, sqrt_hi, sqrt_p) =
    amount1 / (sqrt_p − sqrt_lo)

// لإيداع متماثل في مركز في النطاق، خذ الحد الأدنى.
L = min(L_from_amount0, L_from_amount1)

خطوة المبادلة أحادية التيك

داخل نطاق تيك واحد، تتصرف المجموعة مثل CPMM. بالنظر إلى sqrt_p الحالي وsqrt_target:
Δamount0_step = L · (sqrt_target − sqrt_p) / (sqrt_p · sqrt_target)     // عند المبادلة مقابل token0
Δamount1_step = L · (sqrt_target − sqrt_p)                              // عند المبادلة مقابل token1

خطوة الإدخال الدقيق

بالنظر إلى Δin_remaining:
// الجذر التربيعي للسعر المرشح الجديد إذا ملأنا حتى حد التيك:
sqrt_after_full = sqrt_target
amount_to_full  = Δamount_in_to_reach(sqrt_p → sqrt_target)

if Δin_remaining ≥ amount_to_full:
    // استهلك بقية الحاوية
    sqrt_p'         = sqrt_target
    Δin_consumed    = amount_to_full
    Δout            = amount_out_at_boundary
else:
    // لا نعبر؛ حل لـ sqrt_p النهائي
    sqrt_p'         = L · sqrt_p / (L + Δin_remaining · sqrt_p)      // لمبادلات 0→1
    Δin_consumed    = Δin_remaining
    Δout            = L · (sqrt_p − sqrt_p')                          // متناسب مع Δsqrt
مبادلة 0→1 تخفض sqrt_p (السعر ينخفض عندما نبيع token0). مبادلة 1→0 ترفعه. الصيغ متماثلة مع sqrt_p وsqrt_target مبدلين.

خطوة الإخراج الدقيق

نفس البنية، حل لـ Δin بدلاً من ذلك.

حلقة المبادلة متعددة التيك

تكرر المبادلة على التيكات حتى ينضب الإدخال أو يتم الوصول إلى حد السعر:
while Δin_remaining > 0 and sqrt_p != sqrt_price_limit:
    next_tick = find_next_initialized_tick(pool.tick_current, direction)
    sqrt_target = min(next_tick.sqrt_price, sqrt_price_limit)       // اتجاهيًا

    (Δin, Δout, sqrt_p') = single_step(sqrt_p, sqrt_target, L, Δin_remaining)

    Δin_remaining -= Δin
    accumulated_out += Δout

    if sqrt_p' == next_tick.sqrt_price:
        // عبور التيك
        L += next_tick.liquidity_net * direction_sign
        flip_fee_growth_outside(next_tick)
        match_limit_orders_at_tick(next_tick, ...)        // انظر products/clmm/math
        pool.tick_current = next_tick.tick_index
    sqrt_p = sqrt_p'
تستخدم كل single_step الـ L الحالية للمجموعة. يتغير L فقط عند عبور تيك مهيأ. السيولة بين التيكات ثابتة، وهو ما يجعل رياضيات الخطوة بصيغة مغلقة. liquidity_net عند تيك هو المجموع الموقّع لسيولة المراكز التي تبدأ عند ذلك التيك ناقص تلك التي تنتهي هناك. يضيف عبور صعودي liquidity_net؛ عبور هبوطي يطرحه. عندما تكون لدى المجموعة أوامر محددة مفتوحة عند تيك، تستهلك خطوة عبور التيك أيضًا جزء من إدخال المبادلة لملء تلك الأوامر بشكل استباقي (FIFO عبر الفئات). تتم توثيق خوارزمية المطابقة والرسوم الديناميكية التي قد تنطبق فوق خطوة القاعدة في products/clmm/math؛ فهي لا تغير الصيغ أحادية الخطوة المغلقة أعلاه.

مراكمات نمو الرسوم

تتتبع CLMM الرسوم لكل وحدة سيولة نشطة، لكل جانب، عمومًا ولكل تيك:
fee_growth_global_0_x64     // Q64.64، رتيب
fee_growth_global_1_x64
tick.fee_growth_outside_0_x64   // "الرسوم المستحقة بينما كان هذا التيك خارج النطاق النشط"
tick.fee_growth_outside_1_x64
في كل single_step:
step_lp_fee = (Δin · fee_rate) · (1 − protocol_fraction − fund_fraction)
fee_growth_global += step_lp_fee · 2^64 / L     // فقط لجانب الإدخال
(لا تتحرك fee_growth_global للجانب الآخر في هذه الخطوة، لأنه لم يتم دفع أي رمز على ذلك الجانب كإدخال.) عند عبور تيك، يقوم البرنامج بـ قلب fee_growth_outside:
tick.fee_growth_outside_0_x64 = fee_growth_global_0_x64 − tick.fee_growth_outside_0_x64
tick.fee_growth_outside_1_x64 = fee_growth_global_1_x64 − tick.fee_growth_outside_1_x64
“خارج” نسبي إلى tick_current. عندما يكون tick_current فوق التيك، خارج يعني “أدناه”. عندما يكون tick_current أدناه، خارج يعني “أعلاه”. القلب يبدّل التفسير.

fee_growth_inside لمركز

بالنظر إلى مركز [tick_lower, tick_upper] والـ tick_current الحالي:
if tick_current >= tick_upper:
    inside = tick_lower.fee_growth_outside − tick_upper.fee_growth_outside
else if tick_current < tick_lower:
    inside = tick_upper.fee_growth_outside − tick_lower.fee_growth_outside
else:     // المركز في النطاق
    inside = fee_growth_global
           − tick_lower.fee_growth_outside
           − tick_upper.fee_growth_outside
الرسوم غير المجمعة للمركز لجانب الرمز s هي:
tokens_owed_s += L · (fee_growth_inside_s − fee_growth_inside_last_s) / 2^64
fee_growth_inside_last_s = fee_growth_inside_s
يتم تشغيل هذا التحديث في كل تفاعل مع المركز (IncreaseLiquidity وDecreaseLiquidity وCollectFees).

مثال عملي — عبور تيك واحد

مجموعة (مبسطة):
  • sqrt_p_x64 = 2^64 · 1.0 = 2^64 (السعر = 1.0)
  • L = 1_000_000
  • tick_current = 0
  • التيك المهيأ التالي أدناه: tick = −60، sqrt_price = 1.0001^(−30) ≈ 0.99700، liquidity_net = −400_000 (ينتهي هذا التيك مركزًا، لذا عبور هبوطي يزيل 400k)
  • معدل الرسوم: 0.25%
مبادلة: Δin = 10_000 token0، الاتجاه = 0→1. الخطوة 1 — حتى sqrt_target = 0.99700 · 2^64:
amount_in_to_target = L · (1/sqrt_target − 1/sqrt_p)
                    = 1_000_000 · (1/0.99700 − 1/1.0)
                    ≈ 1_000_000 · 0.003009
                    ≈ 3_009
3,009 < 10,000، لذا نملأ هذه الخطوة بالكامل:
Δin_step  = 3_009 / (1 − 0.0025)  = 3_017    // بما في ذلك الرسوم
Δout_step = L · (sqrt_p − sqrt_target) ≈ 1_000_000 · 0.00299 ≈ 2_990
sqrt_p    = 0.99700 · 2^64
tick_current = −60
L         = 1_000_000 + (−400_000)  = 600_000         // عبور التيك
fee_growth_outside في التيك −60 مقلوب
Δin_remaining = 10_000 − 3_017 = 6_983
الخطوة 2 — مع L = 600_000 الجديدة: التيك المهيأ التالي (مثلاً tick = −120) عند sqrt = 0.99402. أعد الحساب amount_in_to_target:
amount_in_to_target = 600_000 · (1/0.99402 − 1/0.99700)
                    ≈ 600_000 · 0.003010
                    ≈ 1_806
لا يزال أقل من Δin_remaining. عبور مرة أخرى. استمر حتى يصل Δin_remaining إلى الصفر. يتراكم تسلسل كامل Δout إلى مخرجات المبادلة النهائية.

التهيئة وحماية الامتلاء

  • MIN_SQRT_PRICE_X64 وMAX_SQRT_PRICE_X64 مقابلان لـ tick = ±443636. أي مبادلة قد تدفع sqrt_p خارج هذا النطاق ترتد.
  • معامل sqrt_price_limit للمستخدم يجب أن يقع في نفس الفترة؛ يتحقق البرنامج منه.
  • يتم حساب منتجات L · Δsqrt في u256 ثم إزاحتها للخلف إلى u128 لتجنب الامتلاء.

الفروقات مقابل Uniswap v3

  • الأوراكل. تخزن ObservationState الخاصة بـ Raydium (block_timestamp, tick_cumulative, seconds_per_liquidity_cumulative) في حاوية حلقية؛ تنسيق سلك مختلف قليلاً عن Uniswap لكن نفس رياضيات TWAP.
  • Token-2022. يدعم Raydium CLMM رموز Token-2022؛ المتغير الذي يحتوي على رسم نقل يتطلب تعديلات إضافية لكمية ما قبل/بعد المبادلة. انظر algorithms/token-2022-transfer-fees.
  • خريطة البت للتيك. تضغط Raydium خريطة البت للتيك المهيأ إلى [u64; 16] لكل مجموعة للبحث السريع find_next_initialized_tick؛ تستخدم Uniswap تعيينًا مفتوحًا لكل كلمة على السلسلة. المفاضلة بين الإيجار وتكلفة البحث.
  • فتحات المكافآت. تدعم Raydium 3 تدفقات مكافآت لكل مجموعة مع عدادات reward_growth_global_x64 منفصلة؛ نفس البنية كمراكم نمو الرسوم.

المؤشرات

المصادر:
  • ورقة Uniswap v3 البيضاء (الاشتقاق القياسي لرياضيات جذر السعر التربيعي).
  • مصدر برنامج Raydium CLMM.