Pressione ESC para fechar

Lucro de Bots MEV & Taxas de Gás: Guia de Arbitragem

A economia pura do MEV se resume a uma competição brutal por espaço em blocos, onde uma latência de rede de poucos milissegundos elimina todo o lucro potencial. Rodar seu próprio bot no Ethereum ou em redes EVM de camada 2 deixou de ser dinheiro fácil há muito tempo. O mercado é dominado por searchers especializados que alugam servidores em datacenters em Frankfurt e Tóquio, colocalizados diretamente com os nós dos validadores.

Números Reais e Rentabilidade

Um bot solo rodando em um servidor caseiro ou em uma VPS de nuvem padrão opera no vermelho em 95% das vezes devido aos leilões de gas. A rentabilidade depende da estratégia:

  • Arbitragem Atômica (Atomic Arbitrage): As margens de lucro caíram para frações de porcento. O lucro líquido diário de um bot de sucesso fica entre $100 e $3.000 em períodos de volatilidade. O risco de perda de capital é zero, pois a transação é encapsulada em um único smart contract atômico: se as condições não baterem, toda a cadeia sofre rollback.
  • Ataques Sandwich (Sandwich Attacks): O rendimento teórico é maior, variando de $500 a $10.000 por dia em pares de baixa liquidez no Uniswap v2 ou AMMs similares. A prática é bem mais pesada. Bots concorrentes enfileiram operações via private transaction pools, encobrindo as propinas (bribes) dos rivais para os validadores.
  • Liquidações (Liquidations): O mercado spot de protocolos de empréstimo como Aave traz ganhos expressivos, mas exige milhões de dólares em liquidez para cobrir dívidas e liquidar posições instantaneamente. Jogadores solo não têm vez aqui.

Estrutura de Custos de Gas e Operação com Builders

Seu principal gasto ao rodar um bot MEV não são as transações bem-sucedidas, mas sim as tentativas falhas e os leilões de prioridade de gas (Gas Priority Auction).

  • Mempool Pública: Enviar uma transação contornando relays privados garante prejuízo. Um bot comum avista a transação da vítima, dispara a sua com um gas mais alto, mas os bots rivais interceptam antes via RPCs privados. No fim, sua transação executa pelo pior preço ou é revertida, queimando gas real na blockchain.
  • Block Builders e Flashbots: A arbitragem moderna roda via eth_sendBundle. Você empacota várias transações em um bundle e o envia direto aos block builders (Beaverbuild, Titan, Flashbots).
  • Taxa de Falha: O lado bom dos bundles privados é que, se a arbitragem falhar, a transação simplesmente não entra no bloco. Você não paga taxa de rede por tiros certeiros que erraram o alvo. O lado ruim: o validador embolsa a maior parte do lucro como gorjeta direta (coinbase.transfer), deixando o desenvolvedor com apenas 5% a 15% do lucro bruto.

Tabela de Métricas de Estratégias MEV

EstratégiaCapital InicialLucro Líquido Diário MédioTaxa de SucessoPrincipal Causa de Prejuízo
Arbitragem Atômicaa partir de $5.000$50 - $50015-25%Perder na latência de rede para os concorrentes
Ataques Sandwicha partir de $20.000$200 - $3.0005-10%Excesso de gasto com gas nos leilões dos validadores
Liquidaçõesa partir de $100.000+$1.000 - $10.000+< 2%Falta de capital para cobrir empréstimos pesados

Exemplo de Envio de Bundle Privado em Python

Abaixo está um esqueleto de script funcional em Python usando a biblioteca web3.py para enviar um bundle por meio de um provedor compatível com o Flashbots. O código foi limpo de abstrações desnecessárias.

import os
from eth_account import Account
from eth_account.signers.local import LocalAccount
from web3 import Web3
from flashbots import flashbot
# Chave para assinar requisições ao relay (reputação no Flashbots).
# NÃO utilize a chave que armazena seus fundos reais.
signature_account: LocalAccount = Account.from_key(os.environ["FLASHBOTS_SIGNER_KEY"])
# Chave do remetente da transação
sender: LocalAccount = Account.from_key(os.environ["SENDER_PRIVATE_KEY"])
w3 = Web3(Web3.HTTPProvider(os.environ["ETH_NODE_URL"]))
flashbot(w3, signature_account, "https://relay-sepolia.flashbots.net")
def build_signed_tx(nonce: int) -> bytes:
    base_fee = w3.eth.get_block("latest")["baseFeePerGas"]
    tx = {
        "to": sender.address,          # exemplo: auto-transferência
        "value": 0,
        "gas": 21_000,
        "maxFeePerGas": base_fee * 2 + Web3.to_wei(2, "gwei"),
        "maxPriorityFeePerGas": Web3.to_wei(2, "gwei"),
        "nonce": nonce,
        "chainId": w3.eth.chain_id,
        "type": 2,
    }
    return sender.sign_transaction(tx).rawTransaction  # em versões mais recentes: .raw_transaction
