Java Integration Guide for TRC20-USDT: Step-by-Step Tutorial with Code Examples

·

Integrating TRC20-USDT into your Java-based application can significantly reduce transaction fees and speed up transfers compared to ERC20 networks. This comprehensive guide walks you through the entire process—from environment setup to executing real transactions—with fully functional code snippets. Whether you're building a crypto wallet, payment gateway, or blockchain service, this tutorial delivers practical insights for seamless TRC20 integration.

Prerequisites and Setup

To begin, ensure your development environment supports Java 8+ and Maven. The Tron blockchain requires specific libraries that aren't available in public Maven repositories by default. You'll need to manually import the wallet-cli JAR package from Tron's official GitHub repository.

👉 Discover how to securely manage blockchain transactions using advanced tools.

Add the Required Dependency

Use the following Maven configuration after downloading and installing the JAR locally:

<dependency>
    <groupId>com.tron</groupId>
    <artifactId>wallet-cli</artifactId>
    <version>1.0.0</version>
</dependency>

To install the JAR locally, clone Tron’s GitHub demo project, build it, and run:

mvn install:install-file -Dfile=wallet-cli-1.0.0.jar -DgroupId=com.tron -DartifactId=wallet-cli -Dversion=1.0.0 -Dpackaging=jar

Once installed, add it to your project’s pom.xml as shown above.


Core Functionalities with Sample Code

Generate a New TRC20 Wallet Address (Offline)

Creating a wallet address offline ensures private key security. The following method generates a hex-encoded address and converts it into the standard base58 format starting with T.

private static SecureRandom random = new SecureRandom();

public static Map<String, String> createAddress() {
    ECKey eCkey = new ECKey(random);
    String privateKey = ByteArray.toHexString(eCkey.getPrivKeyBytes());
    byte[] addressBytes = eCkey.getAddress();
    String hexAddress = ByteArray.toHexString(addressBytes);
    Map<String, String> addressInfo = new HashMap<>(3);
    addressInfo.put("address", toViewAddress(hexAddress));
    addressInfo.put("hexAddress", hexAddress);
    addressInfo.put("privateKey", privateKey);
    return addressInfo;
}

public static String toViewAddress(String hexAddress) {
    return encode58Check(ByteArray.fromHexString(hexAddress));
}

public static String encode58Check(byte[] input) {
    try {
        byte[] hash0 = hash(true, input);
        byte[] hash1 = hash(true, hash0);
        byte[] inputCheck = new byte[input.length + 4];
        System.arraycopy(input, 0, inputCheck, 0, input.length);
        System.arraycopy(hash1, 0, inputCheck, input.length, 4);
        return Base58.encode(inputCheck);
    } catch (Throwable t) {
        logger.error("Data encoding error: " + Hex.toHexString(input), t);
    }
    return null;
}
Security Note: Store private keys securely using encryption or hardware modules. Never expose them in logs or client-side code.

Query TRC20-USDT Balance by Address

Use TronGrid’s public node to query token balances. Replace the contract address if working with tokens other than USDT.

private static final String tronUrl = "https://api.trongrid.io";
private String contract = "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"; // USDT on TRON

public BigDecimal balanceOfTrc20(String address) {
    String url = tronUrl + "/wallet/triggerconstantcontract";
    JSONObject param = new JSONObject();
    param.put("owner_address", TronUtils.toHexAddress(address));
    param.put("contract_address", TronUtils.toHexAddress(contract));
    param.put("function_selector", "balanceOf(address)");

    List<Object> inputParameters = new ArrayList<>();
    inputParameters.add(new Address(TronUtils.toHexAddress(address).substring(2)));
    param.put("parameter", FunctionEncoder.encodeConstructor(inputParameters));

    String result = HttpClientUtils.postJson(url, param.toJSONString());
    if (StringUtils.isNotEmpty(result)) {
        JSONObject obj = JSONObject.parseObject(result);
        JSONArray results = obj.getJSONArray("constant_result");
        if (results != null && results.size() > 0) {
            BigInteger amount = new BigInteger(results.getString(0), 16);
            return new BigDecimal(amount).divide(BigDecimal.TEN.pow(6), 6, RoundingMode.FLOOR);
        }
    }
    return BigDecimal.ZERO;
}

📌 Tip: Always use HTTPS endpoints and consider rate limits when querying frequently.


Retrieve Public Address from Private Key

This utility helps verify ownership or recover an address from an existing key.

public static String getAddressByPrivateKey(String privateKey) {
    byte[] privateBytes = Hex.decode(privateKey);
    ECKey ecKey = ECKey.fromPrivate(privateBytes);
    byte[] from = ecKey.getAddress();
    return toViewAddress(Hex.toHexString(from));
}

Get Latest Block Number

Polling the latest block is essential for monitoring chain activity and detecting confirmations.

public BigInteger getNowBlock() {
    String url = tronUrl + "/wallet/getnowblock";
    String response = HttpRequest.get(url).execute().body();
    JSONObject jsonObject = JSONObject.parseObject(response);
    return jsonObject.getJSONObject("block_header")
                     .getJSONObject("raw_data")
                     .getBigInteger("number");
}

Fetch Transaction Details by Hash

Verify transaction status and retrieve metadata such as timestamp and fee usage.

