TractionEye: индексатор стоимости кошельков в TON
Индексатор, который по запросу восстанавливает историю стоимости любого кошелька TON — от нативных монет до жетонов и LP-позиций на DEX.
- Область
- Финтех, блокчейн TON
- Наша роль
- Архитектура, бэкенд, обработка данных, DevOps, нагрузочное тестирование
- Год
- 2024
TractionEye — Telegram Mini App, которое показывает, как менялась стоимость кошелька в сети TON: график и список активов с ценами и суммой в USD. Мы спроектировали и написали бэкенд: набор микросервисов на Python, которые по первому запросу восстанавливают полную историю балансов из публичных данных блокчейна, оценивают каждый актив, включая LP-токены DEX, и хранят временные ряды в TimescaleDB на PostgreSQL 16.
Задача
- Публичные API отдают текущее состояние и сырые транзакции, а не историю баланса. Её нужно было получить для TON и для каждого жетона, который когда-либо был в кошельке.
- Для графиков за день и за месяц нужна история цен каждого токена в USD с достаточно мелким шагом.
- У LP-токенов DEX нет рыночной цены: её приходится выводить из резервов пула и общего предложения на каждый момент времени.
- Пользователь может открыть любой кошелёк, поэтому индексация должна стартовать с первого запроса и укладываться в секунды или минуты, а не часы.
- Все данные идут от публичных провайдеров TON с жёсткими лимитами RPS на ключ, и эти лимиты делят между собой параллельные воркеры.
Решение
Мы собрали конвейер из независимых сервисов с одной задачей у каждого вокруг общей базы временных рядов. Индексатор кошельков листает транзакции по логическому времени и проигрывает их в обратном порядке от текущего баланса — для TON и для каждого жетон-кошелька. Индексатор цен находит новые токены и подгружает до двух лет истории цен в USD с адаптивным шагом, а потом дополняет ряд инкрементально. Индексатор пулов находит пулы DeDust и STON.fi и считает цены LP-токенов по резервам и предложению из архивного состояния сети. API запросов соединяет балансы с ценами по временным интервалам и отдаёт мини-приложению готовый ряд стоимости. Перед всем этим стоит шлюз на OpenResty с TLS и автоматическим продлением сертификатов. Кошелёк регистрируется при первом запросе и сразу попадает к воркерам; дальше его история за каждый проход углубляется на месяц, а свежие операции подтягиваются каждые несколько минут.
Архитектура
Что умеет система
- Стоимость кошелька во времени
- График стоимости любого кошелька TON за период и с шагом, которые запрашивает клиент.
- Разбивка по активам
- Баланс, текущая цена и стоимость в USD для TON, жетонов и LP-токенов, плюс отдельный эндпоинт истории по каждому токену для детальных графиков.
- Подключение по запросу
- Первый запрос по кошельку запускает его индексацию — без ручной настройки.
- Постоянное обновление
- Свежие операции подхватываются каждые несколько минут, а история в фоне уходит всё глубже.
- Оценка LP-позиций
- Цены LP-токенов пулов DeDust и STON.fi, включая обработку переводов фарминга на DEX.
- Документация и отладка
- Документация OpenAPI (Swagger) и HTML-страницы, на которых рассчитанные ряды можно проверить глазами.
Инженерные решения
- Точный баланс без своей ноды: индексатор идёт от текущего баланса назад по каждой транзакции, вычитая суммы и комиссии, и получает точный баланс после каждого события. Для жетонов направление и сумма перевода декодируются из опкодов сообщений.
- Очередь задач в самой базе: воркер атомарно забирает задачу одним запросом «выбрать, заблокировать, вернуть». Параллельно работают несколько процессов без внешнего брокера, а каждый шаг — одна транзакция, так что при сбое теряется максимум одна единица работы.
- Клиенты API с учётом лимитов: каждый ключ провайдера обёрнут в token bucket не больше чем на N запросов в секунду, а неудачные вызовы повторяются ограниченное число раз.
- Временные ряды в TimescaleDB: агрегация через time_bucket и перенос последнего известного баланса в начало окна превращают редкие транзакции в равномерные точки графика.
- Нагрузочное тестирование: распределённые воркеры Locust на Docker Swarm и отдельный бенчмарк времени до первого графика. В этих тестах медиана первой синхронизации составила около 13 секунд для самых маленьких кошельков и около 2 минут для самых активных.
Схемы
Стек
- Python 3.12
- Flask
- uWSGI
- SQLAlchemy 2
- PostgreSQL 16
- TimescaleDB
- OpenResty
- Lua
- Docker Compose
- Ansible Vault
- Locust
- pytoniq
- Telegram Mini Apps
Что это показывает
- Индексаторы, которые превращают сырые транзакции блокчейна в готовые для аналитики временные ряды
- Оценка DeFi-активов, включая позиции в пулах ликвидности, по состоянию сети
- Микросервисы, которые координируются через базу данных без брокера сообщений и работают в пределах лимитов сторонних API
- Поставка в прод: контейнеры, автоматический TLS, зашифрованная конфигурация и повторяемый деплой в несколько окружений
Вопросы по кейсу
Нужна ли своя нода TON, чтобы получить историю балансов?
Нет. Индексатор берёт данные у публичных провайдеров TON и восстанавливает историю, проигрывая транзакции назад от текущего баланса. Для цен LP-токенов состояние пулов на нужной высоте блока читается из архивного эндпоинта.
Как быстро появляется график для нового кошелька?
Индексация начинается с первого запроса. В нагрузочных тестах медиана первой синхронизации — от примерно 13 секунд для небольших кошельков до примерно 2 минут для самых активных. Дальше история углубляется в фоне.
Подойдёт ли этот подход для других задач?
Да. Та же схема работает для трекеров портфеля, отчётов по PnL и налогам, аналитики кошельков и казначейских дашбордов — на TON и на других блокчейнах с моделью аккаунтов.