Track 1: Exchange and custodial wallet integration

Build a minimal Shasta deposit, withdrawal, idempotent-crediting, and reconciliation workflow for TRX and a test TRC-20 token.

This track is a starting point for exchanges, payment platforms, and custodial wallets integrating TRON. It is designed for teams that manage deposit addresses, withdrawal signing, and internal ledgers on behalf of users.

What you will learn

The track begins with account and asset modeling, then covers data sources, deposit detection, idempotent crediting, withdrawal processing, and reconciliation and recovery.

The throughline is a minimal deposit and withdrawal workflow supporting TRX and one test TRC-20 token. Each stage uses the same Shasta test accounts to produce deposit candidates, idempotent ledger entries, onchain withdrawal results, and reconciliation records.

The completed exercise is a test service for validating data and ledger behavior. It does not satisfy the key infrastructure, approval controls, compliance, security review, capacity, or availability requirements for custody of real funds.

You do not need to learn every node endpoint or accounting rule in advance. Review the stage overview, then build the workflow around the same deposits and withdrawals. Return to the recommended reading when confirmation, event parsing, or broadcast behavior becomes relevant.

Track overview

StageMain topicTask in the minimal workflow
1. Define the account and asset modelDefine networks, addresses, asset identity, amount precision, and key responsibilitiesCreate the test-account inventory, asset registry, and responsibility boundaries
2. Select data sourcesSeparate data sources for deposit discovery, solidified verification, withdrawal broadcast, and balance reconciliationProduce an interface-to-semantics map
3. Detect depositsDetect TRX transfers and TRC-20 Transfer events in solidified dataProduce candidates for both test deposits
4. Implement idempotent creditingBuild stable unique keys from transaction, event, and block positionsRescan the same block range without crediting twice
5. Implement withdrawalsPerform approval, resource checks, construction, local signing, broadcast, and state trackingComplete TRX and test TRC-20 withdrawals
6. Reconcile and recoverTest cursor rollback, query timeouts, repeated broadcast, and ledger-to-chain reconciliationProduce a recovery drill and reconciliation record

Before you begin

You should understand backend services, database transactions, HTTP APIs, and basic ledger concepts. Review TRON accounts and addresses, transaction structure, solidified state, and TRC-20. If the overall exchange-integration boundary is unclear, start with Exchange and custodial wallet integration — What needs to integrate.

The hands-on work requires a Shasta HTTP endpoint, an interface that can query solidified data, at least two test-only accounts, and a verifiable test TRC-20 token. If you need a token, use Deploy a TRC-20 token with TronWeb; that recipe requires an ABI and bytecode produced by an actual compiler.

Store every amount as an integer in its smallest unit. TRX uses sun; display precision for a TRC-20 token comes from the target contract's decimals. Test keys must never control real assets or enter a deposit scanner, log, or general-purpose business database.

This track explains how deposits, withdrawals, and reconciliation use TRON data. Follow the linked pages for node deployment, API parameters, event decoding, and signing code. A production system also needs a hot/cold-wallet design, an HSM or another isolated signer, multi-level approvals, compliance controls, and incident response.

Track stages

1. Define the account and asset model

A custodial system must first define the accounts and assets it controls. Deposit addresses, sweep addresses, withdrawal hot wallets, and cold wallets have different responsibilities. Even if a small prototype reuses a few test accounts, represent those roles separately so that address ownership, user attribution, and signing authority do not become the same concept.

Deposit-address records must also distinguish whether an onchain account has been activated. The first TRX transfer to an inactive address creates account state and charges the sender the account-creation fee and associated Bandwidth cost. “No account state yet” is therefore different from “an activated account with a zero balance.”

Networks and assets need stable identifiers. Current TRON networks use the same address prefix, so an address alone cannot distinguish Mainnet from Shasta. Include the network in configuration and business unique keys. Identify TRX by network and native-asset type. Identify a TRC-20 token by network and contract address, not only by a symbol that may be duplicated or changed.

Record amounts as integer smallest units. The smallest TRX unit is sun; a target TRC-20 contract defines its own decimals. Decimals and symbols are display metadata and must not change the raw integer stored in the ledger. The asset registry should also record the allowed contract address, deposit and withdrawal status, and minimum business amount.

