use alloy::{
eips::BlockNumberOrTag,
network::Network,
primitives::{Address, Bytes, TxHash, U256},
providers::Provider,
rpc::types::{Filter, Log, simulate::SimulatePayload},
transports::TransportResult,
};
use std::future::Future;
use crate::FlashblockPoller;
pub const PRECONF_POLL_INTERVAL: std::time::Duration = std::time::Duration::from_millis(50);
pub trait FlashblocksProviderExt<N: Network>: Provider<N> + Clone + Send + Sync + 'static {
fn watch_flashblocks(&self) -> FlashblockPoller<N, Self>
where
Self: Sized,
{
FlashblockPoller::new(self.clone())
}
fn flashblock(&self) -> impl Future<Output = TransportResult<Option<N::BlockResponse>>> + Send {
async move {
self.get_block_by_number(BlockNumberOrTag::Pending).await
}
}
fn flashblock_balance(
&self,
addr: Address,
) -> impl Future<Output = TransportResult<U256>> + Send {
async move {
self.get_balance(addr)
.block_id(BlockNumberOrTag::Pending.into())
.await
}
}
fn flashblock_nonce(&self, addr: Address) -> impl Future<Output = TransportResult<u64>> + Send {
async move {
self.get_transaction_count(addr)
.block_id(BlockNumberOrTag::Pending.into())
.await
}
}
fn flashblock_call(
&self,
tx: &N::TransactionRequest,
) -> impl Future<Output = TransportResult<Bytes>> + Send {
let tx = tx.clone();
async move {
self.call(tx)
.block(BlockNumberOrTag::Pending.into())
.await
}
}
fn flashblock_estimate_gas(
&self,
tx: &N::TransactionRequest,
) -> impl Future<Output = TransportResult<u64>> + Send {
let tx = tx.clone();
async move {
self.estimate_gas(tx)
.block(BlockNumberOrTag::Pending.into())
.await
}
}
fn flashblock_logs(
&self,
filter: Filter,
) -> impl Future<Output = TransportResult<Vec<Log>>> + Send {
async move {
let filter = filter.to_block(BlockNumberOrTag::Pending);
self.get_logs(&filter).await
}
}
fn flashblock_simulate(
&self,
payload: &SimulatePayload,
) -> impl Future<Output = TransportResult<Vec<alloy::rpc::types::simulate::SimulatedBlock<N::BlockResponse>>>>
+ Send
{
let payload = payload.clone();
async move {
self.simulate(&payload)
.block_id(BlockNumberOrTag::Pending.into())
.await
}
}
fn wait_for_preconfirmation(
&self,
tx_hash: TxHash,
) -> impl Future<Output = TransportResult<N::ReceiptResponse>> + Send {
async move {
loop {
if let Some(receipt) = self.get_transaction_receipt(tx_hash).await? {
return Ok(receipt);
}
tokio::time::sleep(PRECONF_POLL_INTERVAL).await;
}
}
}
fn is_preconfirmed(
&self,
tx_hash: TxHash,
) -> impl Future<Output = TransportResult<bool>> + Send {
async move { Ok(self.get_transaction_receipt(tx_hash).await?.is_some()) }
}
}
impl<N: Network, P: Provider<N> + Clone + Send + Sync + 'static> FlashblocksProviderExt<N> for P {}