use crate::{
stream::{interval, DEFAULT_POLL_INTERVAL},
JsonRpcClient, Middleware, PinBoxFut, Provider, ProviderError,
};
use ethers_core::types::{Transaction, TransactionReceipt, TxHash, U64};
use futures_core::stream::Stream;
use futures_util::stream::StreamExt;
use pin_project::pin_project;
use std::{
fmt,
future::Future,
ops::Deref,
pin::Pin,
task::{Context, Poll},
time::Duration,
};
#[cfg(not(target_arch = "wasm32"))]
use futures_timer::Delay;
#[cfg(target_arch = "wasm32")]
use wasm_timer::Delay;
/// A pending transaction is a transaction which has been submitted but is not yet mined.
/// `await`'ing on a pending transaction will resolve to a transaction receipt
/// once the transaction has enough `confirmations`. The default number of confirmations
/// is 1, but may be adjusted with the `confirmations` method. If the transaction does not
/// have enough confirmations or is not mined, the future will stay in the pending state.
#[pin_project]
pub struct PendingTransaction<'a, P> {
tx_hash: TxHash,
confirmations: usize,
provider: &'a Provider
,
state: PendingTxState<'a>,
interval: Box + Send + Unpin>,
}
impl<'a, P: JsonRpcClient> PendingTransaction<'a, P> {
/// Creates a new pending transaction poller from a hash and a provider
pub fn new(tx_hash: TxHash, provider: &'a Provider
) -> Self {
let delay = Box::pin(Delay::new(DEFAULT_POLL_INTERVAL));
Self {
tx_hash,
confirmations: 1,
provider,
state: PendingTxState::InitialDelay(delay),
interval: Box::new(interval(DEFAULT_POLL_INTERVAL)),
}
}
/// Returns the Provider associated with the pending transaction
pub fn provider(&self) -> Provider
where
P: Clone,
{
self.provider.clone()
}
/// Sets the number of confirmations for the pending transaction to resolve
/// to a receipt
pub fn confirmations(mut self, confs: usize) -> Self {
self.confirmations = confs;
self
}
/// Sets the polling interval
pub fn interval>(mut self, duration: T) -> Self {
let duration = duration.into();
self.interval = Box::new(interval(duration));
if matches!(self.state, PendingTxState::InitialDelay(_)) {
self.state = PendingTxState::InitialDelay(Box::pin(Delay::new(duration)))
}
self
}
}
macro_rules! rewake_with_new_state {
($ctx:ident, $this:ident, $new_state:expr) => {
*$this.state = $new_state;
$ctx.waker().wake_by_ref();
return Poll::Pending
};
}
macro_rules! rewake_with_new_state_if {
($condition:expr, $ctx:ident, $this:ident, $new_state:expr) => {
if $condition {
rewake_with_new_state!($ctx, $this, $new_state);
}
};
}
impl<'a, P: JsonRpcClient> Future for PendingTransaction<'a, P> {
type Output = Result