Які вразливості знаходить фаззинг?
Зауважимо: коли ви деплоїте контракт пулу ліквідності з AMM, ми бачимо ризики: unit-тести проходять, обмеження slippage встановлено коректно, аудитор знаходить пару багів — ви їх виправляєте. За місяць хтось знімає 90% ліквідності однією транзакцією, використовуючи комбінацію з трьох викликів, які не передбачені. Виявляється, інваріант k = x * y порушується за певних цін. Чим більше функцій і взаємозалежностей, тим більше таких «темних кутів». Fuzzing smart contract (фаззинг-тестування) змушує контракт пройти через мільйони випадкових сценаріїв і зафіксувати той єдиний, який ламає логіку. У типовому проекті фаззинг виявляє в середньому 8,5 вразливостей — в 3 рази більше, ніж ручний аудит. Це не просто цифри — це запобігані втрати ліквідності та врятовані протоколи. Фаззинг в 3 рази ефективніший за ручний аудит у виявленні edge cases.
Сценарії, в яких фаззинг незамінний
Типовий unit-тест покриває один шлях виконання. Якщо userA викликає withdraw з сумою 100 — баланс зменшується на 100. Але в реальності транзакції переплітаються: два flash loan, зміна ціни oracle, прямий виклик нативної функції та reentrancy. Кожен із цих факторів може накластися. Фаззинг поєднує їх випадковим чином, що дозволяє знайти комбінації, неочевидні для людини. Ми шукаємо:
- Порушення інваріантів: totalSupply == sum(balances), k = x * y для пулів.
- Переповнення uint256 при операціях з високою точністю.
- Race conditions при апгрейді контрактів (storage collision).
- Помилки округлення в DeFi протоколах з великими обсягами.
- Можливість подвійного виведення коштів через reentrancy та delegatecall.
Стек та методологія фаззингу
Echidna — основний інструмент property-based тестів
Echidna (розробка Trail of Bits) — фаззер для Ethereum смарт-контрактів. Ми пишемо інваріанти як assert у самому контракті або окремі тестові контракти. У документації Echidna підкреслюється, що property-based тестування ефективне для пошуку порушень інваріантів.
contract TestLiquidityPool is Test { LiquidityPool pool; // інваріант: сумарна ліквідність не може бути від'ємною function echidna_test_total_supply_nonnegative() public view returns (bool) { return pool.totalSupply() >= 0; } // інваріант: k = x * y не зменшується безпідставно function echidna_test_k_invariant() public view returns (bool) { (uint112 x, uint112 y, ) = pool.getReserves(); uint256 k = uint256(x) * uint256(y); return k >= pool.MIN_K(); } } Echidna генерує послідовності викликів, мутує аргументи та перевіряє інваріанти після кожного блоку. Якщо порушення знайдено — він виводить мінімальну послідовність транзакцій, яка до нього призводить.
Foundry — інваріантні тести з високою швидкістю
Foundry (fuzz testing) дозволяє запускати тести з рандомними аргументами та перевіряти постумови. Ми комбінуємо Foundry з Echidna: Foundry для швидкої локальної перевірки, Echidna для глибинного перебору.
contract InvariantTest is StdInvariant { LiquidityPool pool; function setUp() public { pool = new LiquidityPool(); targetContract(address(pool)); } // інваріант: баланс пулу відповідає sum позицій function invariant_totalSupplyEqualsSumBalances() public { (uint112 x, uint112 y, ) = pool.getReserves(); assertApproxEqRel(pool.totalSupply(), x + y, 1e15); } } Slither + Echidna — статика та динаміка
Slither статично аналізує storage layout, знаходить storage collision та uninitialized storage. Echidna динамічно перевіряє, чи можна скористатися цими проблемами. Цей тандем особливо ефективний для тестування upgradeable контрактів.
Вибір інструменту для фаззингу
| Інструмент | Тип | Швидкість | Глибина | Складність налаштування |
|---|---|---|---|---|
| Echidna | Property-based | Середня | Висока | Середня |
| Foundry | Fuzz + invariant | Висока | Середня | Низька |
| Slither | Статичний | Швидка | Низька (статич.) | Низька |
Echidna знаходить в 3 рази більше edge cases, ніж ручний аудит, але вимагає написання інваріантів. Foundry прогоняє 10 млн тестів за годину, що в 2 рази швидше за Hardhat. У нашій практиці фаззинг виявив в середньому 8,5 вразливостей на проект.
Етапи фаззинг-тестування: від аудиту до звіту
- Аналіз архітектури (2–3 дні). Вивчення коду, виділення критичних функцій та state змінних. Визначення інваріантів спільно з замовником.
- Написання фаззерів (5–7 днів). Розробка тестових контрактів з інваріантами в Echidna та Foundry. Налаштування sequence mutator та custom fuzzer для складної логіки (наприклад, random swap paths).
- Запуск та аналіз (5–10 днів). Прогін мінімум 50 млн тестових випадків. Для кожного failure: дебаг, класифікація (Critical/High/Medium). Повторний прогін після виправлень.
- Звіт та рекомендації (3–5 днів). Документ з детальним описом усіх знайдених проблем, послідовністю транзакцій та кодом виправлень. Оцінка залишкового ризику після фіксів.
| Етап | Тривалість | Виконання |
|---|---|---|
| Аналіз | 2-3 дні | Визначення інваріантів |
| Розробка фаззерів | 5-7 днів | Кодування тестів |
| Прогін | 5-10 днів | 50 млн тестових випадків |
| Звіт | 3-5 днів | Документація та рекомендації |
Приклад фрагмента звіту
ID: INV-001 | Severity: High Опис: Порушення інваріанту totalSupply == sum(balances) після виклику withdraw з reentrancy. Sequence: addLiquidity(100, 200) -> transferFrom(...) -> withdraw(50) -> withdraw(50) з reentrancy callback. Рекомендація: Використовувати Checks-Effects-Interactions pattern.
Що входить в роботу
- Налаштування середовища (Docker, Foundry, Echidna).
- Визначення та кодування 10–30 інваріантів.
- Прогін фаззера з автоматичним збором failure.
- Ручна верифікація кожного failure (не хибне спрацювання).
- Консультація щодо виправлення вразливостей.
- Підсумковий звіт у PDF.
Чому фаззинг варто замовляти у нас?
5+ років досвіду в розробці смарт-контрактів на Solidity та Rust. 50+ проектів, що пройшли аудит, включаючи DeFi протоколи зі значним TVL. Власна методологія комбінування статики, фаззингу та формальної верифікації. Гарантія: ми не закриваємо аудит, доки не знайдемо хоча б одну підтверджену вразливість, або повернемо гроші (умови обговорюються). Економія на подальших виправленнях може сягати сотень тисяч доларів.
Строки та вартість
Від 15 до 30 робочих днів залежно від обсягу коду та кількості контрактів. Вартість розраховується індивідуально — ми не називаємо ціну наосліп. Напишіть нам, оцінимо ваш проект за 1–2 дні.
Типові помилки при фаззингу та способи їх запобігання
- Перегенерація state: якщо фаззер не вміє викликати функцію з різними параметрами, він застрягне в одному сценарії. Рішення — використовувати sequence fuzzer.
- Відсутність перевірки oracle price: фаззер може подавати будь-які ціни, але якщо вони виходять за допустимий діапазон, контракт повинен відхиляти їх. Багато протоколів нехтують цим.
- Ігнорування gas limit: деякі інваріанти виконуються тільки за певної витрати газу. Фаззер повинен варіювати gas limit.
Зв'яжіться з нами, щоб обговорити деталі та отримати консультацію щодо вашого проекту. Замовте фаззинг-тестування — ми допоможемо усунути приховані вразливості до того, як їх знайдуть зловмисники.
Ми проводимо invariant testing (інваріантне тестування) та solidity security audit контрактів.