Separate key responsibilities at this stage. Deposit scanning and balance queries require only addresses. A transaction-building service can create unsigned transactions without private keys. Only a controlled signer should sign a reviewed withdrawal. A test prototype may use an isolated test signer, but signing capability must not live in a public API or scanning process.

Recommended reading

  1. Exchange and custodial wallet integration — What needs to integrate

    Read “Asset movement” and “Platform security, resources, and operations,” then consult the Pre-launch checklist as needed. The staking matrix is not a prerequisite for this stage.

  2. Accounts and keys — Address format and Address and data encoding — Address formats

    Continue through “Key pairs” in the accounts page and through “Conversion methods” in the encoding page. Standardize Base58Check, hex, and API representations. Leave transaction payload and ABI encoding until the withdrawal stage.

  3. TRC-20 — Key facts and TRC-20 contract interaction — decimals

    Confirm that a TRC-20 asset is identified by contract address and understand the boundary between decimals, symbol, and balance. Issuance and allowance methods are not prerequisites for the registry.

  4. Accounts — Activating an account

    Distinguish an inactive address from a zero-balance account and include first-transfer account-creation costs in deposit-address and sweep policies.

Stage task

Create an account table containing each test address, network, business role, user attribution, deposit and withdrawal permissions, and signing method. Create an asset registry containing Shasta TRX and one test TRC-20 token, with asset ID, contract address, symbol, decimals, smallest unit, and deposit and withdrawal status.

Draw the responsibility boundaries between the scanner, deposit service, ledger, withdrawal approval, transaction builder, signer, and broadcaster. Identify which components read only addresses, which can create unsigned data, which can access test keys, and which data each component may write.

Before selecting data sources: Confirm that the network, account roles, asset identity, amount precision, and key responsibilities have fixed definitions, and that a TRC-20 asset cannot be identified only by name or symbol.

2. Select data sources

Deposits, withdrawals, and reconciliation require different data semantics; one generic “transaction query” is not sufficient. Deposit discovery can scan solidified SolidityNode blocks or use indexed APIs with confirmed-only filters. The final crediting decision should retain evidence from solidified blocks or receipts. Withdrawal construction and broadcast use a FullNode; final withdrawal state comes from a SolidityNode.

Indexed services are convenient for account-level TRX and TRC-20 history, but clients must handle pagination, rate limits, retries, and indexing delay. A self-hosted block scanner controls its cursor and parsing logic but must operate a node and parse every block and receipt. A minimal prototype can choose either approach as the primary deposit source while retaining a solidified query path for verification by txID and block height.

Reconciliation needs an explicit data cutoff. Standard balance endpoints do not return a snapshot at an arbitrary historical height. A minimal implementation can read the latest solidified height from one SolidityNode immediately before and after its balance queries. If the height changes, query again or mark deposits and withdrawals in the interval as in transit. If strict historical reconstruction is required, validate archive-query support separately or replay the internal asset ledger.

For every interface, record the network, endpoint, source type, observed block height, whether the result is indexed, and the retry behavior on failure.

Recommended reading

  1. API reference — FullNode and SolidityNode selection guide

    Continue through “Ecosystem APIs” to understand construction, broadcast, latest state, solidified state, and indexed data. Return to Query solidified data before reconciliation.

  2. Confirmation semantics — State semantics quick reference

    Continue through “Latest head is not solidified state” and “Indexed data is not native node state.” Leave broadcast and receipt details until the withdrawal stage.

  3. Exchange and custodial wallet integration — Architecture choice: TronGrid vs self-hosted full node

    Continue through Deposit-monitoring patterns, then choose either indexed history or solidified block scanning.

  4. RPC and indexer providers — Comparison dimensions

    Focus on this page only if you are evaluating an external provider or need historical state. Skip the provider list if you have already selected self-hosted nodes and do not depend on a third-party index.

Stage task

Create an interface map for TRX deposit discovery, TRC-20 deposit discovery, solidified verification, withdrawal construction, withdrawal broadcast, withdrawal-result queries, TRX balance, and TRC-20 balance. For each entry, record the endpoint, interface type, data source, observed height, and timeout policy.

