Моніторинг on-chain метрик проекту

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

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

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

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

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

Мониторинг on-chain метрик проекту

Ваш смарт-контракт задейплоен. Що з ним відбувається в реальному часі — знає ли команда? Скільки унікальних користувачів взаємодіяло за останні 24 години? Не аномально ли виріс об'єм транзакцій прямо зараз? Немає ли паттернів що указують на спробу експлойту? On-chain мониторинг відповідає на ці запитання до появи проблеми, а не після.

Що мониторити та зачем

Розділю метрики на три категорії за призначенням:

Операційні — для DevOps та команди:

  • Частота викликів ключових функцій контракту
  • Gas consumption по методам (аномальний ріст = дорогі операції або атака)
  • Кількість failed транзакцій (ріст failed/total ratio = можлива атака або баг)
  • TVL (Total Value Locked) якщо контракт тримає активи

Бізнес — для продукту:

  • DAU/MAU on-chain (унікальні адреси за період)
  • Retention — адреси що повернулись через N днів
  • Об'єм в USD через конкретні функції
  • Топ-N адрес по активності (whale мониторинг)

Безпека — для Security команди:

  • Крупні виводи (> threshold) за короткий період
  • Необичні паттерни викликів (flash loan + контракт в одному блоці)
  • Зміни в ownership/admin ролі
  • Виклики з нових адрес з великим балансом

Джерела даних

Event logs — основний источник. Добре спроектований контракт емітирує подію для кожної значимої дії. Якщо подій немає — додайте їх (якщо контракт обновляємий) або використовуйте trace calls.

Trace calls — внутрішні виклики між контрактами. Потрібен debug_traceTransaction або trace_transaction. Використовується для відслідження руху засобів через кілька контрактів в одній транзакції.

Storage slots — пряме читання стану контракту. eth_getStorageAt(address, slot, blockNumber). Корисно для метрик які не емітуються в события: поточний TVL, розміри пулів.

Dune Analytics / Flipside — SQL запити до проіндексованих блокчейн даних. Швидкий старт для аналітики, але vendor lock-in та задержка даних (не реалтайм).

Архітектура мониторингу

                  ┌─────────────────┐
                  │  Blockchain RPC  │
                  │  (Alchemy/own)   │
                  └────────┬────────┘
                           │ eth_getLogs / WebSocket
              ┌────────────▼──────────────┐
              │      Event Collector       │
              │  (підписка на контракт)    │
              └────────────┬──────────────┘
                           │
              ┌────────────▼──────────────┐
              │    Metrics Processor       │
              │  Декодування ABI,          │
              │  агрегація, enrichment     │
              └──────┬────────────┬────────┘
                     │            │
        ┌────────────▼──┐  ┌──────▼──────────────┐
        │  TimescaleDB  │  │  Prometheus/VictoriaDB│
        │  (історія)    │  │  (реалтайм метрики)   │
        └───────────────┘  └──────────────────────┘
                                     │
                           ┌─────────▼──────────┐
                           │   Grafana Dashboard │
                           │   + Alertmanager    │
                           └────────────────────┘

Реалізація event collector

import { createPublicClient, webSocket, parseAbiItem, decodeEventLog } from 'viem';
import { mainnet } from 'viem/chains';

const client = createPublicClient({
  chain: mainnet,
  transport: webSocket('wss://eth-mainnet.g.alchemy.com/v2/YOUR_KEY'),
});

const CONTRACT_ABI = [
  parseAbiItem('event Deposit(address indexed user, uint256 amount)'),
  parseAbiItem('event Withdraw(address indexed user, uint256 amount)'),
  parseAbiItem('event Swap(address indexed user, address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOut)'),
];

// WebSocket підписка на события контракту
const unwatch = client.watchContractEvent({
  address: CONTRACT_ADDRESS,
  abi: CONTRACT_ABI,
  onLogs: async (logs) => {
    for (const log of logs) {
      await processEvent(log);
    }
  },
  onError: (error) => {
    console.error('WS error, reconnecting...', error);
    // viem автоматично переподключається
  },
});

async function processEvent(log: any) {
  const decoded = decodeEventLog({ abi: CONTRACT_ABI, ...log });
  
  // Запис в TimescaleDB
  await db.query(`
    INSERT INTO contract_events 
      (time, block_number, tx_hash, event_name, user_address, amount_usd)
    VALUES (NOW(), $1, $2, $3, $4, $5)
  `, [log.blockNumber, log.transactionHash, decoded.eventName, 
      decoded.args.user, await convertToUSD(decoded.args.amount)]);
  
  // Інкремент Prometheus счітчика
  eventCounter.labels(decoded.eventName).inc();
}

Prometheus метрики та алерти

import { Counter, Gauge, Histogram, Registry } from 'prom-client';

