انتقل إلى المحتوى الرئيسي
بلوكتشينMar 28, 2026

Deep EVM #14: بناء باحث دورات المراجحة — البحث بالعمق أولاً على رسم بياني للمجمعات

OS
Open Soft Team

Engineering Team

مشكلة المراجحة الدورية

المراجحة الدورية هي العثور على مسار عبر عدة مجمعات سيولة يبدأ وينتهي بنفس الرمز مع ربح صافٍ. على سبيل المثال:

ETH → USDC (Uniswap V2)
USDC → DAI (Curve)
DAI → ETH (Sushiswap)

إذا كان الناتج النهائي أكثر ETH مما بدأت به (بعد خصم الغاز)، فهناك فرصة مراجحة.

نمذجة المشكلة كرسم بياني

كل رمز هو عقدة. كل مجمع سيولة هو حافة (أو أكثر) بين الرموز التي يدعمها:

struct Pool {
    address: Address,
    token0: Address,
    token1: Address,
    reserve0: U256,
    reserve1: U256,
    fee: u32,  // بالنقاط الأساسية
}

struct Graph {
    adjacency: HashMap<Address, Vec<Edge>>,
}

struct Edge {
    pool: Pool,
    target_token: Address,
}

خوارزمية DFS

البحث بالعمق أولاً يستكشف كل المسارات الممكنة من رمز البداية:

fn find_cycles(
    graph: &Graph,
    start: Address,
    current: Address,
    path: &mut Vec<Edge>,
    visited: &mut HashSet<Address>,
    cycles: &mut Vec<Vec<Edge>>,
    max_depth: usize,
) {
    if path.len() > max_depth {
        return;
    }
    
    if path.len() >= 2 && current == start {
        cycles.push(path.clone());
        return;
    }
    
    if visited.contains(&current) && current != start {
        return;
    }
    visited.insert(current);
    
    if let Some(edges) = graph.adjacency.get(&current) {
        for edge in edges {
            path.push(edge.clone());
            find_cycles(
                graph, start, edge.target_token,
                path, visited, cycles, max_depth,
            );
            path.pop();
        }
    }
    visited.remove(&current);
}

حساب الربح

لكل دورة مكتشفة، نحسب الناتج المتوقع:

fn calculate_output(
    amount_in: U256,
    reserve_in: U256,
    reserve_out: U256,
    fee_bps: u32,
) -> U256 {
    let amount_with_fee = amount_in * (10000 - fee_bps);
    let numerator = amount_with_fee * reserve_out;
    let denominator = reserve_in * 10000 + amount_with_fee;
    numerator / denominator
}

fn simulate_cycle(cycle: &[Edge], amount_in: U256) -> U256 {
    let mut current = amount_in;
    for edge in cycle {
        current = calculate_output(
            current,
            edge.pool.reserve_in(),
            edge.pool.reserve_out(),
            edge.pool.fee,
        );
    }
    current  // إذا > amount_in، هناك ربح
}

تحسين المبلغ الأمثل

المبلغ الأمثل ليس دائماً الأقصى. استخدم البحث الثنائي:

fn find_optimal_amount(
    cycle: &[Edge],
    min: U256,
    max: U256,
) -> (U256, U256) {
    let mut lo = min;
    let mut hi = max;
    let mut best_amount = min;
    let mut best_profit = U256::ZERO;
    
    for _ in 0..64 {
        let mid = (lo + hi) / 2;
        let output = simulate_cycle(cycle, mid);
        let profit = output.saturating_sub(mid);
        
        if profit > best_profit {
            best_profit = profit;
            best_amount = mid;
        }
        
        // فحص الاتجاه
        let output_plus = simulate_cycle(cycle, mid + 1);
        if output_plus.saturating_sub(mid + 1) > profit {
            lo = mid;
        } else {
            hi = mid;
        }
    }
    (best_amount, best_profit)
}

الأداء

التحديات الرئيسية:

  • عدد المسارات — رسم بياني بـ 1000 رمز و5000 مجمع يولد ملايين الدورات المحتملة
  • قيد الوقت — 12 ثانية بين الكتل على إيثيريوم
  • تحديث الحالة — الاحتياطيات تتغير مع كل كتلة

التحسينات:

  1. التقليم المبكر — تجاهل المسارات التي لا يمكنها تحقيق ربح
  2. التوازي — توزيع البحث على عدة خيوط باستخدام rayon
  3. التخزين المؤقت — تخبئة حسابات المخرجات المتكررة
  4. تحديد العمق — الحد من طول الدورة (عادة 2-4 قفزات)

الخلاصة

باحث دورات المراجحة هو قلب أي روبوت MEV مراجحة. المكونات الأساسية: رسم بياني للمجمعات، DFS للعثور على الدورات، محاكاة لحساب الربح، وبحث ثنائي للمبلغ الأمثل. الباقي تحسين.

الوسوم