Solidity bindings with tron_sol!
tron_sol! generates alloy-compatible Solidity types together with a
provider-bound contract instance for TRON. Use it when you have a Solidity
interface or JSON ABI and want typed calls, return values, and events.
The macro is available with the contract feature, which is included in the
default tronz feature set:
use tronz::contract::tron_sol;Generate a typed instance
Add #[sol(rpc)] to generate a provider-bound Instance with one typed method
per Solidity function:
use tronz::contract::tron_sol;
tron_sol! {
#[sol(rpc)]
interface IToken {
function name() external view returns (string);
function balanceOf(address owner) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
}Bind it to an address and provider:
let token = IToken::new(address, provider);
let name = token.name().call().await?;
let balance = token.balanceOf(address).call().await?;The instance is generic over the provider's read capability, so binding to a
read-only SolidityProvider yields typed calls
against solidified state (the .send() write path is simply unavailable there).
Read-only calls use .call().await. When a view branches on msg.sender, set
it with .caller(address) on the call builder; without a signer it defaults to
the zero address. In 0.5, .caller() also selects the sender/owner when that
call is sent as a write. Contract deployments use .from(address) on
DeployBuilder. With a signer-backed provider, state-changing calls use
.send().await and return a
PendingTransaction:
let pending = token.transfer(to, tronz::U256::from(1u64)).send().await?;
let receipt = pending.get_receipt().await?;TRON Address values are accepted for Solidity address parameters. The
0x41 prefix is removed for ABI encoding and restored when decoding a returned
address.
JSON ABI files
The macro also accepts abigen-style JSON ABI input:
use tronz::contract::tron_sol;
tron_sol! {
#[sol(rpc)]
MyContract, "abi/MyContract.json"
}Paths are resolved at compile time. The generated bindings are rebuilt when the ABI changes.
Typed events
An #[sol(rpc)] interface containing events generates a typed filter method:
let transfers = token
.Transfer_filter()
.address(token.address())
.query_tx(tx_id)
.await?;Filters can query one transaction with query_tx, one block with query_block,
or a historical interval with query_range. For ongoing polling, use
EventWatcher, which handles new blocks,
confirmations, filtering, and decoding; users do not need to write a manual
per-block query_block loop.
For complete runnable programs, see:
For contracts whose ABI is only known at runtime, use Interface and
ContractInstance instead of tron_sol!; see the
dynamic ABI example.