const registry = new Registry();

const eventCounter = new Counter({
  name: 'contract_events_total',
  help: 'Total contract events by type',
  labelNames: ['event_name'],
  registers: [registry],
});

const tvlGauge = new Gauge({
  name: 'contract_tvl_usd',
  help: 'Total Value Locked in USD',
  registers: [registry],
});

const largeWithdrawalCounter = new Counter({
  name: 'contract_large_withdrawals_total',
  help: 'Withdrawals above threshold',
  labelNames: ['threshold_category'],
  registers: [registry],
});

// HTTP endpoint для Prometheus scraping
app.get('/metrics', async (req, res) => {
  res.set('Content-Type', registry.contentType);
  res.send(await registry.metrics());
});

Правила Alertmanager:

groups:
  - name: contract_security
    rules:
      # Крупний вивід — немедленний алерт
      - alert: LargeWithdrawal
        expr: rate(contract_large_withdrawals_total[5m]) > 0
        for: 0m
        labels:
          severity: critical
        annotations:
          summary: "Large withdrawal detected from contract"

      # Аномальний ріст failed транзакцій
      - alert: HighFailureRate
        expr: |
          rate(contract_failed_txns_total[10m]) / 
          rate(contract_total_txns_total[10m]) > 0.1
        for: 5m
        annotations:
          summary: "More than 10% of transactions failing"

      # TVL падає швидко
      - alert: TVLDrop
        expr: |
          (contract_tvl_usd - contract_tvl_usd offset 1h) / 
          contract_tvl_usd offset 1h < -0.2
        for: 2m
        annotations:
          summary: "TVL dropped by more than 20% in 1 hour"

Whale та аномалія детектор

import asyncio
from web3 import AsyncWeb3

WHALE_THRESHOLD_USD = 100_000

async def monitor_large_transactions(contract, event_name: str):
    async for event in contract.events[event_name].get_logs(fromBlock='latest'):
        amount_usd = await get_usd_value(event.args.amount, event.args.token)
        
        if amount_usd > WHALE_THRESHOLD_USD:
            await send_telegram_alert(
                f"🐋 Whale {event_name}: ${amount_usd:,.0f}\n"
                f"Address: {event.args.user}\n"
                f"Tx: https://etherscan.io/tx/{event.transactionHash.hex()}"
            )
            
        # Перевірка flash loan паттерну: deposit + withdraw в одному блоці
        if await is_flash_loan_pattern(event):
            await send_telegram_alert(
                f"⚠️ Flash loan pattern detected in block {event.blockNumber}",
                level='WARNING'
            )

Grafana дашборд

Ключові панелі для DeFi протоколу:

Overview: TVL (gauge + time series), 24h Volume, DAU, Total Users (cumulative)

Activity: Events per minute (time series, розбивка по типу), Gas used per block, Failed tx ratio

Security: Large transactions (таблиця з останніми whale транзакціями), New whale addresses (адреси з першою транзакцією в контракті + крупна сума), Flash loan detection события

Economics: Fee revenue over time, Token price кореляція з активністю

Дашборд у JSON — версіонується в git разом з кодом контракту.

Історичні дані та ретроспективний аналіз

Реалтайм мониторинг ловить аномалії зараз. Для ретроспективного аналізу потрібна історія:

-- Щоденні активні користувачи
SELECT 
    date_trunc('day', time) AS day,
    COUNT(DISTINCT user_address) AS dau,
    SUM(amount_usd) AS volume_usd
FROM contract_events
WHERE event_name IN ('Deposit', 'Swap')
GROUP BY 1
ORDER BY 1 DESC;

-- Retention: користувачі що повернулись через 7 днів
WITH first_use AS (
    SELECT user_address, MIN(time) AS first_time
    FROM contract_events GROUP BY 1
),
return_use AS (
    SELECT DISTINCT e.user_address
    FROM contract_events e
    JOIN first_use f ON e.user_address = f.user_address
    WHERE e.time > f.first_time + INTERVAL '7 days'
      AND e.time < f.first_time + INTERVAL '14 days'
)
SELECT 
    COUNT(r.user_address)::float / COUNT(f.user_address) AS week1_retention
FROM first_use f
LEFT JOIN return_use r ON f.user_address = r.user_address;

Процес розгортування

День 1: настройка event collector, підключення до RPC, запис сирих событій в TimescaleDB. Тест на кількох блоках з реальними транзакціями.

День 2: Prometheus метрики, перший Grafana дашборд, настройка базових алертів (TVL drop, high failure rate).

День 3: whale детектор, security алерти, тестування алертів через симуляцію транзакцій, runbook для команди.

Усього 1-3 дні залежно від складності контракту та кількості мониторюваних метрик.