1use crate::{
2 fillers::{FillerControlFlow, TxFiller},
3 provider::SendableTx,
4 Provider,
5};
6use alloy_network::{Network, TransactionBuilder};
7use alloy_primitives::Address;
8use alloy_transport::TransportResult;
9use async_trait::async_trait;
10use dashmap::DashMap;
11use futures::lock::Mutex;
12use std::sync::Arc;
13
14#[cfg_attr(target_family = "wasm", async_trait(?Send))]
16#[cfg_attr(not(target_family = "wasm"), async_trait)]
17pub trait NonceManager: Clone + Send + Sync + std::fmt::Debug {
18 async fn get_next_nonce<P, N>(&self, provider: &P, address: Address) -> TransportResult<u64>
20 where
21 P: Provider<N>,
22 N: Network;
23}
24
25#[derive(Clone, Debug, Default)]
32#[non_exhaustive]
33pub struct SimpleNonceManager;
34
35#[cfg_attr(target_family = "wasm", async_trait(?Send))]
36#[cfg_attr(not(target_family = "wasm"), async_trait)]
37impl NonceManager for SimpleNonceManager {
38 async fn get_next_nonce<P, N>(&self, provider: &P, address: Address) -> TransportResult<u64>
39 where
40 P: Provider<N>,
41 N: Network,
42 {
43 provider.get_transaction_count(address).pending().await
44 }
45}
46
47#[derive(Clone, Debug, Default)]
56pub struct CachedNonceManager {
57 nonces: Arc<DashMap<Address, Arc<Mutex<u64>>>>,
58}
59
60#[cfg_attr(target_family = "wasm", async_trait(?Send))]
61#[cfg_attr(not(target_family = "wasm"), async_trait)]
62impl NonceManager for CachedNonceManager {
63 async fn get_next_nonce<P, N>(&self, provider: &P, address: Address) -> TransportResult<u64>
64 where
65 P: Provider<N>,
66 N: Network,
67 {
68 const NONE: u64 = u64::MAX;
70
71 let nonce = {
74 let rm = self.nonces.entry(address).or_insert_with(|| Arc::new(Mutex::new(NONE)));
75 Arc::clone(rm.value())
76 };
77
78 let mut nonce = nonce.lock().await;
79 let new_nonce = if *nonce == NONE {
80 trace!(%address, "fetching nonce");
82 provider.get_transaction_count(address).await?
83 } else {
84 trace!(%address, current_nonce = *nonce, "incrementing nonce");
85 *nonce + 1
86 };
87 *nonce = new_nonce;
88 Ok(new_nonce)
89 }
90}
91
92#[derive(Clone, Debug, Default)]
121pub struct NonceFiller<M: NonceManager = CachedNonceManager> {
122 nonce_manager: M,
123}
124
125impl<M: NonceManager> NonceFiller<M> {
126 pub const fn new(nonce_manager: M) -> Self {
132 Self { nonce_manager }
133 }
134
135 pub const fn simple() -> NonceFiller<SimpleNonceManager> {
140 NonceFiller { nonce_manager: SimpleNonceManager }
141 }
142
143 pub fn cached() -> NonceFiller<CachedNonceManager> {
149 NonceFiller { nonce_manager: CachedNonceManager::default() }
150 }
151
152 pub const fn nonce_manager(&self) -> &M {
154 &self.nonce_manager
155 }
156
157 pub const fn nonce_manager_mut(&mut self) -> &mut M {
159 &mut self.nonce_manager
160 }
161}
162
163impl<M: NonceManager, N: Network> TxFiller<N> for NonceFiller<M> {
164 type Fillable = u64;
165
166 fn status(&self, tx: &<N as Network>::TransactionRequest) -> FillerControlFlow {
167 if tx.nonce().is_some() {
168 return FillerControlFlow::Finished;
169 }
170 if tx.from().is_none() {
171 return FillerControlFlow::missing("NonceManager", vec!["from"]);
172 }
173 FillerControlFlow::Ready
174 }
175
176 fn fill_sync(&self, _tx: &mut SendableTx<N>) {}
177
178 async fn prepare<P>(
179 &self,
180 provider: &P,
181 tx: &N::TransactionRequest,
182 ) -> TransportResult<Self::Fillable>
183 where
184 P: Provider<N>,
185 {
186 let from = tx.from().expect("checked by 'ready()'");
187 self.nonce_manager.get_next_nonce(provider, from).await
188 }
189
190 async fn fill(
191 &self,
192 nonce: Self::Fillable,
193 mut tx: SendableTx<N>,
194 ) -> TransportResult<SendableTx<N>> {
195 if let Some(builder) = tx.as_mut_builder() {
196 builder.set_nonce(nonce);
197 }
198 Ok(tx)
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205 use crate::{ProviderBuilder, WalletProvider};
206 use alloy_consensus::Transaction;
207 use alloy_primitives::{address, U256};
208 use alloy_rpc_types_eth::TransactionRequest;
209
210 async fn check_nonces<P, N, M>(
211 filler: &NonceFiller<M>,
212 provider: &P,
213 address: Address,
214 start: u64,
215 ) where
216 P: Provider<N>,
217 N: Network,
218 M: NonceManager,
219 {
220 for i in start..start + 5 {
221 let nonce = filler.nonce_manager.get_next_nonce(&provider, address).await.unwrap();
222 assert_eq!(nonce, i);
223 }
224 }
225
226 #[tokio::test]
227 async fn smoke_test() {
228 let filler = NonceFiller::<CachedNonceManager>::default();
229 let provider = ProviderBuilder::new().connect_anvil();
230 let address = Address::ZERO;
231 check_nonces(&filler, &provider, address, 0).await;
232
233 #[cfg(feature = "anvil-api")]
234 {
235 use crate::ext::AnvilApi;
236 filler.nonce_manager.nonces.clear();
237 provider.anvil_set_nonce(address, 69).await.unwrap();
238 check_nonces(&filler, &provider, address, 69).await;
239 }
240 }
241
242 #[tokio::test]
243 async fn concurrency() {
244 let filler = Arc::new(NonceFiller::<CachedNonceManager>::default());
245 let provider = Arc::new(ProviderBuilder::new().connect_anvil());
246 let address = Address::ZERO;
247 let tasks = (0..5)
248 .map(|_| {
249 let filler = Arc::clone(&filler);
250 let provider = Arc::clone(&provider);
251 tokio::spawn(async move {
252 filler.nonce_manager.get_next_nonce(&provider, address).await
253 })
254 })
255 .collect::<Vec<_>>();
256
257 let mut ns = Vec::new();
258 for task in tasks {
259 ns.push(task.await.unwrap().unwrap());
260 }
261 ns.sort_unstable();
262 assert_eq!(ns, (0..5).collect::<Vec<_>>());
263
264 assert_eq!(filler.nonce_manager.nonces.len(), 1);
265 assert_eq!(*filler.nonce_manager.nonces.get(&address).unwrap().value().lock().await, 4);
266 }
267
268 #[tokio::test]
269 async fn no_nonce_if_sender_unset() {
270 let provider = ProviderBuilder::new()
271 .disable_recommended_fillers()
272 .with_cached_nonce_management()
273 .connect_anvil();
274
275 let tx = TransactionRequest {
276 value: Some(U256::from(100)),
277 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
278 gas_price: Some(20e9 as u128),
279 gas: Some(21000),
280 ..Default::default()
281 };
282
283 assert!(provider.send_transaction(tx).await.is_err());
285 }
286
287 #[tokio::test]
288 async fn increments_nonce() {
289 let provider = ProviderBuilder::new()
290 .disable_recommended_fillers()
291 .with_cached_nonce_management()
292 .connect_anvil_with_wallet();
293
294 let from = provider.default_signer_address();
295 let tx = TransactionRequest {
296 from: Some(from),
297 value: Some(U256::from(100)),
298 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
299 gas_price: Some(20e9 as u128),
300 gas: Some(21000),
301 ..Default::default()
302 };
303
304 let pending = provider.send_transaction(tx.clone()).await.unwrap();
305 let tx_hash = pending.watch().await.unwrap();
306 let mined_tx = provider
307 .get_transaction_by_hash(tx_hash)
308 .await
309 .expect("failed to fetch tx")
310 .expect("tx not included");
311 assert_eq!(mined_tx.nonce(), 0);
312
313 let pending = provider.send_transaction(tx).await.unwrap();
314 let tx_hash = pending.watch().await.unwrap();
315 let mined_tx = provider
316 .get_transaction_by_hash(tx_hash)
317 .await
318 .expect("fail to fetch tx")
319 .expect("tx didn't finalize");
320 assert_eq!(mined_tx.nonce(), 1);
321 }
322
323 #[tokio::test]
324 async fn cloned_managers() {
325 let cnm1 = CachedNonceManager::default();
326 let cnm2 = cnm1.clone();
327
328 let provider = ProviderBuilder::new().connect_anvil();
329 let address = Address::ZERO;
330
331 assert_eq!(cnm1.get_next_nonce(&provider, address).await.unwrap(), 0);
332 assert_eq!(cnm2.get_next_nonce(&provider, address).await.unwrap(), 1);
333 assert_eq!(cnm1.get_next_nonce(&provider, address).await.unwrap(), 2);
334 assert_eq!(cnm2.get_next_nonce(&provider, address).await.unwrap(), 3);
335 }
336}