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