Skip to content

A Go SDK for interacting with the TRON blockchain — transfers, balances, smart contracts, and RPC made easy.

License

Notifications You must be signed in to change notification settings

mehdi124/tron-go-sdk

Repository files navigation

TRON Go SDK

Go Version License Go Report Card

A professional, production-ready Go SDK for interacting with the TRON blockchain. This SDK provides a clean, type-safe API for wallet management, native TRX transfers, TRC20 token transfers, smart contract interactions, and transaction queries.

Features

  • 🔐 Wallet Management: Generate new wallets, validate addresses
  • 💸 Native TRX Transfers: Send and receive TRX with fee estimation
  • 🪙 TRC20 Token Support: Transfer TRC20 tokens with ease
  • 📜 Smart Contract Interactions: Call smart contract functions with ABI encoding
  • 💰 Fee Estimation: Accurate fee estimation for both native and smart contract transactions
  • 🔍 Transaction Queries: Get transaction details, balances, and confirmations
  • 🌐 Network Support: Both mainnet and testnet (Shasta) support
  • 🔒 Security First: Secure key handling, input validation, and error handling
  • Well Tested: Comprehensive unit and integration tests
  • 📚 Well Documented: Extensive documentation and examples

Installation

go get github.com/mehdi124/tron-go-sdk

Quick Start

1. Get Your API Key

Get your free API key from TronGrid.

2. Configure the SDK

Option A: Environment Variables

Create a .env file:

NETWORK=mainnet
TRON_API_KEY=your_api_key_here

Then initialize the client:

package main

import (
    "github.com/mehdi124/tron-go-sdk/sdk"
)

func main() {
    client, err := sdk.NewClientFromEnv()
    if err != nil {
        panic(err)
    }
    // Use client...
}

Option B: Programmatic Configuration

package main

import (
    "github.com/mehdi124/tron-go-sdk/sdk"
)

func main() {
    cfg := sdk.DefaultConfig(sdk.NetworkMainnet, "your_api_key")
    client, err := sdk.NewClient(cfg)
    if err != nil {
        panic(err)
    }
    // Use client...
}

Usage Examples

Generate a New Wallet

address, privateKey, err := client.Wallet().Generate()
if err != nil {
    panic(err)
}
fmt.Printf("Address: %s\n", address)
fmt.Printf("Private Key: %s\n", privateKey)

Validate an Address

isValid := client.Wallet().ValidateAddress("TYourAddressHere...")
if !isValid {
    fmt.Println("Invalid address")
}

Convert Address Formats

// Convert Base58 address to hex format
hexAddr, err := client.Wallet().Base58ToHex("TYourAddressHere...")
if err != nil {
    panic(err)
}
fmt.Printf("Hex address: %s\n", hexAddr)

// Convert hex address to Base58 format
base58Addr, err := client.Wallet().HexToBase58("41a614f803b6fd780986a42c78ec9c7f77e6ded13c")
if err != nil {
    panic(err)
}
fmt.Printf("Base58 address: %s\n", base58Addr)

Get Balance

balance, err := client.Transaction().GetBalance(context.Background(), transaction.BalanceRequest{
    Address:          types.Address("TYourAddressHere..."),
    DecimalPrecision: 6, // TRX has 6 decimal places
    RoundPrecision:   6,
})
if err != nil {
    panic(err)
}
fmt.Printf("Balance: %s TRX\n", balance.String())

Transfer Native TRX

resp, err := client.Transaction().TransferNative(context.Background(), transaction.NativeTransferRequest{
    FromAddress:      types.Address("TYourFromAddress..."),
    ToAddress:        types.Address("TYourToAddress..."),
    Amount:           types.FloatToMoney(1.0), // 1 TRX
    PrivateKey:       "your_private_key_hex",
    DecimalPrecision: 6,
})
if err != nil {
    panic(err)
}
fmt.Printf("Transaction ID: %s\n", resp.TxID)

Estimate Transfer Fee

fee, err := client.Transaction().EstimateFee(context.Background(), transaction.EstimateFeeRequest{
    FromAddress:      types.Address("TYourFromAddress..."),
    ToAddress:        types.Address("TYourToAddress..."),
    Amount:           types.FloatToMoney(1.0),
    DecimalPrecision: 6,
})
if err != nil {
    panic(err)
}
fmt.Printf("Estimated Fee: %s TRX\n", fee.String())

Transfer TRC20 Tokens

