Skip to content
Logo

Example: contract_estimate_energy

To run this example:

  • Clone the examples repository: git clone https://github.com/throgxyz/examples.git
  • Run: cargo run -p examples-contracts --example contract_estimate_energy
//! Estimate energy consumption before executing a contract call.
//!
//! `estimate_energy` simulates the call and returns the energy it would
//! consume. Use this to set an appropriate `fee_limit` before sending.
//!
//! Energy cost in TRX = `energy_used × dynamic_energy_price / 1_000_000`
//!
//! No private key required for the estimate itself. A signer is optional but
//! improves accuracy (the simulation uses the signer's address as caller).
//!
//! Required env:
//!   TRON_CONTRACT — TRC20 contract address to simulate a call against
//!
//! Optional env:
//!   TRON_API_KEY  — TronGrid API key
//!   TRON_ADDRESS  — caller address for the simulation (defaults to contract addr)
//!
//! ```bash
//! TRON_CONTRACT=<addr> cargo run -p examples-contracts --example contract_estimate_energy
//! ```
 
use tronz::{
    ProviderBuilder, TRONGRID_NILE, TronProvider, U256,
    contract::{ContractExt, Interface, SolCall, trc20::ITRC20},
};
 
#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let contract_str = std::env::var("TRON_CONTRACT").expect("TRON_CONTRACT env var required");
    let api_key = std::env::var("TRON_API_KEY").ok();
 
    let contract: tronz::Address = contract_str.parse()?;
 
    let provider = ProviderBuilder::new().maybe_api_key(api_key).on_grpc(TRONGRID_NILE).await?;
 
    // ── Estimate energy for `balanceOf` ───────────────────────────────────────
    //
    // `balanceOf` is a view function — it reads state but doesn't modify it.
    // The energy estimate is usually small (~700 energy units for USDT).
 
    let calldata: tronz::primitives::Bytes = ITRC20::balanceOfCall {
        account: contract.into(), // query the contract's own balance
    }
    .abi_encode()
    .into();
 
    let instance = provider.contract(contract, Interface::empty());
    let energy_estimate = instance.call_raw(calldata).estimate_energy().await?;
    println!("=== Energy estimate ===");
    println!("  function   : balanceOf(address)");
    println!("  energy     : {energy_estimate} units");
 
    // Convert to approximate TRX cost.
    // Dynamic energy price varies; 420 sun/energy is a typical ballpark.
    let approx_sun = energy_estimate * 420;
    println!(
        "  approx fee : {} sun  (~{:.6} TRX at 420 sun/energy)",
        approx_sun,
        approx_sun as f64 / 1_000_000.0
    );
 
    // ── Estimate energy for `transfer` ────────────────────────────────────────
    //
    // `transfer` is a state-changing function and costs more energy.
    // The estimate uses the current state; actual cost may differ slightly.
 
    let transfer_calldata: tronz::primitives::Bytes = ITRC20::transferCall {
        to: contract.into(), // dummy: transfer to self
        amount: U256::from(1u64),
    }
    .abi_encode()
    .into();
 
    let transfer_energy = instance.call_raw(transfer_calldata).estimate_energy().await?;
    println!("\n  function   : transfer(address,uint256)");
    println!("  energy     : {transfer_energy} units");
 
    let approx_sun2 = transfer_energy * 420;
    println!(
        "  approx fee : {} sun  (~{:.6} TRX at 420 sun/energy)",
        approx_sun2,
        approx_sun2 as f64 / 1_000_000.0
    );
 
    // ── Chain parameters ──────────────────────────────────────────────────────
    //
    // The actual energy price is stored in chain parameters.
 
    let params = provider.chain_parameters().await?;
    if let Some(price) = params.get("getEnergyFee") {
        println!("\n=== Current energy price ===");
        println!("  getEnergyFee  : {price} sun/energy");
        println!(
            "  transfer cost : {} sun  ({:.6} TRX)",
            transfer_energy * price,
            transfer_energy as f64 * *price as f64 / 1_000_000.0
        );
    }
 
    Ok(())
}

Find the source code on GitHub here.