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
153impl<M: NonceManager, N: Network> TxFiller<N> for NonceFiller<M> {
154 type Fillable = u64;
155
156 fn status(&self, tx: &<N as Network>::TransactionRequest) -> FillerControlFlow {
157 if tx.nonce().is_some() {
158 return FillerControlFlow::Finished;
159 }
160 if tx.from().is_none() {
161 return FillerControlFlow::missing("NonceManager", vec!["from"]);
162 }
163 FillerControlFlow::Ready
164 }
165
166 fn fill_sync(&self, _tx: &mut SendableTx<N>) {}
167
168 async fn prepare<P>(
169 &self,
170 provider: &P,
171 tx: &N::TransactionRequest,
172 ) -> TransportResult<Self::Fillable>
173 where
174 P: Provider<N>,
175 {
176 let from = tx.from().expect("checked by 'ready()'");
177 self.nonce_manager.get_next_nonce(provider, from).await
178 }
179
180 async fn fill(
181 &self,
182 nonce: Self::Fillable,
183 mut tx: SendableTx<N>,
184 ) -> TransportResult<SendableTx<N>> {
185 if let Some(builder) = tx.as_mut_builder() {
186 builder.set_nonce(nonce);
187 }
188 Ok(tx)
189 }
190}
191
192#[cfg(test)]
193mod tests {
194 use super::*;
195 use crate::{ProviderBuilder, WalletProvider};
196 use alloy_consensus::Transaction;
197 use alloy_primitives::{address, U256};
198 use alloy_rpc_types_eth::TransactionRequest;
199
200 async fn check_nonces<P, N, M>(
201 filler: &NonceFiller<M>,
202 provider: &P,
203 address: Address,
204 start: u64,
205 ) where
206 P: Provider<N>,
207 N: Network,
208 M: NonceManager,
209 {
210 for i in start..start + 5 {
211 let nonce = filler.nonce_manager.get_next_nonce(&provider, address).await.unwrap();
212 assert_eq!(nonce, i);
213 }
214 }
215
216 #[tokio::test]
217 async fn smoke_test() {
218 let filler = NonceFiller::<CachedNonceManager>::default();
219 let provider = ProviderBuilder::new().connect_anvil();
220 let address = Address::ZERO;
221 check_nonces(&filler, &provider, address, 0).await;
222
223 #[cfg(feature = "anvil-api")]
224 {
225 use crate::ext::AnvilApi;
226 filler.nonce_manager.nonces.clear();
227 provider.anvil_set_nonce(address, 69).await.unwrap();
228 check_nonces(&filler, &provider, address, 69).await;
229 }
230 }
231
232 #[tokio::test]
233 async fn concurrency() {
234 let filler = Arc::new(NonceFiller::<CachedNonceManager>::default());
235 let provider = Arc::new(ProviderBuilder::new().connect_anvil());
236 let address = Address::ZERO;
237 let tasks = (0..5)
238 .map(|_| {
239 let filler = Arc::clone(&filler);
240 let provider = Arc::clone(&provider);
241 tokio::spawn(async move {
242 filler.nonce_manager.get_next_nonce(&provider, address).await
243 })
244 })
245 .collect::<Vec<_>>();
246
247 let mut ns = Vec::new();
248 for task in tasks {
249 ns.push(task.await.unwrap().unwrap());
250 }
251 ns.sort_unstable();
252 assert_eq!(ns, (0..5).collect::<Vec<_>>());
253
254 assert_eq!(filler.nonce_manager.nonces.len(), 1);
255 assert_eq!(*filler.nonce_manager.nonces.get(&address).unwrap().value().lock().await, 4);
256 }
257
258 #[tokio::test]
259 async fn no_nonce_if_sender_unset() {
260 let provider = ProviderBuilder::new()
261 .disable_recommended_fillers()
262 .with_cached_nonce_management()
263 .connect_anvil();
264
265 let tx = TransactionRequest {
266 value: Some(U256::from(100)),
267 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
268 gas_price: Some(20e9 as u128),
269 gas: Some(21000),
270 ..Default::default()
271 };
272
273 assert!(provider.send_transaction(tx).await.is_err());
275 }
276
277 #[tokio::test]
278 async fn increments_nonce() {
279 let provider = ProviderBuilder::new()
280 .disable_recommended_fillers()
281 .with_cached_nonce_management()
282 .connect_anvil_with_wallet();
283
284 let from = provider.default_signer_address();
285 let tx = TransactionRequest {
286 from: Some(from),
287 value: Some(U256::from(100)),
288 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
289 gas_price: Some(20e9 as u128),
290 gas: Some(21000),
291 ..Default::default()
292 };
293
294 let pending = provider.send_transaction(tx.clone()).await.unwrap();
295 let tx_hash = pending.watch().await.unwrap();
296 let mined_tx = provider
297 .get_transaction_by_hash(tx_hash)
298 .await
299 .expect("failed to fetch tx")
300 .expect("tx not included");
301 assert_eq!(mined_tx.nonce(), 0);
302
303 let pending = provider.send_transaction(tx).await.unwrap();
304 let tx_hash = pending.watch().await.unwrap();
305 let mined_tx = provider
306 .get_transaction_by_hash(tx_hash)
307 .await
308 .expect("fail to fetch tx")
309 .expect("tx didn't finalize");
310 assert_eq!(mined_tx.nonce(), 1);
311 }
312
313 #[tokio::test]
314 async fn cloned_managers() {
315 let cnm1 = CachedNonceManager::default();
316 let cnm2 = cnm1.clone();
317
318 let provider = ProviderBuilder::new().connect_anvil();
319 let address = Address::ZERO;
320
321 assert_eq!(cnm1.get_next_nonce(&provider, address).await.unwrap(), 0);
322 assert_eq!(cnm2.get_next_nonce(&provider, address).await.unwrap(), 1);
323 assert_eq!(cnm1.get_next_nonce(&provider, address).await.unwrap(), 2);
324 assert_eq!(cnm2.get_next_nonce(&provider, address).await.unwrap(), 3);
325 }
326}