// Token transfers require sufficient fee limit to cover energy costs
// If FeeLimit is 0, defaults to 10,000,000 sun (10 TRX)
resp, err := client.Transaction().TransferToken(context.Background(), transaction.TokenTransferRequest{
    FromAddress:      types.Address("TYourFromAddress..."),
    ToAddress:        types.Address("TYourToAddress..."),
    ContractAddress:  types.Address("TContractAddress..."),
    Amount:           types.FloatToMoney(100.0), // 100 tokens
    PrivateKey:       "your_private_key_hex",
    DecimalPrecision: 18, // Most tokens use 18 decimals
    FeeLimit:         10000000, // Optional: 10 TRX in sun (default if 0)
})
if err != nil {
    panic(err)
}
fmt.Printf("Transaction ID: %s\n", resp.TxID)

Note: If you get "out of energy" errors, increase the FeeLimit value. The default is 10,000,000 sun (10 TRX), but some contracts may require more. You can estimate the fee first using EstimateFee().

Read from Smart Contract (View Functions)

// Read-only function calls don't require private keys and don't create transactions
result, err := client.SmartContract().Read(context.Background(), smartcontract.ReadRequest{
    FromAddress:      types.Address("TYourFromAddress..."),
    ContractAddress:  types.Address("TContractAddress..."),
    FunctionSelector: "balanceOf(address)",
    Args: []interface{}{
        "TAddressToQuery...",
    },
    DecimalPrecision: 18,
})
if err != nil {
    panic(err)
}
fmt.Printf("Result: %v\n", result)
// Extract constant_result for decoded values
if constantResult, ok := result["constant_result"].([]interface{}); ok {
    fmt.Printf("Balance (hex): %v\n", constantResult)
}

Call Smart Contract Function (Write Functions)

// Write functions modify contract state and require private keys
txID, err := client.SmartContract().Call(context.Background(), smartcontract.CallRequest{
    FromAddress:      types.Address("TYourFromAddress..."),
    ContractAddress:  types.Address("TContractAddress..."),
    FunctionSelector: "transfer(address,uint256)",
    Args: []interface{}{
        "TRecipientAddress...",
        big.NewInt(1000000000000000000), // 1 token with 18 decimals
    },
    PrivateKey:       "your_private_key_hex",
    DecimalPrecision: 18,
    FeeLimit:         1000000,
    CallValue:        0,
})
if err != nil {
    panic(err)
}
fmt.Printf("Transaction ID: %s\n", txID)

Estimate Smart Contract Call Fee

fee, err := client.SmartContract().EstimateFee(context.Background(), smartcontract.EstimateFeeRequest{
    FromAddress:      types.Address("TYourFromAddress..."),
    ContractAddress:  types.Address("TContractAddress..."),
    FunctionSelector: "transfer(address,uint256)",
    Args: []interface{}{
        "TRecipientAddress...",
        big.NewInt(1000000000000000000),
    },
    DecimalPrecision: 18,
})
if err != nil {
    panic(err)
}
fmt.Printf("Estimated Fee: %s TRX\n", fee.String())

Get Transaction Details

tx, err := client.Transaction().GetTransaction(context.Background(), transaction.GetTransactionRequest{
    TxID: "your_transaction_hash",
})
if err != nil {
    panic(err)
}
fmt.Printf("Status: %s\n", tx.Status)
fmt.Printf("From: %s\n", tx.From)
fmt.Printf("To: %s\n", tx.To)
fmt.Printf("Value: %s\n", tx.Value.String())
fmt.Printf("Fee: %s\n", tx.Fee.String())
fmt.Printf("Confirmations: %d\n", tx.Confirmations)

Get Native TRX Transactions List

// Get all native TRX transactions for an address
txs, err := client.Transaction().GetNativeTransactions(context.Background(), transaction.GetNativeTransactionsRequest{
    Address: types.Address("TYourAddressHere"),
    Filter:  transaction.TransactionFilterAll, // "in", "out", or "all"
    Limit:   100,                               // Maximum number of transactions
})
if err != nil {
    panic(err)
}

for _, tx := range txs {
    fmt.Printf("Hash: %s, From: %s, To: %s, Value: %s TRX\n", 
        tx.Hash, tx.From, tx.To, tx.Value.String())
}

Get TRC20 Token Transactions List

// Get TRC20 token transactions for an address
txs, err := client.Transaction().GetTokenTransactions(context.Background(), transaction.GetTokenTransactionsRequest{
    Address:         types.Address("TYourAddressHere"),
    ContractAddress: types.Address("TContractAddressHere"),
    Filter:          transaction.TransactionFilterIn, // "in", "out", or "all"
    Limit:           50,                              // Maximum number of transactions
})
if err != nil {
    panic(err)
}

for _, tx := range txs {
    fmt.Printf("Hash: %s, From: %s, To: %s, Value: %s tokens\n", 
        tx.Hash, tx.From, tx.To, tx.Value.String())
}

Configuration

Environment Variables

The SDK supports the following environment variables:

