Розробка системи real-time детекції експлойтів смарт-контрактів
Euler Finance взлом в березні 2023 — $197M за кілька транзакцій. BNB Bridge взлом — $570M за одну транзакцію. В обох випадках протоколи мали достатньо часу (кілька блоків, іноді кілька транзакцій) щоб помітити аномалію та зупинити наступну транзакцію. Але автоматичної системи детекції не було.
Real-time моніторинг смарт-контрактів — система, яка аналізує кожну транзакцію до або під час її включення в блок, і може ініціювати захисну реакцію (пауза контракту, whitelist enforcement, alert) швидше ніж атака завершиться.
Існують три часові вікна для детекції: mempool (транзакція відправлена, не включена — найранніше, але тільки pending txs), block execution (транзакція включена в блок, але блок ще не finalized — не застосовується для ланцюгів з instant finality), post-block (блок finalized — занадто пізно для превентивної дії, тільки для alert та post-mortem).
Архітектура системи моніторингу
Mempool-рівень детекція
Найранніший момент детекції — mempool. Транзакція відправлена атакуючим, але ще не включена в блок. Для класичних атак (не MEV-bundle через private mempool) це дає 1-12 секунд на Ethereum (час до наступного блоку).
Private mempool обмеження. Більшість MEV-атак на DeFi сьогодні йдуть через private mempool (Flashbots, MEV Blocker, тощо) — транзакції напрямо валідатору, не в публічний mempool. Mempool-моніторинг не видить такі транзакції до включення в блок. Це обмеження системи.
Але багато protocol-level атак (особливо multi-step: спочатку borrow, потім dump, потім drain) проходять через публічний mempool хоча б частково.
Блокуючий виклик через власний node:
// Підписка на pending транзакції через WebSocket
const provider = new ethers.WebSocketProvider(ALCHEMY_WS_URL);
provider.on("pending", async (txHash) => {
try {
const tx = await provider.getTransaction(txHash);
if (!tx || !tx.to) return;
// Перевіряємо тільки транзакції до наших контрактів
if (!MONITORED_CONTRACTS.has(tx.to.toLowerCase())) return;
const risk = await analyzeTransaction(tx);
if (risk.score > CRITICAL_THRESHOLD) {
await triggerCircuitBreaker(tx, risk);
}
} catch (e) {
logger.error("Mempool analysis error", e);
}
});
Ethereum Mempool API (Blocknative, Bloxroute) надають більш надійний доступ до mempool з фільтрацією за адресою. Коштує грошей, але набагато надійніше ніж self-hosted нода.
Transaction simulation
Перед прийняттям рішення про ризик потрібно зрозуміти, що робить транзакція — не тільки її calldata. eth_call з поточним state дозволяє симулювати виконання без відправки в мережу:
async function simulateTransaction(tx: TransactionRequest): Promise<SimulationResult> {
// Tenderly API для детального trace зі змінами state
const simulation = await tenderly.simulate({
network_id: "1",
from: tx.from,
to: tx.to,
input: tx.data,
value: tx.value?.toString() ?? "0",
save: false,
});
return {
success: simulation.transaction.status,
gasUsed: simulation.transaction.gas_used,
stateChanges: simulation.transaction.transaction_info.state_diff,
events: simulation.transaction.transaction_info.logs,
balanceChanges: extractBalanceChanges(simulation),
};
}
Tenderly, Alchemy Simulate, Blocknative надають simulation API. Ключова розумінність: симуляція показує всі state changes до виконання. Якщо симуляція показує, що баланс протоколу впаде >10% за одну транзакцію — це аномалія.
Invariant перевірка
Після симуляції перевіряємо набір інваріантів протоколу:
interface ProtocolInvariant {
name: string;
check: (stateBefore: ProtocolState, stateAfter: ProtocolState) => boolean;
severity: "critical" | "high" | "medium";
}
const INVARIANTS: ProtocolInvariant[] = [
{
name: "TVL_DROP_THRESHOLD",
check: (before, after) => {
const tvlChange = (after.tvl - before.tvl) / before.tvl;
return tvlChange > -0.10; // не більше 10% падіння за одну транзакцію
},
severity: "critical",
},
{
name: "PRICE_IMPACT_LIMIT",
check: (before, after) => {
if (!after.lastSwap) return true;
return Math.abs(after.lastSwap.priceImpact) < 0.20; // < 20%
},
severity: "high",
},
{
name: "BORROW_UTILIZATION",
check: (before, after) => {
return after.borrowUtilization < 0.95; // < 95%
},
severity: "high",
},
{
name: "FLASH_LOAN_IN_PROGRESS",
check: (before, after) => {
// Flash loan сам по собі не експлойт, але в комбінації з іншими ознаками
return !after.hasActiveFlashLoan || after.flashLoanRepaid;
},
severity: "medium",
},
];
Circuit breaker інтеграція
Виявити атаку недостатньо — потрібен механізм зупинки. Варіанти:
Pause Guardian. Спеціальна адреса (multisig або automated guardian контракт) з правом викликати pause() на протоколі. Мониторингова система може мати привілейований ключ для викликання pause. Ризик: compromise цього ключа = DoS протоколу. Мітигація: pause guardian може тільки pauseне unpause (unpause вимагає Governor + Timelock).
On-chain circuit breaker. Контракт з логікою для автоматичної паузи при порушенні інваріантів:
contract CircuitBreaker {
uint256 public constant MAX_TVL_DROP_BPS = 1000; // 10%
uint256 public lastTVL;
bool public paused;
modifier checkCircuit() {
_;
uint256 currentTVL = getTVL();
if (lastTVL > 0) {
uint256 dropBps = (lastTVL - currentTVL) * 10000 / lastTVL;
if (dropBps > MAX_TVL_DROP_BPS) {
paused = true;
emit CircuitBreakerTriggered(lastTVL, currentTVL, dropBps);
}
}
lastTVL = currentTVL;
}
function deposit(uint256 amount) external checkCircuit {
require(!paused, "Circuit breaker active");
// ... логіка депозиту
}
}
On-chain circuit breaker не вимагає off-chain інфраструктури, але додає gas overhead до кожної транзакції та збільшує attack surface (можна маніпулювати getTVL() щоб штучно спричинити circuit breaker?).
Defender Relayer (OpenZeppelin Defender). Defender дозволяє налаштовувати автоматичні дії: при детекції аномальної подій — Relayer викликає pause() від привілейованої адреси. Defender зберігає приватний ключ в HSM, автоматизація налаштовується через UI або код.
ML-детекція аномалій
Rule-based інварианти ловлять відомі паттерни. ML підходить для виявлення невідомих аномалій.
Feature engineering для on-chain транзакцій
Ознаки для класифікації транзакцій:
| Ознака | Опис | Важливість |
|---|---|---|
gas_used / gas_limit |
Високе використання газу — складна транзакція | Висока |
value_transferred / pool_tvl |
Обсяг відносно ліквідності пулу | Критична |
call_depth |
Глибина вкладених викликів | Висока |
unique_contracts_touched |
Скільки контрактів викликано | Висока |
flash_loan_amount |
Flash loan флаг та обсяг | Висока |
time_since_last_tx |
Аномально швидкі послідовні транзакції | Середня |
sender_age |
Новий адрес — вища підозрілість | Середня |
token_price_delta |
Зміна ціни токена під час транзакції | Висока |
Моделі детекції аномалій
Isolation Forest — добре працює для multivariate anomaly detection без labeled attack data. Навчається на нормальних транзакціях, флагує outliers.
LSTM Autoencoder — для sequence аномалій: серія транзакцій, які в цілому аномальні. Важливо для multi-step атак (кілька транзакцій становлять атаку).
Gradient Boosting (XGBoost/LightGBM) — якщо існує labeled attack data (відомі історичні експлойти). Вимагає balance класів (атаки рідкісні), SMOTE для oversampling.
Дані для навчання: Forta Network, Dune Analytics, DeBank мають історичні дані транзакцій. Відомі exploit транзакції (Euler, Ronin, BNB Bridge) — negative клас. Нормальна торгівля — positive клас.
Latency обмеження. ML inference повинна умістити в ~200ms для mempool детекції. Прості моделі (Isolation Forest, логістична регресія) — ок. LSTM на CPU — ~50-100ms для inference. Якщо швидше потрібно — GPU inference або quantized моделі (ONNX runtime).
Alert інфраструктура інтеграція
Alert маршрутизація
Виявлена аномалія повинна дійти до правильної людини швидко. Stack:
- PagerDuty / OpsGenie — для critical alerts (потенційна атака). Телефонний дзвінок на on-call duty officer о 3 ночі.
- Telegram / Discord bot — для high/medium alerts. Канал мониторингового bot.
- Grafana dashboard — real-time метрики: TVL, transaction volume, price impact, circuit breaker status.
async function routeAlert(alert: Alert) {
if (alert.severity === "critical") {
await pagerduty.triggerIncident({
title: `CRITICAL: ${alert.name} detected`,
body: formatAlertBody(alert),
severity: "critical",
});
// Автоматично ініціювати pause якщо confidence > 0.9
if (alert.confidence > 0.9 && alert.autoActionEnabled) {
await pauseGuardian.pause(alert.transactionHash);
}
}
// Завжди відправити в Discord для аудиту
await discord.send(ALERTS_CHANNEL, formatDiscordAlert(alert));
// Метрики в Prometheus
metrics.increment("alerts_total", { severity: alert.severity, type: alert.name });
}
Forta Network інтеграція
Forta — децентралізована мониторингова мережа. Розробники розгортають detection bots (Node.js або Python), які отримують кожну транзакцію та генерують alerts. Bot-runner nodes виконують bots та публікують alerts on-chain.
Перевага: не потрібна власна node інфраструктура. Недолік: latency (post-block), немає mempool мониторингу, latency залежить від Forta інфраструктури.
Для кастомного протоколу: Forta bot як додатковий шар поверх власного мониторингу — redundancy важлива.
Production інфраструктура
Node інфраструктура
Для mempool мониторингу потрібне надійне WebSocket підключення до Ethereum node. Self-hosted archive нода (Geth, Reth) на bare metal дає найменшу latency, але вимагає 2+ TB SSD та maintenance. Managed: Alchemy, QuickNode — надійні, але WebSocket може throttle під високим навантаженням.
Для production: dual-provider setup. Primary (наприклад, Alchemy) + fallback (QuickNode). Автоматичне переключення при degraded connection.
Масштабованість
При мониторингу 10+ протоколів на кількох ланцюгах:
- Горизонтальне масштабування: окремий worker per chain
- Message queue (Kafka, RabbitMQ) між detector та action layers
- State management: Redis для кешування protocol state (TVL, prices) — уникнути повторних RPC запитів
| Компонент | Технологія |
|---|---|
| Mempool моніторинг | Node.js + ethers.js v6 + WS provider |
| Transaction simulation | Tenderly API / Alchemy Simulate |
| ML inference | Python FastAPI + ONNX runtime |
| Alert маршрутизація | PagerDuty + Telegram bot |
| Dashboard | Grafana + Prometheus |
| Pause автоматизація | OpenZeppelin Defender |
| Redundancy | Forta Network bots |
Timeline розробки
MVP (rule-based детекція + alerts + manual pause): 4-6 тижнів.
Повна система (ML детекція + automated circuit breaker + Forta інтеграція + dashboard): 3-5 місяців.
Важливо: мониторингова система сама вимагає security review. Compromise automated pause guardian може використовуватись для DoS атаки на протокол — заблокувати протокол у критичний момент. Захист: rate limiting на pause calls, multisig для unpause, transparency log всіх automated дій.







