Разработка системы защиты от сэндвич-атак

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка системы защиты от сэндвич-атак
Средняя
от 1 рабочего дня до 3 рабочих дней
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1221
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1163
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    855
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1056
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    828

Разработка системы защиты от сэндвич-атак

Сэндвич-атака — это форма MEV (Maximal Extractable Value), при которой атакующий видит pending транзакцию пользователя в mempool, выставляет свою транзакцию с более высоким газом перед ней (frontrun) и ещё одну сразу после (backrun). Пользователь получает значительно худший курс обмена, разница уходит атакующему.

В Uniswap-подобных AMM это работает прямолинейно: атакующий покупает токен до пользователя (цена растёт), продаёт после (цена возвращается вниз). Разница — прибыль MEV-бота. По данным EigenPhi, крупные sandwich-боты на Ethereum зарабатывали сотни тысяч долларов в неделю за счёт обычных пользователей.

Механика атаки и слабые места

Для понимания защиты нужно чётко понимать, где именно уязвимость.

Публичный mempool: транзакции видны всем до включения в блок. MEV-бот читает параметры swap (адрес токена, сумму, slippage tolerance) и вычисляет прибыльность атаки.

Высокий slippage tolerance: пользователь указывает допустимое отклонение цены (например, 5%). Чем выше tolerance — тем шире возможное окно для сэндвича. Swap с slippage 1% атаковать значительно сложнее.

Детерминированный price impact: для AMM с известной формулой (x*y=k или стабильная curve) атакующий точно вычисляет, сколько нужно купить перед жертвой для максимальной прибыли.

Защиты на уровне пользователя и протокола

Приватные RPC и MEV-protection провайдеры

Самая простая защита: отправлять транзакции не в публичный mempool, а напрямую блок-строителям через приватные каналы.

Flashbots Protect: транзакции идут в Flashbots bundle. Атакующий не видит их в публичном mempool. Бесплатно для пользователя.

MEV Blocker: сервис от CoW Protocol. Транзакции отправляются нескольким searcher'ам, которые конкурируют за best execution (refund части MEV обратно пользователю).

Bloxroute: платный сервис с защищёнными каналами к майнерам/валидаторам.

// Использование Flashbots Protect через ethers.js
const { FlashbotsBundleProvider } = require('@flashbots/ethers-provider-bundle');
const { ethers } = require('ethers');

async function protectedSwap(swapParams, wallet, provider) {
    // Подключаемся к Flashbots relay
    const flashbotsProvider = await FlashbotsBundleProvider.create(
        provider,
        wallet,  // auth signer (может быть отдельный кошелёк)
        'https://relay.flashbots.net'
    );
    
    // Собираем swap транзакцию как обычно
    const swapTx = await buildSwapTransaction(swapParams);
    
    // Отправляем через Flashbots — транзакция не попадает в публичный mempool
    const bundleSubmission = await flashbotsProvider.sendPrivateTransaction(
        {
            signer: wallet,
            transaction: swapTx
        },
        { maxBlockNumber: (await provider.getBlockNumber()) + 10 }
    );
    
    const receipt = await bundleSubmission.wait();
    return receipt;
}

Минимизация slippage tolerance

Протоколы должны рекомендовать и применять разумные slippage по умолчанию вместо завышенных.

// В смарт-контракте: жёсткий лимит на максимальный slippage
contract SlippageProtectedRouter {
    uint256 public constant MAX_SLIPPAGE_BPS = 300; // 3% максимум
    
    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to
    ) external returns (uint256[] memory amounts) {
        // Вычисляем текущую цену и проверяем slippage
        uint256 expectedOut = getAmountOut(amountIn, path);
        uint256 slippageBps = (expectedOut - amountOutMin) * 10000 / expectedOut;
        
        require(slippageBps <= MAX_SLIPPAGE_BPS, "Slippage too high");
        
        return _executeSwap(amountIn, amountOutMin, path, to);
    }
}

Commit-reveal схема

Пользователь в первой транзакции публикует commitment (хеш параметров swap), во второй — раскрывает. MEV-боты не знают параметры до второй транзакции, когда уже поздно встраиваться перед ней.

contract CommitRevealSwap {
    mapping(bytes32 => Commitment) public commitments;
    
    struct Commitment {
        address user;
        uint256 blockNumber;
        bool revealed;
    }
    
    uint256 public constant MIN_BLOCKS_BEFORE_REVEAL = 1;
    uint256 public constant MAX_BLOCKS_BEFORE_REVEAL = 10;
    
    // Шаг 1: пользователь публикует хеш параметров
    function commit(bytes32 commitHash) external {
        commitments[commitHash] = Commitment({
            user: msg.sender,
            blockNumber: block.number,
            revealed: false
        });
    }
    
    // Шаг 2: раскрытие и исполнение
    function reveal(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        bytes32 salt
    ) external {
        bytes32 commitHash = keccak256(abi.encodePacked(
            msg.sender, amountIn, amountOutMin, 
            keccak256(abi.encode(path)), salt
        ));
        
        Commitment storage commitment = commitments[commitHash];
        require(commitment.user == msg.sender, "Not your commit");
        require(!commitment.revealed, "Already revealed");
        require(
            block.number >= commitment.blockNumber + MIN_BLOCKS_BEFORE_REVEAL,
            "Too early"
        );
        require(
            block.number <= commitment.blockNumber + MAX_BLOCKS_BEFORE_REVEAL,
            "Expired"
        );
        
        commitment.revealed = true;
        _executeSwap(amountIn, amountOutMin, path, msg.sender);
    }
}

