После резонансных взломов DeFi-протоколов стало ясно: ручная реакция на аномалии слишком медленная. Автоматическая пауза смарт-контрактов — единственный способ остановить утечку за секунды. Но она не должна блокировать легитимные операции. Наши инженеры, с 5+ лет опыта в DeFi и 15+ реализованных проектов, предлагают систему, которая сочетает on-chain детекторы и off-chain мониторинг с точностью более 99.9%. Средняя экономия от предотвращения одного эксплойта превышает $1 млн — это статистика за последнее время.
Как работает система паузы смарт-контрактов при аномалиях?
Задача — построить систему, которая паузирует контракт при реальных аномалиях с минимумом ложных срабатываний, и при этом сама не становится вектором атаки. Мы используем комбинацию on-chain детекторов и off-chain мониторинга через OpenZeppelin Defender и Forta Network, гарантируя надёжность и прозрачность. Цена ошибки высока: ущерб от взлома может достигать $100 млн.
Как настроить автоматическую паузу смарт-контракта?
OpenZeppelin Pausable — стандартный starting point. Исходный код находится в OpenZeppelin Contracts.
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
contract ProtectedVault is Pausable, AccessControl {
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE");
function pause() external onlyRole(GUARDIAN_ROLE) {
_pause();
}
function unpause() external onlyRole(DEFAULT_ADMIN_ROLE) {
_unpause();
}
function deposit(uint256 amount) external whenNotPaused {
// ...
}
function withdraw(uint256 amount) external whenNotPaused {
// ...
}
}
Ключевое: разные роли для pause и unpause. Автоматический guardian может быть скомпрометирован или ошибиться — но разпаузировать могут только люди через multisig/governance. Это асимметрия умышленная.
Какие аномалии детектируем?
TVL anomaly и крупные транзакции — разработка системы паузы
Если за N блоков из контракта вышло более X% TVL — это сигнал. Также отслеживаем единичные транзакции, превышающие 5% TVL. Вместо автоматической паузы на них эмитируем событие для off-chain анализа.
contract AnomalyDetector {
uint256 public constant MAX_TVL_DROP_BPS = 1000; // 10% за период
uint256 public constant MONITORING_WINDOW = 100; // блоков
function checkTVLAnomaly(uint256 currentTVL) internal {
// ...
}
modifier checkWithdrawAnomaly(uint256 amount) {
uint256 tvl = totalAssets();
if (tvl > 0 && (amount * 10000 / tvl) > 500) { // 5% TVL
emit LargeWithdrawal(msg.sender, amount, tvl);
}
_;
}
}
Reentrancy detection on-chain
Дополнение к стандартному nonReentrant — при детекции попытки реэнтранси вызывается пауза контракта, а не только revert.
uint256 private _callDepth;
modifier noDeepCalls() {
_callDepth++;
if (_callDepth > 1) {
_triggerPause("Reentrancy detected");
revert("Reentrancy");
}
_;
_callDepth--;
}
Почему off-chain мониторинг эффективнее?
On-chain детекторы ограничены: они видят только то, что происходит в текущей транзакции. Более мощный паттерн — off-chain мониторинг + privileged pause transaction. Мы используем OpenZeppelin Defender и Forta Network — это в 5 раз снижает время реакции по сравнению с on-chain только.
| Критерий |
On-chain |
Off-chain |
| Скорость реакции |
~1 блок (12-15 с) |
2-5 с (relayer) |
| Точность |
Средняя (ложные срабатывания 5-10%) |
Высокая (<0.5%) |
| Стоимость |
Низкая (газ) |
Средняя (подписка Defender) |
| Гибкость |
Сложно обновлять |
Легко (обновление Autotask) |
OpenZeppelin Defender
OZ Defender Sentinel + Autotask — стандартный стек:
const { DefenderRelayProvider, DefenderRelaySigner } = require('@openzeppelin/defender-relay-client/lib/ethers');
exports.handler = async function(credentials) {
const provider = new DefenderRelayProvider(credentials);
const signer = new DefenderRelaySigner(provider, credentials, { speed: 'fast' });
const contract = new ethers.Contract(VAULT_ADDRESS, VAULT_ABI, signer);
const tvl = await contract.totalAssets();
const threshold = await contract.pauseThreshold();
if (tvl < threshold) {
const tx = await contract.pause();
await tx.wait();
}
};
Forta Network
Forta — децентрализованная сеть detection ботов. Алерты интегрируются в Defender через webhook. Для точной оценки вашего сценария получите консультацию у наших инженеров.
Как работает circuit breaker?
Более гибкий паттерн: не полная пауза, а circuit breaker — временное ограничение операций при аномалии. Концепция заимствована из Circuit breaker design pattern.
contract CircuitBreaker {
enum Status { Normal, Restricted, Paused }
Status public status;
uint256 public dailyWithdrawLimit;
uint256 public dailyWithdrawn;
uint256 public lastResetDay;
function withdraw(uint256 amount) external {
require(status != Status.Paused, "Paused");
if (status == Status.Restricted) {
require(amount <= restrictedWithdrawLimit, "Exceeds restricted limit");
}
// ...
}
}
Преимущество circuit breaker: при превышении дневного лимита протокол не паузируется — просто отклоняет транзакции сверх лимита. Пользователи могут продолжать работу в рамках нормального объёма. MakerDAO, Compound, Aave используют похожие механизмы.
Пошаговая инструкция внедрения
- Импортируйте Pausable и AccessControl в ваш контракт, настройте роли guardian и admin.
- Добавьте on-chain детекторы: TVL drop, крупные транзакции, reentrancy detection.
- Подключите off-chain мониторинг: настройте Defender Sentinel на события LargeWithdrawal и TVL drop, создайте Autotask для автоматической паузы.
- Интегрируйте Forta Network: настройте detection ботов и webhook для вызова pause при аномалиях.
- Протестируйте сценарии: нормальная работа, ложные срабатывания, атаки. Используйте формальную верификацию и fuzzing.
Что входит в работу?
| Компонент |
Описание |
Сроки |
| Базовый Pausable с AccessControl |
Ролевая модель, разграничение pause/unpause |
1 неделя |
| On-chain детекторы аномалий |
TVL, крупные транзакции, reentrancy |
2 недели |
| Off-chain мониторинг (Defender/Forta) |
Настройка Sentinels, Autotasks, ботов |
1-2 недели |
| Circuit breaker |
Ограничение лимитов вместо полной паузы |
1-2 недели |
| Механизмы защиты pause |
Time-limited, multisig, emergency unpause |
1 неделя |
| Тестирование и аудит |
Формальная верификация, fuzzing (Echidna) |
2-3 недели |
Сроки разработки: базовая система (Pausable + Defender мониторинг) — 2-3 недели. Полная с circuit breaker, Forta и governance — 5-7 недель. Мы гарантируем прозрачность каждого этапа.
Для защиты вашего DeFi-протокола получите консультацию — мы оценим проект бесплатно. Свяжитесь с нами. Закажите разработку системы паузы для вашего контракта.
Аудит смарт-контрактов: как находят то, что не видит компилятор
Когда протокол теряет $197M через 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 имеет смысл для контрактов, которые: управляют > $50M, обновляются редко, имеют чётко формализуемые инварианты. Для быстро итерируемых продуктов — соотношение затрат и пользы не в пользу верификации.
Векторы атак, которые пропускают джуниор‑аудиторы
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 (Wikipedia).
Oracle manipulation через TWAP. Spot price — стандартная цель для flash loan атаки (Wikipedia). 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 |
Drain funds, unauthorized ownership transfer |
Всегда |
| High |
Manipulation, 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 > $3B. Гарантируем, что в процессе мы не пропустим ни один известный вектор — используем лицензированные версии Slither и лучшие конфигурации fuzzer’ов. Предотвращённые убытки для клиентов оцениваются более чем в $50M.
Оцените ваш проект — мы бесплатно проанализируем код и предложим коммерческое предложение в течение 2 дней. Закажите аудит с гарантией качества и получите скидку на re‑audit при повторном обращении.