use alloy_dyn_abi::DynSolValue;
use alloy_json_abi::JsonAbi;
use alloy_primitives::Selector;
use tronz_primitives::{Address, Bytes};
use tronz_provider::TronProvider;
use crate::{call::CallBuilder, deploy::DeployBuilder, error::Result, interface::Interface};
#[derive(Clone)]
pub struct ContractInstance<P> {
address: Address,
provider: P,
interface: Interface,
}
impl<P> ContractInstance<P> {
#[inline]
pub fn new(address: Address, provider: P, interface: Interface) -> Self {
Self { address, provider, interface }
}
#[inline]
pub fn address(&self) -> Address {
self.address
}
#[inline]
pub fn set_address(&mut self, address: Address) {
self.address = address;
}
#[inline]
pub fn at(mut self, address: Address) -> Self {
self.set_address(address);
self
}
#[inline]
pub fn abi(&self) -> &JsonAbi {
self.interface.abi()
}
#[inline]
pub fn provider(&self) -> &P {
&self.provider
}
#[inline]
pub fn interface(&self) -> &Interface {
&self.interface
}
}
impl<P> std::ops::Deref for ContractInstance<P> {
type Target = Interface;
#[inline]
fn deref(&self) -> &Self::Target {
&self.interface
}
}
impl<P> std::fmt::Debug for ContractInstance<P> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ContractInstance").field("address", &self.address).finish()
}
}
impl<P: TronProvider> ContractInstance<P> {
#[inline]
pub fn new_raw(provider: P, address: Address) -> Self {
Self { address, provider, interface: Interface::empty() }
}
#[inline]
pub fn call_raw(&self, data: Bytes) -> CallBuilder<P> {
CallBuilder::new(self.provider.clone(), self.address, data)
}
pub fn function(&self, fn_name: &str, args: &[DynSolValue]) -> Result<CallBuilder<P>> {
let data = self.encode_input(fn_name, args)?;
Ok(CallBuilder::new(self.provider.clone(), self.address, data))
}
pub fn function_from_selector(
&self,
selector: &Selector,
args: &[DynSolValue],
) -> Result<CallBuilder<P>> {
let data = self.encode_input_with_selector(selector, args)?;
Ok(CallBuilder::new(self.provider.clone(), self.address, data))
}
pub async fn call(&self, fn_name: &str, args: &[DynSolValue]) -> Result<Vec<DynSolValue>> {
let output = self.function(fn_name, args)?.call().await?;
self.decode_output(fn_name, &output)
}
pub async fn call_with_selector(
&self,
selector: &Selector,
args: &[DynSolValue],
) -> Result<Vec<DynSolValue>> {
let output = self.function_from_selector(selector, args)?.call().await?;
self.decode_output_with_selector(selector, &output)
}
}
pub trait ContractExt: TronProvider + Sized {
fn contract(&self, address: Address, interface: Interface) -> ContractInstance<Self> {
ContractInstance::new(address, self.clone(), interface)
}
fn deploy(&self, bytecode: impl Into<tronz_primitives::Bytes>) -> DeployBuilder<Self> {
DeployBuilder::new(self.clone(), bytecode)
}
}
impl<P: TronProvider> ContractExt for P {}