use crate::{Contract, ContractError};
use ethers_core::{
abi::{Abi, Tokenize},
types::{transaction::eip2718::TypedTransaction, BlockNumber, Bytes, TransactionRequest},
};
use ethers_providers::Middleware;
#[cfg(not(feature = "legacy"))]
use ethers_core::types::Eip1559TransactionRequest;
use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct Deployer<M> {
pub tx: TypedTransaction,
abi: Abi,
client: Arc<M>,
confs: usize,
block: BlockNumber,
}
impl<M: Middleware> Deployer<M> {
pub fn confirmations<T: Into<usize>>(mut self, confirmations: T) -> Self {
self.confs = confirmations.into();
self
}
pub fn block<T: Into<BlockNumber>>(mut self, block: T) -> Self {
self.block = block.into();
self
}
pub fn legacy(mut self) -> Self {
self.tx = match self.tx {
TypedTransaction::Eip1559(inner) => {
let tx: TransactionRequest = inner.into();
TypedTransaction::Legacy(tx)
}
other => other,
};
self
}
pub async fn send(self) -> Result<Contract<M>, ContractError<M>> {
let pending_tx = self
.client
.send_transaction(self.tx, Some(self.block.into()))
.await
.map_err(ContractError::MiddlewareError)?;
let receipt = pending_tx
.confirmations(self.confs)
.await
.map_err(|_| ContractError::ContractNotDeployed)?
.ok_or(ContractError::ContractNotDeployed)?;
let address = receipt
.contract_address
.ok_or(ContractError::ContractNotDeployed)?;
let contract = Contract::new(address, self.abi.clone(), self.client);
Ok(contract)
}
pub fn abi(&self) -> &Abi {
&self.abi
}
pub fn client(&self) -> &M {
&self.client
}
}
#[derive(Debug, Clone)]
pub struct ContractFactory<M> {
client: Arc<M>,
abi: Abi,
bytecode: Bytes,
}
impl<M: Middleware> ContractFactory<M> {
pub fn new(abi: Abi, bytecode: Bytes, client: Arc<M>) -> Self {
Self {
client,
abi,
bytecode,
}
}
pub fn deploy<T: Tokenize>(self, constructor_args: T) -> Result<Deployer<M>, ContractError<M>> {
let params = constructor_args.into_tokens();
let data: Bytes = match (self.abi.constructor(), params.is_empty()) {
(None, false) => {
return Err(ContractError::ConstructorError);
}
(None, true) => self.bytecode.clone(),
(Some(constructor), _) => constructor
.encode_input(self.bytecode.to_vec(), ¶ms)?
.into(),
};
#[cfg(feature = "legacy")]
let tx = TransactionRequest {
to: None,
data: Some(data),
..Default::default()
};
#[cfg(not(feature = "legacy"))]
let tx = Eip1559TransactionRequest {
to: None,
data: Some(data),
..Default::default()
};
let tx = tx.into();
Ok(Deployer {
client: Arc::clone(&self.client), abi: self.abi,
tx,
confs: 1,
block: BlockNumber::Latest,
})
}
}