use std::sync::Arc;
use alloy_primitives::Address;
use alloy_provider::Provider;
use alloy_provider::fillers::NonceManager;
use alloy_transport::TransportResult;
use async_trait::async_trait;
use dashmap::DashMap;
use tokio::sync::Mutex;
#[derive(Clone, Debug, Default)]
pub struct PendingNonceManager {
nonces: Arc<DashMap<Address, Arc<Mutex<u64>>>>,
}
impl PendingNonceManager {
pub async fn reset_nonce(&self, address: Address) {
if let Some(nonce_lock) = self.nonces.get(&address) {
let mut nonce = nonce_lock.lock().await;
*nonce = u64::MAX; #[cfg(feature = "telemetry")]
tracing::debug!(%address, "reset nonce cache, will requery on next use");
}
}
}
#[async_trait]
impl NonceManager for PendingNonceManager {
async fn get_next_nonce<P, N>(&self, provider: &P, address: Address) -> TransportResult<u64>
where
P: Provider<N>,
N: alloy_network::Network,
{
const NONE: u64 = u64::MAX;
let nonce = {
let rm = self
.nonces
.entry(address)
.or_insert_with(|| Arc::new(Mutex::new(NONE)));
Arc::clone(rm.value())
};
let mut nonce = nonce.lock().await;
let new_nonce = if *nonce == NONE {
#[cfg(feature = "telemetry")]
tracing::trace!(%address, "fetching nonce");
provider.get_transaction_count(address).pending().await?
} else {
#[cfg(feature = "telemetry")]
tracing::trace!(%address, current_nonce = *nonce, "incrementing nonce");
*nonce + 1
};
*nonce = new_nonce;
Ok(new_nonce)
}
}