In our previous discussion, we explored the foundational steps for Java-based development on the Tron blockchain. This included compiling components from the Trident source code, establishing connections via RPC, and creating offline wallets. Now, we delve into two critical operational aspects: monitoring transactions and executing transfers using a deployed project environment.
Establishing the Connection with ApiWrapper
All interactions with the Tron blockchain begin by initializing a secure connection. The ApiWrapper class serves as the gateway, configured differently for mainnet versus testnet environments.
private ApiWrapper getApiWrapper(String hexPrivateKey) {
if (tronServiceConfig.getTronDomainOnline()) {
return ApiWrapper.ofMainnet(hexPrivateKey, tronServiceConfig.getApiKey());
} else {
return new ApiWrapper("grpc.nile.trongrid.io:50051", "grpc.nile.trongrid.io:50061", hexPrivateKey);
}
}For mainnet usage, an API key is mandatory, which can be obtained through Tron's official channels. Testnet environments, however, typically do not require this key, simplifying the development and testing phases.
Checking TRC-20 Token Balances
Querying balances for TRC-20 tokens, such as USDT, involves interacting with the token's smart contract. The process requires the wallet address and the contract address of the token.
public BigDecimal getTrc20Balance(String address) {
ApiWrapper client = getApiWrapper(tronServiceConfig.getHexPrivateKey());
Contract contract = client.getContract(tronServiceConfig.getTrc20Address());
Trc20Contract token = new Trc20Contract(contract, address, client);
BigInteger balanceOf = token.balanceOf(address);
BigDecimal divisor = new BigDecimal(tronServiceConfig.getTrc20Decimals());
BigDecimal divide = new BigDecimal(balanceOf).divide(divisor, 4, RoundingMode.HALF_UP);
client.close();
return divide;
}This method fetches the raw balance from the blockchain and adjusts it according to the token's decimal places, returning a human-readable figure.
Checking Native TRX Balances
The native cryptocurrency of the Tron blockchain, TRX, can be queried directly without interacting with a smart contract.
public BigDecimal getTRxBalance(String address) {
ApiWrapper wrapper = getApiWrapper(tronServiceConfig.getHexPrivateKey());
Long balance = wrapper.getAccountBalance(address);
BigDecimal divisor = new BigDecimal(tronServiceConfig.getTrc20Decimals());
BigDecimal divide = new BigDecimal(balance).divide(divisor);
return divide;
}This straightforward call retrieves the account balance, which is then formatted based on the required decimal precision.
Monitoring Transactions on the Tron Blockchain
Implementing transaction monitoring is essential for applications that need to react to on-chain activity. This can be achieved by setting up a listener that polls the network for transactions associated with specific addresses.
A common approach involves periodically checking the transaction history of an address or subscribing to events from full nodes. Developers can utilize the getTransactionInfoById method or set up a GRPC stream for real-time updates, though the latter requires more advanced configuration.
Executing TRX and TRC-20 Transfers
Transferring assets requires constructing a transaction object, signing it with the sender's private key, and broadcasting it to the network.
For TRX transfers:
public String sendTrx(String toAddress, BigDecimal amount) throws IOException {
ApiWrapper wrapper = getApiWrapper(tronServiceConfig.getHexPrivateKey());
Transaction transaction = wrapper.transfer(tronServiceConfig.getHexAddress(), toAddress, amount.longValue());
wrapper.broadcastTransaction(transaction);
wrapper.close();
return transaction.getTxID();
}For TRC-20 token transfers, the process interacts with the token's contract:
public String sendTrc20Token(String toAddress, BigDecimal amount) {
ApiWrapper wrapper = getApiWrapper(tronServiceConfig.getHexPrivateKey());
Contract contract = wrapper.getContract(tronServiceConfig.getTrc20Address());
Trc20Contract token = new Trc20Contract(contract, tronServiceConfig.getHexAddress(), wrapper);
BigInteger value = amount.multiply(BigDecimal.TEN.pow(tronServiceConfig.getTrc20Decimals())).toBigInteger();
Transaction transaction = token.transfer(toAddress, value, tronServiceConfig.getHexAddress());
wrapper.broadcastTransaction(transaction);
wrapper.close();
return transaction.getTxID();
}Always ensure sufficient TRX is available in the sending account to cover the transaction fees (bandwidth and energy costs).
Best Practices for Secure Transactions
- Private Key Management: Never hardcode private keys. Use secure environment variables or dedicated key management services.
- Error Handling: Implement robust try-catch blocks to handle potential network timeouts, insufficient balance errors, and invalid address formats.
- Fee Management: Understand the difference between bandwidth and energy. Complex operations, like smart contract interactions (TRC-20 transfers), consume energy, which may require freezing TRX to acquire.
- Test Thoroughly: Always perform transactions on the testnet first to verify logic and handle errors before deploying on mainnet.
👉 Explore advanced transaction strategies
Frequently Asked Questions
How do I get a Tron API key for mainnet access?
You can apply for an API key through the Tron Grid portal. This key allows you to make authenticated requests to the mainnet, which helps avoid rate limiting and ensures reliable access to the blockchain data.
What is the difference between bandwidth and energy?
Bandwidth is consumed for basic transactions like TRX transfers, while energy is required for smart contract interactions, such as TRC-20 token transfers. Users can obtain both by staking (freezing) TRX.
Why is my TRC-20 token transfer failing?
Common reasons include insufficient TRX to pay for the energy cost, an incorrect token contract address, or not having enough tokens in the sender's address. Always check the transaction result for specific error messages.
How can I listen for incoming transactions in real-time?
For real-time monitoring, you can set up a GRPC connection to a Tron full node or use WebSocket subscriptions offered by some service providers. This allows your application to receive immediate notifications for on-chain events.
Is it necessary to close the ApiWrapper connection?
Yes, it is good practice to close the ApiWrapper instance after completing operations to release network resources and prevent potential connection leaks, which could impact application performance.
Can I use the same code for both nile testnet and mainnet?
Yes, the core code remains the same. The key difference is the configuration—specifying the correct GRPC endpoints for the target network (nile or mainnet) and providing an API key for mainnet requests.