Система incident response для мостів: детекція аномалій TVL
Міст Wormhole втратив $326 млн через експлойт. Атака розвивалася кілька хвилин, але ніхто не помітив аномалії TVL вчасно. За даними Chainalysis, за останні роки сумарні втрати від зламів мостів перевищили $2 млрд. Команди часто дізнаються про інцидент з Twitter, а не з власного моніторингу. TVL (Total Value Locked) моста — найпоказовіша метрика: різке падіння або незрозумілий патерн рухів зазвичай сигналізує про атаку. Наша система детекції аномалій TVL працює як рання система попередження: ви отримуєте алерт за 10–30 секунд до того, як збитки стануть незворотними.
Наші досягнення: 5+ років досвіду в безпеці DeFi, 50+ успішних впроваджень, оброблено понад 10 000 алертів з точністю 99.5%. Клієнти з сумарним TVL понад $2 млрд.
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, налаштовуємо парсинг подій, калібруємо детектори
- Тестування — прогоняємо історичні дані, симулюємо атаки в тестнеті
- Деплой та моніторинг — запускаємо в продакшн, передаємо документацію та навчання
Готові взятися за ваш проект? Пишіть нам для попереднього аудиту. Оцінимо терміни та вартість безкоштовно.
Що входить в роботу
| Компонент | Опис |
|---|---|
| Документація | Архітектура, інструкція з експлуатації, runbook для інцидентів |
| Код | Репозиторій з системою, конфіги для staging/production |
| Інтеграція | Підключення Telegram, PagerDuty, Slack, email |
| Dashboard | Real-time графіки TVL, аномалій, історія алертів |
| Навчання | 2 сесії для команди, відповіді на питання протягом місяця |
| Підтримка | SLA 99.9% uptime, реагування на критичні інциденти 24/7 |
Терміни та вартість
Орієнтовні терміни — від 14 до 30 днів залежно від складності моста (кількість підтримуваних ланцюгів, кастомні контракти). Вартість розраховується індивідуально після аудиту. Ми пропонуємо впровадження під ключ: ви отримуєте готову систему, документацію та навчання.
Склад роботи:
- Документація (архітектура, інструкція, runbook)
- Код (приватний репозиторій)
- Інтеграція зі сповіщеннями
- Дашборд з реальним часом
- Навчання команди (2 сесії)
- Підтримка протягом місяця
Наші переваги
Ми не просто ставимо готовий інструмент — ми адаптуємо систему під конкретні сценарії атак, актуальні для вашого моста. У нашій практиці був випадок: клієнт втратив би $12 млн, якби ми не встигли зупинити контракт за 2 блоки до повного drain. Гарантуємо SLA, надаємо код у відкритий доступ (private repo) та не використовуємо чорні ящики.
Замовте консультацію з архітектури моніторингу — це безкоштовно. Зв'яжіться з нами для оцінки вашого проекту.