Variable Description Required Default
NETWORK Network type: mainnet or testnet No mainnet
TRON_API_KEY Your TronGrid API key Yes -
TRON_ENDPOINT Custom API endpoint URL No Auto-set based on network
BLOCK_EXPLORER_URL Custom block explorer URL No Auto-set based on network

Example .env file:

NETWORK=testnet
TRON_API_KEY=your_api_key_here
TRON_ENDPOINT=https://api.shasta.trongrid.io
BLOCK_EXPLORER_URL=https://shasta.tronscan.org

Network Options

  • sdk.NetworkMainnet: TRON mainnet (default)
  • sdk.NetworkTestnet: TRON testnet (Shasta by default)

Note: The SDK defaults to Shasta testnet when using NetworkTestnet. To use other testnets (e.g., Nile) or custom endpoints, you have several options:

Option 1: Override Endpoint Directly

cfg := sdk.DefaultConfig(sdk.NetworkTestnet, apiKey)
cfg.Endpoint = "https://api.nileex.io" // For Nile testnet
cfg.BlockExplorerURL = "https://nileex.io" // Optional: set explorer URL

Option 2: Use Helper Function

// For known testnets
cfg := sdk.NewConfigWithCustomEndpoint(sdk.NetworkTestnet, apiKey, "https://api.nileex.io")
client, err := sdk.NewClient(cfg)

Option 3: Environment Variable

export TRON_ENDPOINT="https://api.nileex.io"
export BLOCK_EXPLORER_URL="https://nileex.io"  # Optional

Then use sdk.NewClientFromEnv() which will automatically use the custom endpoint.

Option 4: Custom Private Network

cfg := &sdk.Config{
    Network:          sdk.NetworkTestnet, // or NetworkMainnet
    APIKey:           "your_api_key",
    Endpoint:         "https://your-custom-node.com",
    BlockExplorerURL: "https://your-explorer.com", // Optional
    // ... other config options
}
client, err := sdk.NewClient(cfg)

Configuration Options

cfg := &sdk.Config{
    Network:              sdk.NetworkMainnet,
    APIKey:               "your_api_key",
    Endpoint:             "https://api.trongrid.io", // Optional, auto-set based on network
    BlockExplorerURL:     "https://tronscan.org",    // Optional
    BaseFeeMarginPercent: 10,                        // Safety margin for fee estimation
    TokenGasLimit:        100000,                     // Gas limit for token transfers
    SmartContractGasLimit: 1000000,                   // Gas limit for smart contract calls
    EnergyUsageTotal:     4200,                       // Energy usage for fee calculation
}

Error Handling

The SDK uses structured error types:

if err != nil {
    var sdkErr *sdk.Error
    if errors.As(err, &sdkErr) {
        switch sdkErr.Code {
        case sdk.ErrCodeInvalidAddress:
            // Handle invalid address
        case sdk.ErrCodeInsufficientBalance:
            // Handle insufficient balance
        case sdk.ErrCodeNetworkError:
            // Handle network error
        default:
            // Handle other errors
        }
    }
}

Security Best Practices

  1. Never commit private keys or API keys to version control
  2. Use environment variables for sensitive configuration
  3. Always validate addresses before sending transactions
  4. Use testnet for development and testing
  5. Double-check transaction details before broadcasting
  6. Keep dependencies up to date
  7. Use HTTPS endpoints only

Testing

Run Unit Tests

go test ./... -v

Run Integration Tests (Testnet)

NETWORK=testnet TRON_API_KEY=your_testnet_key go test ./tests/integration/... -v

Advanced Configuration

Custom Testnet URLs

The SDK supports connecting to any TRON-compatible endpoint:

// Example: Connect to Nile testnet
cfg := sdk.NewConfigWithCustomEndpoint(
    sdk.NetworkTestnet,
    "your_api_key",
    "https://api.nileex.io",
)
client, err := sdk.NewClient(cfg)

Fee Configuration

Adjust fee estimation parameters:

cfg := sdk.DefaultConfig(sdk.NetworkMainnet, apiKey)
cfg.BaseFeeMarginPercent = 20  // 20% safety margin (default: 10%)
cfg.TokenGasLimit = 200000     // Higher gas limit for complex token transfers
cfg.SmartContractGasLimit = 2000000  // Higher limit for complex contracts
cfg.EnergyUsageTotal = 4200    // Energy usage constant

Error Codes Reference

Error Code Description
ErrCodeInvalidConfiguration Invalid SDK configuration
ErrCodeInvalidAddress Invalid TRON address format
ErrCodeInvalidAmount Invalid transaction amount
ErrCodeInsufficientBalance Insufficient balance for transaction
ErrCodeNetworkError Network/HTTP request failed
ErrCodeTransactionFailed Transaction broadcast failed
ErrCodeContractError Smart contract call/encoding error
ErrCodeInvalidPrivateKey Invalid or missing private key
ErrCodeInvalidResponse Invalid API response format