Недостаток: двухэтапный процесс создаёт UX трения. Применим для крупных свапов, неудобен для частых небольших операций.

Batch Auctions: архитектурное решение CoW Protocol

CoW Protocol решает проблему сэндвичей на архитектурном уровне через batch auctions. Вместо немедленного исполнения каждого swap:

  1. Заявки на swap собираются за период (несколько блоков)
  2. Off-chain solver находит оптимальное исполнение для всего батча (CoW — Coincidence of Wants: если A меняет ETH на USDC, а B меняет USDC на ETH — можно исполнить напрямую)
  3. Единая транзакция с результатами батча публикуется on-chain
  4. Все участники батча получают uniform clearing price

В batch auction нет смысла для сэндвича: атакующий не может встроиться между заявкой и исполнением, потому что они разнесены во времени и исполняются оптом.

Обычный AMM:
Block N:   frontrun_buy → user_swap → backrun_sell
           (атакующий заработал за счёт user_swap)

CoW Batch Auction:
Block N:   submit_order(user1), submit_order(user2), ...
Block N+3: solver publishes settlement_tx с uniform price
           (нет места для frontrun/backrun внутри батча)

Dynamic Slippage на основе on-chain условий

Смарт-контракт или frontend может динамически вычислять разумный slippage на основе текущей рыночной волатильности и объёма свапа.

async function calculateSafeDynamicSlippage(
    tokenIn, tokenOut, amountIn, provider
) {
    // Получаем TWAP из Uniswap V3 oracle
    const [twapPrice, spotPrice] = await Promise.all([
        getTWAPPrice(tokenIn, tokenOut, 1800, provider),  // 30-min TWAP
        getSpotPrice(tokenIn, tokenOut, provider)
    ]);
    
    // Текущее отклонение spot от TWAP
    const currentDeviation = Math.abs(spotPrice - twapPrice) / twapPrice;
    
    // Оценка price impact от нашего свапа
    const priceImpact = await estimatePriceImpact(tokenIn, tokenOut, amountIn, provider);
    
    // Базовый slippage + буфер на волатильность
    const baseSlippage = priceImpact * 1.2;  // 20% буфер сверх price impact
    const volatilityBuffer = currentDeviation * 0.5;
    
    const recommendedSlippage = Math.min(
        baseSlippage + volatilityBuffer,
        0.03  // максимум 3%
    );
    
    return {
        recommendedSlippageBps: Math.ceil(recommendedSlippage * 10000),
        priceImpact: priceImpact,
        currentVolatility: currentDeviation
    };
}

Мониторинг и детекция атак

Система защиты должна включать компонент мониторинга: отслеживание конкретных MEV-ботов, статистика потерь пользователей, алерты при всплеске сэндвич-активности.

// Детекция сэндвич паттерна через анализ транзакций в блоке
async function detectSandwichInBlock(blockNumber, provider, uniswapAddress) {
    const block = await provider.getBlock(blockNumber, true);
    const uniswapTxs = block.transactions.filter(
        tx => tx.to?.toLowerCase() === uniswapAddress.toLowerCase()
    );
    
    const sandwiches = [];
    
    for (let i = 1; i < uniswapTxs.length - 1; i++) {
        const prev = uniswapTxs[i - 1];
        const current = uniswapTxs[i];
        const next = uniswapTxs[i + 1];
        
        // Признаки сэндвича: prev и next от одного адреса,
        // current — от другого, противоположные направления
        if (prev.from === next.from && prev.from !== current.from) {
            const prevDecoded = decodeSwap(prev.data);
            const nextDecoded = decodeSwap(next.data);
            
            // Frontrun покупает то, что продаёт жертва
            if (prevDecoded && nextDecoded && 
                prevDecoded.tokenIn === nextDecoded.tokenOut) {
                sandwiches.push({
                    attacker: prev.from,
                    victim: current.from,
                    frontrunTx: prev.hash,
                    victimTx: current.hash,
                    backrunTx: next.hash,
                    estimatedProfit: calculateSandwichProfit(prevDecoded, nextDecoded)
                });
            }
        }
    }
    
    return sandwiches;
}

Сроки разработки

Интеграция Flashbots Protect в существующий swap интерфейс — 1–2 недели. Commit-reveal механизм в смарт-контракте — 2–3 недели включая тесты. Динамический slippage с TWAP-оракулом — 2–3 недели. Мониторинговая система детекции сэндвичей — 3–4 недели. Полный batch auction протокол по модели CoW — 2–4 месяца.