feat(contract): return multicall pending transaction (#2044)
* feat(contract): return multicall pending transaction * fix: tests * docs: update CHANGELOG.md
This commit is contained in:
parent
b4b153a364
commit
015eeabea8
|
@ -291,6 +291,8 @@
|
|||
|
||||
### Unreleased
|
||||
|
||||
- Return pending transaction from `Multicall::send`
|
||||
[#2044](https://github.com/gakonst/ethers-rs/pull/2044)
|
||||
- Add abigen to default features
|
||||
[#1684](https://github.com/gakonst/ethers-rs/pull/1684)
|
||||
- Add extra Multicall helper methods
|
||||
|
|
|
@ -4,21 +4,18 @@ use crate::{
|
|||
event::{EthEvent, Event},
|
||||
EthLogDecode,
|
||||
};
|
||||
|
||||
use ethers_core::{
|
||||
abi::{Abi, Detokenize, Error, EventExt, Function, Tokenize},
|
||||
types::{Address, Filter, Selector, ValueOrArray},
|
||||
};
|
||||
use ethers_providers::Middleware;
|
||||
use std::{marker::PhantomData, sync::Arc};
|
||||
|
||||
#[cfg(not(feature = "legacy"))]
|
||||
use ethers_core::types::Eip1559TransactionRequest;
|
||||
#[cfg(feature = "legacy")]
|
||||
use ethers_core::types::TransactionRequest;
|
||||
|
||||
use ethers_providers::Middleware;
|
||||
|
||||
use std::{fmt::Debug, marker::PhantomData, sync::Arc};
|
||||
|
||||
/// A Contract is an abstraction of an executable program on the Ethereum Blockchain.
|
||||
/// It has code (called byte code) as well as allocated long-term memory
|
||||
/// (called storage). Every deployed Contract has an address, which is used to connect
|
||||
|
@ -161,6 +158,7 @@ pub struct Contract<M> {
|
|||
|
||||
impl<M> std::ops::Deref for Contract<M> {
|
||||
type Target = BaseContract;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.base_contract
|
||||
}
|
||||
|
@ -177,19 +175,24 @@ impl<M> Clone for Contract<M> {
|
|||
}
|
||||
|
||||
impl<M> Contract<M> {
|
||||
/// Returns the contract's address
|
||||
/// Returns the contract's address.
|
||||
pub fn address(&self) -> Address {
|
||||
self.address
|
||||
}
|
||||
|
||||
/// Returns a reference to the contract's ABI
|
||||
/// Returns a reference to the contract's ABI.
|
||||
pub fn abi(&self) -> &Abi {
|
||||
&self.base_contract.abi
|
||||
}
|
||||
|
||||
/// Returns a pointer to the contract's client
|
||||
/// Returns a pointer to the contract's client.
|
||||
pub fn client(&self) -> Arc<M> {
|
||||
self.client.clone()
|
||||
Arc::clone(&self.client)
|
||||
}
|
||||
|
||||
/// Returns a reference to the contract's client.
|
||||
pub fn client_ref(&self) -> &M {
|
||||
Arc::as_ref(&self.client)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,10 +304,7 @@ impl<M: Middleware> Contract<M> {
|
|||
///
|
||||
/// Clones `self` internally
|
||||
#[must_use]
|
||||
pub fn at<T: Into<Address>>(&self, address: T) -> Self
|
||||
where
|
||||
M: Clone,
|
||||
{
|
||||
pub fn at<T: Into<Address>>(&self, address: T) -> Self {
|
||||
let mut this = self.clone();
|
||||
this.address = address.into();
|
||||
this
|
||||
|
@ -314,10 +314,7 @@ impl<M: Middleware> Contract<M> {
|
|||
///
|
||||
/// Clones `self` internally
|
||||
#[must_use]
|
||||
pub fn connect<N>(&self, client: Arc<N>) -> Contract<N>
|
||||
where
|
||||
N: Clone,
|
||||
{
|
||||
pub fn connect<N>(&self, client: Arc<N>) -> Contract<N> {
|
||||
Contract { base_contract: self.base_contract.clone(), client, address: self.address }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@ use crate::{
|
|||
};
|
||||
use ethers_core::{
|
||||
abi::{AbiDecode, Detokenize, Function, Token},
|
||||
types::{Address, BlockNumber, Bytes, Chain, NameOrAddress, TxHash, H160, U256},
|
||||
types::{Address, BlockNumber, Bytes, Chain, NameOrAddress, H160, U256},
|
||||
};
|
||||
use ethers_providers::Middleware;
|
||||
use ethers_providers::{Middleware, PendingTransaction};
|
||||
use std::{convert::TryFrom, sync::Arc};
|
||||
|
||||
pub mod multicall_contract;
|
||||
|
@ -223,8 +223,7 @@ impl TryFrom<u8> for MulticallVersion {
|
|||
///
|
||||
/// // `await`ing the `send` method waits for the transaction to be broadcast, which also
|
||||
/// // returns the transaction hash
|
||||
/// let tx_hash = multicall.send().await?;
|
||||
/// let _tx_receipt = PendingTransaction::new(tx_hash, &client).await?;
|
||||
/// let _tx_receipt = multicall.send().await?.await.expect("tx dropped");
|
||||
///
|
||||
/// // you can also query ETH balances of multiple addresses
|
||||
/// let address_1 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".parse::<Address>()?;
|
||||
|
@ -569,7 +568,7 @@ impl<M: Middleware> Multicall<M> {
|
|||
/// .add_call(broadcast_1, false)
|
||||
/// .add_call(broadcast_2, false);
|
||||
///
|
||||
/// let _tx_hash = multicall.send().await?;
|
||||
/// let _tx_receipt = multicall.send().await?.await.expect("tx dropped");
|
||||
///
|
||||
/// # let call_1 = contract.method::<_, String>("getValue", ())?;
|
||||
/// # let call_2 = contract.method::<_, Address>("lastSender", ())?;
|
||||
|
@ -735,7 +734,7 @@ impl<M: Middleware> Multicall<M> {
|
|||
v @ (MulticallVersion::Multicall2 | MulticallVersion::Multicall3) => {
|
||||
let is_v2 = v == MulticallVersion::Multicall2;
|
||||
let call = if is_v2 { self.as_try_aggregate() } else { self.as_aggregate_3() };
|
||||
let return_data = call.call().await?;
|
||||
let return_data = ContractCall::call(&call).await?;
|
||||
self.calls
|
||||
.iter()
|
||||
.zip(return_data.into_iter())
|
||||
|
@ -789,7 +788,7 @@ impl<M: Middleware> Multicall<M> {
|
|||
}
|
||||
|
||||
/// Signs and broadcasts a batch of transactions by using the Multicall contract as proxy,
|
||||
/// returning the transaction hash once the transaction confirms.
|
||||
/// returning the pending transaction.
|
||||
///
|
||||
/// Note: this method will broadcast a transaction from an account, meaning it must have
|
||||
/// sufficient funds for gas and transaction value.
|
||||
|
@ -811,32 +810,18 @@ impl<M: Middleware> Multicall<M> {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub async fn send(&self) -> Result<TxHash, M> {
|
||||
// Broadcast transaction and return the transaction hash
|
||||
// TODO: Can we make this return a PendingTransaction directly instead?
|
||||
// Seems hard due to `returns a value referencing data owned by the current function`
|
||||
|
||||
// running clippy --fix on this throws E0597
|
||||
#[allow(clippy::let_and_return)]
|
||||
let tx_hash = match self.version {
|
||||
MulticallVersion::Multicall => {
|
||||
let call = self.as_aggregate();
|
||||
let hash = *call.send().await?;
|
||||
hash
|
||||
}
|
||||
MulticallVersion::Multicall2 => {
|
||||
let call = self.as_try_aggregate();
|
||||
let hash = *call.send().await?;
|
||||
hash
|
||||
}
|
||||
MulticallVersion::Multicall3 => {
|
||||
let call = self.as_aggregate_3_value();
|
||||
let hash = *call.send().await?;
|
||||
hash
|
||||
}
|
||||
pub async fn send(&self) -> Result<PendingTransaction<'_, M::Provider>, M> {
|
||||
let tx = match self.version {
|
||||
MulticallVersion::Multicall => self.as_aggregate().tx,
|
||||
MulticallVersion::Multicall2 => self.as_try_aggregate().tx,
|
||||
MulticallVersion::Multicall3 => self.as_aggregate_3_value().tx,
|
||||
};
|
||||
|
||||
Ok(tx_hash)
|
||||
self.contract
|
||||
.client_ref()
|
||||
.send_transaction(tx, self.block.map(Into::into))
|
||||
.await
|
||||
.map_err(|e| MulticallError::ContractError(ContractError::MiddlewareError(e)))
|
||||
}
|
||||
|
||||
/// v1
|
||||
|
|
|
@ -491,8 +491,7 @@ mod eth_tests {
|
|||
multicall_send.clear_calls().add_call(broadcast, false).add_call(broadcast2, false);
|
||||
|
||||
// broadcast the transaction and wait for it to be mined
|
||||
let tx_hash = multicall_send.legacy().send().await.unwrap();
|
||||
let _tx_receipt = PendingTransaction::new(tx_hash, client.provider()).await.unwrap();
|
||||
let _tx_receipt = multicall_send.legacy().send().await.unwrap().await.unwrap();
|
||||
|
||||
// Do another multicall to check the updated return values
|
||||
// The `getValue` calls should return the last value we set in the batched broadcast
|
||||
|
|
Loading…
Reference in New Issue