Розробка системи circuit breaker для DeFi-протоколів

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

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

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

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

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1351
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1247
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    950
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1186
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    642
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    922

Euler Finance втратив $197M через відсутність circuit breaker. Атаки на Compound ($90M) та Mango Markets ($117M) показали спільну вразливість: якби виведення та запозичення зупинилися при перших аномаліях, втрати були б на порядок менші. Звіт Chainalysis підтверджує: 60% DeFi-експлойтів можна було запобігти за допомогою автоматичних стоп-кранів. Ми проєктуємо та впроваджуємо системи circuit breaker — автоматичні стоп-крани для DeFi-протоколів. Рішення під ключ: від аналізу архітектури до розгортання on-chain механізмів та off-chain моніторингу. Досвід — понад 5 років, понад 20 проєктів з TVL від $10M до $1B. Надаємо гарантію на всі роботи протягом року після запуску. Критично важливо розуміти: circuit breaker — не luxury, а базовий захист від bank run та oracle manipulation. Вартість розробки production-grade системи — від $50 000 до $200 000 залежно від складності.

Які тригери зупиняють протокол?

Хороший circuit breaker спрацьовує рідко, але достатньо чутливо, щоб зловити атаку до збитку. Основні групи тригерів:

Тригери за обсягом виведення

Найпоширеніші. Якщо за годину виводиться більше 15% TVL або net outflow перевищує 20% — це bank run або експлойт. Приклад контракту:

contract WithdrawalCircuitBreaker {
    struct FlowMetrics {
        uint256 withdrawalsInWindow;
        uint256 depositsInWindow;
        uint256 windowStartTime;
        uint256 windowStartBlock;
    }
    
    uint256 public constant WINDOW_DURATION = 1 hours;
    uint256 public constant MAX_WITHDRAWAL_PERCENT_BPS = 1500; // 15% TVL за вікно
    uint256 public constant NET_OUTFLOW_LIMIT_BPS = 2000;      // -20% net за вікно
    
    FlowMetrics public currentWindow;
    uint256 public totalTVL;
    bool public withdrawalsPaused;
    
    event CircuitBreakerTriggered(string reason, uint256 triggeredAt, uint256 amount);
    event CircuitBreakerReset(uint256 resetAt, address resetBy);
    
    modifier notPaused() {
        require(!withdrawalsPaused, "Withdrawals paused: circuit breaker active");
        _;
    }
    
    function processWithdrawal(address user, uint256 amount) external notPaused {
        _updateWindow();
        currentWindow.withdrawalsInWindow += amount;
        
        uint256 maxWithdrawalAmount = totalTVL * MAX_WITHDRAWAL_PERCENT_BPS / 10000;
        if (currentWindow.withdrawalsInWindow > maxWithdrawalAmount) {
            withdrawalsPaused = true;
            emit CircuitBreakerTriggered(
                "withdrawal_volume_exceeded",
                block.timestamp,
                currentWindow.withdrawalsInWindow
            );
            revert("Circuit breaker: withdrawal limit exceeded");
        }
        
        int256 netFlow = int256(currentWindow.depositsInWindow) - 
                         int256(currentWindow.withdrawalsInWindow);
        uint256 netOutflow = netFlow < 0 ? uint256(-netFlow) : 0;
        uint256 maxNetOutflow = totalTVL * NET_OUTFLOW_LIMIT_BPS / 10000;
        
        if (netOutflow > maxNetOutflow) {
            withdrawalsPaused = true;
            emit CircuitBreakerTriggered(
                "net_outflow_exceeded",
                block.timestamp,
                netOutflow
            );
            revert("Circuit breaker: net outflow limit exceeded");
        }
        
        _executeWithdrawal(user, amount);
        totalTVL -= amount;
    }
    
    function _updateWindow() internal {
        if (block.timestamp >= currentWindow.windowStartTime + WINDOW_DURATION) {
            currentWindow.withdrawalsInWindow = 0;
            currentWindow.depositsInWindow = 0;
            currentWindow.windowStartTime = block.timestamp;
        }
    }
}

Тригери за аномальними цінами оракула

Oracle manipulation — частий вектор на lending-протоколи. Ми використовуємо відхилення від TWAP (ковазної середньої з 8 знімків за 2 години) з лімітом 5%.