def send_private_bundle(target_block: int):
    nonce = w3.eth.get_transaction_count(sender.address)
    bundle = [{"signed_transaction": build_signed_tx(nonce)}]
    # Simulação antes do envio
    w3.flashbots.simulate(bundle, target_block)
    result = w3.flashbots.send_bundle(bundle, target_block_number=target_block)
    result.wait()  # aguarda o processamento do bloco target_block
    try:
        return result.receipts()
    except Exception:
        return None  # bundle não incluído no bloco: pode tentar novamente no próximo bloco
if __name__ == "__main__":
    target = w3.eth.block_number + 1
    receipts = send_private_bundle(target)
    print("Incluído no bloco" if receipts else "Bundle não incluído, tente novamente no próximo bloco")

Um bundle vale apenas para um único bloco alvo, então na prática você precisa rodar o envio em um loop por vários blocos consecutivos. Ficar de fora não indica erro: a disputa se resume ao valor da gorjeta paga ao builder.

A lucratividade de um bot próprio esbarra nos custos de infraestrutura. Alugar um servidor dedicado em rack colocalizado com o validador em um datacenter sai por pelo menos $500 mensais. Sem esse boost de hardware, seu bot simplesmente não consegue calcular o estado do pool mais rápido que os rivais. Vence quem tiver o menor cabo até o validador e o algoritmo de busca de spread mais afiado.

Os flash loans possibilitam a execução de operações de arbitragem em larga escala sem a necessidade de um capital próprio pesado, utilizando empréstimos sem garantia dentro de uma única transação com revert garantido em caso de prejuízo.

Flash loans e a arquitetura de smart contracts

Ter centenas de milhares de dólares de capital próprio para rodar arbitragem não é obrigatório. Contratos de integração com os pools da Aave v3 ou Balancer permitem pegar flash loans sem garantia dentro do escopo de uma única transação. O bot pega o ativo emprestado, roda ele pelas DEX pairs, devolve o empréstimo acrescido da taxa de 0.09% e embolsa o saldo remanescente na carteira do criador. Se o saldo final ficar negativo após todas as contas, a transação inteira sofre revert e o emissor perde apenas o gas da chamada da função.

Escrever um contrato de arbitragem em Solidity exige uma otimização pesada voltada para o bytecode da EVM. O uso de interfaces padrão de ERC-20 via SafeERC20 adiciona verificações extras que comem gas precioso na hora de checar limites de transação. Desenvolvedores experientes mandam chamadas diretas de baixo nível via call, reduzindo ao máximo as operações de leitura e escrita em memória persistente (SLOAD/SSTORE).

Exemplo de template em Solidity

Abaixo está um template baseado em flash loan da Aave V3 para pools da Uniswap V2, totalmente limpo de bibliotecas externas:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
interface IERC20 {
    function balanceOf(address account) external view returns (uint256);
    function transfer(address to, uint256 amount) external returns (bool);
    function approve(address spender, uint256 amount) external returns (bool);
}
/// Aave V3: flash loan de um único ativo
interface IPool {
    function flashLoanSimple(
        address receiverAddress,
        address asset,
        uint256 amount,
        bytes calldata params,
        uint16 referralCode
    ) external;
}
interface IUniswapV2Pair {
    function token0() external view returns (address);
    function getReserves() external view returns (uint112, uint112, uint32);
    function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;
}
/// Arbitragem em flash loan da Aave V3: asset -> tokenB (pair1) -> asset (pair2).
/// Exemplo para pools do tipo Uniswap V2. Não auditado.
contract FlashArbitrage {
    error Unauthorized();
    error InvalidCaller();
    error InvalidInitiator();
    error TransferFailed();
    error ApproveFailed();
    error InsufficientProfit(uint256 balanceAfter, uint256 required);
    address private immutable OWNER;
    IPool private immutable POOL;
    constructor(address aavePool) {
        OWNER = msg.sender;
        POOL = IPool(aavePool); // pegue o endereço do Pool através do PoolAddressesProvider da rede correspondente
    }
    modifier onlyOwner() {
        if (msg.sender != OWNER) revert Unauthorized();
        _;
    }
    /// Ponto de entrada. Empresta `amount` do token `asset` e dispara o loop em executeOperation.
    function executeArbitrage(
        address asset,
        uint256 amount,
        address tokenB,
        address pair1,
        address pair2,
        uint256 minProfit
    ) external onlyOwner {
        bytes memory params = abi.encode(tokenB, pair1, pair2, minProfit);
        POOL.flashLoanSimple(address(this), asset, amount, params, 0);
    }
    /// Callback da Aave V3. Chamado pelo pool logo após a liberação do empréstimo.
    function executeOperation(
        address asset,
        uint256 amount,
        uint256 premium,
        address initiator,
        bytes calldata params
    ) external returns (bool) {
        // 1. O callback só pode ser chamado pelo pool da Aave...
        if (msg.sender != address(POOL)) revert InvalidCaller();
        // 2. ...e exclusivamente a pedido do próprio contrato
        if (initiator != address(this)) revert InvalidInitiator();
        (address tokenB, address pair1, address pair2, uint256 minProfit) =
            abi.decode(params, (address, address, address, uint256));
        // O saldo já inclui os fundos emprestados
        uint256 balanceBefore = IERC20(asset).balanceOf(address(this));
        uint256 amountB = _swap(pair1, asset, amount);
        _swap(pair2, tokenB, amountB);
        // Lucro = balanceAfter - balanceBefore - premium (taxa do empréstimo)
        uint256 balanceAfter = IERC20(asset).balanceOf(address(this));
        uint256 required = balanceBefore + premium + minProfit;
        if (balanceAfter < required) revert InsufficientProfit(balanceAfter, required);
        // A Aave puxa a dívida sozinha via transferFrom, então o approve é necessário
        _safeApprove(asset, address(POOL), amount + premium);
        return true;
    }
    function withdraw(address token, uint256 amount) external onlyOwner {
        _safeTransfer(token, OWNER, amount);
    }
    function _swap(address pair, address tokenIn, uint256 amountIn) private returns (uint256 amountOut) {
        (uint256 r0, uint256 r1, ) = IUniswapV2Pair(pair).getReserves();
        bool zeroForOne = tokenIn == IUniswapV2Pair(pair).token0();
        (uint256 reserveIn, uint256 reserveOut) = zeroForOne ? (r0, r1) : (r1, r0);
        // Fórmula da Uniswap V2 (taxa de 0,3%)
        uint256 amountInWithFee = amountIn * 997;
        amountOut = (amountInWithFee * reserveOut) / (reserveIn * 1000 + amountInWithFee);
        _safeTransfer(tokenIn, pair, amountIn);
        IUniswapV2Pair(pair).swap(
            zeroForOne ? 0 : amountOut,
            zeroForOne ? amountOut : 0,
            address(this),
            "" // data vazio: swap normal, não é flash swap
        );
    }
    function _safeTransfer(address token, address to, uint256 amount) private {
        if (token.code.length == 0) revert TransferFailed();
        (bool ok, bytes memory data) = token.call(abi.encodeCall(IERC20.transfer, (to, amount)));
        if (!ok || (data.length != 0 && !abi.decode(data, (bool)))) revert TransferFailed();
    }
    function _safeApprove(address token, address spender, uint256 amount) private {
        if (token.code.length == 0) revert ApproveFailed();
        (bool ok, bytes memory data) = token.call(abi.encodeCall(IERC20.approve, (spender, amount)));
        if (!ok || (data.length != 0 && !abi.decode(data, (bool)))) revert ApproveFailed();
    }
}

