Розробка системи детекції MEV-атак

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Розробка системи детекції MEV-атак
Складний
~1-2 тижні
Часті запитання

Напрямки блокчейн-розробки

Етапи блокчейн-розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1306
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1218
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    920
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1147
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    610
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    885

Розробка системи детекції MEV-атак

MEV (Maximal Extractable Value)—це вартість, яку валідатори та searcher-и видобувають, переупорядковуючи транзакції всередину блоку. Технічно це не завжди «атака»—частина MEV безвредна (арбітраж між DEX відновлює цінову рівновагу). Але sandwich attacks, liquidation front-running та time-bandit атаки наносять прямий ущерб користувачам та протоколам. Система детекції MEV вирішує дві задачі: постфактум аналіз (що сталося з користувачем) та проактивний захист (запобігання конкретним типам атак).

Типологія MEV атак

Sandwich Attack

Класика та найпоширеніший тип. Схема:

  1. Жертва відправляє swap на DEX з великим slippage tolerance
  2. Зловмисник бачить транзакцію в mempool
  3. Вставляє buy ПЕРЕД жертвою (front-run), поднімаючи ціну
  4. Жертва виконується по вищій ціні
  5. Зловмисник продає ПІСЛЯ жертви (back-run), фіксуючи прибуток

Ідентифікатор у блоці: три транзакції підряд з характерним паттерном.

Liquidation Front-Running

Позиція на lending протоколі (Aave, Compound) стає ліквідуємою. Кілька ботів бачать це та гонятися за liquidation reward. Перший виграв—решта потратили gas впустую. Це не атака на користувача, але створює waste та MEV гонку.

Більш агресивна версія: зловмисник маніпулює цінов ім оракулом (через flash loan у пулі, що використовується як oracle), щоб вивести позицію під liquidation.

Arbitrage MEV

Технічно не атака: якщо ціна ETH на Uniswap v3 відрізняється від Curve на 0,3%—арбітражний бот вирівнює ціну, отримуючи прибуток. Це корисно для ринку. Тим не менш, протоколи повинні розуміти арбітражні потоки.

JIT (Just-in-Time) Liquidity

Специфічно для Uniswap v3. Зловмисник бачить крупний swap у mempool, додає concentrated liquidity точно в потрібний range перед swap, отримує fees, видаляє ліквідність після. Честні LP втрачають fees. Спірна форма MEV—технічно дозволена протоколом.

Time-Bandit Attack

Реорг атака: якщо MEV в кількох блоках назад перевищує вартість реорганізації ланцюга—зловмисний валідатор може спробувати переписати історію. На Ethereum post-Merge це надзвичайно складно та дорого, але залишається теоретичною загрозою для PoS ланцюгів з малим stake.

On-chain детекція сендвіч-атак

Алгоритм ідентифікації

Сендвіч—три транзакції в одному блоці з визначеними зв'язками:

from dataclasses import dataclass
from typing import Optional
import pandas as pd

@dataclass
class SwapEvent:
    tx_hash: str
    block_number: int
    tx_index: int  # позиція у блоці
    sender: str
    token_in: str
    token_out: str
    amount_in: int
    amount_out: int
    pool: str

def detect_sandwiches(swaps_in_block: list[SwapEvent]) -> list[dict]:
    sandwiches = []

    # Групуємо по пулу
    by_pool = {}
    for swap in swaps_in_block:
        by_pool.setdefault(swap.pool, []).append(swap)

    for pool, pool_swaps in by_pool.items():
        # Сортуємо по позиції в блоці
        pool_swaps.sort(key=lambda s: s.tx_index)

        # Шукаємо паттерн: A купує → жертва купує → A продає (однакові token_in/out)
        for i, front in enumerate(pool_swaps[:-2]):
            victim = pool_swaps[i + 1]
            back = pool_swaps[i + 2]

            is_sandwich = (
                front.sender == back.sender and           # один зловмисник
                front.sender != victim.sender and          # жертва інша
                front.token_in == victim.token_in and      # однакове напрямок
                back.token_in == front.token_out and       # розворот
                back.token_out == front.token_in
            )

            if is_sandwich:
                # Лічимо profit зловмисника
                attacker_profit = (
                    back.amount_out - front.amount_in
                )
                # Лічимо ущерб жертви: різниця в execution price
                victim_price = victim.amount_out / victim.amount_in

                sandwiches.append({
                    'front_tx': front.tx_hash,
                    'victim_tx': victim.tx_hash,
                    'back_tx': back.tx_hash,
                    'attacker': front.sender,
                    'pool': pool,
                    'attacker_profit_tokens': attacker_profit,
                    'block': front.block_number,
                })

    return sandwiches

Вимірювання ущербу жертви

Для точного розрахунку ущербу потрібно симулювати як виконалася б транзакція жертви без front-run. Потребує доступу до archive node та replay з state override:

async def simulate_swap_without_frontrun(
    victim_tx: dict,
    frontrun_tx: dict,
    block_number: int,
    rpc_url: str
) -> dict:
    """
    Симулює victim_tx на стані ДО frontrun_tx
    """
    w3 = AsyncWeb3(AsyncWeb3.AsyncHTTPProvider(rpc_url))

    # Отримуємо стан на попередньому блоці
    prev_block_state = block_number - 1

    # eth_call з block_number = prev_block (без frontrun)
    result = await w3.eth.call(
        {
            'from': victim_tx['from'],
            'to': victim_tx['to'],
            'data': victim_tx['input'],
            'gas': victim_tx['gas'],
        },
        prev_block_state
    )

    return {'simulated_output': result}

