Skip to content
Logo

Transaction lifecycle

A write goes through four stages. The builders and PendingTransaction hide most of the work, but it helps to know what happens under the hood.

 build → fill + sign → broadcast → confirm
builder    on send()    on send()   get_receipt()
  1. Build. A builder (e.g. send_trx()) collects your fields. No I/O yet.
  2. Fill + sign. On .send(), the filler chain derives fields such as fee_limit, then the wallet signs the transaction id. The node-built transaction already contains TAPOS.
  3. Broadcast. ...the signed transaction is sent to the node. .send() resolves to a PendingTransaction.
  4. Confirm. Await the receipt with .get_receipt().

Sending

let pending = provider
    .send_trx()
    .to(to)
    .amount(Trx::from_sun(1_000_000)?)
    .send()
    .await?;
 
// The transaction id is available immediately after broadcast.
println!("tx_id: {:#x}", pending.tx_id());

Waiting for confirmation

get_receipt() polls the node until the transaction is indexed (every 3 seconds, up to ~60 seconds), then returns the TransactionInfo receipt:

let info = pending.get_receipt().await?;
 
println!("block       : {}", info.block_number);
println!("status      : {:?}", info.status);       // Success | Failed
println!("energy used : {}", info.energy_usage);
println!("net used    : {}", info.net_usage);
println!("net fee     : {} sun", info.net_fee.as_sun());

By default, get_receipt() returns a confirmed receipt whether execution succeeded or failed. Add require_success() to turn a failed execution into PendingTransactionError::Reverted. Configure polling with with_poll_interval() and the wall-clock deadline with with_timeout():

use std::time::Duration;
 
let info = pending
    .with_poll_interval(Duration::from_secs(2))
    .with_timeout(Duration::from_secs(60))
    .require_success()
    .get_receipt()
    .await?;

If the transaction isn't confirmed within the limit, you get PendingTransactionError::ConfirmationTimeout — the transaction may still confirm later, so you can re-query it with get_transaction_info(tx_id) (which returns None until it is indexed).

Reading the receipt

TransactionInfo carries everything about the confirmed transaction:

FieldMeaning
statusTxStatus::Success or Failed
block_number / block_timestampWhere/when it was included
energy_usage / energy_feeEnergy consumed and TRX burned for energy
net_usage / net_feeBandwidth consumed and TRX burned for bandwidth
contract_resultDetailed VM result (Success, Revert, OutOfEnergy, …)
revert_reasonDecoded revert string, if the contract reverted
logsEmitted event logs
contract_addressSet for contract-deploy transactions

For contract calls, always check both status and contract_result — a transaction can be on-chain (status: Success at the network level) while the contract itself reverted.