Skip to content
This repository was archived by the owner on Oct 19, 2024. It is now read-only.

Commit 015eeab

Browse files
authored
feat(contract): return multicall pending transaction (#2044)
* feat(contract): return multicall pending transaction * fix: tests * docs: update CHANGELOG.md
1 parent b4b153a commit 015eeab

File tree

4 files changed

+33
-50
lines changed

4 files changed

+33
-50
lines changed

Diff for: CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,8 @@
291291

292292
### Unreleased
293293

294+
- Return pending transaction from `Multicall::send`
295+
[#2044](https://github.com/gakonst/ethers-rs/pull/2044)
294296
- Add abigen to default features
295297
[#1684](https://github.com/gakonst/ethers-rs/pull/1684)
296298
- Add extra Multicall helper methods

Diff for: ethers-contract/src/contract.rs

+14-17
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,18 @@ use crate::{
44
event::{EthEvent, Event},
55
EthLogDecode,
66
};
7-
87
use ethers_core::{
98
abi::{Abi, Detokenize, Error, EventExt, Function, Tokenize},
109
types::{Address, Filter, Selector, ValueOrArray},
1110
};
11+
use ethers_providers::Middleware;
12+
use std::{marker::PhantomData, sync::Arc};
1213

1314
#[cfg(not(feature = "legacy"))]
1415
use ethers_core::types::Eip1559TransactionRequest;
1516
#[cfg(feature = "legacy")]
1617
use ethers_core::types::TransactionRequest;
1718

18-
use ethers_providers::Middleware;
19-
20-
use std::{fmt::Debug, marker::PhantomData, sync::Arc};
21-
2219
/// A Contract is an abstraction of an executable program on the Ethereum Blockchain.
2320
/// It has code (called byte code) as well as allocated long-term memory
2421
/// (called storage). Every deployed Contract has an address, which is used to connect
@@ -161,6 +158,7 @@ pub struct Contract<M> {
161158

162159
impl<M> std::ops::Deref for Contract<M> {
163160
type Target = BaseContract;
161+
164162
fn deref(&self) -> &Self::Target {
165163
&self.base_contract
166164
}
@@ -177,19 +175,24 @@ impl<M> Clone for Contract<M> {
177175
}
178176

179177
impl<M> Contract<M> {
180-
/// Returns the contract's address
178+
/// Returns the contract's address.
181179
pub fn address(&self) -> Address {
182180
self.address
183181
}
184182

185-
/// Returns a reference to the contract's ABI
183+
/// Returns a reference to the contract's ABI.
186184
pub fn abi(&self) -> &Abi {
187185
&self.base_contract.abi
188186
}
189187

190-
/// Returns a pointer to the contract's client
188+
/// Returns a pointer to the contract's client.
191189
pub fn client(&self) -> Arc<M> {
192-
self.client.clone()
190+
Arc::clone(&self.client)
191+
}
192+
193+
/// Returns a reference to the contract's client.
194+
pub fn client_ref(&self) -> &M {
195+
Arc::as_ref(&self.client)
193196
}
194197
}
195198

@@ -301,10 +304,7 @@ impl<M: Middleware> Contract<M> {
301304
///
302305
/// Clones `self` internally
303306
#[must_use]
304-
pub fn at<T: Into<Address>>(&self, address: T) -> Self
305-
where
306-
M: Clone,
307-
{
307+
pub fn at<T: Into<Address>>(&self, address: T) -> Self {
308308
let mut this = self.clone();
309309
this.address = address.into();
310310
this
@@ -314,10 +314,7 @@ impl<M: Middleware> Contract<M> {
314314
///
315315
/// Clones `self` internally
316316
#[must_use]
317-
pub fn connect<N>(&self, client: Arc<N>) -> Contract<N>
318-
where
319-
N: Clone,
320-
{
317+
pub fn connect<N>(&self, client: Arc<N>) -> Contract<N> {
321318
Contract { base_contract: self.base_contract.clone(), client, address: self.address }
322319
}
323320
}

Diff for: ethers-contract/src/multicall/mod.rs

+16-31
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ use crate::{
44
};
55
use ethers_core::{
66
abi::{AbiDecode, Detokenize, Function, Token},
7-
types::{Address, BlockNumber, Bytes, Chain, NameOrAddress, TxHash, H160, U256},
7+
types::{Address, BlockNumber, Bytes, Chain, NameOrAddress, H160, U256},
88
};
9-
use ethers_providers::Middleware;
9+
use ethers_providers::{Middleware, PendingTransaction};
1010
use std::{convert::TryFrom, sync::Arc};
1111

1212
pub mod multicall_contract;
@@ -223,8 +223,7 @@ impl TryFrom<u8> for MulticallVersion {
223223
///
224224
/// // `await`ing the `send` method waits for the transaction to be broadcast, which also
225225
/// // returns the transaction hash
226-
/// let tx_hash = multicall.send().await?;
227-
/// let _tx_receipt = PendingTransaction::new(tx_hash, &client).await?;
226+
/// let _tx_receipt = multicall.send().await?.await.expect("tx dropped");
228227
///
229228
/// // you can also query ETH balances of multiple addresses
230229
/// let address_1 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".parse::<Address>()?;
@@ -569,7 +568,7 @@ impl<M: Middleware> Multicall<M> {
569568
/// .add_call(broadcast_1, false)
570569
/// .add_call(broadcast_2, false);
571570
///
572-
/// let _tx_hash = multicall.send().await?;
571+
/// let _tx_receipt = multicall.send().await?.await.expect("tx dropped");
573572
///
574573
/// # let call_1 = contract.method::<_, String>("getValue", ())?;
575574
/// # let call_2 = contract.method::<_, Address>("lastSender", ())?;
@@ -735,7 +734,7 @@ impl<M: Middleware> Multicall<M> {
735734
v @ (MulticallVersion::Multicall2 | MulticallVersion::Multicall3) => {
736735
let is_v2 = v == MulticallVersion::Multicall2;
737736
let call = if is_v2 { self.as_try_aggregate() } else { self.as_aggregate_3() };
738-
let return_data = call.call().await?;
737+
let return_data = ContractCall::call(&call).await?;
739738
self.calls
740739
.iter()
741740
.zip(return_data.into_iter())
@@ -789,7 +788,7 @@ impl<M: Middleware> Multicall<M> {
789788
}
790789

791790
/// Signs and broadcasts a batch of transactions by using the Multicall contract as proxy,
792-
/// returning the transaction hash once the transaction confirms.
791+
/// returning the pending transaction.
793792
///
794793
/// Note: this method will broadcast a transaction from an account, meaning it must have
795794
/// sufficient funds for gas and transaction value.
@@ -811,32 +810,18 @@ impl<M: Middleware> Multicall<M> {
811810
/// # Ok(())
812811
/// # }
813812
/// ```
814-
pub async fn send(&self) -> Result<TxHash, M> {
815-
// Broadcast transaction and return the transaction hash
816-
// TODO: Can we make this return a PendingTransaction directly instead?
817-
// Seems hard due to `returns a value referencing data owned by the current function`
818-
819-
// running clippy --fix on this throws E0597
820-
#[allow(clippy::let_and_return)]
821-
let tx_hash = match self.version {
822-
MulticallVersion::Multicall => {
823-
let call = self.as_aggregate();
824-
let hash = *call.send().await?;
825-
hash
826-
}
827-
MulticallVersion::Multicall2 => {
828-
let call = self.as_try_aggregate();
829-
let hash = *call.send().await?;
830-
hash
831-
}
832-
MulticallVersion::Multicall3 => {
833-
let call = self.as_aggregate_3_value();
834-
let hash = *call.send().await?;
835-
hash
836-
}
813+
pub async fn send(&self) -> Result<PendingTransaction<'_, M::Provider>, M> {
814+
let tx = match self.version {
815+
MulticallVersion::Multicall => self.as_aggregate().tx,
816+
MulticallVersion::Multicall2 => self.as_try_aggregate().tx,
817+
MulticallVersion::Multicall3 => self.as_aggregate_3_value().tx,
837818
};
838819

839-
Ok(tx_hash)
820+
self.contract
821+
.client_ref()
822+
.send_transaction(tx, self.block.map(Into::into))
823+
.await
824+
.map_err(|e| MulticallError::ContractError(ContractError::MiddlewareError(e)))
840825
}
841826

842827
/// v1

Diff for: ethers-contract/tests/it/contract.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -491,8 +491,7 @@ mod eth_tests {
491491
multicall_send.clear_calls().add_call(broadcast, false).add_call(broadcast2, false);
492492

493493
// broadcast the transaction and wait for it to be mined
494-
let tx_hash = multicall_send.legacy().send().await.unwrap();
495-
let _tx_receipt = PendingTransaction::new(tx_hash, client.provider()).await.unwrap();
494+
let _tx_receipt = multicall_send.legacy().send().await.unwrap().await.unwrap();
496495

497496
// Do another multicall to check the updated return values
498497
// The `getValue` calls should return the last value we set in the batched broadcast

0 commit comments

Comments
 (0)