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

Returning a PendingTransaction after sending a tx #107

Merged
merged 7 commits into from
Dec 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions ethers-contract/src/call.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use super::base::{decode_fn, AbiError};
use ethers_core::{
abi::{Detokenize, Function, InvalidOutputType},
types::{Address, BlockNumber, Bytes, TransactionRequest, TxHash, U256},
types::{Address, BlockNumber, Bytes, TransactionRequest, U256},
};
use ethers_providers::Middleware;
use ethers_providers::{Middleware, PendingTransaction};

use std::{fmt::Debug, marker::PhantomData, sync::Arc};

Expand Down Expand Up @@ -126,9 +126,9 @@ where
}

/// Signs and broadcasts the provided transaction
pub async fn send(self) -> Result<TxHash, ContractError<M>> {
pub async fn send(&self) -> Result<PendingTransaction<'_, M::Provider>, ContractError<M>> {
self.client
.send_transaction(self.tx, self.block)
.send_transaction(self.tx.clone(), self.block)
.await
.map_err(ContractError::MiddlewareError)
}
Expand Down
15 changes: 6 additions & 9 deletions ethers-contract/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ use super::{

use ethers_core::{
abi::{Abi, Detokenize, Error, EventExt, Function, Tokenize},
types::{Address, Filter, NameOrAddress, Selector, TransactionRequest, TxHash},
types::{Address, Filter, NameOrAddress, Selector, TransactionRequest},
};
use ethers_providers::{Middleware, PendingTransaction};
use ethers_providers::Middleware;

use rustc_hex::ToHex;
use std::{fmt::Debug, marker::PhantomData, sync::Arc};
Expand Down Expand Up @@ -90,11 +90,12 @@ use std::{fmt::Debug, marker::PhantomData, sync::Arc};
/// .await?;
///
/// // Non-constant methods are executed via the `send()` call on the method builder.
/// let tx_hash = contract
/// .method::<_, H256>("setValue", "hi".to_owned())?.send().await?;
/// let call = contract
/// .method::<_, H256>("setValue", "hi".to_owned())?;
/// let pending_tx = call.send().await?;
///
/// // `await`ing on the pending transaction resolves to a transaction receipt
/// let receipt = contract.pending_transaction(tx_hash).confirmations(6).await?;
/// let receipt = pending_tx.confirmations(6).await?;
///
/// # Ok(())
/// # }
Expand Down Expand Up @@ -283,8 +284,4 @@ impl<M: Middleware> Contract<M> {
pub fn client(&self) -> &M {
&self.client
}

pub fn pending_transaction(&self, tx_hash: TxHash) -> PendingTransaction<'_, M::Provider> {
self.client.pending_transaction(tx_hash)
}
}
6 changes: 2 additions & 4 deletions ethers-contract/src/factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,14 @@ impl<M: Middleware> Deployer<M> {
/// be sufficiently confirmed (default: 1), it returns a [`Contract`](crate::Contract)
/// struct at the deployed contract's address.
pub async fn send(self) -> Result<Contract<M>, ContractError<M>> {
let tx_hash = self
let pending_tx = self
.client
.send_transaction(self.tx, Some(self.block))
.await
.map_err(ContractError::MiddlewareError)?;

// TODO: Should this be calculated "optimistically" by address/nonce?
let receipt = self
.client
.pending_transaction(tx_hash)
let receipt = pending_tx
.confirmations(self.confs)
.await
.map_err(|_| ContractError::ContractNotDeployed)?;
Expand Down
8 changes: 5 additions & 3 deletions ethers-contract/src/multicall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub static ADDRESS_BOOK: Lazy<HashMap<U256, Address>> = Lazy::new(|| {
/// use ethers::{
/// abi::Abi,
/// contract::{Contract, Multicall},
/// providers::{Middleware, Http, Provider},
/// providers::{Middleware, Http, Provider, PendingTransaction},
/// types::{Address, H256, U256},
/// };
/// use std::{convert::TryFrom, sync::Arc};
Expand Down Expand Up @@ -110,7 +110,7 @@ pub static ADDRESS_BOOK: Lazy<HashMap<U256, Address>> = Lazy::new(|| {
/// // `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 = client.pending_transaction(tx_hash).await?;
/// let _tx_receipt = PendingTransaction::new(tx_hash, &client).await?;
///
/// // you can also query ETH balances of multiple addresses
/// let address_1 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".parse::<Address>()?;
Expand Down Expand Up @@ -345,7 +345,9 @@ impl<M: Middleware> Multicall<M> {
let contract_call = self.as_contract_call();

// Broadcast transaction and return the transaction hash
let tx_hash = contract_call.send().await?;
// TODO: Can we make this return a PendingTransaction directly instead?
// Seems hard due to `returns a value referencing data owned by the current function`
let tx_hash = *contract_call.send().await?;

Ok(tx_hash)
}
Expand Down
41 changes: 20 additions & 21 deletions ethers-contract/tests/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ mod eth_tests {
use super::*;
use ethers::{
contract::Multicall,
providers::{Http, Middleware, Provider, StreamExt},
providers::{Http, Middleware, PendingTransaction, Provider, StreamExt},
types::{Address, U256},
utils::Ganache,
};
Expand Down Expand Up @@ -51,13 +51,9 @@ mod eth_tests {
.unwrap();
let calldata = contract_call.calldata().unwrap();
let gas_estimate = contract_call.estimate_gas().await.unwrap();
let tx_hash = contract_call.send().await.unwrap();
let tx = client.get_transaction(tx_hash).await.unwrap().unwrap();
let tx_receipt = client
.get_transaction_receipt(tx_hash)
.await
.unwrap()
.unwrap();
let pending_tx = contract_call.send().await.unwrap();
let tx = client.get_transaction(*pending_tx).await.unwrap().unwrap();
let tx_receipt = pending_tx.await.unwrap();
assert_eq!(last_sender.clone().call().await.unwrap(), client2.address());
assert_eq!(get_value.clone().call().await.unwrap(), "hi");
assert_eq!(tx.input, calldata);
Expand Down Expand Up @@ -88,6 +84,8 @@ mod eth_tests {
.unwrap()
.send()
.await
.unwrap()
.await
.unwrap();
}

Expand All @@ -99,7 +97,7 @@ mod eth_tests {
let contract = deploy(client.clone(), abi, bytecode).await;

// make a call with `client2`
let _tx_hash = contract
let _tx_hash = *contract
.method::<_, H256>("setValue", "hi".to_owned())
.unwrap()
.send()
Expand Down Expand Up @@ -143,13 +141,11 @@ mod eth_tests {

// and we make a few calls
for i in 0..num_calls {
let tx_hash = contract
let call = contract
.method::<_, H256>("setValue", i.to_string())
.unwrap()
.send()
.await
.unwrap();
let _receipt = contract.pending_transaction(tx_hash).await.unwrap();
let pending_tx = call.send().await.unwrap();
let _receipt = pending_tx.await.unwrap();
}

for i in 0..num_calls {
Expand Down Expand Up @@ -180,13 +176,14 @@ mod eth_tests {
let contract = deploy(client, abi, bytecode).await;

// make a call without the signer
let tx_hash = contract
let _receipt = contract
.method::<_, H256>("setValue", "hi".to_owned())
.unwrap()
.send()
.await
.unwrap()
.await
.unwrap();
let _receipt = contract.pending_transaction(tx_hash).await.unwrap();
let value: String = contract
.method::<_, String>("getValue", ())
.unwrap()
Expand Down Expand Up @@ -313,7 +310,9 @@ mod eth_tests {

// broadcast the transaction and wait for it to be mined
let tx_hash = multicall_send.send().await.unwrap();
let _tx_receipt = client4.pending_transaction(tx_hash).await.unwrap();
let _tx_receipt = PendingTransaction::new(tx_hash, client.provider())
.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
Expand Down Expand Up @@ -385,14 +384,14 @@ mod celo_tests {
assert_eq!(value, "initial value");

// make a state mutating transaction
let tx_hash = contract
let call = contract
.method::<_, H256>("setValue", "hi".to_owned())
.unwrap()
.unwrap();
let pending_tx = call
.send()
.await
.unwrap();
let receipt = contract.pending_transaction(tx_hash).await.unwrap();
assert_eq!(receipt.status.unwrap(), 1.into());
let _receipt = pending_tx.await.unwrap();

let value: String = contract
.method("getValue", ())
Expand Down
12 changes: 6 additions & 6 deletions ethers-middleware/src/gas_escalator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub use linear::LinearGasPrice;

use async_trait::async_trait;
use ethers_core::types::{BlockNumber, TransactionRequest, TxHash, U256};
use ethers_providers::{interval, FromErr, Middleware, StreamExt};
use ethers_providers::{interval, FromErr, Middleware, PendingTransaction, StreamExt};
use futures_util::lock::Mutex;
use std::sync::Arc;
use std::{pin::Pin, time::Instant};
Expand Down Expand Up @@ -97,18 +97,18 @@ where
&self,
tx: TransactionRequest,
block: Option<BlockNumber>,
) -> Result<TxHash, Self::Error> {
let tx_hash = self
) -> Result<PendingTransaction<'_, Self::Provider>, Self::Error> {
let pending_tx = self
.inner()
.send_transaction(tx.clone(), block)
.await
.map_err(GasEscalatorError::MiddlewareError)?;

// insert the tx in the pending txs
let mut lock = self.txs.lock().await;
lock.push((tx_hash, tx, Instant::now(), block));
lock.push((*pending_tx, tx, Instant::now(), block));

Ok(tx_hash)
Ok(pending_tx)
}
}

Expand Down Expand Up @@ -188,7 +188,7 @@ where
.send_transaction(replacement_tx.clone(), priority)
.await
{
Ok(tx_hash) => tx_hash,
Ok(tx_hash) => *tx_hash,
Err(err) => {
if err.to_string().contains("nonce too low") {
// ignore "nonce too low" errors because they
Expand Down
4 changes: 2 additions & 2 deletions ethers-middleware/src/gas_oracle/middleware.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::{GasOracle, GasOracleError};
use async_trait::async_trait;
use ethers_core::types::*;
use ethers_providers::{FromErr, Middleware};
use ethers_providers::{FromErr, Middleware, PendingTransaction};
use thiserror::Error;

#[derive(Debug)]
Expand Down Expand Up @@ -60,7 +60,7 @@ where
&self,
mut tx: TransactionRequest,
block: Option<BlockNumber>,
) -> Result<TxHash, Self::Error> {
) -> Result<PendingTransaction<'_, Self::Provider>, Self::Error> {
if tx.gas_price.is_none() {
tx.gas_price = Some(self.get_gas_price().await?);
}
Expand Down
4 changes: 2 additions & 2 deletions ethers-middleware/src/nonce_manager.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use async_trait::async_trait;
use ethers_core::types::*;
use ethers_providers::{FromErr, Middleware};
use ethers_providers::{FromErr, Middleware, PendingTransaction};
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use thiserror::Error;

Expand Down Expand Up @@ -87,7 +87,7 @@ where
&self,
mut tx: TransactionRequest,
block: Option<BlockNumber>,
) -> Result<TxHash, Self::Error> {
) -> Result<PendingTransaction<'_, Self::Provider>, Self::Error> {
if tx.nonce.is_none() {
tx.nonce = Some(self.get_transaction_count_with_manager(block).await?);
}
Expand Down
10 changes: 5 additions & 5 deletions ethers-middleware/src/signer.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use ethers_core::{
types::{
Address, BlockNumber, Bytes, NameOrAddress, Signature, Transaction, TransactionRequest,
TxHash, U256,
U256,
},
utils::keccak256,
};
use ethers_providers::{FromErr, Middleware};
use ethers_providers::{FromErr, Middleware, PendingTransaction};
use ethers_signers::Signer;

use async_trait::async_trait;
Expand Down Expand Up @@ -44,11 +44,11 @@ use thiserror::Error;
///
/// // ...and sign transactions
/// let tx = TransactionRequest::pay("vitalik.eth", 100);
/// let tx_hash = client.send_transaction(tx, None).await?;
/// let pending_tx = client.send_transaction(tx, None).await?;
///
/// // You can `await` on the pending transaction to get the receipt with a pre-specified
/// // number of confirmations
/// let receipt = client.pending_transaction(tx_hash).confirmations(6).await?;
/// let receipt = pending_tx.confirmations(6).await?;
///
/// // You can connect with other wallets at runtime via the `with_signer` function
/// let wallet2: LocalWallet = "cd8c407233c0560f6de24bb2dc60a8b02335c959a1a17f749ce6c1ccf63d74a7"
Expand Down Expand Up @@ -242,7 +242,7 @@ where
&self,
mut tx: TransactionRequest,
block: Option<BlockNumber>,
) -> Result<TxHash, Self::Error> {
) -> Result<PendingTransaction<'_, Self::Provider>, Self::Error> {
if let Some(ref to) = tx.to {
if let NameOrAddress::Name(ens_name) = to {
let addr = self
Expand Down
2 changes: 1 addition & 1 deletion ethers-middleware/tests/gas_oracle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ async fn using_gas_oracle() {
.value(10000);
let tx_hash = provider.send_transaction(tx, None).await.unwrap();

let tx = provider.get_transaction(tx_hash).await.unwrap().unwrap();
let tx = provider.get_transaction(*tx_hash).await.unwrap().unwrap();
assert_eq!(tx.gas_price, expected_gas_price);
}

Expand Down
2 changes: 1 addition & 1 deletion ethers-middleware/tests/nonce_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ async fn nonce_manager() {
.send_transaction(TransactionRequest::pay(address, 100u64), None)
.await
.unwrap();
tx_hashes.push(tx);
tx_hashes.push(*tx);
}

// sleep a bit to ensure there's no flakiness in the test
Expand Down
5 changes: 3 additions & 2 deletions ethers-middleware/tests/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,10 @@ async fn test_send_transaction() {

let balance_before = client.get_balance(client.address(), None).await.unwrap();
let tx = TransactionRequest::pay(client.address(), 100);
let tx_hash = client.send_transaction(tx, None).await.unwrap();
let _receipt = client
.pending_transaction(tx_hash)
.send_transaction(tx, None)
.await
.unwrap()
.confirmations(3)
.await
.unwrap();
Expand Down
Loading