Різниця між реальним amount_out та симульованим—це MEV видобуто у жертви.

Детекція через mempool мониторинг

Flashbots MEV-Share та MEV-Boost дані

Flashbots публікує MEV-Boost дані через API: https://boost-relay.flashbots.net/relay/v1/data/bidtraces/proposer_payload_delivered. Історичні дані про блоки, що пройшли через MEV-Boost, з інформацією про MEV-bid.

Більш детальні дані—через Flashbots MEV-Share API: інформація про вміст bundle, яку builder-и публікують post-execution.

Власний mempool спостерігач

Для real-time: підключення до mempool через eth_subscribe("pendingTransactions"):

import { createPublicClient, webSocket, parseAbi, decodeEventLog } from 'viem';

const client = createPublicClient({
    transport: webSocket('wss://mainnet.infura.io/ws/v3/KEY'),
});

// Підписка на pending транзакції
const unwatch = client.watchPendingTransactions({
    onTransactions: async (hashes) => {
        for (const hash of hashes) {
            const tx = await client.getTransaction({ hash });
            if (tx && isLargeSwap(tx)) {
                // Це транзакція з великим slippage - можлива жертва
                await analyzeMevRisk(tx);
            }
        }
    },
});

Проблема: більшість MEV ботів зараз використовують приватні mempool-и (Flashbots bundles, MEV Blocker). Публічний mempool бачить тільки частину картини.

Захисні механізми для протоколів

Commit-Reveal для чутливих операцій

Користувач спочатку публікує хеш транзакції (commit), потім reveal. Зловмисник не знає параметри до reveal:

contract CommitRevealSwap {
    mapping(bytes32 => uint256) public commits;
    uint256 public constant REVEAL_DELAY = 2; // блоків

    function commit(bytes32 commitment) external {
        commits[commitment] = block.number;
    }

    function reveal(
        address tokenIn,
        address tokenOut,
        uint256 amountIn,
        uint256 minAmountOut,
        bytes32 salt
    ) external {
        bytes32 commitment = keccak256(
            abi.encodePacked(msg.sender, tokenIn, tokenOut, amountIn, minAmountOut, salt)
        );
        require(commits[commitment] != 0, "No commit");
        require(block.number >= commits[commitment] + REVEAL_DELAY, "Too early");
        delete commits[commitment];
        // виконати swap
    }
}

Тісний Slippage + Deadline

Користувачі з minAmountOut = 0 або дуже високим slippage—легкі жертви. Протокол повинен:

  • Обчислювати рекомендований slippage на основі pool depth
  • Попереджувати про high slippage у UI
  • Короткий deadline (не більше 10-15 хвилин) для запобігання stale транзакцій

MEV Blocker інтеграція

Для frontend: маршрутизація транзакцій через MEV Blocker (CoW Protocol) або Flashbots Protect замість публічного mempool-у. Тільки доверені builder-и бачать транзакції, не публічні searcher-и.

// Відправка через Flashbots Protect RPC
const provider = new ethers.JsonRpcProvider(
    'https://rpc.flashbots.net',
    1 // mainnet
);

Це не вимагає змін у смарт-контрактах—тільки переключення RPC endpoint.

TWAP Oracle замість Spot Price

Для протоколів, що використовують цени з AMM: Uniswap v3 TWAP (Time-Weighted Average Price) стійкий до flash loan маніпуляцій—не можна зсунути TWAP за один блок.

function getTWAP(address pool, uint32 secondsAgo) public view returns (uint256 price) {
    uint32[] memory secondsAgos = new uint32[](2);
    secondsAgos[0] = secondsAgo;
    secondsAgos[1] = 0;

    (int56[] memory tickCumulatives,) = IUniswapV3Pool(pool).observe(secondsAgos);
    int56 tickCumulativesDelta = tickCumulatives[1] - tickCumulatives[0];
    int24 arithmeticMeanTick = int24(tickCumulativesDelta / int56(uint56(secondsAgo)));

    price = TickMath.getSqrtRatioAtTick(arithmeticMeanTick);
}

Аналітична частина: мониторинг та reporting

MEV dashboard: візуалізація історичних MEV подій по протоколу. Відповідає на запитання: скільки користувачів пострадало від sandwich за останній місяць? Які пулі найбільш атакуються? Яка середня шкода на подію?

Eigenφhi, Flashbots MEV-Explore, EigenPhi—публічні інструменти для історичного аналізу. Для власного мониторингу—The Graph subgraph + Dune Analytics.

Тип атаки Метод детекції Складність Точність
Sandwich Паттерн у блоці Середня Висока
JIT liquidity LP + swap timing Середня Висока
Oracle manipulation Price deviation + flash loan Висока Середня
Liquidation front-run Race transactions Низька Висока
Time-bandit Reorg detection Дуже висока Низька

Стек та терміни

Backend: Python (detection engine) + TypeScript (real-time mempool). Archive node доступ (Erigon self-hosted або Alchemy archive). PostgreSQL для зберігання подій. Dune Analytics інтеграція для візуалізації.

Розробка full-stack MEV detection системи: 10-16 тиж. Тільки post-hoc on-chain аналіз sandwich атак: 4-6 тиж. Flashbots Protect frontend інтеграція: 1-2 дні.