Skip to main content
Three common tasks with four clients. Replace <YOUR_KEY> with the key of one of your endpoints and TXYZ… with a real address. The WU in the comments are what Node API charges for exactly these calls.

Connect

The first call reads account data — 1 WU.
grpcurl needs the TRON .proto files and takes addresses as base64 bytes — see gRPC.

Send USDT

Build the transaction through the node, sign it on your side, broadcast it through the node. Your private key never leaves your server. One transfer costs 2 WU; with tronpy 3 WU, plus 2 WU once to load the contract. In these examples from (sender) and to are the sender’s and the recipient’s addresses, amount is in the token’s smallest unit (USDT has 6 decimals: 1 USDT = 1000000), and PRIVATE_KEY is the sender’s private key. fee_limit is the most TRX, in sun, the transfer may burn: 30000000 is 30 TRX.
With curl, parameter is the ABI-encoded arguments of transfer(address,uint256) in hex: the recipient’s 20-byte address (its hex form without the leading 41) left-padded with zeros to 64 hex characters, then the amount, also padded to 64. The node answers with an unsigned transaction and its txID. Sign txID with the sender’s private key, add the signature to the transaction as "signature": ["<hex>"], and send that transaction object as signed.json. With grpcurl, call.json is a TriggerSmartContract message: owner_address, contract_address and data (the 4-byte function selector followed by the ABI-encoded arguments), all as base64 bytes. The message has no fee limit field: set raw_data.fee_limit on the returned transaction, then sign the SHA-256 of the new raw_data — the txid that came back no longer matches after that change. See gRPC.
Re-sending the same signed transaction is safe: the network executes a transaction ID only once, and a repeat broadcast comes back as DUP_TRANSACTION_ERROR. A transaction that has expired must be built and signed again.

Watch USDT transfers

Read the newest block header, then the receipts of that block, and keep the USDT ones. The header is 1 WU and the receipts of a fresh block 2 WU — 3 WU per block. Following every block of the chain this way is about 2.6M WU a month.
Each receipt of a USDT call carries the token’s Transfer events in log. In an event, topics[0] is ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, topics[1] and topics[2] are the sender and the recipient (the last 40 hex characters are the address without its 41 prefix), and data is the amount. receipt.result is SUCCESS for a transfer that went through. The filter above keeps direct calls to the USDT contract; to also catch USDT moved by other contracts, check the address of every log entry instead — a614f803b6fd780986a42c78ec9c7f77e6ded13c for USDT.
A new block arrives about every 3 seconds. Remember the last block you processed and fetch receipts for every number after it, so a slow poll never skips a block. Receipts of a block deeper than 20 below the head are no longer fresh and are charged by their size — see Quota units.