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_arch = "wasm32", async_trait(?Send))]
16#[cfg_attr(not(target_arch = "wasm32"), 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_arch = "wasm32", async_trait(?Send))]
36#[cfg_attr(not(target_arch = "wasm32"), 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_arch = "wasm32", async_trait(?Send))]
61#[cfg_attr(not(target_arch = "wasm32"), 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 provider.get_transaction_count(address).await?
82 } else {
83 *nonce + 1
84 };
85 *nonce = new_nonce;
86 Ok(new_nonce)
87 }
88}
89
90#[derive(Clone, Debug, Default)]
119pub struct NonceFiller<M: NonceManager = SimpleNonceManager> {
120 nonce_manager: M,
121}
122
123impl<M: NonceManager> NonceFiller<M> {
124 pub const fn new(nonce_manager: M) -> Self {
126 Self { nonce_manager }
127 }
128}
129
130impl<M: NonceManager, N: Network> TxFiller<N> for NonceFiller<M> {
131 type Fillable = u64;
132
133 fn status(&self, tx: &<N as Network>::TransactionRequest) -> FillerControlFlow {
134 if tx.nonce().is_some() {
135 return FillerControlFlow::Finished;
136 }
137 if tx.from().is_none() {
138 return FillerControlFlow::missing("NonceManager", vec!["from"]);
139 }
140 FillerControlFlow::Ready
141 }
142
143 fn fill_sync(&self, _tx: &mut SendableTx<N>) {}
144
145 async fn prepare<P>(
146 &self,
147 provider: &P,
148 tx: &N::TransactionRequest,
149 ) -> TransportResult<Self::Fillable>
150 where
151 P: Provider<N>,
152 {
153 let from = tx.from().expect("checked by 'ready()'");
154 self.nonce_manager.get_next_nonce(provider, from).await
155 }
156
157 async fn fill(
158 &self,
159 nonce: Self::Fillable,
160 mut tx: SendableTx<N>,
161 ) -> TransportResult<SendableTx<N>> {
162 if let Some(builder) = tx.as_mut_builder() {
163 builder.set_nonce(nonce);
164 }
165 Ok(tx)
166 }
167}
168
169#[cfg(test)]
170mod tests {
171 use super::*;
172 use crate::{ProviderBuilder, WalletProvider};
173 use alloy_consensus::Transaction;
174 use alloy_primitives::{address, U256};
175 use alloy_rpc_types_eth::TransactionRequest;
176
177 async fn check_nonces<P, N, M>(
178 filler: &NonceFiller<M>,
179 provider: &P,
180 address: Address,
181 start: u64,
182 ) where
183 P: Provider<N>,
184 N: Network,
185 M: NonceManager,
186 {
187 for i in start..start + 5 {
188 let nonce = filler.nonce_manager.get_next_nonce(&provider, address).await.unwrap();
189 assert_eq!(nonce, i);
190 }
191 }
192
193 #[tokio::test]
194 async fn smoke_test() {
195 let filler = NonceFiller::<CachedNonceManager>::default();
196 let provider = ProviderBuilder::new().on_anvil();
197 let address = Address::ZERO;
198 check_nonces(&filler, &provider, address, 0).await;
199
200 #[cfg(feature = "anvil-api")]
201 {
202 use crate::ext::AnvilApi;
203 filler.nonce_manager.nonces.clear();
204 provider.anvil_set_nonce(address, 69).await.unwrap();
205 check_nonces(&filler, &provider, address, 69).await;
206 }
207 }
208
209 #[tokio::test]
210 async fn concurrency() {
211 let filler = Arc::new(NonceFiller::<CachedNonceManager>::default());
212 let provider = Arc::new(ProviderBuilder::new().on_anvil());
213 let address = Address::ZERO;
214 let tasks = (0..5)
215 .map(|_| {
216 let filler = Arc::clone(&filler);
217 let provider = Arc::clone(&provider);
218 tokio::spawn(async move {
219 filler.nonce_manager.get_next_nonce(&provider, address).await
220 })
221 })
222 .collect::<Vec<_>>();
223
224 let mut ns = Vec::new();
225 for task in tasks {
226 ns.push(task.await.unwrap().unwrap());
227 }
228 ns.sort_unstable();
229 assert_eq!(ns, (0..5).collect::<Vec<_>>());
230
231 assert_eq!(filler.nonce_manager.nonces.len(), 1);
232 assert_eq!(*filler.nonce_manager.nonces.get(&address).unwrap().value().lock().await, 4);
233 }
234
235 #[tokio::test]
236 async fn no_nonce_if_sender_unset() {
237 let provider = ProviderBuilder::new()
238 .disable_recommended_fillers()
239 .with_cached_nonce_management()
240 .on_anvil();
241
242 let tx = TransactionRequest {
243 value: Some(U256::from(100)),
244 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
245 gas_price: Some(20e9 as u128),
246 gas: Some(21000),
247 ..Default::default()
248 };
249
250 assert!(provider.send_transaction(tx).await.is_err());
252 }
253
254 #[tokio::test]
255 async fn increments_nonce() {
256 let provider = ProviderBuilder::new()
257 .disable_recommended_fillers()
258 .with_cached_nonce_management()
259 .on_anvil_with_wallet();
260
261 let from = provider.default_signer_address();
262 let tx = TransactionRequest {
263 from: Some(from),
264 value: Some(U256::from(100)),
265 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
266 gas_price: Some(20e9 as u128),
267 gas: Some(21000),
268 ..Default::default()
269 };
270
271 let pending = provider.send_transaction(tx.clone()).await.unwrap();
272 let tx_hash = pending.watch().await.unwrap();
273 let mined_tx = provider
274 .get_transaction_by_hash(tx_hash)
275 .await
276 .expect("failed to fetch tx")
277 .expect("tx not included");
278 assert_eq!(mined_tx.nonce(), 0);
279
280 let pending = provider.send_transaction(tx).await.unwrap();
281 let tx_hash = pending.watch().await.unwrap();
282 let mined_tx = provider
283 .get_transaction_by_hash(tx_hash)
284 .await
285 .expect("fail to fetch tx")
286 .expect("tx didn't finalize");
287 assert_eq!(mined_tx.nonce(), 1);
288 }
289
290 #[tokio::test]
291 async fn cloned_managers() {
292 let cnm1 = CachedNonceManager::default();
293 let cnm2 = cnm1.clone();
294
295 let provider = ProviderBuilder::new().on_anvil();
296 let address = Address::ZERO;
297
298 assert_eq!(cnm1.get_next_nonce(&provider, address).await.unwrap(), 0);
299 assert_eq!(cnm2.get_next_nonce(&provider, address).await.unwrap(), 1);
300 assert_eq!(cnm1.get_next_nonce(&provider, address).await.unwrap(), 2);
301 assert_eq!(cnm2.get_next_nonce(&provider, address).await.unwrap(), 3);
302 }
303}