На Solana, где каждую секунду создается тысячи транзакций, если вы пытаетесь отслеживать все обновления аккаунтов в сети, ваш бот быстро утонет в огромном количестве шумных данных. Ограничения пропускной способности RPC-узлов, нагрузка на процессор при разборе данных и сетевая задержка моментально уничтожат возможность арбитража.
Эффективный Searcher никогда не «слепо слушает». Они используют стратегию, называемую «мониторинг, управляемый инвентарем»: сначала строят глобальный индекс пула ликвидности по всему интернету в автономном режиме, отбирая высокодоходные «кандидаты на арбитраж», а затем точно подписываются на них.
В этой статье мы разберем, как построить такую высокопроизводительную систему Inventory.
1. Основная концепция: сужение поля боя, фокусировка на решающей точке
1.1 Зачем строить Inventory?
На Solana DEX (децентрализованные биржи), такие как Raydium и Orca, существует десятки тысяч пулов ликвидности. Однако для стратегий арбитража доступны только те пары, которые одновременно присутствуют в нескольких протоколах (например, SOL/USDC есть в Raydium и в Orca), что создает атомарные возможности для арбитража.
Задача Inventory заключается в:
Коллекция при холодном запуске: получение полного списка пулов с API различных DEX.
Вычисление пересечения: определение совпадающих пар токенов.
Фильтрация белого списка: исключение мертвых и низколиквидных пулов, создание «белого списка для мониторинга».
1.2 Драйв по инвентарю против драйва по полному объему
Драйв по полному объему: подписка на все логи, поиск возможностей, затем проверка таблицы. Преимущества — широкий охват, недостатки — чрезвычайно высокая задержка и избыточность обработки данных.
Драйв по инвентарю: подписка только на обновления учетных записей из белого списка. Преимущества — мгновенная реакция, экономия ресурсов RPC, предпочтительный выбор для высокочастотного арбитража.
2. Техническая архитектура: высокопроизводительная состояние-машина на Rust
В исполняющей среде Rust модуль Inventory спроектирован как одиночка (singleton) с высокой степенью параллелизма и потокобезопасности, доступный для совместного использования несколькими модулями стратегий.
2.1 Ключевые структуры данных: DashMap и Arc
Из-за многопоточной параллельной обработки данных Solana, Inventory должен справляться с чрезвычайно высокой частотой чтения и записи:
DashMap: это высокопроизводительная параллельная хеш-таблица. В отличие от стандартного HashMap + Mutex, она делит блокировки на фрагменты (Shard), что предотвращает глобальную блокировку при частой обработке состояний.
Arc (Atomic Reference Counted): используется для безопасного совместного использования адресов памяти Inventory между различными задачами Tokio (например, задачами прослушивания, ценообразования, выполнения), обеспечивая доступ к данным без копирования.
2.2 Логика многоуровневого индексирования
Внутри системы поддерживается двухуровневый индекс:
Глобальный индекс пулов: отображает адрес пула на метаданные токена (Mint, Decimals, Vault).
Карта пар арбитража: отслеживает «кандидатов на арбитраж». Например, при вводе адреса Mint SOL сразу возвращаются сведения о пуле Raydium A и пуле Orca B.
3. Реализация алгоритма: быстрое пересечение за O(N+M)
Ключевая идея построения белого списка — «нахождение пересечения».
Сканирование протокола A (Raydium): все пулы сохраняются во временной хеш-таблице по шаблону Token_A → Pool_Address.
Сканирование протокола B (Orca): перебор списка пулов, если в хеш-таблице протокола A найден один и тот же Token_A, это означает обнаружение потенциальной арбитражной возможности.
Создание Watchlist: добавление адресов обнаруженных пулов в «список мониторинга».
Временная сложность: завершается всего за два линейных просмотра, даже при наличии десятков тысяч пулов, холодный запуск завершается за миллисекунды.
4. Точки оптимизации производительности: скорость из инженерных деталей
4.1 Кэширование API и отказоустойчивость
Официальные API протоколов, такие как Raydium, часто недостаточно стабильны. Мы добавили локальное постоянное кэширование в инженерную реализацию.
При холодном запуске сначала читается локальный файл pools_cache.json.
Фоновый асинхронный запрос на обновление кэша через API.
Это гарантирует, что даже в экстремальных условиях сети робот может немедленно возобновить работу.
4.2 Ограничение подписок и фрагментация
Большинство узлов RPC ограничивают количество accountSubscribe для одного подключения (например, 50–100).
Inventory автоматически сортирует Watchlist по «жаркости пулов» (объему транзакций/TVL), приоритетно подписываясь на топ N пулов с наибольшим потенциалом дохода, либо распределяя подписки по нескольким узлам RPC с помощью балансировки нагрузки.
5. Прототип алгоритма (реализация на Python)
Хотя в продакшене мы используем Rust, основная логика может быть ясно продемонстрирована на следующем примере на Python:
from dataclasses import dataclass
from typing import Dict, List, Set
@dataclass(frozen=True)
class PoolMetadata:
address: str
token_mint: str
def build_arbitrage_radar(ray_pools: List[PoolMetadata], orca_pools: List[PoolMetadata]):
# 1. Создание индекса Raydium (Token → Pool)
ray_index = {p.token_mint: p.address for p in ray_pools}
arbitrage_watchlist = []
# 2. Сканирование Orca на поиск пересечений
for o_pool in orca_pools:
if o_pool.token_mint in ray_index:
# Обнаружено пересечение: этот токен имеет ликвидность в обоих DEX
arbitrage_watchlist.append({
"token": o_pool.token_mint,
"raydium_pool": ray_index[o_pool.token_mint],
"orca_pool": o_pool.address
})
return arbitrage_watchlist
# Мок-данные для демонстрации
ray_list = [PoolMetadata("RAY_SOL_POOL", "SOL_MINT"), PoolMetadata("RAY_BONK_POOL", "BONK_MINT")]
orca_list = [PoolMetadata("ORCA_SOL_POOL", "SOL_MINT"), PoolMetadata("ORCA_WIF_POOL", "WIF_MINT")]
watchlist = build_arbitrage_radar(ray_list, orca_list)
print(f"[*] Обнаружено {len(watchlist)} потенциальных арбитражных путей")
В выводе будет присутствовать путь для SOL, так как оба DEX имеют пул для SOL.
6. Заключение: радар включен
Модуль Inventory — это «сито» всей системы MEV, которое фильтрует всю шумовую информацию в сети и оставляет только те цели, которые светятся прибылью.
Без Inventory: ваш робот беспорядочно обрабатывает десятки тысяч недействительных сообщений.
С Inventory: ваш робот внимательно следит только за десятками пулов, которые постоянно меняются, и готов в любой момент нажать на курок.
Следующие шаги
После получения белого списка следующим шагом является как можно быстрее захватить изменения этих учетных записей. В следующей статье мы перейдем к модулю Scout и рассмотрим, как реализовать мониторинг транзакций и анализ данных с задержкой менее миллисекунды с использованием протоколов gRPC/WebSocket.
Эта статья написана Levi.eth и посвящена высокопроизводительной инженерной практике в экосистеме Solana.