Реализация ценовой истории NFT в мобильном приложении
NFT-коллекция выглядит как набор JPEG, пока не видишь, как её floor price вырастал с 0.05 до 12 ETH за три недели. Именно ценовая история превращает трекер NFT из статичного каталога в аналитический инструмент.
Откуда берётся история цен
Блокчейн сам по себе не хранит «историю цен» как сущность. Продажа NFT — это Transfer-событие в смарт-контракте ERC-721 плюс движение ETH между адресами в той же транзакции. Чтобы построить price history, нужно агрегировать on-chain события. Самостоятельно парсить Ethereum — дорого. Поэтому используют специализированные API:
OpenSea API v2 (/api/v2/events/collection/{slug}) возвращает события типа sale с ценой в wei и timestamp. Ограничение — 4 запроса в секунду на бесплатном ключе. Для исторических данных глубже 30 дней нужен платный план.
Reservoir API (/sales/v6) — более щедрый по глубине истории и rate limit. Поддерживает несколько маркетплейсов одновременно (OpenSea, Blur, X2Y2). Пагинация через continuation токен.
Alchemy NFT API (/getNFTSales) — удобен, если уже используете Alchemy для других on-chain запросов.
На Flutter типичный репозиторий выглядит так:
class NftSalesRepository {
final Dio _dio;
final String _reservoirKey;
Future<List<NftSale>> getSalesHistory({
required String contractAddress,
required String tokenId,
DateTime? from,
}) async {
final params = {
'tokens': '$contractAddress:$tokenId',
'startTimestamp': from?.millisecondsSinceEpoch ~/ 1000,
'limit': 100,
};
final resp = await _dio.get(
'https://api.reservoir.tools/sales/v6',
queryParameters: params,
options: Options(headers: {'x-api-key': _reservoirKey}),
);
return (resp.data['sales'] as List)
.map((e) => NftSale.fromJson(e))
.toList();
}
}
Цена приходит в ETH (или другой нативной валюте сети), но пользователи ожидают видеть USD. Курс ETH/USD нужно подтягивать отдельно — через CoinGecko API или Alchemy Price API, кэшировать с TTL 60 секунд и применять к историческим точкам постфактум.
Визуализация
Для отрисовки графика на Flutter хорошо работает fl_chart. Данные продаж нужно нормализовать перед рендером: убрать очевидные wash-trade выбросы (продажа между связанными кошельками по нерыночной цене), агрегировать по дням или неделям в зависимости от глубины истории.
На React Native — Victory Native XL (работает на Reanimated 3, без перерисовки через bridge) или react-native-gifted-charts.
LineChart(
LineChartData(
lineBarsData: [
LineChartBarData(
spots: sales.map((s) => FlSpot(
s.timestamp.toDouble(),
s.priceUsd,
)).toList(),
isCurved: true,
gradient: LinearGradient(colors: [Colors.purple, Colors.blue]),
belowBarData: BarAreaData(show: true, color: Colors.purple.withOpacity(0.1)),
),
],
titlesData: FlTitlesData(
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
getTitlesWidget: (value, meta) => _formatDate(value),
),
),
),
),
)
Что входит в работу
- Интеграция Reservoir API или OpenSea API с пагинацией
- Модели данных:
NftSale,PricePointс конвертацией wei → ETH → USD - Кэширование в SQLite (drift/floor) с TTL
- График с выбором временного диапазона (7d / 30d / All)
- Обработка пустой истории и ошибок сети
Сроки
Реализация от 2 до 4 рабочих дней в зависимости от платформы и сложности дизайна графика. Стоимость рассчитывается индивидуально после анализа требований.