Call the latest-block endpoint, the latest-solidified-block endpoint, and one indexed query. Save their heights and timestamps. Confirm that deposits and final withdrawal state do not come directly from an unsolidified head, and define how indexed candidates return to solidified data for verification.

Before detecting deposits: Confirm that each business operation uses a data source with matching semantics, indexed output is not treated as native node state, and the reconciliation cutoff and in-transit interval can be reproduced.

3. Detect deposits

A deposit scanner identifies assets received by platform-controlled addresses from solidified data. For a standard TRX transfer, parse the sender, recipient, and amount in sun from TransferContract, then verify that the recipient belongs to the platform. Create a deposit candidate only after the network, asset, recipient, and amount all satisfy policy.

For a TRC-20 deposit, parse the Transfer(address,address,uint256) event from a successfully executed transaction receipt. The emitting contract must equal the token contract in the registry, the event recipient must belong to the platform, and the amount must remain a raw uint256 integer. Looking only at a TriggerSmartContract selector or parameters misses transfers emitted through other contract paths and does not prove execution success.

A deposit candidate should retain enough onchain evidence to include network, asset ID, txID, block height and hash, transaction position, contract or event position, sender, recipient, raw amount, execution result, and discovery source. A deposit below the business minimum or for a disabled asset should produce an auditable rejection or review record instead of disappearing silently.

A minimal prototype may support only top-level TransferContract TRX deposits. If the product accepts TRX received through contract execution, production scope must also parse internal_transactions[], exclude entries with rejected = true, and include the internal-transfer position in unique keys and tests.

Recommended reading

  1. Exchange wallet integration — Parsing blocks for deposit detection

    Read 5.1, 5.2, and 5.4 in sequence for the solidified cursor, TransferContract, TRC-20 events, execution results, and internal transactions. Node deployment and other asset types can wait.

  2. TRC-20 protocol interface — Event reference and Events and logs — Decoding a log entry

    Verify the standard Transfer event, then review how to decode address, topics, and data. Event-definition syntax and frontend usage are not required here.

  3. Confirmation semantics — Transaction body is not execution receipt

    Use this distinction to parse a standard TRX transfer from the transaction body while requiring a successful receipt for TRC-20, with solidified data as the final evidence.

  4. Scan solidified TRX and TRC-20 deposits

    Run a block-scanning prototype to verify solidified cursors, TRX contract positions, TRC-20 event positions, and persistent unique keys. It produces deposit candidates and does not modify a user ledger.

  5. Listen to contract events

    Run this only if TronGrid Events is the candidate source. Focus on confirmed filtering, pagination, and event position. In-memory deduplication in the example does not replace a database uniqueness constraint or solidified verification.

Stage task

Send a small amount of Shasta TRX and an allowlisted test TRC-20 token to a platform test address. Discover them through solidified block scanning or a confirmed-only index, verify them against solidified data, and produce candidate records with full onchain positions and raw integer amounts.

Prepare samples using the wrong token contract, a non-platform recipient, a failed contract call, and an amount below the business minimum. Confirm that none can enter a creditable state. If the prototype does not support internal TRX transfers, state that limitation in its service contract and test record.

Before implementing idempotent crediting: Confirm that TRX and TRC-20 candidates come from solidified data, that the TRC-20 record verifies contract address, event, and execution result, and that every candidate resolves to a specific block, transaction, and event position.

4. Implement idempotent crediting

A scanner will observe the same onchain transfer repeatedly after restarts, pagination retries, cursor rollback, and manual review. Safe rescanning does not mean avoiding duplicate reads; it means ensuring that the same onchain action can change the ledger only once, no matter how often it is processed.

Each asset needs an event-level position. A top-level TRX transfer can use network, asset ID, and txID as the business unique key. A TRC-20 transfer uses network, token contract, txID, and event position: the log[] array position for a node receipt or event_index for a TronGrid event. Block height, block hash, and transaction index support recovery and audit but do not replace stable transaction or event identity.

Candidate insertion, uniqueness checking, and ledger crediting should occur in one database transaction, with a database uniqueness constraint as the final safeguard. States may include discovered, verified, credited, under review, and rejected, but retrying a state transition must never increase the user's balance twice. Keep an immutable ledger entry rather than overwriting a balance as a substitute for crediting history.

