TractionEye: net-worth indexer for TON wallets
An indexer that rebuilds any TON wallet's net-worth history on demand, from native coins to jettons and DEX LP positions.
- Domain
- Fintech, TON blockchain
- Our role
- Architecture, backend, data engineering, DevOps, load testing
- Year
- 2024
TractionEye is a Telegram Mini App that shows how a TON wallet's net worth changes over time, with a chart and a list of assets, prices and USD values. We designed and built its backend: Python indexing microservices that rebuild a wallet's full balance history on the first request from public blockchain data, price every asset including DEX liquidity-pool tokens, and serve chart-ready time series from TimescaleDB on PostgreSQL 16.
Challenge
- Public APIs return current state and raw transactions, not balance history. We needed that history for TON and for every jetton a wallet ever held.
- Charts for one day and one month need historical USD prices for each token at a fine enough resolution.
- DEX LP tokens have no market price. Their value has to be derived from pool reserves and total supply at each point in time.
- Any user can open any wallet, so indexing has to start on the first request and finish in seconds to minutes, not hours.
- All data comes from public TON providers with per-key RPS caps, shared by several workers running in parallel.
Solution
We built a pipeline of independent, single-purpose services around a shared time-series database. The wallet indexer pages through transactions by logical time and replays them backwards from the current balance, for TON and for each jetton wallet. The price indexer detects new tokens, backfills up to two years of USD prices with an adaptive step and then keeps the series current. The pool indexer discovers DeDust and STON.fi pools and prices their LP tokens from reserves and supply read from archived chain state. The query API joins balances with prices in time buckets and returns a ready net-worth series to the mini app. An OpenResty gateway handles TLS with automatic certificate renewal. The first API request registers a wallet and the workers pick it up right away; after that its history grows one month deeper per pass, and recent activity is refreshed every few minutes.
Architecture
What the system does
- Net worth over time
- A net-worth series for any TON wallet, at the period and resolution the client asks for.
- Per-asset breakdown
- Balance, current price and USD value for TON, jettons and LP tokens, plus a per-token history endpoint for drill-down charts.
- On-demand onboarding
- The first request for a wallet starts indexing it, with no manual setup.
- Continuous refresh
- Recent activity is picked up every few minutes, and history grows deeper in the background.
- LP position valuation
- LP token prices for DeDust and STON.fi pools, including handling of DEX farming transfers.
- Docs and debug views
- OpenAPI (Swagger) documentation and HTML views for checking computed series by eye.
Engineering decisions
- Exact balances without a full node: the indexer starts from the current balance and walks back through every transaction, subtracting amounts and fees, to get the exact balance after each event. Jetton transfer direction and amount are decoded from message opcodes.
- A work queue in the database: workers claim jobs with one atomic "select, lock and return" update, so many processes run in parallel with no external broker. Each step is a single database transaction, so a crash loses at most one in-flight unit of work.
- Rate-limit-aware API clients: each provider key sits behind a token-bucket pool that hands out at most N permits per second, and failed calls retry with bounded attempts.
- Time-series queries on TimescaleDB: time_bucket aggregation plus carry-forward of the last known balance turn sparse transactions into evenly spaced chart points.
- Load testing: distributed Locust workers on Docker Swarm and a separate time-to-first-chart benchmark. In those tests, the median first sync ranged from about 13 seconds for the smallest wallets to about 2 minutes for the most active ones.
Diagrams
Stack
- Python 3.12
- Flask
- uWSGI
- SQLAlchemy 2
- PostgreSQL 16
- TimescaleDB
- OpenResty
- Lua
- Docker Compose
- Ansible Vault
- Locust
- pytoniq
- Telegram Mini Apps
What this shows
- Blockchain indexers that turn raw on-chain transactions into analytics-ready time series
- DeFi valuation: pricing tokens and liquidity-pool positions from on-chain state
- Microservices that coordinate through the database with no message broker and stay within third-party rate limits
- Production delivery: containers, automated TLS, encrypted configuration and repeatable multi-environment deploys
Questions about this case
Do you need your own TON node to get balance history?
No. The indexer reads from public TON data providers and rebuilds history by replaying transactions backwards from the current balance. For LP token prices, pool state at a given block height is read from an archive endpoint.
How long until a new wallet's chart appears?
Indexing starts on the first request. In load tests, the median first sync ranged from about 13 seconds for small wallets to about 2 minutes for the most active ones. Deeper history keeps filling in the background.
Can this approach be reused for other products?
Yes. The same design fits portfolio trackers, PnL and tax reporting, wallet analytics and treasury dashboards, on TON or other account-based chains.