Docs

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.

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

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.00014,
        description: 'Pay TRX for energy consumption'
      },
      {
        name: 'Rent energy',
        cost: energyEstimate * 0.0001,
        description: 'Rent energy from third-party (30% cheaper)'
      },
      {
        name: 'Stake TRX',
        cost: energyEstimate / 4000,
        description: 'Stake TRX for reusable energy (best for frequent use)'
      }
    ];
    
    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. Gas Estimation - Factor in energy costs for smart contract calls
  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.