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:
# async fn run(provider: impl tronz::TronProvider, address: tronz::Address) -> anyhow::Result<()> {
let token = IToken::new(address, provider);
let name = token.name().call().await?;
let balance = token.balanceOf(address).call().await?;
# Ok(()) }Read-only calls use .call().await. With a signer-backed provider,
state-changing calls use .send().await and return a
PendingTransaction:
# async fn run(token: IToken::Instance<impl tronz::TronProvider>, to: tronz::Address) -> anyhow::Result<()> {
let pending = token.transfer(to, tronz::U256::from(1u64)).send().await?;
let receipt = pending.get_receipt().await?;
# Ok(()) }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:
# async fn run(token: IToken::Instance<impl tronz::TronProvider>, tx_id: tronz::primitives::TxId) -> anyhow::Result<()> {
let transfers = token
.Transfer_filter()
.address(token.address())
.query_tx(tx_id)
.await?;
# Ok(()) }Filters can query one transaction with query_tx or all transaction receipts
in a block with query_block. TRON does not expose Ethereum's eth_getLogs, so
scan a block range by calling query_block for each block.
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.
