Tron Blockchain
TRC-20 and native TRX custody for Bicrypto Ecosystem — per-user Tron addresses, TronGrid deposit detection, pooled withdrawals, and the energy and bandwidth accounting that decides whether a payout goes out at all.
The Tron addon extends Ecosystem custody onto Tron. It adds one chain service to the install, and with it: per-user Tron addresses, deposit detection for native TRX and any TRC-20 token you import, and a withdrawal path that signs and broadcasts through TronWeb.
It is a small product with one large operational consequence. Tron does not charge fees the way every other chain in the platform does. There is no gas price paid out of the amount being sent and no fee-payer primitive that lets the platform sign on someone else's behalf. Instead every transaction consumes two metered resources — energy and bandwidth — and whichever account signs must own them or burn TRX to substitute for them.
That single fact is where Tron installs go wrong, and Energy and bandwidth is the page to read before you take a deposit.
What it requires
| Requirement | Why | If it is missing |
|---|---|---|
| Bicrypto core | Everything | Nothing to extend |
| Ecosystem | Wallets, the vault, deposit monitoring, the withdrawal queue | The addon has no host — every code path it uses lives in Ecosystem |
| An activated Tron licence | The chain service refuses to initialise without it | Every Tron flow returns "TRON service not available" |
| A TronGrid API key (mainnet) | Deposit polling | The monitor rate-limits itself into shutdown |
| A Tron master wallet holding TRX | Funding TRC-20 network fees | TRC-20 withdrawals queue and never leave |
This addon does not need ScyllaDB on its own account. Ecosystem does, for trading; Tron custody works without it.
What it actually adds
A chain service at backend/src/blockchains/tron.ts, discovered at runtime.
Ecosystem imports it through a safe-import shim, so an install without the addon
extracted simply reports the service as absent rather than crashing.
Per-user Tron addresses. Every ECO wallet that holds a Tron-backed currency
gets a base58 address beginning with T, generated from a fresh BIP-39 mnemonic
at m/44'/195'/0'/0/0 and encrypted with the Ecosystem vault key.
Deposit detection over the TronGrid REST API — a 30-second per-session poll while a user has the deposit page open, plus the shared background scanner for addresses whose owner has closed the tab.
Withdrawals for native TRX and TRC-20 tokens, with pooled sourcing when a user's own address does not physically hold the coins, and automatic TRX top-ups from the master wallet to cover the signer's energy and bandwidth.
It does not add token deployment. Ecosystem can deploy ERC20 contracts on EVM chains and SPL mints on Solana; on Tron you import an existing contract address. USDT on Tron is an import, not a deployment.
Two asset types, two different code paths
Almost every operational difference on this chain follows from which of these you are looking at.
| Native TRX | TRC-20 token | |
|---|---|---|
| Registered as | contractType: NATIVE |
contractType: PERMIT — the seeder rewrites anything else, and the deposit path ignores a hand-set NO_PERMIT |
| Deposit detected by | TransferContract records on the account endpoint |
The TronGrid TRC-20 transfer endpoint, filtered by contract |
| Dust floor | 0.001 TRX | 1 / 10^(decimals − 3) — 0.001 for a 6-decimal token |
| Withdrawal signed by | The user's own address only | The user's address, or any custodial wallet holding the token |
| Network cost | Bandwidth, burned from the amount's own account | Energy plus bandwidth, funded by the master wallet |
| Master wallet involved | No | Yes — the payout cannot proceed without it |
The right-hand column is the one that costs money to misunderstand. A Tron master wallet with no TRX does not break native TRX withdrawals at all; it silently stalls every TRC-20 payout on the install.
On EVM chains, a token that cannot delegate its own fee deposits into a shared
custodial contract the platform deployed. Tron has no such mechanism in this
product. Every Tron deposit — native or TRC-20, whatever contractType the token
row carries — lands at the user's own address. Requesting a custodial wallet on
Tron is not something the platform does.
So the seeder does not leave the value open. resolveContractType in
seeders/20240402234741-ecosystemTokens.js rewrites every non-native TRON token
to PERMIT before inserting it, and the same seeder runs an UPDATE that resets
any TRON row whose contractType is neither NATIVE nor PERMIT. The admin
import form applies no such rule, so you can still create a NO_PERMIT TRC-20 by
hand — it deposits to the user's own address anyway, because
usesCustodialDeposit() in ecosystem/utils/custody.ts refuses the custodial
path for every chain in NON_CUSTODIAL_CHAINS and TRON is one of them, and the
row is reset to PERMIT the next time the seeders run.
It is not ignored everywhere, which is why the row is still worth getting
right. The deposit WebSocket's onClose reads contractType with no chain check
to decide how long to keep the poller alive after the customer closes the tab:
two minutes for NO_PERMIT, ten for anything else. A hand-flagged TRC-20 stops
being watched sooner, for a reason that does not apply on this chain.
Do not read the deposit record as evidence either way. The Tron service stamps
contractType: "NO_PERMIT" on every TRC-20 deposit it hands to
storeAndBroadcastTransaction, whatever the token row says — so a correctly
configured token still produces records that read NO_PERMIT. The
custodial-address unlock that value would otherwise trigger is skipped only
because the same line is guarded on a to field the Tron payload never sets.
Where to start
Licence, the chain toggle, four environment variables, the master wallet and the diagnostics probe that names what is still missing.
How Tron charges for transactions, what the platform does about it, and why staking TRX is an operator decision the product does not make for you.
Address derivation, the two detection endpoints, dust filtering, and why Tron deposits credit without a confirmation-depth wait.
Pooled sourcing, the gas top-up, on-chain receipt confirmation, and every terminal state a Tron payout can reach.
Every variable the Tron service reads, what it defaults to, and which one takes the whole chain down when it is wrong.
Deposits not crediting, withdrawals stuck PENDING, OUT_OF_ENERGY, and the
"private key not found" error on old wallets.
Three things to know on day zero
TRON_NETWORK is a total-outage variable. It accepts mainnet, shasta and
nile. Any other value — including a typo, including mainnet-beta — makes the
service throw during construction, and every Tron flow on the install is dead
until it is corrected. This is not a degradation.
Tron is exempt from the token-network check. Ecosystem normally refuses to
issue a deposit address when a token row's network disagrees with the chain's
configured network. Tron is on the network-agnostic list, so that guard never
fires here. A Tron address is textually valid on mainnet, Shasta and Nile alike —
what changes is which chain the monitor watches. Switch TRON_NETWORK on a live
install and existing addresses keep being issued while their deposits stop being
seen.
The deposit monitor stops itself. After ten consecutive polling errors it
logs and shuts down that address's loop rather than hammering TronGrid forever.
Without TRON_API_KEY on mainnet, anonymous quota is enough to get there. This is
the single most common cause of "deposits worked yesterday".