public boolean transactionStatus(String hash) {
    JSONObject parseObject = JSON.parseObject(getTransactionById(hash));
    if (parseObject.isEmpty()) return false;
    String contractRet = parseObject.getJSONArray("ret").getJSONObject(0).getString("contractRet");
    return "SUCCESS".equals(contractRet);
}

public String getTransactionById(String hash) {
    String url = tronUrl + "/walletsolidity/gettransactionbyid";
    Map<String, Object> map = new HashMap<>();
    map.put("value", hash);
    return HttpClientUtils.postJson(url, JSON.toJSONString(map));
}

Execute TRC20-USDT Transfer

This is the core functionality—sending USDT across the TRON network.

public String sendTrc20(String privateKey, String toAddress, BigDecimal amount) throws Throwable {
    String ownerAddress = TronUtils.getAddressByPrivateKey(privateKey);
    JSONObject jsonObject = new JSONObject();
    jsonObject.put("contract_address", TronUtils.toHexAddress(contract));
    jsonObject.put("function_selector", "transfer(address,uint256)");

    List<Object> inputParameters = new ArrayList<>();
    inputParameters.add(new Address(TronUtils.toHexAddress(toAddress).substring(2)));
    inputParameters.add(new Uint256(amount.multiply(BigDecimal.TEN.pow(6)).toBigInteger()));
    
    jsonObject.put("parameter", FunctionEncoder.encodeConstructor(inputParameters));
    jsonObject.put("owner_address", TronUtils.toHexAddress(ownerAddress));
    jsonObject.put("call_value", 0);
    jsonObject.put("fee_limit", 6000000L);

    String response = HttpClientUtils.postJson(tronUrl + "/wallet/triggersmartcontract", jsonObject.toString());
    JSONObject result = JSONObject.parseObject(response);

    if (result.containsKey("Error")) {
        throw new RuntimeException("Transaction failed: " + result.getString("Error"));
    }

    JSONObject tx = result.getJSONObject("transaction");
    tx.getJSONObject("raw_data").put("data", Hex.toHexString("memo".getBytes()));
    
    return signAndBroadcast(tronUrl, privateKey, tx);
}
Important: Each transaction consumes bandwidth or energy. Ensure the sender has enough TRX to cover fees.

Send Native TRX and Check Balance

Support for native TRX operations enhances wallet versatility.

public String sendTrx(BigDecimal amount, String toAddress, String note) throws Throwable {
    String url = tronUrl + "/wallet/createtransaction";
    JSONObject param = new JSONObject();
    String privateKey = "your_private_key";
    
    param.put("owner_address", TronUtils.toHexAddress(TronUtils.getAddressByPrivateKey(privateKey)));
    param.put("to_address", TronUtils.toHexAddress(toAddress));
    param.put("amount", amount.multiply(BigDecimal.TEN.pow(6)).toBigInteger());

    String result = HttpClientUtils.postJson(url, param.toJSONString());
    if (StringUtils.isNotEmpty(result)) {
        JSONObject transaction = JSONObject.parseObject(result);
        if (transaction.containsKey("Error")) {
            throw new RuntimeException("Insufficient balance");
        }
        transaction.getJSONObject("raw_data").put("data", Hex.toHexString(note.getBytes()));
        return TronUtils.signAndBroadcast(tronUrl, privateKey, transaction);
    }
    throw new RuntimeException("Transaction creation failed");
}

public BigDecimal balanceOf(String address) {
    String url = tronUrl + "/wallet/getaccount";
    JSONObject param = new JSONObject();
    param.put("address", TronUtils.toHexAddress(address));
    
    String result = HttpClientUtils.postJson(url, param.toJSONString());
    if (!StringUtils.isEmpty(result)) {
        JSONObject obj = JSONObject.parseObject(result);
        BigInteger balance = obj.getBigInteger("balance");
        if (balance != null) {
            return new BigDecimal(balance).divide(BigDecimal.TEN.pow(6), 6, RoundingMode.FLOOR);
        }
    }
    return BigDecimal.ZERO;
}

👉 Explore powerful tools for managing digital assets efficiently.


Frequently Asked Questions (FAQ)

Q: Do I need TRX to send TRC20-USDT?
A: Yes. Every transaction on the TRON network consumes bandwidth or energy. If bandwidth is insufficient, TRX is burned to cover fees.

Q: Can I use testnet for development?
A: Absolutely. Use https://api.nileex.io as the node URL and obtain test USDT via TronGrid’s faucet.

Q: How do I prevent replay attacks?
A: Use visible: true in API calls and validate block timestamps. Also, avoid reusing nonce values.

Q: Is it safe to broadcast transactions via third-party nodes?
A: Public nodes like TronGrid are generally secure, but for production systems, consider running your own full node.

Q: What causes “out of energy” errors?
A: Smart contract interactions require energy. Freeze TRX to gain energy or pay with available balance.

Q: How fast are confirmations on TRON?
A: Blocks are produced every 3 seconds. Most exchanges require 19 confirmations (~57 seconds).


Final Thoughts

Integrating TRC20-USDT in Java offers a cost-effective alternative to Ethereum-based tokens. With low fees and fast settlement times, TRON is ideal for micropayments and high-frequency transfers.

👉 Start exploring blockchain development with reliable infrastructure support.