Docs
Docs
Home
Getting Started
Agent Tooling
CLI
Supported Chains
Acala
Aptos
Arbitrum
Arc
Asset Hub
Astar
Avalanche
Base
Berachain
Bifrost
Binance Smart Chain
Bittensor
Blast
Boba Network
Bridge Hub
Celo
Centrifuge
Chiliz
Cronos
Enjin
Ethereum
Etherlink
Flow EVM Gateway
Gnosis
Hydration
Hyperliquid
Immutable
Ink
IoTeX
Kusama
Linea
LISK
Manta Atlantic
Manta Pacific
Mantle
MegaETH
Monad
Movement
Neuroweb
opBNB
Optimism
Plasma
Polkadot
Polygon
Pulsechain
Robinhood
Ronin
Scroll
Sonic
Starknet
Taiko
Tempo
Sui
TRON
Unichain
Viction
World Chain
XDC Network
XX Network
Zetachain
zkSync Era
Zora
Supported ChainsTRONTRON HTTP API

TRC20 Token Transfers - Complete Guide

Complete guide to TRC20 token transfers on TRON - from USDT to custom tokens. Learn balance checking, approvals, transfers, and error handling with Dwellir RPC.

TRON RPC endpoint: endpoint URLs, plans and pricing.

Master TRC20 Token Operations

Dwellir's TRON endpoints provide comprehensive TRC20 token support with optimized smart contract interactions. Build powerful token applications with our complete TRC20 integration guide.

Start building with TRC20 tokens

Complete guide to implementing TRC20 token transfers on the TRON network. Learn how to check balances, approve spending, transfer tokens, and handle all TRC20 operations.

Overview of TRC20 Standard

TRC20 is TRON's fungible token standard, similar to Ethereum's ERC20. Popular tokens include:

  • USDT (Tether) - TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t
  • USDC (USD Coin) - TEkxiTehnzSmSe2XqrBj4w32RUN966rdz8
  • JST (JUST) - TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9
  • WTRX (Wrapped TRX) - TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR

Key TRC20 Functions

  • balanceOf(address) - Check token balance
  • transfer(address,uint256) - Transfer tokens
  • approve(address,uint256) - Approve spending
  • transferFrom(address,address,uint256) - Transfer on behalf
  • allowance(address,address) - Check approved amount

Implementation Examples

Energy and fee_limit for USDT transfers

On TRON mainnet on 3 November 2026, a USDT transfer used 64,285 energy when the recipient already held USDT and 130,285 when it held none. At a getEnergyFee of 100 sun, a sender without staked or delegated energy burns 6.4285 TRX or 13.0285 TRX. TRON energy for USDT transfers shows the measured receipts.

  • fee_limit caps all the energy a call may use, including staked and delegated energy. Size it for the 130,285 case: 13.0285 TRX plus headroom. A lower value fails transfers to new recipients with OUT_OF_ENERGY, and the network still charges the energy used.
  • wallet/triggersmartcontract builds the transaction without executing it. Its response has no energy_used, so the energy_used || 0 reads in the examples above report 0. It also returns result.result: true for a transfer that will revert.
  • Simulate with wallet/triggerconstantcontract before signing. A reverted simulation also returns result.result: true, so check result.message and transaction.ret as well:
JavaScript
async function simulateTransfer(apiUrl, tokenAddress, fromAddress, parameter) {
  const response = await fetch(`${apiUrl}/wallet/triggerconstantcontract`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      owner_address: fromAddress,
      contract_address: tokenAddress,
      function_selector: 'transfer(address,uint256)',
      parameter,
      visible: true
    })
  });
  const result = await response.json();
  // visible: true returns message as text; visible: false returns it as hex.
  const raw = result.result?.message ?? '';
  const message = /^([0-9a-f]{2})+$/i.test(raw) ? Buffer.from(raw, 'hex').toString() : raw;
  const reverted = result.transaction?.ret?.[0]?.ret === 'FAILED';
  if (result.result?.result !== true || message || reverted) {
    throw new Error(`Transfer would fail: ${message || 'unknown reason'}`);
  }
  return result.energy_used;
}

Best Practices

1. Error Handling

JavaScript
async function safeTokenTransfer(tokenAddress, fromAddress, toAddress, amount) {
  try {
    // 1. Validate inputs
    if (!isValidTronAddress(fromAddress) || !isValidTronAddress(toAddress)) {
      throw new Error('Invalid address format');
    }
    
    if (amount <= 0) {
      throw new Error('Amount must be positive');
    }
    
    // 2. Check token exists
    const tokenInfo = await getTokenInfo(tokenAddress);
    if (!tokenInfo) {
      throw new Error('Token contract not found');
    }
    
    // 3. Check balance
    const balance = await getTokenBalance(tokenAddress, fromAddress);
    const amountInDecimals = amount * Math.pow(10, tokenInfo.decimals);
    
    if (parseFloat(balance) < amountInDecimals) {
      throw new Error('Insufficient token balance');
    }
    
    // 4. Check energy/bandwidth
    const resourceCheck = await checkResourcesForTransfer(fromAddress);
    if (!resourceCheck.canExecute) {
      throw new Error(`Insufficient resources: ${resourceCheck.reason}`);
    }
    
    // 5. Create transaction
    const transferResult = await createTokenTransfer(
      tokenAddress,
      fromAddress,
      toAddress,
      amountInDecimals.toString()
    );
    
    return {
      success: true,
      transaction: transferResult,
      estimatedCost: resourceCheck.estimatedCost
    };
    
  } catch (error) {
    return {
      success: false,
      error: error.message,
      code: error.code || 'UNKNOWN_ERROR'
    };
  }
}

