use alloy_json_abi::JsonAbi;
use tronz_abi::TronAbi;
use tronz_primitives::{Address, Bytes, Trx};
use tronz_provider::{
Error as ProviderError, PendingTransaction, TronProvider,
types::{ContractType, CreateSmartContract, TransactionRequest},
};
use crate::error::{ContractError, Result};
pub struct DeployBuilder<P> {
provider: P,
bytecode: Bytes,
abi: DeploymentAbi,
call_value: Trx,
fee_limit: Option<Trx>,
consume_user_resource_percent: i64,
origin_energy_limit: i64,
name: String,
}
enum DeploymentAbi {
Json(JsonAbi),
Tron(TronAbi),
}
impl<P: TronProvider> DeployBuilder<P> {
pub fn new(provider: P, bytecode: impl Into<Bytes>) -> Self {
Self {
provider,
bytecode: bytecode.into(),
abi: DeploymentAbi::Tron(TronAbi::new()),
call_value: Trx::ZERO,
fee_limit: None,
consume_user_resource_percent: 100,
origin_energy_limit: 10_000_000,
name: String::new(),
}
}
#[inline]
pub fn abi(mut self, abi: JsonAbi) -> Self {
self.abi = DeploymentAbi::Json(abi);
self
}
#[inline]
pub fn tron_abi(mut self, abi: TronAbi) -> Self {
self.abi = DeploymentAbi::Tron(abi);
self
}
#[inline]
pub fn value(mut self, trx: Trx) -> Self {
self.call_value = trx;
self
}
#[inline]
pub fn fee_limit(mut self, limit: Trx) -> Self {
self.fee_limit = Some(limit);
self
}
#[inline]
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = name.into();
self
}
#[inline]
pub fn consume_user_resource_percent(mut self, pct: i64) -> Self {
self.consume_user_resource_percent = pct;
self
}
#[inline]
pub fn origin_energy_limit(mut self, limit: i64) -> Self {
self.origin_energy_limit = limit;
self
}
pub async fn deploy(self) -> Result<Address> {
let pending = self.send().await?;
let info = pending.get_receipt().await?;
info.contract_address.ok_or(ContractError::ContractNotDeployed)
}
pub async fn send(self) -> Result<PendingTransaction<P>> {
let owner = self
.provider
.signer_address()
.ok_or_else(ProviderError::no_signer)
.map_err(ContractError::Provider)?;
let abi = match self.abi {
DeploymentAbi::Json(abi) => TronAbi::try_from(abi)?,
DeploymentAbi::Tron(abi) => abi,
};
let mut req = TransactionRequest::default().with_contract(
ContractType::CreateSmartContract(CreateSmartContract {
owner_address: owner,
bytecode: self.bytecode,
abi,
call_value: self.call_value,
consume_user_resource_percent: self.consume_user_resource_percent,
origin_energy_limit: self.origin_energy_limit,
name: self.name,
}),
);
if let Some(limit) = self.fee_limit {
req = req.with_fee_limit(limit);
}
self.provider.send_transaction(req).await.map_err(ContractError::Provider)
}
}