How to Interact With TRC-20 Smart Contracts

·

Interacting with TRC-20 tokens, such as USDT on the Tron network, requires calling specific functions on their smart contracts. This guide provides practical methods using TronWeb, HTTP API, and wallet-cli, focusing on the Shasta testnet for examples.

Understanding TRC-20 Contracts

TRC-20 is a technical standard for smart contracts on the Tron blockchain, enabling the creation of fungible tokens. These contracts have predefined functions that allow users to read data (like token name or balance) and perform actions (like transfers).

Key functions include:

Prerequisites for Interaction

Before interacting with any contract, ensure you have:

👉 Explore more strategies for finding and verifying contract addresses

Reading Contract Data (Constant Calls)

Constant calls are read-only operations that do not modify the blockchain state, cost nothing, and do not require broadcasting a transaction.

Getting the Token Name

The name() function returns the full name of the token (e.g., "Tether USD").

Using TronWeb:

const TronWeb = require('tronweb');
const fullNode = new TronWeb.providers.HttpProvider("https://api.shasta.trongrid.io");
const solidityNode = new TronWeb.providers.HttpProvider("https://api.shasta.trongrid.io");
const eventServer = new TronWeb.providers.HttpProvider("https://api.shasta.trongrid.io");
const privateKey = "your_private_key";
const tronWeb = new TronWeb(fullNode, solidityNode, eventServer, privateKey);

async function getTokenName() {
    const contractAddress = "TQQg4EL8o1BSeKJY4MJ8TB8XK7xufxFBvK";
    try {
        let contract = await tronWeb.contract().at(contractAddress);
        let result = await contract.name().call();
        console.log('Token Name: ', result);
    } catch(error) {
        console.error("Error:", error);
    }
}
getTokenName();

Using wallet-cli:

TriggerConstantContract [ownerAddress] [contractAddress] name() # false

Getting the Token Symbol

The symbol() function returns the token's ticker symbol (e.g., "USDT").

Using HTTP API:

curl -X POST https://api.shasta.trongrid.io/wallet/triggerconstantcontract -d '{
"contract_address":"419E62BE7F4F103C36507CB2A753418791B1CDC182",
"function_selector":"symbol()",
"owner_address":"41977C20977F412C2A1AA4EF3D49FEE5EC4C31CDFB"
}'

Getting Token Decimals and Total Supply

The decimals() function reveals the token's smallest divisible unit, while totalSupply() shows the total number of minted tokens. The calls are structurally identical to name() and symbol(), simply replacing the function selector.

Querying and Managing Token Balances

Checking an Account Balance

Use the balanceOf(address) function to check the TRC-20 token balance of any wallet.

Using TronWeb:

// ...TronWeb initialization code from above
async function checkBalance() {
    const contractAddress = "TQQg4EL8o1BSeKJY4MJ8TB8XK7xufxFBvK";
    let queryAddress = "TM2TmqauSEiRf16CyFgzHV2BVxBejY9iyR";
    try {
        let contract = await tronWeb.contract().at(contractAddress);
        let result = await contract.balanceOf(queryAddress).call();
        console.log('Balance: ', result);
    } catch(error) {
        console.error("Error:", error);
    }
}

Executing Transactions (State-Changing Calls)

These operations change the blockchain state, require bandwidth and energy, and must be broadcast to the network. They often require a fee limit and signing with a private key.

Transferring Tokens

The transfer(address _to, uint256 _value) function sends tokens from the caller's address to another.

Using TronWeb:

// ...TronWeb initialization code
async function transferTokens() {
    const contractAddress = "TQQg4EL8o1BSeKJY4MJ8TB8XK7xufxFBvK";
    try {
        let contract = await tronWeb.contract().at(contractAddress);
        let result = await contract.transfer(
            "TVDGpn4hCSzJ5nkHPLetk8KQBtwaT...", // recipient address
            1000000 // amount (considering decimals)
        ).send({
            feeLimit: 100000000 // Set an appropriate fee limit in Sun
        });
        console.log('Transaction Result: ', result);
    } catch(error) {
        console.error("Error:", error);
    }
}

👉 Get advanced methods for calculating precise transaction fees

Using HTTP API & wallet-cli: For these methods, after triggering the contract, you must also sign and broadcast the transaction for it to be confirmed on the network.

Token Approvals and Delegated Transfers

The approve(address _spender, uint256 _value) function allows a spender to withdraw tokens from your account up to a specified value. The transferFrom() function is then used by the spender to execute the transfer.

Example TronWeb Usage for approve():

// User A approves User B to spend 100 USDT
await contract.approve(
    "TA1g2WQiXbU...", // spender's address (User B)
    100000000 // amount (e.g., 100 USDT with 6 decimals)
).send({ feeLimit: 100000000 });

Example TronWeb Usage for transferFrom():

// User B transfers 50 USDT from User A to User C
await contract.transferFrom(
    "TM2TmqauSEiRf16CyFgzHV2BVxBej...", // from (User A)
    "TVDGpn4hCSzJ5nkHPLetk8KQBtwaT...", // to (User C)
    50000000 // amount
).send({ feeLimit: 10000000 });

Checking Allowance

Use allowance(address _owner, address _spender) to check the remaining amount of tokens a spender is approved to withdraw from an owner's account.

Confirming Transaction Success

After broadcasting a state-changing transaction, you must confirm its success. Use the getTransactionInfoById API call, passing the transaction ID returned when you broadcast the transaction. A successful call will show a result field of 'SUCCESS'.

Frequently Asked Questions

What is the difference between triggerconstantcontract and triggersmartcontract?
triggerconstantcontract is for read-only calls that do not change the blockchain state and are free. triggersmartcontract is for functions that modify state (like transfers), requiring fees and broadcast.

Why did my transaction fail?
Common reasons include insufficient TRX for energy/bandwidth fees, setting a feeLimit too low, incorrect parameter encoding, or the smart contract logic itself failing (e.g., trying to transfer more tokens than you own).

How do I find the correct contract address for a TRC-20 token?
Always use official sources like the project's website or verified block explorers like Tronscan. Never use an address from an unverified source.

Do I need a full node to interact with contracts?
No, you can use public API endpoints provided by services like TronGrid. For the Shasta testnet, you can use https://api.shasta.trongrid.io.

How do I handle parameter encoding for complex function calls?
Parameters must be ABI-encoded into a hexadecimal string. TronWeb handles this automatically. If using HTTP APIs directly, you will need to use tools to encode parameters correctly.

What is the purpose of the owner_address field in API calls?
This is the address that is initiating the contract call. For constant calls, it can be any valid address. for state-changing calls, it must be the address that holds the tokens and is signing the transaction.