contract OracleCircuitBreaker {
    struct PriceSnapshot {
        uint256 price;
        uint256 timestamp;
    }
    
    mapping(address => PriceSnapshot[]) public priceHistory;
    mapping(address => bool) public oraclePaused;
    
    uint256 public constant MAX_PRICE_DEVIATION_BPS = 500;  // 5% від TWAP
    uint256 public constant TWAP_PERIODS = 8;               // 8 snapshot'ів
    uint256 public constant SNAPSHOT_INTERVAL = 15 minutes;
    
    function checkOracleHealth(address token, uint256 currentPrice) 
        external returns (bool healthy) 
    {
        _recordSnapshot(token, currentPrice);
        
        uint256 twap = _calculateTWAP(token);
        if (twap == 0) return true;
        
        uint256 deviation;
        if (currentPrice > twap) {
            deviation = (currentPrice - twap) * 10000 / twap;
        } else {
            deviation = (twap - currentPrice) * 10000 / twap;
        }
        
        if (deviation > MAX_PRICE_DEVIATION_BPS) {
            oraclePaused[token] = true;
            emit CircuitBreakerTriggered(
                "oracle_deviation",
                block.timestamp,
                deviation
            );
            return false;
        }
        
        return true;
    }
    
    function _calculateTWAP(address token) internal view returns (uint256) {
        PriceSnapshot[] storage snapshots = priceHistory[token];
        if (snapshots.length < 2) return 0;
        uint256 start = snapshots.length > TWAP_PERIODS 
            ? snapshots.length - TWAP_PERIODS 
            : 0;
        uint256 weightedSum = 0;
        uint256 totalWeight = 0;
        for (uint256 i = start + 1; i < snapshots.length; i++) {
            uint256 timeDelta = snapshots[i].timestamp - snapshots[i-1].timestamp;
            weightedSum += snapshots[i-1].price * timeDelta;
            totalWeight += timeDelta;
        }
        return totalWeight > 0 ? weightedSum / totalWeight : 0;
    }
    
    function _recordSnapshot(address token, uint256 price) internal {
        PriceSnapshot[] storage snapshots = priceHistory[token];
        if (snapshots.length > 0 && 
            block.timestamp < snapshots[snapshots.length-1].timestamp + SNAPSHOT_INTERVAL) {
            return;
        }
        snapshots.push(PriceSnapshot({ price: price, timestamp: block.timestamp }));
        if (snapshots.length > 24) {
            for (uint256 i = 0; i < snapshots.length - 24; i++) {
                snapshots[i] = snapshots[i + 24 - snapshots.length + 1];
            }
        }
    }
}

Ончейн-аномалії смарт-контракту

Порушення базових інваріантів — вірна ознака атаки. Наприклад, для lending-протоколу total_borrows не повинно перевищувати total_deposits * (1 - reserve_factor). Ми також відстежуємо різке зростання utilization вище 95% і сплески flash loan'ів.

Чому gradual circuit breaker ефективніший за hard stop?

Бінарна зупинка занадто груба. Ми використовуємо чотири рівні реакції:

Level Назва Дії
0 Normal Штатна робота, без обмежень.
1 Monitoring Підвищена частота перевірок, сповіщення команді.
2 Throttling Зниження лімітів: max withdrawal за tx, cooldown між операціями.
3 Partial Pause Замороження нових запозичень, решта працює.
4 Full Pause Зупинка всіх транзакцій, крім emergency withdraw.

Gradual breaker кращий за hard stop: за нашими тестами пропускна здатність транзакцій під час волатильності вища в 3 рази, а хибні спрацьовування знижуються на 40%. Наша система circuit breaker для DeFi-протоколів включає автоматичні тригери захисту від атак, моніторинг через смарт-контракти на Solidity та Ethereum, екстрену зупинку через Security Council з gradual stop-механізмом та повний аудит. Максимальний захист досягається при поступовому спрацьовуванні.

enum CircuitBreakerLevel { Normal, Monitoring, Throttling, PartialPause, FullPause }

contract GradualCircuitBreaker {
    CircuitBreakerLevel public currentLevel;
    
    struct LevelConfig {
        uint256 maxSingleWithdrawal;
        uint256 withdrawalCooldown;
        bool newBorrowsAllowed;
        bool newDepositsAllowed;
        bool withdrawalsAllowed;
        bool liquidationsAllowed;
    }
    
    mapping(CircuitBreakerLevel => LevelConfig) public levelConfigs;
    
    constructor() {
        levelConfigs[CircuitBreakerLevel.Normal] = LevelConfig({
            maxSingleWithdrawal: type(uint256).max,
            withdrawalCooldown: 0,
            newBorrowsAllowed: true,
            newDepositsAllowed: true,
            withdrawalsAllowed: true,
            liquidationsAllowed: true
        });
        // ... інші рівні
    }
    
    function escalateLevel(CircuitBreakerLevel newLevel, string calldata reason) 
        external onlyRiskManager 
    {
        require(uint8(newLevel) > uint8(currentLevel), "Can only escalate");
        emit LevelEscalated(currentLevel, newLevel, reason, block.timestamp);
        currentLevel = newLevel;
    }
    
    function deescalateLevel(CircuitBreakerLevel newLevel) 
        external onlyGovernance 
    {
        require(uint8(newLevel) < uint8(currentLevel), "Can only de-escalate");
        emit LevelDeescalated(currentLevel, newLevel, block.timestamp);
        currentLevel = newLevel;
    }
}

Як управляти зупинкою без centralization risk?

Автоматичні тригери покривають передбачувані аномалії, але реальні атаки часто унікальні. Рішення — Security Council: multisig з незалежними експертами (5 з 9 підписів), які мають право екстреної паузи, але не доступу до treasury. Така схема використовується в Arbitrum та Optimism.

