Парсинг данных NFT-коллекций (floor price, volume, holders)
OpenSea API возвращает floor price с задержкой 5-15 минут и агрегирует данные по своей методологии. Для торговых ботов, аналитических платформ и minting dApps, которым нужен реальный floor — это неприемлемо. Мы разрабатываем парсеры, которые читают события прямо из блокчейна, обеспечивая точность до секунды. Это единственный способ получить актуальный floor без задержек.
Наш опыт — 5+ лет в блокчейн-разработке и десятки проектов по парсингу NFT-данных. Мы знаем все тонкости: реорганизации цепочек, rate limits валидаторов, wash trading и как их обрабатывать. Гарантируем стабильную работу парсера даже на высоконагруженных коллекциях.
В этой статье разберём полную архитектуру парсера NFT-данных: выбор стека, индексирование событий, вычисление floor price, хранение в ClickHouse и типовые проблемы. Также покажем, что входит в наше решение под ключ.
Источники данных: что откуда брать
On-chain события
Для ERC-721/ERC-1155 коллекций все продажи видны через события маркетплейсов. Каждый маркетплейс эмитирует собственное событие:
- OpenSea Seaport:
OrderFulfilled(...)— контракт0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC - Blur:
TakerAsk/TakerBidна0x000000000000Ad05Ccc4F10045630fb830B95127 - LooksRare v2:
TakerAsk/TakerBid - X2Y2:
EvInventory
Floor price нельзя получить из событий напрямую — события показывают исполненные ордера, а не активные листинги. Для актуального floor нужно либо индексировать active listings через маркетплейс API, либо использовать агрегаторы.
Holders и transfers
Transfer(address indexed from, address indexed to, uint256 indexed tokenId) — стандарт ERC-721. Полный граф владения строится через replay всех Transfer событий от блока деплоя. Unique holders = уникальные адреса to за вычетом адресов, которые затем перевели токены на другой адрес.
Для ERC-1155: TransferSingle и TransferBatch. Здесь владение — это баланс, не бинарное состояние: balanceOf(address, tokenId).
Как мы вычисляем floor price?
Два подхода:
1. Маркетплейс API агрегация — запрашиваем floor у OpenSea, Blur, LooksRare, берём минимум. Проблема: rate limits и кэширование на стороне API. Мы используем кэш на 60 секунд и fallback при превышении лимитов.
2. Orderbook индексирование — подписываемся на события создания/отмены ордеров. Seaport: OrderValidated (создание), OrderCancelled, OrderFulfilled (исполнение). Строим локальный orderbook, вычисляем floor самостоятельно. Точнее, но сложнее в поддержке при обновлениях контрактов маркетплейса. Мы рекомендуем первый подход для большинства проектов, второй — для торговых ботов с субсекундным откликом.
| Метод | Точность | Сложность | Задержка |
|---|---|---|---|
| API агрегация | Средняя | Низкая | ~60 сек |
| Orderbook | Высокая | Средняя | <5 сек |
Архитектура парсера
Стек
ethereum-node (Alchemy/Infura/Quicknode) → ethers.js / viem (event filtering) → message queue (Redis Streams / BullMQ) → PostgreSQL / ClickHouse (storage) → REST/WebSocket API (выдача данных) Для исторических данных — getLogs с фильтром по address и topics[0]. Блоки батчим по 2000 (ограничение большинства RPC провайдеров на eth_getLogs):
async function fetchTransferEvents( contract: string, fromBlock: number, toBlock: number, provider: JsonRpcProvider ) { const iface = new Interface(['event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)']); const filter = { address: contract, topics: [iface.getEventTopic('Transfer')], fromBlock, toBlock, }; const logs = await provider.getLogs(filter); return logs.map(log => iface.parseLog(log)); } Для real-time: WebSocket подписка через provider.on(filter, callback) или Alchemy eth_subscribe newLogs.
Хранение и запросы
ClickHouse эффективнее PostgreSQL для time-series NFT данных — аналитические запросы на миллионах строк в 10-50x быстрее. Схема:
| Колонка | Тип | Описание |
|---|---|---|
block_number |
UInt64 | Блок события |
tx_hash |
FixedString(66) | Хэш транзакции |
contract |
FixedString(42) | Адрес коллекции |
token_id |
UInt256 | ID токена |
from |
FixedString(42) | Продавец/отправитель |
to |
FixedString(42) | Покупатель/получатель |
price_wei |
UInt256 | Цена в wei |
marketplace |
LowCardinality(String) | Маркетплейс |
timestamp |
DateTime | Время блока |
Партиционирование по месяцам (toYYYYMM(timestamp)), сортировочный ключ (contract, timestamp).
Почему on-chain данные точнее OpenSea API?
OpenSea API использует собственный пул ордеров и кэширует floor price с задержкой до 15 минут. Это критично для арбитражных ботов и аналитики в реальном времени. On-chain данные — единственный источник истины. Мы гарантируем точность до последнего подтверждённого блока (финализация за 2 эпохи — 64 блока на Ethereum PoS).
Решение типовых проблем
Rate limits
Alchemy Free — 330 CUPS, Growth — 660 CUPS. При историческом парсинге крупной коллекции (BAYC: 500k+ Transfer событий) без throttling получим 429. Реализуем exponential backoff + queue с concurrency control.
Как избежать rate limits при историческом парсинге?
Используйте exponential backoff и несколько RPC эндпоинтов. Мы настраиваем очередь с максимум 5 параллельных запросов и таймаутом 30 секунд.Реорганизации блокчейна
События из последних 12 блоков нужно помечать как «pending» и подтверждать только после finality. Для Ethereum PoS — 2 эпохи (64 блока) для экономического finality.
Wash trading
Объём по адресам с циклическими переводами искажает статистику. Базовая эвристика: сделки где from и to — связанные адреса (получали ETH из одного источника) помечаются флагом.
Что входит в работу
- Архитектура парсера под вашу задачу
- Код на TypeScript с использованием ethers.js/viem
- Настройка ClickHouse для хранения и аналитики
- Дашборд в Grafana с ключевыми метриками (floor price, volume, holders)
- REST/WebSocket API для интеграции с вашим приложением
- Полная документация и обучение команды
- Поддержка после запуска
Мы предоставляем решение под ключ. Оценим ваш проект за 1 день.
Ориентиры по срокам
Парсер Transfer событий + holders tracker — 1 день. Добавление floor price через маркетплейс API + кэш — ещё полдня. Исторический бэкфилл для крупной коллекции + дашборд — 2-3 дня суммарно.
Свяжитесь с нами, чтобы получить консультацию и точную оценку для вашего проекта.







