How to Monitor TRON Blockchain Transactions (TRX and USDT) with Java

·

Monitoring blockchain transactions in real-time is essential for applications like cryptocurrency wallets, exchanges, and payment gateways. The TRON network, known for its high throughput and low transaction fees, supports seamless tracking of native TRX and USDT (TRC20) transfers. This guide walks you through a robust, production-ready Java implementation to monitor TRON blockchain transactions by polling blocks and parsing transfer events—ideal for integrating deposit and withdrawal logic into your system.

Core Workflow Overview

The solution follows a block-by-block polling mechanism using TRON’s public HTTP API (https://api.trongrid.io). Since TRON does not support WebSocket-based event streaming for all use cases, we rely on periodic polling to detect new blocks and extract relevant transaction data.

Key Steps in the Process:

  1. Fetch the latest block number from the TRON network.
  2. Compare it with the last processed block stored in Redis.
  3. Iterate through each unprocessed block, retrieving transaction data.
  4. Parse transactions to identify TRX and USDT (TRC20) transfers.
  5. Update Redis with the latest block number after processing.
  6. Handle rate limiting and ensure system stability.

This method ensures reliable detection of on-chain activity with minimal latency.


🔧 Technical Prerequisites

Before implementing the solution, ensure you have the following:

1. TRON API Key

To avoid rate-limiting (RQS), obtain a free API key from TronGrid.

👉 Generate your free TRON API access and start monitoring transactions securely.

2. Required Dependencies (Maven)

<dependencies>
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.13</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>2.0.33</version>
    </dependency>
</dependencies>

These libraries handle HTTP communication and JSON parsing efficiently.


🧱 System Architecture & Components

The implementation consists of several modular components:


💻 Core Implementation Code

1. Scheduled Task Runner

package com.app.web.task;

import com.app.web.trx.TrxEventDataService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;

@Slf4j
@Component
public class Web3Task {

    @Resource
    private TrxEventDataService trxEventDataService;

    /**
     * Executes every 10 seconds after an initial 20s delay
     */
    @Scheduled(initialDelay = 20_000, fixedDelay = 10_000)
    public void exec() {
        String contractUsdt = "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"; // USDT on TRON
        String url = "https://api.trongrid.io";
        String apiKey = "your_trongrid_api_key"; // Replace with your key

        trxEventDataService.exec(contractUsdt, url, apiKey);
        System.out.println("Sync completed -------------");
    }
}
This task runs periodically, fetching new blocks and processing transactions without missing any.

2. Transaction Processing Service

package com.app.web.trx;

import com.alibaba.fastjson.*;
import com.app.common.util.RedisUtil;
import org.springframework.stereotype.Service;
import tron_scan.ScanBlock;
import java.io.*;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;

@Service
public class TrxEventDataService {

    private static final ScanBlock scan = new ScanBlock();
    public static final String REDIS_BLOCK_NUM = "REDIS_BLOCK_NUM";

    public void exec(String contractUsdt, String url, String apiKey) {
        scan.set_api_key(apiKey);
        scan.set_uri(url);

        String endNumStr = scan.GetNowBlockNum();
        String startNumber = RedisUtil.get(REDIS_BLOCK_NUM);

        if (startNumber == null) {
            RedisUtil.set(REDIS_BLOCK_NUM, endNumStr);
            startNumber = endNumStr;
        }

        int start = Integer.parseInt(startNumber);
        int end = Integer.parseInt(endNumStr);

        for (int i = start + 1; i < end; i++) {
            final int index = i;
            String returnStr = sendPost(url + "/walletsolidity/getblockbynum", "{\"num\":" + i + "}", apiKey);

            if (JSON.isValid(returnStr)) {
                JSONObject json = JSON.parseObject(returnStr);

                if (json.size() == 0) {
                    try {
                        System.out.println("No data, retrying in 30s...");
                        Thread.sleep(30000);
                        returnStr = sendPost(url + "/walletsolidity/getblockbynum", "{\"num\":" + i + "}", apiKey);
                        json = JSON.parseObject(returnStr);
                    } catch (InterruptedException e) { /* ignored */ }
                }

                if (json.containsKey("blockID") && json.containsKey("transactions")) {
                    String value = AnalysisOt.getTransferEvent(json.getJSONArray("transactions").toJSONString(), String.valueOf(i));
                    processTransferData(value, contractUsdt);
                }
            }

            RedisUtil.set(REDIS_BLOCK_NUM, index + "");
            System.out.println("Processed block: " + i + " - Sleeping 1s...");
            try { Thread.sleep(1000); } catch (InterruptedException e) { }
        }
    }

    private void processTransferData(String allData, String contractUsdt) {
        JSONArray jsonArray = JSON.parseArray(allData);
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject transfer = jsonArray.getJSONObject(i);
            if (!"SUCCESS".equals(transfer.getString("contractRet"))) continue;

            String type = transfer.getString("type");
            BigDecimal amount = new BigDecimal(transfer.getString("amount"));
            BigDecimal divisor = new BigDecimal("1000000");
            String formattedAmount = amount.divide(divisor, 6, BigDecimal.ROUND_HALF_UP).toString();

            if ("TriggerSmartContract".equals(type) && 
                contractUsdt.equalsIgnoreCase(transfer.getString("contract_address"))) {
                System.out.println("USDT Transfer: " +
                    transfer.getString("from_address") + " → " +
                    transfer.getString("to_address") + " | " +
                    formattedAmount + " USDT | Tx: " +
                    transfer.getString("txID"));
            } else if ("TransferContract".equals(type)) {
                System.out.println("TRX Transfer: " +
                    transfer.getString("from_address") + " → " +
                    transfer.getString("to_address") + " | " +
                    formattedAmount + " TRX | Tx: " +
                    transfer.getString("txID"));
            }
        }
    }

    public String sendPost(String url, String json, String apiKey) {
        StringBuilder response = new StringBuilder();
        try {
            URL requestUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) requestUrl.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);
            conn.setReadTimeout(10000);
            conn.setRequestProperty("accept", "application/json");
            conn.setRequestProperty("TRON-PRO-API-KEY", apiKey);
            conn.setRequestProperty("User-Agent", "Mozilla/5.0");
            conn.setDoOutput(true);
            conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");

            try (OutputStream os = conn.getOutputStream()) {
                byte[] data = json.getBytes(StandardCharsets.UTF_8);
                os.write(data, 0, data.length);
            }

            if (conn.getResponseCode() == 200) {
                try (BufferedReader br = new BufferedReader(
                    new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
                    String line;
                    while ((line = br.readLine()) != null) {
                        response.append(line);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return response.toString();
    }
}

🔍 Understanding Transfer Event Parsing

The AnalysisOt.getTransferEvent() method decodes raw transaction data:


⚠️ Best Practices & Considerations

1. Rate Limiting

2. Error Handling

3. Data Consistency

👉 Discover advanced tools to enhance your blockchain monitoring infrastructure.


❓ Frequently Asked Questions (FAQ)

Q1: Why can’t I use WebSockets for real-time TRON event listening?

A: While TRON supports some WebSocket endpoints, they are unstable or limited in production. Polling via HTTP APIs remains the most reliable method for mission-critical systems.

Q2: How do I handle service downtime?

If the service stops, it resumes from the last saved block in Redis. Since TRON produces a block every ~3 seconds and our system processes one per second, it will catch up quickly once restarted.

Q3: Can this monitor other TRC20 tokens besides USDT?

Yes! Just replace the contract address with any valid TRC20 token address (e.g., BTT, JST). The parsing logic works universally for standard TRC20 transfers.

Q4: Is Redis mandatory?

While not strictly required, Redis provides fast, persistent storage for block numbers. Alternatives include MySQL, PostgreSQL, or even file-based storage—but Redis is optimal for performance.

Q5: How accurate is the transaction parsing?

The parser accurately identifies successful transfers by checking contractRet=SUCCESS and validates input data length and method signatures (a9059cbb). Failed or reverted transactions are filtered out.

Q6: Can I deploy this in a clustered environment?

Yes, but ensure only one instance processes blocks at a time to prevent duplication. Use distributed locking (e.g., Redis SETNX) or run the task on a single node.


🔑 Core Keywords


By following this guide, you can build a scalable and resilient system to monitor TRON-based assets. Whether you're building a wallet, exchange, or payment processor, this foundation ensures timely detection of deposits and withdrawals.

👉 Enhance your blockchain application with secure, real-time data tools today.