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.
- 🔐 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
go get github.com/mehdi124/tron-go-sdkGet your free API key from TronGrid.
Create a .env file:
NETWORK=mainnet
TRON_API_KEY=your_api_key_hereThen 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...
}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...
}address, privateKey, err := client.Wallet().Generate()
if err != nil {
panic(err)
}
fmt.Printf("Address: %s\n", address)
fmt.Printf("Private Key: %s\n", privateKey)isValid := client.Wallet().ValidateAddress("TYourAddressHere...")
if !isValid {
fmt.Println("Invalid address")
}// 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)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())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)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())// 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-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)
}// 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)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())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 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 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())
}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.orgsdk.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:
cfg := sdk.DefaultConfig(sdk.NetworkTestnet, apiKey)
cfg.Endpoint = "https://api.nileex.io" // For Nile testnet
cfg.BlockExplorerURL = "https://nileex.io" // Optional: set explorer URL// For known testnets
cfg := sdk.NewConfigWithCustomEndpoint(sdk.NetworkTestnet, apiKey, "https://api.nileex.io")
client, err := sdk.NewClient(cfg)export TRON_ENDPOINT="https://api.nileex.io"
export BLOCK_EXPLORER_URL="https://nileex.io" # OptionalThen use sdk.NewClientFromEnv() which will automatically use the custom endpoint.
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)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
}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
}
}
}- Never commit private keys or API keys to version control
- Use environment variables for sensitive configuration
- Always validate addresses before sending transactions
- Use testnet for development and testing
- Double-check transaction details before broadcasting
- Keep dependencies up to date
- Use HTTPS endpoints only
go test ./... -vNETWORK=testnet TRON_API_KEY=your_testnet_key go test ./tests/integration/... -vThe 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)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 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 |
See the examples/ directory for complete working examples:
examples/wallet/generate_wallet.go- Wallet generationexamples/transaction/native/main.go- Native TRX transferexamples/transaction/token/main.go- TRC20 token transferexamples/smart_contract/call/main.go- Smart contract write function callexamples/smart_contract/read/main.go- Smart contract read function callexamples/smart_contract/fee/main.go- Fee estimationexamples/transaction_query/get/main.go- Transaction queryexamples/transaction_query/list/main.go- Transaction listingexamples/testnet/shasta.go- Comprehensive Shasta testnet testing
Contributions are welcome! Please read our contributing guidelines and submit pull requests.
This project is licensed under the MIT License - see the LICENSE file for details.
1. "API key is required" error
- Ensure
TRON_API_KEYenvironment 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
- Reuse SDK Client: Create one client instance and reuse it
- Use Context: Always pass context for cancellation/timeout support
- Batch Operations: Group multiple operations when possible
- Error Handling: Always check errors and handle them appropriately
- Fee Estimation: Always estimate fees before sending transactions
- Test on Testnet First: Always test your code on Shasta testnet before mainnet
- Validate Inputs: Always validate addresses and amounts before transactions
- Handle Errors Gracefully: Use structured error handling with error codes
- Secure Key Management: Never hardcode private keys, use environment variables
- Monitor Transactions: Always check transaction status after broadcasting
- Use Appropriate Gas Limits: Set appropriate fee limits for your use case
Generate() (Address, string, error)- Generate new walletValidateAddress(address string) bool- Validate TRON addressBase58ToHex(base58Addr string) (string, error)- Convert Base58 to hexHexToBase58(hexAddr string) (string, error)- Convert hex to Base58
TransferNative(ctx, req) (*NativeTransferResponse, error)- Transfer native TRXTransferToken(ctx, req) (*TokenTransferResponse, error)- Transfer TRC20 tokensGetBalance(ctx, req) (Money, error)- Get account balanceGetTransaction(ctx, req) (*Transaction, error)- Get transaction detailsGetNativeTransactions(ctx, req) ([]Transaction, error)- List native transactionsGetTokenTransactions(ctx, req) ([]Transaction, error)- List token transactionsEstimateFee(ctx, req) (Money, error)- Estimate native transfer fee
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
For issues, questions, or contributions, please open an issue on GitHub.
This project is licensed under the MIT License - see the LICENSE file for details.
Built with ❤️ by mehdi124