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
This commit is contained in:
parent
5b7578296b
commit
3a2fd3e814
|
@ -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<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)
|
||||
}
|
||||
|
|
|
@ -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<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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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};
|
||||
|
@ -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>()?;
|
||||
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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", ())
|
||||
|
|
|
@ -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<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
|
||||
|
@ -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
|
||||
|
|
|
@ -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<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?);
|
||||
}
|
||||
|
|
|
@ -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<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?);
|
||||
}
|
||||
|
|
|
@ -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<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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -58,7 +58,6 @@ mod tests {
|
|||
|
||||
// the base provider
|
||||
let provider = Provider::<Http>::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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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::Provider> {
|
||||
self.inner().provider()
|
||||
}
|
||||
|
||||
async fn get_block_number(&self) -> Result<U64, Self::Error> {
|
||||
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<BlockNumber>,
|
||||
) -> Result<TxHash, Self::Error> {
|
||||
) -> Result<PendingTransaction<'_, Self::Provider>, 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<TxHash, Self::Error> {
|
||||
async fn send_raw_transaction<'a>(
|
||||
&'a self,
|
||||
tx: &Transaction,
|
||||
) -> Result<PendingTransaction<'a, Self::Provider>, 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<TxpoolContent, Self::Error> {
|
||||
|
|
|
@ -133,6 +133,10 @@ impl<P: JsonRpcClient> Middleware for Provider<P> {
|
|||
unreachable!("There is no inner provider here")
|
||||
}
|
||||
|
||||
fn provider(&self) -> &Provider<Self::Provider> {
|
||||
self
|
||||
}
|
||||
|
||||
////// Blockchain Status
|
||||
//
|
||||
// Functions for querying the state of the blockchain
|
||||
|
@ -299,7 +303,7 @@ impl<P: JsonRpcClient> Middleware for Provider<P> {
|
|||
&self,
|
||||
mut tx: TransactionRequest,
|
||||
_: Option<BlockNumber>,
|
||||
) -> Result<TxHash, ProviderError> {
|
||||
) -> Result<PendingTransaction<'_, P>, ProviderError> {
|
||||
if tx.from.is_none() {
|
||||
tx.from = self.3;
|
||||
}
|
||||
|
@ -318,22 +322,28 @@ impl<P: JsonRpcClient> Middleware for Provider<P> {
|
|||
}
|
||||
}
|
||||
|
||||
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<TxHash, ProviderError> {
|
||||
async fn send_raw_transaction<'a>(
|
||||
&'a self,
|
||||
tx: &Transaction,
|
||||
) -> Result<PendingTransaction<'a, P>, 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<P: JsonRpcClient> Middleware for Provider<P> {
|
|||
.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]
|
||||
|
|
|
@ -136,8 +136,8 @@ mod eth_tests {
|
|||
|
||||
async fn generic_pending_txs_test<M: Middleware>(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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)?);
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
|
@ -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)?);
|
||||
|
|
|
@ -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)?);
|
||||
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Reference in New Issue