Разработка отчёта аудита смарт-контрактов
Отчёт аудита — это документ, который команда протокола предоставляет публично перед запуском. Инвесторы, пользователи, и интеграторы читают его чтобы оценить риски. Плохой отчёт — это либо пустышка которую заказали "для галочки", либо настолько технически перегруженный текст, что никто не понимает реальных рисков. Хороший отчёт честно описывает что было найдено, что исправлено, и что осталось.
Важно понимать: аудитор не может гарантировать отсутствие багов. Аудитор может сказать "я проверил эти конкретные свойства этими конкретными методами и не нашёл проблем". Честный отчёт это и описывает.
Структура профессионального отчёта
Executive Summary
Первый раздел читают не разработчики — его читают инвесторы, партнёры, юристы. Здесь: общий вывод (critical issues found? fixed?), scope (какие контракты, какой commit hash, какие цепи), методология (manual review, fuzzing, formal verification?), и summary таблица находок по severity.
Summary таблица должна быть на первой странице:
| Severity | Found | Fixed | Acknowledged | Disputed |
|---|---|---|---|---|
| Critical | 2 | 2 | 0 | 0 |
| High | 4 | 3 | 1 | 0 |
| Medium | 7 | 6 | 1 | 0 |
| Low | 12 | 8 | 4 | 0 |
| Informational | 15 | 5 | 10 | 0 |
Если critical issues остались unfixed или acknowledged (не исправлены, но команда согласна с риском) — это красный флаг для читателя. Аудитор не может заставить исправить — только задокументировать.
Scope и ограничения
Точный scope — обязательная часть. Без него непонятно что именно проверялось. Должно быть:
- Конкретные файлы и функции (не "весь протокол")
- Commit hash репозитория
- Что не входило в scope (оракулы, admin keys, frontend)
- Временные ограничения и их влияние на глубину проверки
Профессиональный аудитор честно пишет: "Из-за объёма кода и временных ограничений fuzzing проводился только для core swap функций, модуль lending проверен только manual review." Это защищает и аудитора, и помогает читателю понять уровень уверенности.
Методология
Раздел объясняет как проводился аудит:
Manual code review — построчное чтение кода с фокусом на известные классы уязвимостей: reentrancy, integer overflow/underflow, access control, front-running, oracle manipulation, flash loan vectors.
Automated analysis — Slither (статический анализ), Mythril (symbolic execution), 4naly3er. Эти инструменты находят очевидные паттерны, но генерируют много false positives. Результаты требуют ручной валидации.
Fuzzing — Foundry Invariant testing или Echidna. Определяются инварианты (свойства которые должны всегда выполняться) и тест-корпус прогоняется с миллионами случайных inputs. Пример инварианта: "сумма всех балансов пользователей не превышает totalSupply токена".
Formal verification (если применялась) — Certora Prover или K framework. Математическое доказательство свойств контракта. Дорого и применяется для критических компонентов (AMM invariant, lending liquidation logic).
Формат описания находок
Каждая находка — отдельная секция со стандартной структурой:
Заголовок с ID и severity. H-01: Reentrancy in withdraw() allows draining funds. ID нужен для отслеживания статуса (fixed/acknowledged), severity — для приоритизации.
Severity классификация:
- Critical — потеря средств пользователей, полный контроль контракта злоумышленником
- High — потеря части средств, обход критической логики
- Medium — нарушение инвариантов без прямой потери средств, DoS
- Low — неоптимальное поведение, потенциальный вектор в определённых условиях
- Informational — code quality, gas inefficiency, best practice нарушения
Описание уязвимости. Что именно неправильно и почему это проблема. Конкретная функция, строки кода, механизм эксплуатации.
Proof of Concept. Для critical и high — обязателен. Это тест (желательно Foundry test) который демонстрирует эксплуатацию. Без PoC severity легко оспорить:
function test_reentrancy_drain() public {
// Setup: deploy attacker contract
Attacker attacker = new Attacker(address(vault));
deal(address(token), address(attacker), 1 ether);
// Attack: trigger reentrancy
attacker.attack();
// Verify: attacker drained vault
assertGt(token.balanceOf(address(attacker)), 100 ether);
assertEq(token.balanceOf(address(vault)), 0);
}
Рекомендация по исправлению. Конкретная — не "добавьте проверку", а "добавьте nonReentrant модификатор из OpenZeppelin ReentrancyGuard к функции withdraw и перенесите state update перед внешним вызовом (Checks-Effects-Interactions паттерн)".
Response команды и статус. После того как команда отвечает — аудитор добавляет статус: Fixed (с указанием commit hash где исправлено), Acknowledged (команда знает о риске и принимает его), Disputed (команда не согласна с severity или существованием проблемы). Для disputed — аудитор может добавить контраргументы.
Приложения
Appendix A: Test Coverage. Процент покрытия по строкам/функциям/ветвям. forge coverage --report lcov.低кое coverage (< 70%) — само по себе риск: непокрытый код не проверен тестами команды.
Appendix B: Automated Tools Output. Raw output Slither/Mythril с пометками что было triaged как false positive и почему.
Appendix C: Code Quality. Стиль кода, документация (NatSpec), события для off-chain мониторинга, upgradeability паттерн (proxy?), admin key риски.
Работа с командой
Качественный аудит — это диалог, не монолог. После первичного review аудитор передаёт findings команде, команда исправляет и объясняет спорные моменты. Аудитор проверяет исправления (verify fixes). Итоговый отчёт отражает финальное состояние.
Хорошая практика: публиковать не только финальный отчёт, но и changelog — что было найдено, что исправлено. Это показывает зрелость команды.
Срок подготовки отчёта: 1-3 недели в зависимости от объёма кода и глубины проверки. Средний DeFi протокол (5-10 контрактов, 2000-5000 строк Solidity) — 2 недели.







