use tronz_primitives::{Address, Bytes, Trx};
use tronz_provider::{
Error as ProviderError, PendingTransaction, TronProvider,
transport::TronTransport as _,
types::{ContractType, TransactionRequest, TriggerSmartContract},
};
use crate::error::{ContractError, Result};
pub struct CallBuilder<P> {
provider: P,
address: Address,
data: Bytes,
call_value: Trx,
call_token_value: Trx,
token_id: i64,
}
impl<P: TronProvider> CallBuilder<P> {
pub(crate) fn new(provider: P, address: Address, data: Bytes) -> Self {
Self {
provider,
address,
data,
call_value: Trx::ZERO,
call_token_value: Trx::ZERO,
token_id: 0,
}
}
#[inline]
pub fn value(mut self, trx: Trx) -> Self {
self.call_value = trx;
self
}
#[inline]
pub fn token(mut self, token_id: i64, value: Trx) -> Self {
self.token_id = token_id;
self.call_token_value = value;
self
}
pub async fn estimate_energy(&self) -> Result<i64> {
let caller = self.provider.signer_address().unwrap_or(self.address);
let params = TriggerSmartContract {
owner_address: caller,
contract_address: self.address,
call_value: self.call_value,
data: self.data.clone(),
call_token_value: self.call_token_value,
token_id: self.token_id,
};
self.provider.estimate_energy(params).await.map_err(ContractError::Provider)
}
pub async fn call(self) -> Result<Bytes> {
let caller = self.provider.signer_address().unwrap_or(self.address);
let params = TriggerSmartContract {
owner_address: caller,
contract_address: self.address,
call_value: self.call_value,
data: self.data,
call_token_value: self.call_token_value,
token_id: self.token_id,
};
let result = self
.provider
.transport()
.trigger_constant_contract(params)
.await
.map_err(|e| ContractError::Provider(ProviderError::Transport(e.into())))?;
if result.revert_reason.is_some() {
return Err(ContractError::Revert(result.output));
}
Ok(result.output)
}
pub async fn send(self) -> Result<PendingTransaction<P>> {
let caller = self
.provider
.signer_address()
.ok_or_else(ProviderError::no_signer)
.map_err(ContractError::Provider)?;
let req = TransactionRequest::default().with_contract(ContractType::TriggerSmartContract(
TriggerSmartContract {
owner_address: caller,
contract_address: self.address,
call_value: self.call_value,
data: self.data,
call_token_value: self.call_token_value,
token_id: self.token_id,
},
));
Ok(self.provider.send_transaction(req).await?)
}
}