2. Gas Optimization

JavaScript
class TRC20GasOptimizer {
  async optimizeTransfer(tokenAddress, fromAddress, toAddress, amount) {
    // 1. Estimate energy cost
    const energyEstimate = await estimateEnergyForTransfer(tokenAddress, fromAddress, amount);
    
    // 2. Check if user has enough staked energy
    const resources = await getAccountResources(fromAddress);
    const availableEnergy = resources.EnergyLimit - resources.EnergyUsed;
    
    if (availableEnergy >= energyEstimate) {
      return {
        strategy: 'use_staked_energy',
        cost: 0,
        recommendation: 'Transaction will execute for free'
      };
    }
    
    // 3. Calculate different cost strategies
    const strategies = [
      {
        name: 'Pay with TRX',
        cost: energyEstimate * 0.0001, // getEnergyFee: 100 sun per energy on 3 Nov 2026
        description: 'Pay TRX for energy consumption'
      },
      {
        name: 'Stake TRX',
        cost: energyEstimate / 10, // TRX locked, not spent: 9.999 energy per staked TRX per day on 3 Nov 2026
        description: 'Stake TRX for energy that refills every 24 hours'
      }
    ];
    
    return {
      energyRequired: energyEstimate,
      strategies: strategies.sort((a, b) => a.cost - b.cost),
      recommendation: strategies[0]
    };
  }
}

3. Transaction Monitoring

JavaScript
class TRC20TransactionMonitor {
  async monitorTransfer(txId, expectedAmount, expectedRecipient, tokenAddress) {
    const timeout = 60000; // 1 minute
    const checkInterval = 3000; // 3 seconds
    const startTime = Date.now();
    
    while (Date.now() - startTime < timeout) {
      try {
        const txDetails = await getTransactionById(txId);
        
        if (txDetails.blockNumber) {
          // Transaction confirmed, verify details
          const verification = await this.verifyTransfer(
            txDetails,
            expectedAmount,
            expectedRecipient,
            tokenAddress
          );
          
          return {
            confirmed: true,
            verified: verification.success,
            details: txDetails,
            verification: verification
          };
        }
        
        console.log('Waiting for confirmation...');
        await new Promise(resolve => setTimeout(resolve, checkInterval));
        
      } catch (error) {
        console.error('Monitoring error:', error);
      }
    }
    
    return {
      confirmed: false,
      timeout: true,
      message: 'Transaction confirmation timeout'
    };
  }
  
  async verifyTransfer(txDetails, expectedAmount, expectedRecipient, tokenAddress) {
    // Verify transaction called the correct contract
    const contract = txDetails.raw_data?.contract?.[0];
    if (contract?.parameter?.value?.contract_address !== tokenAddress) {
      return { success: false, reason: 'Wrong contract called' };
    }
    
    // Decode transfer parameters (simplified)
    // In production, use proper ABI decoding
    const data = contract.parameter.value.data;
    if (!data.startsWith('a9059cbb')) { // transfer function selector
      return { success: false, reason: 'Not a transfer call' };
    }
    
    return {
      success: true,
      verified: true,
      message: 'Transfer verified successfully'
    };
  }
}

Security Considerations

  1. Validate Addresses - Always validate TRON addresses before transactions
  2. Check Token Contracts - Verify token contract addresses against known lists
  3. Amount Validation - Validate amounts and handle decimal precision correctly
  4. Resource Checks - Ensure sufficient energy/bandwidth before transactions
  5. Private Key Security - Never expose private keys in client-side code
  6. Transaction Limits - Implement reasonable limits for user protection

Common Pitfalls

  1. Decimal Precision - Always account for token decimals when calculating amounts
  2. Address Format - Use correct encoding for contract parameters
  3. Energy Estimation - Simulate with wallet/triggerconstantcontract, check result.message and transaction.ret, and set fee_limit for a recipient with no tokens
  4. Approval First - Remember to approve before transferFrom operations
  5. Network Congestion - Handle transaction delays and failures gracefully

Need help? Contact our support team or check the TRON documentation.

wallet/votewitnessaccount

Vote for TRON Super Representatives using frozen TRX voting power via Dwellir's high-performance RPC endpoint.

wallet/getnodeinfo

Get comprehensive TRON node information including version, block height, configuration, and peer connections via Dwellir's enterprise RPC endpoint.

On this page

Overview of TRC20 StandardKey TRC20 FunctionsImplementation ExamplesEnergy and fee_limit for USDT transfersBest Practices1. Error Handling2. Gas Optimization3. Transaction MonitoringSecurity ConsiderationsCommon Pitfalls