Refactor factories to use `Borrow<M>` (#2103)
* refactor: abstract factories over Borrow * chore: changelog * fix: docs for factory and type aliases
This commit is contained in:
parent
14be402f40
commit
2607c67ca0
|
@ -299,6 +299,8 @@
|
||||||
|
|
||||||
### Unreleased
|
### Unreleased
|
||||||
|
|
||||||
|
- Make `Factory` objects generic over the borrow trait, to allow non-arc mware
|
||||||
|
[#2103](https://github.com/gakonst/ethers-rs/pull/2103)
|
||||||
- Make `Contract` objects generic over the borrow trait, to allow non-arc mware
|
- Make `Contract` objects generic over the borrow trait, to allow non-arc mware
|
||||||
[#2082](https://github.com/gakonst/ethers-rs/pull/2082)
|
[#2082](https://github.com/gakonst/ethers-rs/pull/2082)
|
||||||
- Return pending transaction from `Multicall::send`
|
- Return pending transaction from `Multicall::send`
|
||||||
|
|
|
@ -243,7 +243,7 @@ where
|
||||||
/// Returns an [`Event`](crate::builders::Event) builder for the provided event.
|
/// Returns an [`Event`](crate::builders::Event) builder for the provided event.
|
||||||
/// This function operates in a static context, then it does not require a `self`
|
/// This function operates in a static context, then it does not require a `self`
|
||||||
/// to reference to instantiate an [`Event`](crate::builders::Event) builder.
|
/// to reference to instantiate an [`Event`](crate::builders::Event) builder.
|
||||||
pub fn event_of_type<D: EthEvent>(client: &Arc<M>) -> Event<M, D> {
|
pub fn event_of_type<D: EthEvent>(client: &M) -> Event<M, D> {
|
||||||
Event {
|
Event {
|
||||||
provider: client,
|
provider: client,
|
||||||
filter: Filter::new().event(&D::abi_signature()),
|
filter: Filter::new().event(&D::abi_signature()),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{Contract, ContractError};
|
use crate::{ContractError, ContractInstance};
|
||||||
|
|
||||||
use ethers_core::{
|
use ethers_core::{
|
||||||
abi::{Abi, Token, Tokenize},
|
abi::{Abi, Token, Tokenize},
|
||||||
|
@ -15,33 +15,62 @@ use ethers_providers::{
|
||||||
#[cfg(not(feature = "legacy"))]
|
#[cfg(not(feature = "legacy"))]
|
||||||
use ethers_core::types::Eip1559TransactionRequest;
|
use ethers_core::types::Eip1559TransactionRequest;
|
||||||
|
|
||||||
use std::{marker::PhantomData, sync::Arc};
|
use std::{borrow::Borrow, marker::PhantomData, sync::Arc};
|
||||||
|
|
||||||
/// Helper which manages the deployment transaction of a smart contract.
|
/// `ContractDeployer` is a [`ContractDeploymentTx`] object with an
|
||||||
|
/// [`Arc`] middleware. This type alias exists to preserve backwards
|
||||||
|
/// compatibility with less-abstract Contracts.
|
||||||
///
|
///
|
||||||
/// This is just a wrapper type for [Deployer] with an additional type to convert the [Contract]
|
/// For full usage docs, see [`ContractDeploymentTx`].
|
||||||
/// that the deployer returns when sending the transaction.
|
pub type ContractDeployer<M, C> = ContractDeploymentTx<Arc<M>, M, C>;
|
||||||
|
|
||||||
|
/// `ContractFactory` is a [`DeploymentTxFactory`] object with an
|
||||||
|
/// [`Arc`] middleware. This type alias exists to preserve backwards
|
||||||
|
/// compatibility with less-abstract Contracts.
|
||||||
|
///
|
||||||
|
/// For full usage docs, see [`DeploymentTxFactory`].
|
||||||
|
pub type ContractFactory<M> = DeploymentTxFactory<Arc<M>, M>;
|
||||||
|
|
||||||
|
/// Helper which manages the deployment transaction of a smart contract. It
|
||||||
|
/// wraps a deployment transaction, and retrieves the contract address output
|
||||||
|
/// by it.
|
||||||
|
///
|
||||||
|
/// Currently, we recommend using the [`ContractDeployer`] type alias.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[must_use = "Deployer does nothing unless you `send` it"]
|
#[must_use = "DeploymentTx does nothing unless you `send` it"]
|
||||||
pub struct ContractDeployer<M, C> {
|
pub struct ContractDeploymentTx<B, M, C> {
|
||||||
/// the actual deployer, exposed for overriding the defaults
|
/// the actual deployer, exposed for overriding the defaults
|
||||||
pub deployer: Deployer<M>,
|
pub deployer: Deployer<B, M>,
|
||||||
/// marker for the `Contract` type to create afterwards
|
/// marker for the `Contract` type to create afterwards
|
||||||
///
|
///
|
||||||
/// this type will be used to construct it via `From::from(Contract)`
|
/// this type will be used to construct it via `From::from(Contract)`
|
||||||
_contract: PhantomData<C>,
|
_contract: PhantomData<C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M, C> Clone for ContractDeployer<M, C> {
|
impl<B, M, C> Clone for ContractDeploymentTx<B, M, C>
|
||||||
|
where
|
||||||
|
B: Clone,
|
||||||
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
ContractDeployer { deployer: self.deployer.clone(), _contract: self._contract }
|
ContractDeploymentTx { deployer: self.deployer.clone(), _contract: self._contract }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Middleware, C: From<Contract<M>>> ContractDeployer<M, C> {
|
impl<B, M, C> From<Deployer<B, M>> for ContractDeploymentTx<B, M, C> {
|
||||||
/// Create a new instance of this [ContractDeployer]
|
fn from(deployer: Deployer<B, M>) -> Self {
|
||||||
pub fn new(deployer: Deployer<M>) -> Self {
|
Self { deployer, _contract: PhantomData }
|
||||||
Self { deployer, _contract: Default::default() }
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B, M, C> ContractDeploymentTx<B, M, C>
|
||||||
|
where
|
||||||
|
B: Borrow<M> + Clone,
|
||||||
|
M: Middleware,
|
||||||
|
C: From<ContractInstance<B, M>>,
|
||||||
|
{
|
||||||
|
/// Create a new instance of this from a deployer.
|
||||||
|
pub fn new(deployer: Deployer<B, M>) -> Self {
|
||||||
|
Self { deployer, _contract: PhantomData }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the number of confirmations to wait for the contract deployment transaction
|
/// Sets the number of confirmations to wait for the contract deployment transaction
|
||||||
|
@ -148,7 +177,7 @@ impl<M: Middleware, C: From<Contract<M>>> ContractDeployer<M, C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a pointer to the deployer's client
|
/// Returns a pointer to the deployer's client
|
||||||
pub fn client(&self) -> Arc<M> {
|
pub fn client(&self) -> &M {
|
||||||
self.deployer.client()
|
self.deployer.client()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,16 +185,20 @@ impl<M: Middleware, C: From<Contract<M>>> ContractDeployer<M, C> {
|
||||||
/// Helper which manages the deployment transaction of a smart contract
|
/// Helper which manages the deployment transaction of a smart contract
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[must_use = "Deployer does nothing unless you `send` it"]
|
#[must_use = "Deployer does nothing unless you `send` it"]
|
||||||
pub struct Deployer<M> {
|
pub struct Deployer<B, M> {
|
||||||
/// The deployer's transaction, exposed for overriding the defaults
|
/// The deployer's transaction, exposed for overriding the defaults
|
||||||
pub tx: TypedTransaction,
|
pub tx: TypedTransaction,
|
||||||
abi: Abi,
|
abi: Abi,
|
||||||
client: Arc<M>,
|
client: B,
|
||||||
confs: usize,
|
confs: usize,
|
||||||
block: BlockNumber,
|
block: BlockNumber,
|
||||||
|
_m: PhantomData<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M> Clone for Deployer<M> {
|
impl<B, M> Clone for Deployer<B, M>
|
||||||
|
where
|
||||||
|
B: Clone,
|
||||||
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Deployer {
|
Deployer {
|
||||||
tx: self.tx.clone(),
|
tx: self.tx.clone(),
|
||||||
|
@ -173,11 +206,16 @@ impl<M> Clone for Deployer<M> {
|
||||||
client: self.client.clone(),
|
client: self.client.clone(),
|
||||||
confs: self.confs,
|
confs: self.confs,
|
||||||
block: self.block,
|
block: self.block,
|
||||||
|
_m: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Middleware> Deployer<M> {
|
impl<B, M> Deployer<B, M>
|
||||||
|
where
|
||||||
|
B: Borrow<M> + Clone,
|
||||||
|
M: Middleware,
|
||||||
|
{
|
||||||
/// Sets the number of confirmations to wait for the contract deployment transaction
|
/// Sets the number of confirmations to wait for the contract deployment transaction
|
||||||
pub fn confirmations<T: Into<usize>>(mut self, confirmations: T) -> Self {
|
pub fn confirmations<T: Into<usize>>(mut self, confirmations: T) -> Self {
|
||||||
self.confs = confirmations.into();
|
self.confs = confirmations.into();
|
||||||
|
@ -206,6 +244,7 @@ impl<M: Middleware> Deployer<M> {
|
||||||
/// Note: this function _does not_ send a transaction from your account
|
/// Note: this function _does not_ send a transaction from your account
|
||||||
pub async fn call(&self) -> Result<(), ContractError<M>> {
|
pub async fn call(&self) -> Result<(), ContractError<M>> {
|
||||||
self.client
|
self.client
|
||||||
|
.borrow()
|
||||||
.call(&self.tx, Some(self.block.into()))
|
.call(&self.tx, Some(self.block.into()))
|
||||||
.await
|
.await
|
||||||
.map_err(ContractError::MiddlewareError)?;
|
.map_err(ContractError::MiddlewareError)?;
|
||||||
|
@ -220,13 +259,13 @@ impl<M: Middleware> Deployer<M> {
|
||||||
///
|
///
|
||||||
/// Note: this function _does not_ send a transaction from your account
|
/// Note: this function _does not_ send a transaction from your account
|
||||||
pub fn call_raw(&self) -> CallBuilder<'_, M::Provider> {
|
pub fn call_raw(&self) -> CallBuilder<'_, M::Provider> {
|
||||||
self.client.provider().call_raw(&self.tx).block(self.block.into())
|
self.client.borrow().provider().call_raw(&self.tx).block(self.block.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Broadcasts the contract deployment transaction and after waiting for it to
|
/// Broadcasts the contract deployment transaction and after waiting for it to
|
||||||
/// be sufficiently confirmed (default: 1), it returns a [`Contract`](crate::Contract)
|
/// be sufficiently confirmed (default: 1), it returns a [`Contract`](crate::Contract)
|
||||||
/// struct at the deployed contract's address.
|
/// struct at the deployed contract's address.
|
||||||
pub async fn send(self) -> Result<Contract<M>, ContractError<M>> {
|
pub async fn send(self) -> Result<ContractInstance<B, M>, ContractError<M>> {
|
||||||
let (contract, _) = self.send_with_receipt().await?;
|
let (contract, _) = self.send_with_receipt().await?;
|
||||||
Ok(contract)
|
Ok(contract)
|
||||||
}
|
}
|
||||||
|
@ -237,9 +276,10 @@ impl<M: Middleware> Deployer<M> {
|
||||||
/// and the corresponding [`TransactionReceipt`](ethers_core::types::TransactionReceipt).
|
/// and the corresponding [`TransactionReceipt`](ethers_core::types::TransactionReceipt).
|
||||||
pub async fn send_with_receipt(
|
pub async fn send_with_receipt(
|
||||||
self,
|
self,
|
||||||
) -> Result<(Contract<M>, TransactionReceipt), ContractError<M>> {
|
) -> Result<(ContractInstance<B, M>, TransactionReceipt), ContractError<M>> {
|
||||||
let pending_tx = self
|
let pending_tx = self
|
||||||
.client
|
.client
|
||||||
|
.borrow()
|
||||||
.send_transaction(self.tx, Some(self.block.into()))
|
.send_transaction(self.tx, Some(self.block.into()))
|
||||||
.await
|
.await
|
||||||
.map_err(ContractError::MiddlewareError)?;
|
.map_err(ContractError::MiddlewareError)?;
|
||||||
|
@ -252,7 +292,7 @@ impl<M: Middleware> Deployer<M> {
|
||||||
.ok_or(ContractError::ContractNotDeployed)?;
|
.ok_or(ContractError::ContractNotDeployed)?;
|
||||||
let address = receipt.contract_address.ok_or(ContractError::ContractNotDeployed)?;
|
let address = receipt.contract_address.ok_or(ContractError::ContractNotDeployed)?;
|
||||||
|
|
||||||
let contract = Contract::new(address, self.abi.clone(), self.client);
|
let contract = ContractInstance::new(address, self.abi.clone(), self.client.clone());
|
||||||
Ok((contract, receipt))
|
Ok((contract, receipt))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,8 +302,8 @@ impl<M: Middleware> Deployer<M> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a pointer to the deployer's client
|
/// Returns a pointer to the deployer's client
|
||||||
pub fn client(&self) -> Arc<M> {
|
pub fn client(&self) -> &M {
|
||||||
self.client.clone()
|
self.client.borrow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,31 +349,43 @@ impl<M: Middleware> Deployer<M> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ContractFactory<M> {
|
pub struct DeploymentTxFactory<B, M> {
|
||||||
client: Arc<M>,
|
client: B,
|
||||||
abi: Abi,
|
abi: Abi,
|
||||||
bytecode: Bytes,
|
bytecode: Bytes,
|
||||||
|
_m: PhantomData<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M> Clone for ContractFactory<M> {
|
impl<B, M> Clone for DeploymentTxFactory<B, M>
|
||||||
|
where
|
||||||
|
B: Clone,
|
||||||
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
ContractFactory {
|
DeploymentTxFactory {
|
||||||
client: self.client.clone(),
|
client: self.client.clone(),
|
||||||
abi: self.abi.clone(),
|
abi: self.abi.clone(),
|
||||||
bytecode: self.bytecode.clone(),
|
bytecode: self.bytecode.clone(),
|
||||||
|
_m: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Middleware> ContractFactory<M> {
|
impl<B, M> DeploymentTxFactory<B, M>
|
||||||
|
where
|
||||||
|
B: Borrow<M> + Clone,
|
||||||
|
M: Middleware,
|
||||||
|
{
|
||||||
/// Creates a factory for deployment of the Contract with bytecode, and the
|
/// Creates a factory for deployment of the Contract with bytecode, and the
|
||||||
/// constructor defined in the abi. The client will be used to send any deployment
|
/// constructor defined in the abi. The client will be used to send any deployment
|
||||||
/// transaction.
|
/// transaction.
|
||||||
pub fn new(abi: Abi, bytecode: Bytes, client: Arc<M>) -> Self {
|
pub fn new(abi: Abi, bytecode: Bytes, client: B) -> Self {
|
||||||
Self { client, abi, bytecode }
|
Self { client, abi, bytecode, _m: PhantomData }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deploy_tokens(self, params: Vec<Token>) -> Result<Deployer<M>, ContractError<M>> {
|
pub fn deploy_tokens(self, params: Vec<Token>) -> Result<Deployer<B, M>, ContractError<M>>
|
||||||
|
where
|
||||||
|
B: Clone,
|
||||||
|
{
|
||||||
// Encode the constructor args & concatenate with the bytecode if necessary
|
// Encode the constructor args & concatenate with the bytecode if necessary
|
||||||
let data: Bytes = match (self.abi.constructor(), params.is_empty()) {
|
let data: Bytes = match (self.abi.constructor(), params.is_empty()) {
|
||||||
(None, false) => return Err(ContractError::ConstructorError),
|
(None, false) => return Err(ContractError::ConstructorError),
|
||||||
|
@ -353,11 +405,12 @@ impl<M: Middleware> ContractFactory<M> {
|
||||||
let tx = tx.into();
|
let tx = tx.into();
|
||||||
|
|
||||||
Ok(Deployer {
|
Ok(Deployer {
|
||||||
client: Arc::clone(&self.client), // cheap clone behind the arc
|
client: self.client.clone(),
|
||||||
abi: self.abi,
|
abi: self.abi,
|
||||||
tx,
|
tx,
|
||||||
confs: 1,
|
confs: 1,
|
||||||
block: BlockNumber::Latest,
|
block: BlockNumber::Latest,
|
||||||
|
_m: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,7 +422,10 @@ impl<M: Middleware> ContractFactory<M> {
|
||||||
/// 1. If there are no constructor arguments, you should pass `()` as the argument.
|
/// 1. If there are no constructor arguments, you should pass `()` as the argument.
|
||||||
/// 1. The default poll duration is 7 seconds.
|
/// 1. The default poll duration is 7 seconds.
|
||||||
/// 1. The default number of confirmations is 1 block.
|
/// 1. The default number of confirmations is 1 block.
|
||||||
pub fn deploy<T: Tokenize>(self, constructor_args: T) -> Result<Deployer<M>, ContractError<M>> {
|
pub fn deploy<T: Tokenize>(
|
||||||
|
self,
|
||||||
|
constructor_args: T,
|
||||||
|
) -> Result<Deployer<B, M>, ContractError<M>> {
|
||||||
self.deploy_tokens(constructor_args.into_tokens())
|
self.deploy_tokens(constructor_args.into_tokens())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ mod error;
|
||||||
pub use error::EthError;
|
pub use error::EthError;
|
||||||
|
|
||||||
mod factory;
|
mod factory;
|
||||||
pub use factory::{ContractDeployer, ContractFactory};
|
pub use factory::{ContractDeployer, ContractDeploymentTx, ContractFactory, DeploymentTxFactory};
|
||||||
|
|
||||||
mod event;
|
mod event;
|
||||||
pub use event::{EthEvent, Event};
|
pub use event::{EthEvent, Event};
|
||||||
|
|
Loading…
Reference in New Issue