Skip to content
Logo

Fillers

A filler automatically populates fields on a transaction before it is signed and broadcast — things the caller shouldn't have to compute by hand. tronz borrows this pattern directly from alloy: you stack fillers on the ProviderBuilder, and they run on every .send().

Why fillers exist

A TRON transaction needs more than just "to" and "amount". It must reference a recent block (TAPOS, for replay protection and expiry), and contract operations need a fee_limit. Rather than make you fetch the latest block and pick a fee each time, fillers do it for you.

For almost any read/write provider, start here:

use tronz::{LocalSigner, ProviderBuilder, TRONGRID_NILE};
 
# async fn run() -> anyhow::Result<()> {
# let signer = LocalSigner::from_hex("PRIVATE_KEY_HEX")?;
let provider = ProviderBuilder::new()
    .with_recommended_fillers()
    .with_signer(signer)
    .on_grpc(TRONGRID_NILE)
    .await?;
# Ok(()) }

with_recommended_fillers() is shorthand for:

# use tronz::{ProviderBuilder, Trx};
# fn run() -> Result<(), tronz::primitives::AmountError> {
# let _ =
ProviderBuilder::new()
    .with_tapos()
    .with_fee_limit("20".parse::<Trx>()?); // 20 TRX
# Ok(()) }

Available fillers

FillerAdded byFills
TAPOSwith_tapos()The reference block hash + expiration (required before broadcast)
Fee limitwith_fee_limit(Trx)A default fee_limit for contract operations
Signerwith_signer(s)Signs the transaction id before broadcast

The signer is itself part of the filler chain — that's why a provider's ability to .send() is encoded in its type. A builder without .with_signer() produces a provider that can read but not send.

Choosing a fee limit per call

The fee-limit filler sets a default. The fee limit is the maximum TRX you'll spend if you don't have enough staked energy/bandwidth. Override it when needed via the transaction builders (see Transactions), or set a different default:

use tronz::{ProviderBuilder, Trx, TRONGRID_NILE};
 
# async fn run() -> anyhow::Result<()> {
let provider = ProviderBuilder::new()
    .with_tapos()
    .with_fee_limit("100".parse()?)  // higher cap for heavy contract calls
    .on_grpc(TRONGRID_NILE)
    .await?;
# Ok(()) }

Estimating energy first

For contract calls you can estimate the energy cost before sending, so you can pick a sensible fee_limit — analogous to estimate_gas in alloy:

# async fn run(provider: impl tronz::TronProvider, params: tronz::providers::types::TriggerSmartContract) -> anyhow::Result<()> {
let energy = provider.estimate_energy(params).await?;
# Ok(()) }