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) {
let nonce_lock = self.nonces.get(&address).map(|r| Arc::clone(&*r));
if let Some(nonce_lock) = nonce_lock {
*nonce_lock.lock().await = 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_guard = nonce.lock().await;
let new_nonce = if *nonce_guard == 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_guard, "incrementing nonce");
*nonce_guard + 1
};
*nonce_guard = new_nonce;
drop(nonce_guard);
Ok(new_nonce)
}
}