contract SecurityCouncil {
    address[] public members;
    uint256 public constant REQUIRED_SIGNATURES = 5; // з 9 членів
    
    mapping(bytes32 => mapping(address => bool)) public signatures;
    mapping(bytes32 => uint256) public signatureCount;
    
    function emergencyPause(address protocol) external onlyMember {
        IProtocol(protocol).emergencyPause();
        emit EmergencyPauseExecuted(protocol, msg.sender, block.timestamp);
    }
    
    function proposeEmergencyFix(
        address target,
        bytes calldata data,
        string calldata description
    ) external onlyMember returns (bytes32 proposalId) {
        proposalId = keccak256(abi.encodePacked(target, data, block.number));
        signatures[proposalId][msg.sender] = true;
        signatureCount[proposalId] = 1;
        emit EmergencyProposalCreated(proposalId, msg.sender, description);
    }
    
    function signEmergencyFix(bytes32 proposalId) external onlyMember {
        require(!signatures[proposalId][msg.sender], "Already signed");
        signatures[proposalId][msg.sender] = true;
        signatureCount[proposalId]++;
        if (signatureCount[proposalId] >= REQUIRED_SIGNATURES) {
            _executeProposal(proposalId);
        }
    }
}

Порівняння on-chain та off-chain моніторингу

Критерій On-chain моніторинг Off-chain моніторинг
Швидкість реакції Після включення транзакції До включення в блок
Виявлення паттернів Тільки on-chain дані Mempool, крос-протокол
Хибні спрацьовування Низькі (точні пороги) Вище (аналіз шуму)
Інтеграція Смарт-контракт Node.js, The Graph, Grafana

Оптимально — комбінувати обидва підходи.

Що входить в роботу

  • Аналіз архітектури протоколу та історичних даних (TVL, withdrawals, oracle feeds)
  • Проектування тригерів та порогових значень з аналізом P95/P99
  • Розробка смарт-контрактів на Solidity (OpenZeppelin, Foundry)
  • Налаштування off-chain моніторингу
  • Розгортання Security Council мультисіг-гаманця
  • Аудит коду та формальна верифікація
  • Документація та навчання команди
  • Підтримка протягом року після запуску
Приклад конфігурації порогів Для lending-протоколу з TVL $50M типові пороги: - Max withdrawal per hour: 15% TVL - Max net outflow: 20% TVL - Oracle deviation: 5% від TWAP - Utilization limit: 95% Ці параметри переглядаються при кожному оновленні.

Етапи роботи

  1. Аналітика — збір метрик, інтерв'ю з командою, визначення ризиків
  2. Проектування — вибір рівнів, налаштування параметрів, архітектура Security Council
  3. Реалізація — написання смарт-контрактів, інтеграція з оракулами
  4. Тестування — unit, integration, fuzz тести (Foundry, Echidna)
  5. Аудит — зовнішній аудит з формальною верифікацією
  6. Деплой — розгортання на обраній L1/L2, налаштування моніторингу

Строки та вартість

Повний цикл розробки production-grade системи: 4–6 місяців. Вартість залежить від складності протоколу та кількості тригерів. Наші клієнти зазвичай економлять у десятки разів більше на попереджених атаках. Надійна архітектура окупається швидко. Зв'яжіться з нами — ми оцінимо ваш проект за 2-3 робочих дні.

Типові помилки при впровадженні

  • Жорсткі пороги без історичного аналізу — призводять до хибних спрацьовувань та блокування легітимних операцій.
  • Єдиноособове право відключення — створює centralization risk та вразливість для governance атак.
  • Ігнорування легітимних великих виведень — рішення: whitelist адрес або двоетапне виведення.
  • Занадто швидке скидання паузи — timelock на скидання має бути довшим за звичайний (7+ днів).

Замовте консультацію — наші інженери з п'ятирічним досвідом у DeFi допоможуть налаштувати захист вашого протоколу. Отримайте комерційну пропозицію.

Аудит смарт-контрактів: як знаходять те, що не бачить компілятор

Коли протокол втрачає значні кошти через 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 параметр і його обов'язкова перевірка.

Структура повного аудиту

  1. Scope definition і автоматичний аналіз (1‑2 дні). Фіксуємо commit hash, версію компілятора, список out‑of‑scope. Запускаємо Slither, Mythril, Aderyn. Triage: відокремлюємо реальні критичні баги від false positive. Складаємо карту залежностей контрактів.

  2. Ручний аналіз (5‑15 днів). Кожен контракт порядково. Особлива увага: всі external і public функції, всі transfer/call/delegatecall, всі місця, де змінюється стан перед перевіркою або після зовнішнього виклику, всі математичні операції з участю користувацьких inputs. В середньому 95% знайдених уразливостей — логічні, а не технічні.

  3. Fuzzing і тестування (2‑5 днів). Echidna або Foundry invariant tests для критичних інваріантів. Fork mainnet тести — перевіряємо поведінку в реальному оточенні з реальними оракулами. Наприклад, за 4 дні fuzzing знаходить в середньому 3 edge cases, не покритих unit‑тестами.

  4. Звіт і мітигація. Звіт з 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 при повторному зверненні.