Skip to content
Logo

SolidityNode provider

A TRON SolidityNode serves solidified state — blocks and receipts confirmed by 2/3+ of the super representatives, which can no longer be reorged. Read it through a SolidityProvider, a read-only companion to the FullNode TronProvider.

use tronz::{SolidityProvider, TRONGRID_MAINNET_SOLIDITY};

Read-only by construction

SolidityProvider has no signer, no fillers, and no broadcast path, so trying to mutate state through it is a compile-time error — not a runtime failure. It talks to the WalletSolidity service, which lives on a different endpoint from the FullNode:

NetworkFullNode (TronProvider)SolidityNode (SolidityProvider)
MainnetTRONGRID_MAINNETTRONGRID_MAINNET_SOLIDITY
NileTRONGRID_NILETRONGRID_NILE_SOLIDITY
Local TREhttp://127.0.0.1:50051http://127.0.0.1:50052

Because it only sees irreversible state, a SolidityNode lags the FullNode head by the solidification window (~19 blocks).

Connecting

use tronz::{SolidityProvider, TRONGRID_MAINNET_SOLIDITY};
 
let solidity = SolidityProvider::connect(TRONGRID_MAINNET_SOLIDITY).await?;
 
let head = solidity.get_now_block().await?;
println!("solidified head: {}", head.number);

See Local TRE node for the Docker command and SDK end-to-end test setup.

Use SolidityProvider::builder() when you need custom timeouts, retries, failover endpoints, or a TronGrid API key:

use core::time::Duration;
use tronz::{SolidityProvider, TRONGRID_MAINNET_SOLIDITY};
 
let solidity = SolidityProvider::builder()
    .with_request_timeout(Duration::from_secs(10))
    .maybe_api_key(api_key)
    .connect(TRONGRID_MAINNET_SOLIDITY)
    .await?;

What you can read

The read surface mirrors the FullNode's, restricted to what WalletSolidity exposes: blocks (get_now_block, get_block_by_number), accounts (get_account), transactions and receipts (get_transaction, get_transaction_info, get_transaction_info_by_block_num, get_transaction_count_by_block_num), contract reads (trigger_constant_contract, estimate_energy), and — since 0.4.1 — the governance and stake/delegation queries (list_witnesses, get_paginated_now_witness_list, get_delegated_resource_index, get_can_delegate_max, get_available_unfreeze_count, get_can_withdraw_unfreeze_amount).

let account = solidity.get_account(address).await?;
println!("solidified balance: {} TRX", account.balance);

Typed contract reads

SolidityProvider implements ContractReadProvider, so the same typed handles you use on a FullNode — .trc20(), .trc721(), tron_sol! bindings, and ContractInstance — bind to it and read solidified state. No manual trigger_constant_contract needed:

use tronz::contract::Trc20Ext;
 
let balance = solidity.trc20(usdt).balance_of(who).await?;

See the typed TRC20 example. For a raw constant call, see the constant-call example.

Waiting for finality

The provider polls for solidification. wait_for_transaction returns the receipt once the transaction is irreversible; wait_for_success additionally fails if it solidified but reverted:

let receipt = solidity.wait_for_success(tx_id).await?;
println!("solidified in block {}", receipt.block_number);

Bridging from a broadcast

FullNode inclusion can still be reorged; solidified state cannot. A PendingTransaction returned from a FullNode .send() can bridge straight to finality against a SolidityProvider:

let pending = full.send_trx().to(to).amount(amount).send().await?;
 
// Broadcast on the FullNode, then wait for irreversible success.
let receipt = pending
    .require_success()
    .get_solidified_receipt(solidity)
    .await?;
println!("final in block {}", receipt.block_number);

See the runnable SolidityNode examples.