SilotechBack End LeaderNov 2022 — Present

Tron energy marketplace

TRON energy (+ bandwidth) marketplace — match ~4/s · ~50ms platform-side; ~1k orders/day · ~60k TRX/day; peak TVL ~$45M (staked TRX delegated via market, Jan–Aug 2026). Correctness over CEX-scale throughput.

Lang
  • Node.js
  • TypeScript
Data
  • Kafka
  • BullMQ
  • MongoDB
  • Redis
Tool
  • Web3 / blockchain
  • Fastify
  • GraphQL
  • Apollo
  • Telegram
Others
  • API design

Intro

Marketplace that connects buyers who need TRON energy or bandwidth with sellers/providers who delegate resource on-chain. Buyer places an order, deposits TRX, matching fills against provider inventory, then DelegateResource lands on chain; providers sell auto or manual; reclaim undelegates when the lock expires; payout closes the loop. The API edge exposes both REST (Fastify) and GraphQL (Apollo) for the order lifecycle. Same ownership window also covers flash-unstake, vote, referral, and a Telegram path that is almost only chain-core (user-owned, anti-dup — nearly no UI/wiring).

Architecture

  • 01Buyers / APIorder · estimate · deposit
  • 02Providersauto-sell · manual delegate
  • 03Telegram chain-coreon-chain intents · anti-dup · nearly no UI
  • 04API serviceFastify REST + Apollo GraphQL · order lifecycle
  • 05Matchingfill · DelegateResource · ~4/s · ~50ms platform-side
  • 06Deposit consumerKafka · TRX credit path
  • 07BullMQ workersdeposit · withdraw · on-chain settle
  • 08Cronsreclaim · payout · flash-unstake · vote · referral
  • 09TRONdelegate / undelegate · ~3s block · confirm separate

What I did

  • Built the API edge (Fastify REST + Apollo GraphQL), matching, and deposit consume-tx from scratch, then handed the surface to the team — kept ownership of correctness boundaries (commit-before-broadcast, no blind rollback on ambiguous broadcast)
  • Owned BullMQ queues + workers from scratch for deposit, withdraw, and on-chain settle — Kafka still credits TRX on the deposit path; BullMQ handles the complementary async jobs
  • Owned crons — reclaim/undelegate on expiry, payout, flash-unstake release paths, vote/referral reward loops
  • Scoped Telegram work to chain-core only (user-owned intents, anti-dup) — nearly no bot UI or product wiring claimed
  • Led a team of ~4 backend on this product; platform-side match ~4/s · ~50ms under constrained volume (~1k orders/day · ~60k TRX/day); peak TVL ~$45M (staked TRX delegated via market, Jan–Aug 2026); product uptime 99.9% (this product — may share the number with trading, stated per product)

Hard problems

Broadcast timeout / DUP → double-delegate

Symptom
Ambiguous broadcast (HTTP timeout or DUP_TRANSACTION_ERROR) treated as hard fail → blind rollback → next tick signs a new delegate → provider locked twice, buyer over-filled.
Cause
Timeout and DUP are ambiguous — the tx may already be in mempool or on chain. Rollback without on-chain recheck invents a second intent.
Fix
Persist commit/sentinel before broadcast; route timeout/DUP into recheck-by-txid instead of immediate rollback. Public bar is correctness (no double-delegate), not CEX fill rate.

Serial matching correctness vs drain

Symptom
Pushing match throughput harder risked overlapping fills on the same provider inventory — over-delegate or unpaid lock.
Cause
Fill path mutates shared delegatable state; parallel drain without a serial correctness boundary races remainAmount / energyDelegatable.
Fix
Kept matching serial where money and resource locks meet; accepted ~4/s platform-side fill as the honest band under that constraint. Chain confirm stays bound by ~3s block time — separate from the ~50ms internal match path.

Reclaim, deposit, and false-success on chain paths

Symptom
Users (or ops) could see “done” while undelegate, Kafka deposit credit, or payout was still ambiguous — disputes look like lost TRX or stuck resource.
Cause
Expiry reclaim, deposit consume, and payout are multi-step; trusting broadcast result alone (or skipping recheck) creates false success-type signals.
Fix
Crons reclaim on lock expiry from authoritative state; deposit path credits via Kafka consumer with durable handling; BullMQ workers own deposit / withdraw / on-chain settle jobs; chain paths wait on recheck before user-facing success. No finer dispute-rate published.

Problem

Buyers needed TRON energy/bandwidth without running their own stake; providers had delegatable resource to sell. The product is a marketplace — order → deposit → match → on-chain delegate — plus reclaim, payout, and adjacent flash-unstake / vote / referral flows. Async paths split cleanly: Kafka credits TRX after durable deposit commits; BullMQ queues + workers (built from scratch) handle deposit, withdraw, and on-chain settle. Throughput is modest; the hard bar is not double-delegating and not lying about chain outcomes.

Trade-offs

  • Correctness over drain — matching stays serial at the money/resource boundary. ~4 fills/s and ~50ms platform-side latency are the published band; they are not on-chain confirm times (TRON block ~3s; delegate confirm is separate).
  • Commit-before-broadcast — persist intent/sentinel before broadcast so timeout/DUP can recheck instead of rolling back blind. Fail-closed (stuck pending, manual clear) is acceptable on money paths.
  • Telegram as chain-core only — almost no UI/wiring claimed; ownership is anti-dup and on-chain intent handling. scan-delegate existed historically and was dropped — not presented as a live component.
  • Complementary async — Kafka consumer credits TRX on the deposit path; BullMQ owns deposit / withdraw / on-chain settle jobs (queues + workers from scratch). Neither replaces the other.
  • Hand-off after build — Fastify REST + Apollo GraphQL API / matching / consume-tx were built from scratch then transferred to the team; crons stayed owned.

Outcomes

Matching/fill ~4/s · ~50ms platform-side (internal match path). Volume ~1k orders/day · ~60k TRX/day under real constraints. Peak TVL ~$45M (staked TRX delegated via market, Jan–Aug 2026). Product uptime 99.9% (this product). Numbers stay small on purpose — correctness (no double-delegate, commit-before-broadcast) mattered more than CEX-scale throughput. Client names and finer failure rates stay internal.