A execução que foi arranjada: lendo a ordem das transações para encontrar um sandwich de MEV
O desafio
A Vertex Desk trocou 40 WETH por ORCA em um roteador público. A cotação na tela dizia cerca de 118.000 ORCA. A execução voltou em 104.880, onze por cento pior, e a mesa quer saber quem ficou com a diferença. Aqui estão os eventos de swap do roteador em quatro blocos consecutivos, na ordem em que a rede os executou: primeiro o bloco, depois a posição dentro dele. A carteira da mesa é 0x4d81ac9f2b7e61d0cc35a84f19e7b2065da3f7c8. Alguém pagou quinze vezes o preço do gás corrente para estar dos dois lados dessa operação. Diga o endereço.
O que você vai aprender
- Ler a posição de bloco e intra-bloco como a ordenação que decide o preço de uma operação
- Identificar o padrão compra, vítima, venda de um ataque sandwich em eventos brutos de swap
- Usar um preço de gás anormal como o sinal de que a ordenação foi comprada
- Diferenciar um sandwich de uma arbitragem comum que compra e vende por coincidência
- Explicar por que a tolerância de slippage, e não o roteador, é o que torna o ataque lucrativo
Habilidades testadas
Pré-requisitos
- O que é um swap de token em um automated market maker
- Que as transações em um bloco têm uma ordem
Como funciona
Em um market maker de produto constante, o preço que você recebe é decidido pelo estado do pool no instante em que sua transação é executada, e esse instante é decidido por onde sua transação cai dentro de um bloco. As duas coisas são públicas antes de acontecerem. Um swap pendente fica na mempool anunciando seu tamanho e o pior preço que aceitará, que é tudo o que alguém precisa para calcular o quanto pode mover o preço contra você e ainda assim fazer com que a operação seja concluída.
Um sandwich é três transações em um único bloco. O atacante compra primeiro, o que empurra o preço para cima. Sua ordem é executada contra o pool que ele acabou de mover, então você paga mais e recebe menos. Em seguida, ele vende para a demanda que sua própria ordem criou, e o pool volta a aproximadamente onde começou. O lucro dele é a diferença, e ela sai da sua execução.
A posição no bloco é comprada, não negociada. Pagar um grande prêmio de gás nas duas pontas é o que garante que uma caia na frente de você e a outra caia atrás, motivo pelo qual um preço de gás fora do padrão ao lado de uma operação comum é o sinal mais evidente nesses dados. Sua tolerância de slippage define o teto: ela diz ao atacante exatamente o quanto ele pode tirar antes que sua transação reverta e ele não fique com nada.
Erros comuns
- Responder 0xa83c15e0. Ele compra e vende no mesmo bloco, mas nas posições 06 e 71, sem nada grande entre elas e sem prêmio de gás. Isso é arbitragem, não um sandwich.
- Responder 0xb27f604c. Ele vende e depois compra, no bloco 21594117. A ordem está invertida, e um sandwich só funciona em uma direção.
- Responder 0x6e0472bd. Ele paga os mesmos 341 gwei no bloco 21594119, mas tem apenas uma ponta. Gás alto sozinho não é o ataque.
- Filtrar por remetente e parar por aí. O atacante também faz uma pequena operação comum no bloco 21594116, então o histórico dele isoladamente parece normal.
- Ler os timestamps. Toda transação em um bloco compartilha o mesmo timestamp. Só o
posdiz o que foi executado primeiro.
Como se proteger
A mesa não pode impedir que outras pessoas reordenem uma fila pública, então a correção é tornar essa reordenação não lucrativa.
- Configure o slippage para a menor tolerância que a operação suportar. Uma ordem de 40 WETH com slippage frouxo é um convite com o valor máximo escrito nele.
- Divida ordens grandes entre blocos ou as encaminhe por um agregador que faça a divisão automaticamente. Um sandwich em um lote pequeno não compensa o gás.
- Envie a ordem por um relay de transações privado para que ela nunca apareça na mempool pública antes de ser executada.
- Compare automaticamente as execuções com as cotações e alerte sobre a diferença. A mesa descobriu esse caso porque alguém, por acaso, olhou o número.