Examples

See the examples/ directory for complete working examples:

  • examples/wallet/generate_wallet.go - Wallet generation
  • examples/transaction/native/main.go - Native TRX transfer
  • examples/transaction/token/main.go - TRC20 token transfer
  • examples/smart_contract/call/main.go - Smart contract write function call
  • examples/smart_contract/read/main.go - Smart contract read function call
  • examples/smart_contract/fee/main.go - Fee estimation
  • examples/transaction_query/get/main.go - Transaction query
  • examples/transaction_query/list/main.go - Transaction listing
  • examples/testnet/shasta.go - Comprehensive Shasta testnet testing

Contributing

Contributions are welcome! Please read our contributing guidelines and submit pull requests.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Troubleshooting

Common Issues

1. "API key is required" error

  • Ensure TRON_API_KEY environment variable is set
  • Or pass API key directly in DefaultConfig()

2. "Invalid address" error

  • Verify address is in Base58 format (starts with 'T')
  • Use client.Wallet().ValidateAddress() to check addresses
  • Ensure address is for the correct network (mainnet vs testnet)

3. "Insufficient balance" error

  • Check account balance using GetBalance()
  • Ensure you have enough TRX for fees
  • For token transfers, ensure you have both TRX (for fees) and tokens

4. Network connection errors

  • Verify your API key is valid and active
  • Check if the endpoint URL is correct
  • Ensure you're using the correct network (mainnet/testnet)
  • For custom endpoints, verify the URL is accessible

5. Smart contract call failures

  • Verify contract address is correct
  • Check function selector matches contract ABI
  • Ensure function parameters are correctly encoded
  • Verify you have sufficient fee limit set

6. "Out of energy" error for token transfers

  • This means the FeeLimit is too low to cover energy costs
  • Default FeeLimit is 10,000,000 sun (10 TRX) which is usually sufficient
  • If you still get this error, increase FeeLimit to 20,000,000 sun (20 TRX) or higher
  • You can estimate the fee first using EstimateFee() and set FeeLimit accordingly
  • Ensure your account has enough TRX balance to cover both the fee and any token amount
  • Note: Token transfers consume energy, which is paid for by burning TRX (up to FeeLimit)

7. Transaction not appearing

  • Wait a few seconds for transaction to be confirmed
  • Check transaction status using GetTransaction()
  • Verify transaction hash on block explorer

Performance Tips

  1. Reuse SDK Client: Create one client instance and reuse it
  2. Use Context: Always pass context for cancellation/timeout support
  3. Batch Operations: Group multiple operations when possible
  4. Error Handling: Always check errors and handle them appropriately
  5. Fee Estimation: Always estimate fees before sending transactions

Best Practices

  1. Test on Testnet First: Always test your code on Shasta testnet before mainnet
  2. Validate Inputs: Always validate addresses and amounts before transactions
  3. Handle Errors Gracefully: Use structured error handling with error codes
  4. Secure Key Management: Never hardcode private keys, use environment variables
  5. Monitor Transactions: Always check transaction status after broadcasting
  6. Use Appropriate Gas Limits: Set appropriate fee limits for your use case

API Reference

Wallet Module

  • Generate() (Address, string, error) - Generate new wallet
  • ValidateAddress(address string) bool - Validate TRON address
  • Base58ToHex(base58Addr string) (string, error) - Convert Base58 to hex
  • HexToBase58(hexAddr string) (string, error) - Convert hex to Base58

Transaction Module

  • TransferNative(ctx, req) (*NativeTransferResponse, error) - Transfer native TRX
  • TransferToken(ctx, req) (*TokenTransferResponse, error) - Transfer TRC20 tokens
  • GetBalance(ctx, req) (Money, error) - Get account balance
  • GetTransaction(ctx, req) (*Transaction, error) - Get transaction details
  • GetNativeTransactions(ctx, req) ([]Transaction, error) - List native transactions
  • GetTokenTransactions(ctx, req) ([]Transaction, error) - List token transactions
  • EstimateFee(ctx, req) (Money, error) - Estimate native transfer fee

Smart Contract Module

  • Call(ctx, req) (string, error) - Execute write function (state-changing)
  • Read(ctx, req) (map[string]interface{}, error) - Execute read function (view)
  • EstimateFee(ctx, req) (Money, error) - Estimate smart contract call fee

Support

For issues, questions, or contributions, please open an issue on GitHub.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

Built with ❤️ by mehdi124

About

A Go SDK for interacting with the TRON blockchain — transfers, balances, smart contracts, and RPC made easy.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Packages

No packages published

Languages