Recommended reading

  1. Events and logs — How events are stored in TransactionInfo

    Read the log[] structure and “Decoding a log entry” to understand that event position in a node receipt comes from array order. You do not need to reread event-definition syntax.

  2. Listen to contract events

    Understand TronGrid event_index, pagination cursors, and deduplication. The recipe demonstrates process-local deduplication; crediting still requires a durable unique key and database transaction.

  3. Exchange wallet integration — The pipeline

    Check the ordering of solidified height, per-block scanning, transaction dispatch, and cursor advancement. Other asset types are not prerequisites for this stage.

  4. Credit deposits idempotently in one transaction

    Run a minimal SQLite ledger to verify that deposit records, ledger entries, processed blocks, and the scan cursor commit in one transaction, and that rescans, concurrent workers, and interrupted processing cannot credit an account twice.

Stage task

Define a business unique key and database uniqueness constraint for both TRX and TRC-20 deposits. Use the idempotent-crediting recipe to map candidates from the previous stage to test accounts, write the deposit and ledger entry in one transaction, and then update the processed block and scan cursor.

Scan the same block range twice. Then simulate duplicate pagination, two workers processing one event concurrently, and a retry after interruption during persistence. Every scenario should produce the same final ledger balance and exactly one effective credit entry for each onchain transfer.

Before implementing withdrawals: Confirm that deposit scanning is safely repeatable, database uniqueness and transactions prevent duplicate balance changes, and ledger entries retain the original txID, event position, and solidified-block evidence.

5. Implement withdrawals

Manage the business withdrawal request separately from onchain transaction attempts. A business withdrawal ID represents request intake, risk checks, and approval. A txID represents one constructed onchain attempt. They are not interchangeable: an expired transaction may require a new txID, while the business request must still pay at most once.

After approval, verify the network, asset, destination, raw integer amount, withdrawal limits, and account balance. A TRX withdrawal requires Bandwidth or enough TRX to pay the resource cost. A TRC-20 withdrawal also requires Energy, token balance, and an appropriate fee_limit. Construct the transaction close to signing and broadcast so that its TAPOS reference and expiration do not expire while approval is pending.

Signing must occur in a controlled environment. The signer accepts only reviewed data that satisfies address, amount, and asset policy, and returns a signature that can be verified locally before broadcast. General business services do not hold private keys and cannot modify signed raw_data.

After broadcast, continue tracking the original txID. Node acceptance is not withdrawal completion; final success requires successful execution and solidification. On a broadcast timeout or duplicate-transaction response, first query and rebroadcast the same signed transaction. Create a new attempt under the same business withdrawal only after confirming that the original never appeared onchain and has expired.

Recommended reading

  1. Transaction signing and broadcast — The three-step workflow

    Read Steps 1 through 4 for construction, local signing, broadcast, receipt, and solidification. The later staking example is not part of this withdrawal flow.

  2. TRC-20 contract interaction — balanceOf and transfer

    Use these for pre-withdrawal balance checks and a standard TRC-20 transfer. Allowance methods are not part of an ordinary hot-wallet withdrawal.

  3. Bandwidth and Energy — Quick comparison and FeeLimit and Energy cost

    Prepare Bandwidth, Energy, and the TRX fee balance and understand fee_limit. Read deployer resource sharing only if platform policy requires it.

  4. Broadcast and RPC errors — Broadcast response codes

    Focus on duplicate transactions, expiration, TAPOS, insufficient resources, and node-busy responses. Continue into P2P and mempool troubleshooting only for self-hosted nodes.

  5. API signing and broadcast flow

    This Shasta recipe demonstrates raw HTTP construction, local signing, and broadcast for TRX and is useful for checking the signer boundary. It does not implement TRC-20 withdrawal or a complete solidification wait.

  6. Send and confirm a TRC-20 transfer

    Complete a test-token withdrawal and wait for a solidified execution receipt under the original txID. The withdrawal service still owns business approval, limits, and ledger idempotency.

Stage task

