Na Solana, que gera milhares de transações por segundo, se você tentar escutar todas as atualizações de conta da rede, seu robô logo será sobrecarregado por uma quantidade imensa de ruído de dados. As limitações de largura de banda dos nós RPC, a pressão de decodificação da CPU e a latência da rede podem instantaneamente destruir oportunidades de arbitragem.
Um buscador eficiente nunca "ouve às cegas". Eles usam uma estratégia chamada "Monitoramento Direcionado por Estoque": primeiro, constroem offline um índice global do pool de liquidez da rede, filtrando os "pools de arbitragem candidatos" de alto valor, e depois realizam uma assinatura precisa.
Este artigo vai detalhar como construir este sistema de Inventory de alto desempenho.
1. Princípio central: reduzir o campo de batalha, focar nos pontos de vitória
1.1 Por que construir o Inventory?
Os DEX (exchanges descentralizadas) na Solana, como Raydium e Orca, possuem dezenas de milhares de pools de liquidez. Mas para estratégias de arbitragem, apenas aqueles pares de negociação que existem simultaneamente em múltiplos protocolos (por exemplo, SOL/USDC que tem pool na Raydium e também na Orca) possuem espaço para arbitragem atômica.
A tarefa do Inventory é:
Inicialização a frio agregada: obter a lista completa de pools de todas as APIs DEX.
Cálculo de interseção: identificar pares de negociação sobrepostos.
Filtragem da lista branca: eliminar pools zumbis e pools de baixa liquidez, gerando uma 'lista de escuta'.
1.2 Conduzido por inventário vs. Conduzido por totalidade
Conduzido por totalidade: Assinar todos os logs e buscar oportunidades para consultar a tabela. A vantagem é a ampla cobertura, a desvantagem é a alta latência e o processamento de dados redundantes.
Conduzido por inventário: Apenas assinar atualizações de contas dentro da lista branca. A vantagem é a resposta extremamente rápida, economizando recursos RPC, sendo a escolha preferida para arbitragem de alta frequência.
2. Arquitetura técnica: Máquina de estado de alta concorrência suportada por Rust
No mecanismo de execução Rust, o módulo Inventory é projetado como um singleton de alta concorrência e seguro para threads, compartilhado por múltiplos módulos de estratégia.
2.1 Estruturas de dados chave: DashMap e Arc
Devido ao processamento de dados da Solana ser paralelo e multithread, o Inventory deve lidar com uma frequência de leitura e gravação extremamente alta:
DashMap: Esta é uma tabela hash concorrente de alto desempenho. Em comparação com o HashMap padrão + Mutex, ela detalha o nível de bloqueio até o nível de fragmentação (Shard), evitando competição global de bloqueio em estados de alta frequência de análise.
Arc (Contagem de Referência Atômica): usado para compartilhar com segurança o endereço de memória do Inventory entre diferentes tarefas Tokio (como tarefas de escuta, tarefas de precificação, tarefas de execução), realizando acesso a dados sem cópia.
2.2 Lógica de indexação em camadas
O sistema mantém dois níveis de índices:
Índice Global de Pool: Registra o mapeamento de endereços de pools para metadados de tokens (Mint, Decimals, Vault).
Mapa de Pares de Arbitragem: Registra 'pares de arbitragem candidatos'. Por exemplo, insira o endereço Mint do SOL e retorne imediatamente suas informações associadas nas pools A da Raydium e B da Orca.
3. Implementação do algoritmo: interseção rápida O(N+M)O(N+M)
O núcleo da construção da lista branca de arbitragem é 'encontrar interseções'.
Escaneando o protocolo A (Raydium): armazenar todos os pools em uma tabela hash temporária de Token_A -> Pool_Address.
Escaneando o protocolo B (Orca): percorrer sua lista de pools e, se encontrar o mesmo Token_A na tabela hash do protocolo A, um potencial de arbitragem é identificado.
Gerar Watchlist: adicionar simultaneamente os endereços de dois pools identificados à 'lista de escuta (Watchlist)'.
Complexidade de tempo: é necessário apenas duas varreduras lineares, mesmo enfrentando dezenas de milhares de pools, a inicialização a frio pode ser concluída em milissegundos.
4. Pontos de otimização de desempenho: velocidade a partir de detalhes do projeto
4.1 Cache de API e tolerância a falhas
A API oficial de protocolos como Raydium muitas vezes não é suficientemente estável. Nós adicionamos um cache persistente local na implementação do projeto.
Durante a inicialização a frio, priorizar a leitura do pools_cache.json local.
Solicitações assíncronas em segundo plano para atualizar o cache da API.
Isso garante que, mesmo em condições extremas de rede, o robô possa retomar o trabalho imediatamente.
4.2 Limite de assinatura e fragmentação
A maioria dos nós RPC tem um limite para o número de conexões de accountSubscribe (como 50-100).
O Inventory classifica automaticamente a Watchlist com base na 'temperatura da pool (volume de negociação/TVL)', priorizando a assinatura das N pools com maior potencial de lucro, ou distribuindo a assinatura em múltiplos nós RPC através de balanceamento de carga.
5. Demonstração do protótipo do algoritmo (implementação lógica em Python)
Embora utilizemos Rust em ambientes de produção, sua lógica subjacente pode ser expressa claramente através do seguinte exemplo em 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. Construir o índice Raydium (Token -> Pool)
ray_index = {p.token_mint: p.address for p in ray_pools}
arbitrage_watchlist = []
# 2. Escanear Orca para encontrar interseções
for o_pool in orca_pools:
if o_pool.token_mint in ray_index:
# Encontrar sobreposição: esse token tem liquidez em ambos os 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
# Exibição de dados Mock
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"[*] Encontrado {len(watchlist)} caminhos potenciais de arbitragem")
# A saída incluirá o caminho de SOL, pois ambos os DEX têm pools de SOL
6. Resumo: O radar foi ativado
O módulo Inventory é a 'rede' de todo o sistema MEV, filtrando o ruído da rede e deixando apenas os alvos que brilham com potencial de lucro.
Sem Inventory: seu robô está processando milhares de informações inválidas sem propósito.
Com Inventory: seu robô foca apenas nas poucas pools de alta frequência que mudam rapidamente, pronto para agir a qualquer momento.
Próximos passos
Com a lista branca, o próximo passo é como capturar em tempo real as mudanças dessas contas. No próximo artigo, iremos para o módulo Scout, analisando como implementar a escuta de transações e a análise de dados em nível submilissegundo através do protocolo gRPC/WebSocket.
Este artigo foi escrito por Levi.eth, focando em práticas de engenharia de alto desempenho no ecossistema Solana.