Este é o terceiro artigo da nossa série “Predadores em Pools: A Arte e a Matemática da Liquidez JIT”. Agora vamos à parte de engenharia: como transformar fórmulas matemáticas em código que é executado mais rápido do que você consegue piscar.
Em 2026, a liquidez JIT não é mais uma competição de ideias, mas de infraestrutura. Se seu bot foi escrito em Python e se comunica com um nó público via HTTP, você não vai apenas perder — nem vai perceber quando seu lucro for retirado.
1. Stack de tecnologia: Por que Rust domina
No mundo do MEV, a disputa é por microssegundos de latência.
- Linguagem: Rust. O uso da biblioteca Alloy (substituta do ethers-rs) se tornou padrão da indústria. Alloy permite trabalhar com tipos de dados Ethereum sem alocações desnecessárias de memória e fornece serialização/deserialização de JSON-RPC extremamente rápida.
- Conexão: IPC/WebSockets. Bots não usam HTTP. Eles se conectam a um nó local via IPC (Inter-Process Communication) para minimizar a pilha de rede.
- Nó próprio (Geth/Reth): Os principais players usam Reth (Rust Ethereum), pois permite customizar o motor para simulação paralela de transações.
2. Smart Contract: Atomicidade ou morte
Para que um ataque JIT seja seguro, as operações “Entrar no pool” e “Sair do pool” devem estar conectadas por uma lógica infalível. Se você adicionar liquidez mas não conseguir retirá-la no mesmo bloco, corre o risco de um grande Impermanent Loss.
O bot usa um Executor Contract. Sua função é receber comandos de um script off-chain e executar uma série de chamadas ao NonfungiblePositionManager (NFPM) do Uniswap v3.
Exemplo de arquitetura do contrato (Solidity 0.8.x):
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface INonfungiblePositionManager {
struct MintParams {
address token0;
address token1;
uint24 fee;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
address recipient;
uint256 deadline;
}
function mint(MintParams calldata params) external returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1);
function decreaseLiquidity(uint256 tokenId, uint128 liquidity, uint256 amount0Min, uint256 amount1Min, uint256 deadline) external;
function collect(uint256 tokenId, address recipient, uint128 amount0Max, uint128 amount1Max) external;
}
contract JITExecutor {
address private immutable owner;
INonfungiblePositionManager public immutable nftManager;
constructor(address _nftManager) {
owner = msg.sender;
nftManager = INonfungiblePositionManager(_nftManager);
}
// Função principal: chamada pelo bot para executar o JIT em uma única passada
function performJit(
INonfungiblePositionManager.MintParams calldata mintParams
) external {
require(msg.sender == owner, "Unauthorized");
// 1. Fornecer tokens ao contrato (normalmente já estão lá ou via Flash Loan)
// 2. Adicionar liquidez (Mint)
(uint256 tokenId, uint128 liquidity, , ) = nftManager.mint(mintParams);
// ATENÇÃO: Em um bundle clássico do Flashbots, este contrato
// finalizará a execução aqui, e a retirada será em uma segunda transação.
// Ou, se usarmos um router específico, tudo em uma única execução.
}
// Função para coletar lucro instantaneamente
function withdrawJit(uint256 tokenId, uint128 liquidity) external {
nftManager.decreaseLiquidity(tokenId, liquidity, 0, 0, block.timestamp);
nftManager.collect(tokenId, msg.sender, type(uint128).max, type(uint128).max);
}
}
3. Flashbots Bundles: Colando a realidade
As transações do bot JIT devem cercar a transação da vítima. Para isso, utiliza-se o mecanismo de Bundles.
O bot envia um array de transações para Flashbots (ou outro relay MEV, como BeaverBuild ou Titan):
- [Tx_Mint] — Sua transação de adição de liquidez.
- [Tx_Target] — A transação do usuário no mempool (que você interceptou).
- [Tx_Burn] — Sua transação de retirada.
Detalhe pouco conhecido: Para economizar gás, bots avançados às vezes não fazem o Burn no mesmo bloco se tiverem certeza de que o preço não sairá do tick no próximo bloco. Mas isso já é um risco de “LP passivo”. Um verdadeiro predador JIT fecha a posição sempre no bloco $N$.
4. Lógica do bot off-chain (Off-chain Engine)
Um bot Rust funciona em loop infinito:
- Streaming do mempool: escuta newPendingTransactions.
- Simulação: Para cada grande transação, o bot faz uma “execução virtual” via eth_call ou revm (Rust EVM) para prever quanto de taxa receberá.
- Geração do bundle: Se o lucro > 0, forma-se o pacote.
- Bidding: O bot adiciona coinbase.transfer() — propina para o validador.
Insider: Em 2026, a gorjeta (tip) para o validador pode chegar a 99% do lucro do bot. Os bots competem pelo 1% restante do lucro líquido, porque em volumes de milhões de dólares, mesmo 1% é muito dinheiro.
5. Dica prática: uso de multicall
Para máxima eficiência, use a lógica multicall dentro do seu contrato. Isso permite executar approve, mint, decreaseLiquidity e collect em uma única transação, se você estiver usando seus próprios fundos e não Flash Loans. Economiza cerca de 40–60k de gás em chamadas repetidas.
Resumo do artigo
A arquitetura de um bot JIT é o ápice da engenharia de smart contracts. Você cria uma liquidez “descartável” que existe apenas por frações de segundo.
No próximo artigo: Passaremos para a “artilharia pesada”. Como realizar ataques JIT sem ter milhões próprios? Vamos explorar Flash-JIT e o uso de Flash Loans para capturar 99,9% da liquidez em pools gigantes.
Domínio de Liquidez JIT: O Guia Completo para MEV na Uniswap: Parte 3 de 5