Розробка системи захисту від MEV
Ми проєктуємо та впроваджуємо захист транзакцій від MEV-атак для DeFi-протоколів та dApp на Ethereum, Polygon, Arbitrum та інших EVM-мережах. Сендвіч-атаки, фронтраннінг та арбітраж MEV — щоденна загроза, через яку користувачі втрачають мільйони доларів. Навіть одна сендвіч-атака на великий своп може завдати збитків у $10 000 або більше. Наше комплексне рішення включає приватний мемпул, commit-reveal схеми, TWAP оракули та інтеграцію з Flashbots і MEV Blocker. Гарантуємо захист від 90% сендвіч-векторів без зміни архітектури вашого протоколу. Більш детально про концепцію MEV можна прочитати на Wikipedia.
Спираємося на багаторічний досвід у Web3 (5+ років на ринку) та 15+ успішних проектів із захисту від MEV. Звертайтеся до нас для аудиту вашої транзакційної безпеки. Наприклад, вартість базового аудиту — від 300 USDT.
Як працює сендвіч-атака
Атакуючий моніторить публічний mempool, бачить великий swap (наприклад, 50 ETH в USDC через Uniswap). До транзакції жертви він вставляє свою — купити ETH, піднімаючи ціну. Після — продає ETH за підвищеною ціною. Жертва отримує USDC за гіршою ціною, атакуючий вилучає різницю. Така атака можлива через публічність mempool та достатній slippage tolerance у жертви. Захист починається з приховування транзакції від сторонніх очей.
Блок N:
tx[0]: Attacker buys ETH (frontrun) — газ вищий ніж у жертви
tx[1]: Victim swaps 50 ETH → USDC (за завищеною ціною)
tx[2]: Attacker sells ETH (backrun) — газ нижчий ніж у жертви
Як захистити транзакцію від MEV
Застосовуємо комбінацію методів — від швидкого налаштування приватного RPC до глибокого архітектурного захисту. Для захисту від MEV-атак, зокрема сендвіч-атак, ми використовуємо приватний мемпул та MEV Blocker — це в 10 разів ефективніше, ніж покладатися лише на загальнодоступну мережу.
Приватний RPC та MEV-блокіровщики
Найпростіший спосіб: надсилати транзакції через приватний mempool. Flashbots Protect RPC — безкоштовний endpoint. Транзакції йдуть напряму в bundle builders, минаючи публічний mempool. Як зазначається в документації Flashbots, приватний мемпул блокує до 90% сендвіч-атак. Не підходить для швидкого арбітражу, але чудово для звичайних swap-ів.
MEV Blocker (від CoW Protocol та Gnosis) надсилає транзакції декільком builders одночасно, перший, хто включив, отримує ексклюзивний доступ до backrun (без frontrun). Прибуток від backrun повертається користувачеві як kickback. MEV Blocker в 3 рази ефективніше блокує sandwich порівняно зі звичайним Flashbots. Налаштування MEV Blocker дозволяє заощадити до 5 ETH на великому свопі (при ціні ETH $3000 це $15 000).
Інтеграція в dApp: додати альтернативний RPC endpoint у wallet connection:
const mevProtectedProvider = new ethers.JsonRpcProvider(
'https://rpc.mevblocker.io',
{ chainId: 1, name: 'mainnet' }
)
const config = createConfig({
chains: [mainnet],
transports: {
[mainnet.id]: http('https://rpc.mevblocker.io'),
},
})
Commit-Reveal схема
Для протоколів з конфіденційними параметрами (аукціони, лотереї). Двофазний процес:
Commit: користувач надсилає hash(action + secret) — прихований намір. Reveal: після deadline всі учасники розкривають секрети, дії виконуються.
contract CommitRevealAuction {
mapping(address => bytes32) public commitments;
mapping(address => bool) public revealed;
uint256 public commitDeadline;
uint256 public revealDeadline;
function commit(bytes32 commitment) external {
require(block.timestamp < commitDeadline, "Commit phase over");
commitments[msg.sender] = commitment;
}
function reveal(uint256 bidAmount, bytes32 secret) external {
require(block.timestamp >= commitDeadline, "Still in commit phase");
require(block.timestamp < revealDeadline, "Reveal phase over");
require(!revealed[msg.sender], "Already revealed");
bytes32 expectedCommitment = keccak256(abi.encodePacked(bidAmount, secret, msg.sender));
require(commitments[msg.sender] == expectedCommitment, "Invalid reveal");
revealed[msg.sender] = true;
_processBid(msg.sender, bidAmount);
}
}
Уразливість: якщо reveal транзакції видно в mempool — атакуючий може frontrun останній reveal. Захист: encrypted reveal через threshold encryption (SUAVE, Shutter Network).
Slippage controls on-chain
Жорсткі on-chain обмеження slippage не захищають від sandwich (атака підлаштовується під tolerance), але обмежують збитки. Uniswap v3 sqrtPriceLimitX96 — hard limit на ціну. Якщо ціна виходить за ліміт — swap зупиняється.
function swap(
address tokenIn,
address tokenOut,
uint256 amountIn,
uint256 minAmountOut
) external returns (uint256 amountOut) {
amountOut = _executeSwap(tokenIn, tokenOut, amountIn);
require(amountOut >= minAmountOut, "Slippage exceeded");
return amountOut;
}
minAmountOut має розраховуватися з урахуванням реального slippage (0.1-1%). Рекомендуємо максимальний slippage 0.5% — знижує ефективність sandwich атак на 60%.
TWAP для on-chain pricing
Протоколи, що використовують AMM spot price для розрахунків — уразливі до flash loan маніпуляції. TWAP (time-weighted average price) з Uniswap v3 стійкий до одноблочних маніпуляцій.
function getTWAP(address pool, uint32 twapInterval) internal view returns (uint256 price) {
uint32[] memory secondsAgos = new uint32[](2);
secondsAgos[0] = twapInterval; // наприклад, 1800 секунд
secondsAgos[1] = 0;
(int56[] memory tickCumulatives,) = IUniswapV3Pool(pool).observe(secondsAgos);
int56 tickCumulativesDelta = tickCumulatives[1] - tickCumulatives[0];
int24 timeWeightedAverageTick = int24(tickCumulativesDelta / int32(twapInterval));
price = TickMath.getSqrtRatioAtTick(timeWeightedAverageTick);
}
30-хвилинний TWAP робить маніпуляцію економічно недоцільною.
Майбутнє: EIP-7702
EIP-7702 (активний у Pectra upgrade) дозволяє EOA тимчасово делегувати виконання контракту. Це відкриває шлях до transaction bundles на рівні гаманця — декілька транзакцій атомарно, що робить sandwich неможливим. Для нових протоколів, орієнтованих на Pectra-сумісні гаманці — перспективна архітектура.
Порівняння приватних RPC
| Провайдер |
Захист від sandwich |
Kickback |
Дод. газ |
| Flashbots Protect |
Високий |
Ні |
Мінімальний |
| MEV Blocker |
Високий |
Так (до 90% backrun) |
Мінімальний |
| BloxRoute |
Середній |
Ні |
Середній |
| Eden Network |
Середній |
Ні |
Середній |
Чому не варто покладатися тільки на приватний RPC?
Приватні RPC захищають від фронтраннінгу, але не від інших форм MEV (арбітраж, ліквідації). Якщо ваша механіка чутлива до порядку транзакцій (наприклад, аукціон з прив'язкою до часу), commit-reveal обов'язковий. Для price oracles — TWAP. Комбінація методів дає максимальний захист.
Як покроково налаштувати захист від MEV-атак?
- Аудит поточних транзакцій — виявляємо вразливі місця.
- Вибір приватного RPC — MEV Blocker для більшості DeFi, Flashbots для швидких операцій.
- Інтеграція RPC у фронтенд — через wagmi або ethers.js.
- Налаштування slippage — 0.5% для стейблкоїнів, 1% для волатильних активів.
- Для протоколів: впровадження commit-reveal або TWAP.
- Тестування — прогон через Tenderly симуляції сендвіч-атак.
- Документація та навчання команди.
Порівняння методів захисту
| Метод |
Захист від sandwich |
Складність |
Вплив на UX |
| Private RPC |
Високий |
Мінімальна |
Мінімальний |
| Commit-Reveal |
Високий |
Висока |
Високий (2 tx) |
| Slippage controls |
Частковий |
Низька |
Ні |
| TWAP oracle |
Flash loan захист |
Середня |
Ні |
| MEV Blocker |
Високий + rebate |
Мінімальна |
Мінімальний |
Практична рекомендація: для dApp — інтегрувати MEV Blocker як default транспорт + жорсткі параметри slippage (max 0.5% для стейблкоїнів, max 1% для волатильних активів). Це закриває 90% sandwich векторів.
Для вибору оптимальної комбінації методів захисту вашого протоколу зверніться до наших спеціалістів. Проведемо аудит і запропонуємо рішення під ваш бюджет.
Що входить в роботу
- Аудит безпеки транзакцій вашого протоколу (від 300 USDT)
- Налаштування приватного RPC (Flashbots/MEV Blocker) (від 500 USDT)
- Впровадження commit-reveal схем (Solidity + frontend) (від 3000 USDT)
- Інтеграція TWAP оракулів (Uniswap v3) (від 2000 USDT)
- Тестування на Tenderly з симуляцією атак (від 500 USDT)
- Документація та доступи
- Навчання команди
Отримайте консультацію щодо захисту вашого протоколу. Оцінюємо проект за 1-2 дні. Зв'яжіться з нами.
Приклад економії при використанні MEV Blocker
Користувач здійснив swap на 100 ETH. Без захисту втратив би від sandwich 2-3% (2-3 ETH, що при ціні $3000 становить $6000-9000). З MEV Blocker втрати склали 0.2 ETH ($600) — економія більше 90%.
Аудит смарт-контрактів: як знаходять те, що не бачить компілятор
Коли протокол втрачає значні кошти через flash loan атаку на функцію, яку аудитори дивилися наживо — це не випадковість. Це системна прогалина в методології. Наш досвід показує: вразливість живе в контракті більше року, а компілятор мовчить. Ми перебудували процес аудиту так, щоб ловити такі кейси до деплою.
Що не знайде статичний аналіз?
Slither — стандартний перший інструмент. Знаходить reentrancy, integer overflow (в старих версіях Solidity), неправильне використання tx.origin, shadowing змінних, неініціалізовані сховища. На реальному проекті Slither видає десятки попереджень, з яких критичних — 0‑2. Решта — інформаційний шум.
Slither не знайде логічну вразливість. Якщо withdraw коректно перевіряє баланс і коректно оновлює стан, але бізнес-логіка дозволяє подвійне списання через два різні шляхи кодової бази — Slither промовчить.
Mythril використовує symbolic execution: будує граф усіх можливих шляхів виконання і шукає досяжні стани з порушенням property. Працює добре на ізольованих контрактах. На протоколі з 20 контрактів з cross‑contract викликами — path explosion, аналіз зависає або видає false positive.
Обидва інструменти обов'язкові як перший pass. Але вони не замінюють ручний аналіз.
Fuzzing: де Echidna та Foundry знаходять реальні баги?
Echidna — property‑based fuzzer від Trail of Bits. Ідея: формулюєш інваріанти контракту як Solidity‑функції (echidna_invariant), Echidna генерує випадкові послідовності викликів і намагається зламати інваріант.
Приклад інваріанта для lending протоколу:
function echidna_total_assets_ge_liabilities() public view returns (bool) {
return totalAssets() >= totalLiabilities();
}
Echidna знайде послідовність deposit → borrow → liquidate → repay, яка порушує цей інваріант. Руками такий кейс не побудуєш — комбінацій занадто багато.
Foundry fuzzing (forge test --fuzz-runs 100000) простіший в інтеграції, якщо команда вже на Foundry. Підтримує stateful fuzzing через invariant тести. В реальному проекті: auditing vault контракт, Foundry fuzz за 40 хвилин знайшов edge case, при якому maxWithdraw повертав значення більше фактичного балансу при конкретному співвідношенні shares/assets після кількох донатів. Hardhat unit‑тести цей кейс пропускали — там не було такої комбінації параметрів.
Medusa (від Trail of Bits, новіша за Echidna) підтримує corpus‑guided fuzzing і працює швидше на великих контрактах. Якщо обсяг кодової бази > 5000 рядків Solidity — дивимося на Medusa.
Як інваріанти допомагають виявити критичні уразливості?
Формальна верифікація доводить, що контракт задовольняє специфікації для всіх можливих вхідних даних — не для N випадкових, а математично для всіх. Інструменти: Certora Prover, K Framework, Halmos.
Certora працює з CVL (Certora Verification Language): пишеш rules і invariants, Prover транслює їх у SMT‑формули і перевіряє через Z3/CVC5. MakerDAO, Aave, Uniswap використовують Certora в CI/CD pipeline — кожен PR верифікується автоматично.
Обмеження: не працює з необмеженими циклами, складно справляється з hash functions і signature verification. Для контрактів з простою математикою (AMM, lending) — відмінно. Для контрактів з довільними зовнішніми викликами — складно написати достатньо повну специфікацію.
Formal verification має сенс для контрактів, які: керують значним TVL, оновлюються рідко, мають чітко формалізовані інваріанти. Для продуктів, що швидко ітеруються, співвідношення витрат і користі не на користь верифікації.
Вектори атак, які пропускають джуніор‑аудитори
Storage collision в proxy патерні. Transparent proxy і UUPS використовують конкретні слоти для зберігання адреси імплементації (EIP‑1967). Якщо в імплементації випадково оголошена змінна в слоті 0, яка перетинається з proxy storage — отримуємо silent override. Slither це не впіймає, якщо proxy та імплементація в різних файлах.
Read‑only reentrancy. Класичний reentrancy guard захищає від зміни стану при рекурсивному виклику. Але якщо зовнішній контракт читає стан через view-функцію в середині транзакції — guard не допомагає. Кілька років тому Curve pools стали вектором атаки саме через це: зовнішній протокол читав get_virtual_price під час reentrancy‑вразливого стану Curve.
Oracle manipulation через TWAP. Spot price — стандартна ціль для flash loan атаки. TWAP складніше маніпулювати, але не неможливо: на малоліквідних парах Uniswap v2 можна зсунути TWAP за кілька блоків при достатньому капіталі. Правильний захист — використовувати Chainlink як primary oracle з TWAP як fallback, з перевіркою deviation threshold.
Gas griefing на unbounded loop. Функція ітерується по масиву користувачів. Атакуючий додає тисячі адрес з нульовими балансами — вартість виклику функції зростає до gas limit, функція стає недоступною. Захист: pull‑pattern замість push, обмеження довжини масивів, batch‑обробка зі збереженням позиції.
Front‑running на MEV. Транзакція видна в mempool до включення в блок. MEV‑бот бачить addLiquidity на значну суму, вставляє свій swap перед нею (sandwich attack). Для AMM це частина моделі. Для протоколів з ціновими функціями — потрібен minAmountOut / deadline параметр і його обов'язкова перевірка.
Структура повного аудиту
-
Scope definition і автоматичний аналіз (1‑2 дні). Фіксуємо commit hash, версію компілятора, список out‑of‑scope. Запускаємо Slither, Mythril, Aderyn. Triage: відокремлюємо реальні критичні баги від false positive. Складаємо карту залежностей контрактів.
-
Ручний аналіз (5‑15 днів). Кожен контракт порядково. Особлива увага: всі external і public функції, всі transfer/call/delegatecall, всі місця, де змінюється стан перед перевіркою або після зовнішнього виклику, всі математичні операції з участю користувацьких inputs. В середньому 95% знайдених уразливостей — логічні, а не технічні.
-
Fuzzing і тестування (2‑5 днів). Echidna або Foundry invariant tests для критичних інваріантів. Fork mainnet тести — перевіряємо поведінку в реальному оточенні з реальними оракулами. Наприклад, за 4 дні fuzzing знаходить в середньому 3 edge cases, не покритих unit‑тестами.
-
Звіт і мітигація. Звіт з severity (Critical/High/Medium/Low/Informational), описом вектора атаки, PoC‑кодом для Critical/High. Розробники виправляють, аудитори роблять re‑audit виправлень.
| Severity |
Приклади |
Чи потребує re‑audit |
| Critical |
Виведення коштів, несанкціоноване перенесення власності |
Завжди |
| High |
Маніпуляція, DoS на ключові функції |
Завжди |
| Medium |
Некоректна поведінка при edge cases |
Рекомендується |
| Low |
Газ‑неефективність, опечатки в events |
За бажанням |
Аудит у CI/CD
Нормальна практика для зрілих протоколів: Slither і Aderyn запускаються в GitHub Actions на кожен PR. Certora Prover — на merge в main. Це не замінює повний аудит перед деплоєм, але ловить регресії.
# .github/workflows/audit.yml
- name: Run Slither
uses: crytic/[email protected]
with:
target: 'src/'
slither-args: '--filter-paths "test|mock|script"'
Чек‑лист обов'язкових перевірок перед деплоєм
- Всі external функції мають перевірки доступу (
onlyOwner, onlyRole)
- Використання
SafeERC20 для зовнішніх токенів
- Відсутність
delegatecall на невідомі адреси
- Перевірка на reentrancy у всіх функціях з зовнішніми викликами
- Наявність
minAmountOut і deadline в AMM‑функціях
- Використання перевіреного оракула (Chainlink) з deviation threshold
Інструменти аудиту: порівняння
| Інструмент |
Тип аналізу |
Що знаходить |
Обмеження |
| Slither |
Статичний |
Reentrancy, integer overflow, access control |
Пропускає логічні уразливості |
| Mythril |
Symbolic execution |
Досяжні стани з порушенням property |
Path explosion на великих базах |
| Echidna |
Fuzzing (property‑based) |
Порушення інваріантів |
Потребує написання інваріантів |
| Certora |
Formal verification |
Математичне доведення властивостей |
Не працює з хешами/підписами |
Що входить в роботу (deliverables)
- Повний звіт у PDF з CVSS‑оцінками кожної уразливості
- PoC‑код для всіх Critical і High (відтворюваний в тестовому середовищі)
- Рекомендації щодо виправлення з прикладом коду
- Re‑audit після внесення правок (до двох ітерацій)
- Коротка пам'ятка для розробників щодо подальшої експлуатації
- Підтримка після деплою протягом 30 днів (консультації та розбір інцидентів)
Терміни
Аудит простого токена або NFT‑контракту — 3‑5 робочих днів. DeFi протокол з lending/AMM — 2‑4 тижні. Повний стек з кількома протоколами, cross‑chain, proxy upgrades — 4‑8 тижнів. Re‑audit виправлень — 3‑7 днів окремо.
Наша команда має 7+ років досвіду в безпеці смарт‑контрактів, перевірила 100+ проектів з сумарним TVL понад значну суму. Гарантуємо, що в процесі ми не пропустимо жоден відомий вектор — використовуємо ліцензовані версії Slither та найкращі конфігурації fuzzer'ів. Запобігнуті збитки для клієнтів оцінюються в значну суму.
Оцініть ваш проект — ми безкоштовно проаналізуємо код і запропонуємо комерційну пропозицію протягом 2 днів. Замовте аудит з гарантією якості та отримайте знижку на re‑audit при повторному зверненні.