Skip to content
Logo

Example: trc20_decode_transfer_event

To run this example:

  • Clone the examples repository: git clone https://github.com/throgxyz/examples.git
  • Run: cargo run -p examples-trc20 --example trc20_decode_transfer_event
//! Decode `Transfer(address,address,uint256)` logs from a confirmed receipt.
//!
//! TRC20 events are EVM-compatible. The `Transfer` event signature hash is the
//! same as ERC-20: `keccak256("Transfer(address,address,uint256)")`.
//!
//! This example fetches a known transaction and decodes all Transfer events in
//! its receipt using the static `sol!` binding from `tronz_contract`.
//!
//! No private key required (read-only).
//!
//! Required env:
//!   TRON_TX_ID  — hex transaction id that emitted Transfer events
//!
//! Optional env:
//!   TRON_API_KEY — TronGrid API key
//!
//! ```bash
//! TRON_TX_ID=<txid> cargo run -p examples-trc20 --example trc20_decode_transfer_event
//! ```
 
// Re-use the static ABI binding from tronz_contract.
use tronz::{
    ProviderBuilder, TRONGRID_NILE, TronProvider,
    contract::{SolEvent, decode_logs, trc20::ITRC20},
    primitives::B256,
};
 
#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let tx_id_hex = std::env::var("TRON_TX_ID").expect("TRON_TX_ID env var required");
    let api_key = std::env::var("TRON_API_KEY").ok();
 
    let tx_id_bytes = hex::decode(tx_id_hex.trim_start_matches("0x"))?;
    let tx_id: B256 = B256::from_slice(&tx_id_bytes);
 
    let provider = ProviderBuilder::new().maybe_api_key(api_key).on_grpc(TRONGRID_NILE).await?;
 
    // ── Fetch receipt ─────────────────────────────────────────────────────────
 
    let info = provider
        .get_transaction_info(tx_id)
        .await?
        .ok_or_else(|| anyhow::anyhow!("transaction not found or not yet confirmed"))?;
    println!("=== Receipt ===");
    println!("  tx_id  : 0x{}", hex::encode(tx_id));
    println!("  status : {:?}", info.status);
    println!("  logs   : {}", info.logs.len());
 
    // ── Decode Transfer events ────────────────────────────────────────────────
    //
    // `decode_logs::<E>` skips logs that don't match and returns Results for
    // those that do. The `Transfer` type was generated by `sol!` in the
    // tronz_contract crate.
 
    let transfer_topic0 = ITRC20::Transfer::SIGNATURE_HASH;
    println!("\n=== Transfer event signature ===");
    println!("  topic0 : 0x{}", hex::encode(transfer_topic0));
 
    let transfers: Vec<_> =
        decode_logs::<ITRC20::Transfer>(&info.logs).collect::<Result<_, _>>()?;
 
    if transfers.is_empty() {
        println!("\n  no Transfer events in this transaction");
        return Ok(());
    }
 
    println!("\n=== Transfer events ({}) ===", transfers.len());
    for (i, t) in transfers.iter().enumerate() {
        // The `from` / `to` fields are `alloy_primitives::Address` (20 bytes).
        // Convert to tronz::Address to display in base58check.
        let from: tronz::Address = t.from.into();
        let to: tronz::Address = t.to.into();
        println!("  [{i}] from  : {from}");
        println!("       to    : {to}");
        println!("       value : {}", t.value);
    }
 
    Ok(())
}

Find the source code on GitHub here.