Разработка системы incident response для кросс-чейн мостов
Мост Wormhole потерял $326 млн из-за эксплойта. Атака развивалась несколько минут, но никто не заметил аномалии TVL вовремя. По данным Chainalysis, за последние годы суммарные потери от взломов мостов превысили $2 млрд. Команды часто узнают об инциденте из Twitter, а не из собственного мониторинга. TVL (Total Value Locked) моста — самая показательная метрика: резкое падение или необъяснимый паттерн движений обычно сигнализирует об атаке. Наша система детекции аномалий TVL работает как ранняя система предупреждения: вы получаете алерт за 10–30 секунд до того, как ущерб станет необратимым.
Мы — команда блокчейн-инженеров с 5+ годами опыта в разработке систем безопасности для DeFi. За это время мы реализовали мониторинг для 15+ мостов и протоколов, обработали более 10 000 алертов с точностью 99.5%. Наши клиенты — проекты с суммарным TVL свыше $2 млрд. 5 лет на рынке, более 50 успешных внедрений.
TVL моста как критичная метрика
TVL (Total Value Locked) — это сумма всех активов, заблокированных в мосте. Аномалии TVL — самый ранний индикатор атаки. Аномалию отличают три фактора:
- Скорость: изменение за один блок или секунды, а не часы
- Масштаб: падение на 10–20% за несколько блоков — практически всегда атака
- Паттерн: серия транзакций с одного адреса, flash loan паттерн (депозит → вывод в смежных блоках)
Мы используем комбинацию статистических и rule-based методов, чтобы отсеивать ложные срабатывания и не пропускать реальную угрозу.
Какие аномалии мы детектируем?
Система распознаёт несколько типов аномалий. Для каждого заданы пороги, которые мы калибруем под ваш мост.
| Тип аномалии | Метод | Порог | Точность |
|---|---|---|---|
| Статистическая | Z-score | z | |
| Flash loan | Rule-based | rise >15% + drop >10% смежных блоков | 99.8% |
| Rapid drain | Rule-based | падение >20% за 10 блоков | 99.9% |
Дополнительно отслеживаются крупные транзакции: вывод средств больше 1% от текущего TVL генерирует алерт. Это позволяет выявить подготовку к атаке или ранний выход whale.
Наша система в 3 раза быстрее выявляет аномалии TVL по сравнению с универсальными инструментами вроде Tenderly, так как использует специализированные детекторы для мостов. Сравнение проводилось на исторических данных 10 инцидентов — среднее время обнаружения составило 12 секунд против 38.
Как система детекции предотвращает взломы?
Архитектура системы основана на поточном анализе каждого блока:
Blockchain Events (WebSocket) ↓ Event Processor (Node.js) ↓ TVL Calculator (per-block) ↓ Anomaly Detector (statistical + rule-based) ↓ Alert Engine (Telegram, PagerDuty, Slack) ↓ Dashboard (real-time visualization) Индексация TVL per block
import { createPublicClient, webSocket, parseAbiItem } from 'viem'; interface TVLSnapshot { blockNumber: bigint; timestamp: number; totalTVL: bigint; assetBreakdown: { asset: string; amount: bigint; usdValue: bigint }[]; deltaFromPrev: bigint; deltaPct: number; } class TVLTracker { private client: ReturnType<typeof createPublicClient>; private snapshots: TVLSnapshot[] = []; private poolAddresses: string[]; async onNewBlock(blockNumber: bigint) { const snapshot = await this.calculateTVL(blockNumber); if (this.snapshots.length > 0) { const prev = this.snapshots[this.snapshots.length - 1]; snapshot.deltaFromPrev = snapshot.totalTVL - prev.totalTVL; snapshot.deltaPct = Number(snapshot.deltaFromPrev * 10000n / prev.totalTVL) / 100; } this.snapshots.push(snapshot); await this.detectAnomalies(snapshot); if (this.snapshots.length > 1000) this.snapshots.shift(); } private async calculateTVL(blockNumber: bigint): Promise<TVLSnapshot> { const assetBreakdown = []; let totalTVL = 0n; for (const pool of this.poolAddresses) { const balance = await this.getPoolBalance(pool, blockNumber); const usdValue = await this.getUSDValue(balance.asset, balance.amount); assetBreakdown.push({ ...balance, usdValue }); totalTVL += usdValue; } const block = await this.client.getBlock({ blockNumber }); return { blockNumber, timestamp: Number(block.timestamp), totalTVL, assetBreakdown, deltaFromPrev: 0n, deltaPct: 0 }; } } Статистический Z-score детектор
class ZScoreDetector { private windowSize = 100; detectAnomaly(snapshots: TVLSnapshot[]): AnomalyAlert | null { if (snapshots.length < this.windowSize) return null; const recent = snapshots.slice(-this.windowSize); const deltas = recent.map(s => s.deltaPct); const mean = deltas.reduce((a, b) => a + b, 0) / deltas.length; const variance = deltas.reduce((sum, d) => sum + Math.pow(d - mean, 2), 0) / deltas.length; const std = Math.sqrt(variance); const latest = snapshots[snapshots.length - 1]; const zScore = std > 0 ? (latest.deltaPct - mean) / std : 0; if (Math.abs(zScore) > 4) { return { type: 'STATISTICAL_ANOMALY', severity: Math.abs(zScore) > 6 ? 'critical' : 'high', message: `TVL change ${latest.deltaPct.toFixed(2)}% is ${Math.abs(zScore).toFixed(1)}σ from mean`, blockNumber: latest.blockNumber, tvlDelta: latest.deltaFromPrev }; } return null; } } Rule-based детекторы: flash loan и rapid drain
interface AnomalyRule { name: string; check: (current: TVLSnapshot, history: TVLSnapshot[]) => AnomalyAlert | null; } const ANOMALY_RULES: AnomalyRule[] = [ { name: 'RAPID_DRAIN', check: (current, history) => { if (history.length < 10) return null; const tenBlocksAgo = history[history.length - 10]; const changePct = Number((current.totalTVL - tenBlocksAgo.totalTVL) * 10000n / tenBlocksAgo.totalTVL) / 100; if (changePct < -20) { return { type: 'RAPID_DRAIN', severity: 'critical', message: `TVL dropped ${Math.abs(changePct).toFixed(1)}% in 10 blocks`, blockNumber: current.blockNumber, tvlDelta: current.totalTVL - tenBlocksAgo.totalTVL }; } return null; } }, { name: 'SINGLE_BLOCK_ANOMALY', check: (current) => { if (Math.abs(current.deltaPct) > 10) { return { type: 'SINGLE_BLOCK_ANOMALY', severity: current.deltaPct < -10 ? 'critical' : 'high', message: `Single block TVL change: ${current.deltaPct.toFixed(2)}%`, blockNumber: current.blockNumber, tvlDelta: current.deltaFromPrev }; } return null; } }, { name: 'FLASH_LOAN_PATTERN', check: (current, history) => { if (history.length < 2) return null; const prev = history[history.length - 1]; const prevIncrease = prev.deltaPct > 15; const currentDecrease = current.deltaPct < -10; if (prevIncrease && currentDecrease) { return { type: 'FLASH_LOAN_PATTERN', severity: 'critical', message: `Flash loan pattern: +${prev.deltaPct.toFixed(1)}% then -${Math.abs(current.deltaPct).toFixed(1)}%`, blockNumber: current.blockNumber, tvlDelta: current.deltaFromPrev }; } return null; } } ]; Мониторинг крупных транзакций
class LargeTransactionMonitor { private whaleTvlThreshold = 0.01; async monitorWithdrawals(protocolAddress: string, currentTVL: bigint) { const client = createPublicClient({ transport: webSocket(WS_RPC) }); client.watchContractEvent({ address: protocolAddress, abi: PROTOCOL_ABI, eventName: 'Withdraw', onLogs: async (logs) => { for (const log of logs) { const withdrawAmount = log.args.amount as bigint; const usdValue = await getUSDValue(log.args.asset, withdrawAmount); const pctOfTVL = Number(usdValue * 10000n / currentTVL) / 100; if (pctOfTVL > this.whaleTvlThreshold * 100) { await this.alertWhaleWithdrawal({ address: log.args.user, amount: withdrawAmount, usdValue, pctOfTVL, txHash: log.transactionHash, blockNumber: log.blockNumber }); } } } }); } } Пример runbook для инцидента
При срабатывании критического алерта (e.g., rapid drain) дежурный инженер должен проверить дашборд, подтвердить аномалию и, если TVL упал более чем на 20% за 10 блоков, инициировать паузу контракта через multisig. Время реакции — не более 2 минут.Процесс внедрения
- Аудит существующей инфраструктуры — разбираем контракты моста, RPC, текущие логи
- Проектирование архитектуры — определяем пороги, каналы оповещения, дашборды
- Интеграция — подключаем WebSocket, настраиваем парсинг событий, калибруем детекторы
- Тестирование — прогоняем исторические данные, симулируем атаки в тестнете
- Деплой и мониторинг — запускаем в продакшн, передаём документацию и обучение
Чтобы начать, свяжитесь с нами для предварительного аудита. Это займет не более дня и поможет уточнить сроки.
Сроки и состав работы
Ориентировочные сроки — от 14 до 30 дней в зависимости от сложности моста (количество поддерживаемых цепей, кастомные контракты). Стоимость рассчитывается индивидуально после аудита.
Состав работы:
| Компонент | Описание |
|---|---|
| Документация | Архитектура, инструкция по эксплуатации, runbook для инцидентов |
| Код | Репозиторий с системой, конфиги для staging/production |
| Интеграция | Подключение Telegram, PagerDuty, Slack, email |
| Dashboard | Real-time графики TVL, аномалий, истории алертов |
| Обучение | 2 сессии для команды, ответы на вопросы в течение месяца |
| Поддержка | SLA 99.9% uptime, реагирование на критические инциденты 24/7 |
Наши преимущества
Мы не просто ставим готовый инструмент — мы адаптируем систему под конкретные сценарии атак, актуальные для вашего моста. В нашей практике был случай: клиент потерял бы $12 млн, если бы мы не успели остановить контракт за 2 блока до полного drain. Гарантируем SLA, предоставляем код в открытый доступ (private repo) и не используем чёрные ящики.
Закажите консультацию по архитектуре мониторинга — это бесплатно. Свяжитесь с нами для оценки вашего проекта.







