From 3a2fd3e814de91914ca644da85f34fc1fd301f8a Mon Sep 17 00:00:00 2001 From: Georgios Konstantopoulos Date: Thu, 17 Dec 2020 13:26:01 +0200 Subject: [PATCH] Returning a `PendingTransaction` after sending a tx (#107) * feat(providers): return a PendingTransaction from send_tx calls * feat(providers): expose the internal provider to all middlewares * fix(middleware): use the returned PendingTx instead of using a hash * fix(contract): use the pending tx returned value Note1: To support that, we need to clone the tx when sending in order to make lifetimes work out Note2: Multicall does not support that feature * fix(ethers): adjust examples * chore: fix provider test * chore: fix celo test BREAKING CHANGE --- ethers-contract/src/call.rs | 8 ++-- ethers-contract/src/contract.rs | 15 +++---- ethers-contract/src/factory.rs | 6 +-- ethers-contract/src/multicall/mod.rs | 8 ++-- ethers-contract/tests/contract.rs | 41 +++++++++--------- ethers-middleware/src/gas_escalator/mod.rs | 12 +++--- .../src/gas_oracle/middleware.rs | 4 +- ethers-middleware/src/nonce_manager.rs | 4 +- ethers-middleware/src/signer.rs | 10 ++--- ethers-middleware/tests/gas_oracle.rs | 2 +- ethers-middleware/tests/nonce_manager.rs | 2 +- ethers-middleware/tests/signer.rs | 5 ++- ethers-middleware/tests/stack.rs | 30 ++++++------- ethers-providers/src/lib.rs | 16 ++++--- ethers-providers/src/provider.rs | 43 +++++++++---------- ethers-providers/tests/provider.rs | 4 +- ethers/examples/contract.rs | 4 +- ethers/examples/ens.rs | 4 +- ethers/examples/ledger.rs | 4 +- ethers/examples/local_signer.rs | 4 +- ethers/examples/transfer_eth.rs | 4 +- ethers/examples/yubi.rs | 4 +- ethers/src/lib.rs | 1 + 23 files changed, 114 insertions(+), 121 deletions(-) diff --git a/ethers-contract/src/call.rs b/ethers-contract/src/call.rs index 3b2a0cfd..29a0d2ad 100644 --- a/ethers-contract/src/call.rs +++ b/ethers-contract/src/call.rs @@ -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}; @@ -126,9 +126,9 @@ where } /// Signs and broadcasts the provided transaction - pub async fn send(self) -> Result> { + pub async fn send(&self) -> Result, ContractError> { self.client - .send_transaction(self.tx, self.block) + .send_transaction(self.tx.clone(), self.block) .await .map_err(ContractError::MiddlewareError) } diff --git a/ethers-contract/src/contract.rs b/ethers-contract/src/contract.rs index d8077d7f..758478c8 100644 --- a/ethers-contract/src/contract.rs +++ b/ethers-contract/src/contract.rs @@ -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}; @@ -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(()) /// # } @@ -283,8 +284,4 @@ impl Contract { pub fn client(&self) -> &M { &self.client } - - pub fn pending_transaction(&self, tx_hash: TxHash) -> PendingTransaction<'_, M::Provider> { - self.client.pending_transaction(tx_hash) - } } diff --git a/ethers-contract/src/factory.rs b/ethers-contract/src/factory.rs index 8e24e2c6..5e3687c4 100644 --- a/ethers-contract/src/factory.rs +++ b/ethers-contract/src/factory.rs @@ -35,16 +35,14 @@ impl Deployer { /// be sufficiently confirmed (default: 1), it returns a [`Contract`](crate::Contract) /// struct at the deployed contract's address. pub async fn send(self) -> Result, ContractError> { - 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)?; diff --git a/ethers-contract/src/multicall/mod.rs b/ethers-contract/src/multicall/mod.rs index cae07d3f..f74f0aab 100644 --- a/ethers-contract/src/multicall/mod.rs +++ b/ethers-contract/src/multicall/mod.rs @@ -61,7 +61,7 @@ pub static ADDRESS_BOOK: Lazy> = 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}; @@ -110,7 +110,7 @@ pub static ADDRESS_BOOK: Lazy> = 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::
()?; @@ -345,7 +345,9 @@ impl Multicall { 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) } diff --git a/ethers-contract/tests/contract.rs b/ethers-contract/tests/contract.rs index 84833f42..74c954e7 100644 --- a/ethers-contract/tests/contract.rs +++ b/ethers-contract/tests/contract.rs @@ -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, }; @@ -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); @@ -88,6 +84,8 @@ mod eth_tests { .unwrap() .send() .await + .unwrap() + .await .unwrap(); } @@ -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() @@ -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 { @@ -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() @@ -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 @@ -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", ()) diff --git a/ethers-middleware/src/gas_escalator/mod.rs b/ethers-middleware/src/gas_escalator/mod.rs index 991c3cb7..97bbb6a8 100644 --- a/ethers-middleware/src/gas_escalator/mod.rs +++ b/ethers-middleware/src/gas_escalator/mod.rs @@ -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}; @@ -97,8 +97,8 @@ where &self, tx: TransactionRequest, block: Option, - ) -> Result { - let tx_hash = self + ) -> Result, Self::Error> { + let pending_tx = self .inner() .send_transaction(tx.clone(), block) .await @@ -106,9 +106,9 @@ where // 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) } } @@ -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 diff --git a/ethers-middleware/src/gas_oracle/middleware.rs b/ethers-middleware/src/gas_oracle/middleware.rs index fed24e0c..d5ee88fd 100644 --- a/ethers-middleware/src/gas_oracle/middleware.rs +++ b/ethers-middleware/src/gas_oracle/middleware.rs @@ -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)] @@ -60,7 +60,7 @@ where &self, mut tx: TransactionRequest, block: Option, - ) -> Result { + ) -> Result, Self::Error> { if tx.gas_price.is_none() { tx.gas_price = Some(self.get_gas_price().await?); } diff --git a/ethers-middleware/src/nonce_manager.rs b/ethers-middleware/src/nonce_manager.rs index f6319d07..361f7880 100644 --- a/ethers-middleware/src/nonce_manager.rs +++ b/ethers-middleware/src/nonce_manager.rs @@ -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; @@ -87,7 +87,7 @@ where &self, mut tx: TransactionRequest, block: Option, - ) -> Result { + ) -> Result, Self::Error> { if tx.nonce.is_none() { tx.nonce = Some(self.get_transaction_count_with_manager(block).await?); } diff --git a/ethers-middleware/src/signer.rs b/ethers-middleware/src/signer.rs index bf76297e..4794f226 100644 --- a/ethers-middleware/src/signer.rs +++ b/ethers-middleware/src/signer.rs @@ -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; @@ -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" @@ -242,7 +242,7 @@ where &self, mut tx: TransactionRequest, block: Option, - ) -> Result { + ) -> Result, Self::Error> { if let Some(ref to) = tx.to { if let NameOrAddress::Name(ens_name) = to { let addr = self diff --git a/ethers-middleware/tests/gas_oracle.rs b/ethers-middleware/tests/gas_oracle.rs index 4174eb94..8366abfd 100644 --- a/ethers-middleware/tests/gas_oracle.rs +++ b/ethers-middleware/tests/gas_oracle.rs @@ -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); } diff --git a/ethers-middleware/tests/nonce_manager.rs b/ethers-middleware/tests/nonce_manager.rs index 189bc8f4..e539f41a 100644 --- a/ethers-middleware/tests/nonce_manager.rs +++ b/ethers-middleware/tests/nonce_manager.rs @@ -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 diff --git a/ethers-middleware/tests/signer.rs b/ethers-middleware/tests/signer.rs index 2e84f0ac..05fa7dde 100644 --- a/ethers-middleware/tests/signer.rs +++ b/ethers-middleware/tests/signer.rs @@ -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(); diff --git a/ethers-middleware/tests/stack.rs b/ethers-middleware/tests/stack.rs index 86339373..f6d2f5bd 100644 --- a/ethers-middleware/tests/stack.rs +++ b/ethers-middleware/tests/stack.rs @@ -58,7 +58,6 @@ mod tests { // the base provider let provider = Provider::::try_from(ganache.endpoint()).unwrap(); - let provider_clone = provider.clone(); // the Gas Price escalator middleware is the first middleware above the provider, // so that it receives the transaction last, after all the other middleware @@ -77,24 +76,21 @@ mod tests { let provider = NonceManagerMiddleware::new(provider, address); let tx = TransactionRequest::new(); - let mut tx_hash = None; + let mut pending_txs = Vec::new(); for _ in 0..10 { - tx_hash = Some(provider.send_transaction(tx.clone(), None).await.unwrap()); - dbg!( - provider - .get_transaction(tx_hash.unwrap()) - .await - .unwrap() - .unwrap() - .gas_price - ); + let pending = provider.send_transaction(tx.clone(), None).await.unwrap(); + let hash = *pending; + let gas_price = provider + .get_transaction(hash) + .await + .unwrap() + .unwrap() + .gas_price; + dbg!(gas_price); + pending_txs.push(pending); } - let receipt = provider_clone - .pending_transaction(tx_hash.unwrap()) - .await - .unwrap(); - - dbg!(receipt); + let receipts = futures_util::future::join_all(pending_txs); + dbg!(receipts.await); } } diff --git a/ethers-providers/src/lib.rs b/ethers-providers/src/lib.rs index 2a00bb9f..33217c86 100644 --- a/ethers-providers/src/lib.rs +++ b/ethers-providers/src/lib.rs @@ -1,4 +1,5 @@ #![cfg_attr(docsrs, feature(doc_cfg))] +#![deny(broken_intra_doc_links)] //! # Clients for interacting with Ethereum nodes //! //! This crate provides asynchronous [Ethereum JSON-RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) @@ -153,6 +154,10 @@ pub trait Middleware: Sync + Send + Debug { fn inner(&self) -> &Self::Inner; + fn provider(&self) -> &Provider { + self.inner().provider() + } + async fn get_block_number(&self) -> Result { self.inner().get_block_number().await.map_err(FromErr::from) } @@ -161,7 +166,7 @@ pub trait Middleware: Sync + Send + Debug { &self, tx: TransactionRequest, block: Option, - ) -> Result { + ) -> Result, Self::Error> { self.inner() .send_transaction(tx, block) .await @@ -268,7 +273,10 @@ pub trait Middleware: Sync + Send + Debug { self.inner().get_accounts().await.map_err(FromErr::from) } - async fn send_raw_transaction(&self, tx: &Transaction) -> Result { + async fn send_raw_transaction<'a>( + &'a self, + tx: &Transaction, + ) -> Result, Self::Error> { self.inner() .send_raw_transaction(tx) .await @@ -357,10 +365,6 @@ pub trait Middleware: Sync + Send + Debug { .map_err(FromErr::from) } - fn pending_transaction(&self, tx_hash: TxHash) -> PendingTransaction<'_, Self::Provider> { - self.inner().pending_transaction(tx_hash) - } - // Mempool inspection for Geth's API async fn txpool_content(&self) -> Result { diff --git a/ethers-providers/src/provider.rs b/ethers-providers/src/provider.rs index b960e42e..635edafb 100644 --- a/ethers-providers/src/provider.rs +++ b/ethers-providers/src/provider.rs @@ -133,6 +133,10 @@ impl Middleware for Provider

{ unreachable!("There is no inner provider here") } + fn provider(&self) -> &Provider { + self + } + ////// Blockchain Status // // Functions for querying the state of the blockchain @@ -299,7 +303,7 @@ impl Middleware for Provider

{ &self, mut tx: TransactionRequest, _: Option, - ) -> Result { + ) -> Result, ProviderError> { if tx.from.is_none() { tx.from = self.3; } @@ -318,22 +322,28 @@ impl Middleware for Provider

{ } } - Ok(self + let tx_hash = self .0 .request("eth_sendTransaction", [tx]) .await - .map_err(Into::into)?) + .map_err(Into::into)?; + + Ok(PendingTransaction::new(tx_hash, self).interval(self.get_interval())) } /// Send the raw RLP encoded transaction to the entire Ethereum network and returns the transaction's hash /// This will consume gas from the account that signed the transaction. - async fn send_raw_transaction(&self, tx: &Transaction) -> Result { + async fn send_raw_transaction<'a>( + &'a self, + tx: &Transaction, + ) -> Result, ProviderError> { let rlp = utils::serialize(&tx.rlp()); - Ok(self + let tx_hash = self .0 .request("eth_sendRawTransaction", [rlp]) .await - .map_err(Into::into)?) + .map_err(Into::into)?; + Ok(PendingTransaction::new(tx_hash, self).interval(self.get_interval())) } /// Signs data using a specific account. This account needs to be unlocked. @@ -510,12 +520,6 @@ impl Middleware for Provider

{ .await } - /// Helper which creates a pending transaction object from a transaction hash - /// using the provider's polling interval - fn pending_transaction(&self, tx_hash: TxHash) -> PendingTransaction<'_, P> { - PendingTransaction::new(tx_hash, self).interval(self.get_interval()) - } - /// Returns the details of all transactions currently pending for inclusion in the next /// block(s), as well as the ones that are being scheduled for future execution only. /// Ref: [Here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_content) @@ -979,22 +983,17 @@ mod tests { let accounts = provider.get_accounts().await.unwrap(); let tx = TransactionRequest::pay(accounts[0], parse_ether(1u64).unwrap()).from(accounts[0]); - let tx_hash = provider.send_transaction(tx, None).await.unwrap(); + let pending_tx = provider.send_transaction(tx, None).await.unwrap(); assert!(provider - .get_transaction_receipt(tx_hash) + .get_transaction_receipt(*pending_tx) .await .unwrap() .is_none()); - // couple of seconds pass - std::thread::sleep(std::time::Duration::new(3, 0)); - - assert!(provider - .get_transaction_receipt(tx_hash) - .await - .unwrap() - .is_some()); + let hash = *pending_tx; + let receipt = pending_tx.await.unwrap(); + assert_eq!(receipt.transaction_hash, hash); } #[tokio::test] diff --git a/ethers-providers/tests/provider.rs b/ethers-providers/tests/provider.rs index 5e77f689..d650a66d 100644 --- a/ethers-providers/tests/provider.rs +++ b/ethers-providers/tests/provider.rs @@ -136,8 +136,8 @@ mod eth_tests { async fn generic_pending_txs_test(provider: M, who: ethers::types::Address) { let tx = TransactionRequest::new().to(who).from(who); - let tx_hash = provider.send_transaction(tx, None).await.unwrap(); - let pending_tx = provider.pending_transaction(tx_hash); + let pending_tx = provider.send_transaction(tx, None).await.unwrap(); + let tx_hash = *pending_tx; let receipt = pending_tx.confirmations(3).await.unwrap(); // got the correct receipt assert_eq!(receipt.transaction_hash, tx_hash); diff --git a/ethers/examples/contract.rs b/ethers/examples/contract.rs index d031b69a..918fdc97 100644 --- a/ethers/examples/contract.rs +++ b/ethers/examples/contract.rs @@ -56,8 +56,8 @@ async fn main() -> Result<()> { let contract = SimpleContract::new(addr, client.clone()); // 10. call the `setValue` method - let tx_hash = contract.set_value("hi".to_owned()).send().await?; - let _receipt = client.pending_transaction(tx_hash).await?; + // (first `await` returns a PendingTransaction, second one waits for it to be mined) + let _receipt = contract.set_value("hi".to_owned()).send().await?.await?; // 11. get all events let logs = contract diff --git a/ethers/examples/ens.rs b/ethers/examples/ens.rs index 196f0311..5f79585e 100644 --- a/ethers/examples/ens.rs +++ b/ethers/examples/ens.rs @@ -18,9 +18,7 @@ async fn main() -> Result<()> { let tx = TransactionRequest::new().to("vitalik.eth").value(100_000); // send it! - let tx_hash = client.send_transaction(tx, None).await?; - - let receipt = client.pending_transaction(tx_hash).await?; + let receipt = client.send_transaction(tx, None).await?.await?; let tx = client.get_transaction(receipt.transaction_hash).await?; println!("{}", serde_json::to_string(&tx)?); diff --git a/ethers/examples/ledger.rs b/ethers/examples/ledger.rs index a08d75a8..cefafdd7 100644 --- a/ethers/examples/ledger.rs +++ b/ethers/examples/ledger.rs @@ -17,10 +17,10 @@ async fn main() -> anyhow::Result<()> { let tx = TransactionRequest::new() .to("vitalik.eth") .value(parse_ether(10)?); - let tx_hash = client.send_transaction(tx, None).await?; + let pending_tx = client.send_transaction(tx, None).await?; // Get the receipt - let _receipt = client.pending_transaction(tx_hash).confirmations(3).await?; + let _receipt = pending_tx.confirmations(3).await?; Ok(()) } diff --git a/ethers/examples/local_signer.rs b/ethers/examples/local_signer.rs index cedfaff5..edfe6cea 100644 --- a/ethers/examples/local_signer.rs +++ b/ethers/examples/local_signer.rs @@ -19,10 +19,10 @@ async fn main() -> Result<()> { let tx = TransactionRequest::new().to(wallet2.address()).value(10000); // send it! - let tx_hash = client.send_transaction(tx, None).await?; + let pending_tx = client.send_transaction(tx, None).await?; // get the mined tx - let receipt = client.pending_transaction(tx_hash).await?; + let receipt = pending_tx.await?; let tx = client.get_transaction(receipt.transaction_hash).await?; println!("Sent tx: {}\n", serde_json::to_string(&tx)?); diff --git a/ethers/examples/transfer_eth.rs b/ethers/examples/transfer_eth.rs index ffd1b128..ad46f36a 100644 --- a/ethers/examples/transfer_eth.rs +++ b/ethers/examples/transfer_eth.rs @@ -18,9 +18,7 @@ async fn main() -> Result<()> { let balance_before = provider.get_balance(from, None).await?; // broadcast it via the eth_sendTransaction API - let tx_hash = provider.send_transaction(tx, None).await?; - - let tx = provider.pending_transaction(tx_hash).await?; + let tx = provider.send_transaction(tx, None).await?.await?; println!("{}", serde_json::to_string(&tx)?); diff --git a/ethers/examples/yubi.rs b/ethers/examples/yubi.rs index af0caa30..fb0d0de8 100644 --- a/ethers/examples/yubi.rs +++ b/ethers/examples/yubi.rs @@ -20,10 +20,10 @@ async fn main() -> anyhow::Result<()> { let tx = TransactionRequest::new() .to("vitalik.eth") .value(parse_ether(10)?); - let tx_hash = client.send_transaction(tx, None).await?; + let pending_tx = client.send_transaction(tx, None).await?; // Get the receipt - let _receipt = client.pending_transaction(tx_hash).confirmations(3).await?; + let _receipt = pending_tx.confirmations(3).await?; Ok(()) } diff --git a/ethers/src/lib.rs b/ethers/src/lib.rs index 195da973..1f45bc15 100644 --- a/ethers/src/lib.rs +++ b/ethers/src/lib.rs @@ -4,6 +4,7 @@ rust_2018_idioms, unreachable_pub )] +#![deny(broken_intra_doc_links)] #![doc(test( no_crate_inject, attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))