Create one Shasta TRX withdrawal and one test TRC-20 withdrawal. Record the business withdrawal ID, approval result, resource and fee checks, unsigned transaction, signature verification, and first txID. Broadcast each transaction, then query its body, execution receipt, and solidified result.

Simulate a broadcast-response timeout and verify that the service continues querying and rebroadcasting the original txID without creating a second payment. Then simulate a transaction that expired and was confirmed never to have appeared onchain. Verify that the replacement attempt receives a new txID while remaining subject to the original business request's single-payment constraint.

Before reconciliation and recovery: Confirm that approval, signing, and broadcast responsibilities are separated; TRX and TRC-20 resources are sufficient; chain state follows the original txID; and business idempotency survives reconstruction of an expired transaction.

6. Reconcile and recover

The service must recover from duplicate data, transient failure, and process interruption. Advance a scan cursor only after every candidate and ledger change in a block has committed. After restart or uncertainty, roll back to an earlier solidified height and rescan. A query timeout means that the result is unknown; it does not prove the absence of a deposit or failure of a withdrawal.

Recovery tests must also cover broadcast. The same signed transaction can be rebroadcast under its original txID; an expired transaction must be reconstructed and signed again. Retain the relationship between every onchain attempt and its business withdrawal ID so the system can always determine whether a payment may already reach the chain.

Reconciliation requires an explicit solidified cutoff for each network, asset, and custodial address. A minimal implementation can query the latest solidified height from one SolidityNode immediately before and after balance reads. If the height is unchanged, record it with the result. If it changes, query again or classify deposits and withdrawals in the interval as in transit. Compare the onchain TRX balance and each TRC-20 contract balance with the internal ledger, listing pending items, fees, and adjustments separately. A standard balance endpoint is not an arbitrary-height snapshot API.

Recommended reading

  1. Confirmation semantics — Latest head is not solidified state

    Continue through “Indexed data is not native node state” to choose a solidified cutoff, save scanning evidence, and explain indexing delay.

  2. Errors and debugging — Retry strategy and Broadcast and RPC errors — Transaction never appears on chain

    Use the first to distinguish safe retries from rebuild-after-fix, and the second for an unknown broadcast result. Consult specific HTTP errors only when they occur.

  3. Exchange and custodial wallet integration — Pre-launch checklist

    Recheck per-asset accounting, solidified data, internal transactions, resources, and signer isolation. Stake 2.0 is outside the minimal reconciliation scope.

Stage task

Run these recovery scenarios: rescan the same block range; move the cursor back several solidified blocks; stop and restart the scanner during pagination; time out a deposit or balance query; and rebroadcast the same signed withdrawal. Record how each condition was detected, the recovery action, and the final ledger result.

Produce a Shasta reconciliation table for TRX and the test TRC-20 token. Include the solidified cutoff, solidified heights observed before and after balance queries, onchain balance, ledger balance, pending items, fees or adjustments, computed difference, and resolution. Any unexplained difference remains a failed item; never erase it by editing a balance directly.

Verify the minimal workflow: Deposits can be rescanned safely from solidified data; withdrawals recover by business ID and original txID; TRX and TRC-20 reconcile at an explicit cutoff; and every difference has evidence and a documented resolution.

Next steps

After this track, you should have a minimal deposit and withdrawal service, replayable deposit-ledger records, onchain results for TRX and test TRC-20 withdrawals, idempotency rules, a recovery drill, and a reconciliation report.

Before production, add hot/cold-wallet and sweeping strategies, an HSM or another isolated signer, multi-level approval, withdrawal limits, address-risk controls, key backup and rotation, database disaster recovery, monitoring and alerts, capacity tests, and security reviews. Complete all compliance processes required for the jurisdiction and business model.

If you later support TRC-10, NFTs, internal TRX transfers, batch withdrawals, Active permissions, or multisig, define detection rules, event-level unique keys, fee models, signing permissions, and reconciliation methods for each asset and transaction path. Do not reuse assumptions made for TRX or one TRC-20 token without validation.

If you are still blocked, share documentation feedback. Include “Track 1,” the current stage, the data source in use, the steps already completed, and the actual error. Never include private keys, mnemonics, API keys, or production account information.