Skip to content
Logo

TRC20 tokens

TRC20 is byte-for-byte compatible with the EVM ERC20 ABI, so tronz generates the full interface with alloy's sol! macro — no JSON ABI required. The easiest way in is the Trc20Ext trait, which adds a .trc20() method to any provider.

use tronz::contract::Trc20Ext;

Binding to a token

# async fn run(provider: impl tronz::TronProvider + Clone) -> anyhow::Result<()> {
use tronz::contract::Trc20Ext;
 
let usdt: tronz::Address = "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t".parse()?;
let token = provider.trc20(usdt);
# Ok(()) }

provider.trc20(address) returns a Trc20Instance bound to that contract.

Reading token data

All reads are constant calls — no signer required:

# async fn run(token: tronz::contract::Trc20Instance<impl tronz::TronProvider>, who: tronz::Address) -> anyhow::Result<()> {
let name = token.name().await?;             // String
let symbol = token.symbol().await?;         // String
let decimals = token.decimals().await?;     // u8
let supply = token.total_supply().await?;   // U256
let balance = token.balance_of(who).await?; // U256
# Ok(()) }

balance_of, total_supply, and allowance return raw U256 values. Apply the token's decimals() to display them in human terms.

Transferring tokens

Writes require a signer on the provider and consume energy. transfer returns a PendingTransaction:

use tronz::U256;
 
# async fn run(token: tronz::contract::Trc20Instance<impl tronz::TronProvider>, to: tronz::Address) -> anyhow::Result<()> {
let pending = token.transfer(to, U256::from(1_000_000u64)).await?;
 
let info = pending.get_receipt().await?;
println!("status         : {:?}", info.status);
println!("contract result: {:?}", info.contract_result);
if let Some(reason) = &info.revert_reason {
    println!("revert reason  : {reason}");
}
# Ok(()) }

Approvals

use tronz::U256;
 
# async fn run(token: tronz::contract::Trc20Instance<impl tronz::TronProvider>, owner: tronz::Address, spender: tronz::Address) -> anyhow::Result<()> {
// Approve a spender.
token.approve(spender, U256::from(1_000_000u64)).await?;
 
// Check the current allowance.
let allowed = token.allowance(owner, spender).await?;
 
// Move tokens you've been approved for.
token.transfer_from(owner, spender, U256::from(500_000u64)).await?;
# Ok(()) }

Encoding helpers

If you need the raw calldata (e.g. to build a transaction manually or estimate energy), the trc20 module exposes encode/decode functions and the generated ITRC20 interface:

use tronz::contract::trc20::{encode_transfer, encode_balance_of};
use tronz::U256;
 
# fn run(to: tronz::Address, who: tronz::Address) {
let calldata = encode_transfer(to, U256::from(1u64));
let bal_call = encode_balance_of(who);
# }

See the full runnable version in Examples → TRC20.