A armadilha de infraestrutura da AWS

Rodar um bot de busca em servidores virtuais da Amazon Web Services ou do Google Cloud é garantia de queimar dinheiro à toa. A virtualização injeta latência (jitter) na pilha de rede, e as rotas compartilhadas sofrem com perda de pacotes quando o mempool tá entupido.

Um setup competitivo exige um servidor dedicado físico (bare-metal) com CPU de alta frequência por núcleos individuais, SSD NVMe rápido rodando um node local do Geth ou Reth e link gigabit direto para os datacenters de Frankfurt. Subir seu próprio node lightweight é mandatório, já que provedores de RPC públicos como Infura ou Alchemy capam artificialmente a velocidade de entrega dos blocos novos e atrasam as notificações de transações pending na casa dos cruciais 100 a 300 milissegundos.

No MEV, o lucro não vai para quem tem o modelo matemático mais complexo, mas sim para quem está fisicamente mais perto do validador e sabe calcular os custos de gas até a última instrução de assembly no bytecode.

Resumir este post do blog com:

FAQ

O lucro líquido diário de um bot de MEV independente varia de $50 a $500 dólares em arbitragem atômica entre DEXs, podendo alcançar de $200 a $3.000 dólares em ataques de sandwich durante períodos de alta volatilidade no mercado. A ausência de colocation físico com os nós validadores gera atrasos de latência e obriga o operador a pagar taxas excessivas em leilões de blocos, fazendo com que instalações comuns operem frequentemente no prejuízo.

As despesas de gás de um bot de MEV consistem nas taxas básicas de execução da rede e nos subornos de prioridade pagos diretamente aos construtores de blocos através de relays privados como o Flashbots via eth_sendBundle. Embora o uso de relays privados evite a queima de gás em tentativas falhas, o sucesso da operação exige que o searcher transfira de 85% a 95% do lucro bruto diretamente para o validador utilizando a função coinbase.transfer.

Bots independentes de ataque de sandwich nas redes EVM principais são majoritariamente inviáveis devido à desvantagem de latência, exigência de alto capital de giro e predominância de mempools privados. Sem acesso a servidores bare-metal dedicados com resposta inferior a um milissegundo, desenvolvedores solos acabam superpagando nas taxas de prioridade dos construtores, destruindo completamente a margem de lucro nas trocas de tokens.
Astra EXMON

Astra is the official voice of EXMON and the editorial collective dedicated to bringing you the most timely and accurate information from the crypto market. Astra represents the combined expertise of our internal analysts, product managers, and blockchain engineers.

...

Deixe seu parecer

O seu endereço de e-mail não será publicado. Campos obrigatórios estão marcados *