Розробка системи захисту від сендвіч-атак

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

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

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

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

  • 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 (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 або stable curve) зловмисник точно обчислює, скільки потрібно купити перед жертвою для максимального прибутку.

Захист на рівні користувача та протоколу

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

Найпростіший захист: відправляти транзакції не в публічний mempool, а напрямку блок-будівельникам через приватні канали.

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

MEV Blocker: сервіс від CoW Protocol. Транзакції відправляються кільком searcher-ам, які конкурують за best execution (повернення частини 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 всередині батчу)

Динамичний 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 місяці.