oxidized_builder/core/
nonce.rs1use crate::common::error::AppError;
2use crate::network::provider::HttpProvider;
3use alloy::primitives::Address;
4use alloy::providers::Provider;
5use std::sync::Arc;
6use tokio::sync::Mutex;
7use crate::common::retry::retry_async;
8use std::time::Duration;
9
10#[derive(Clone)]
11pub struct NonceManager {
12 provider: HttpProvider,
13 address: Address,
14 local_nonce: Arc<Mutex<Option<u64>>>,
15}
16
17impl NonceManager {
18 pub fn new(provider: HttpProvider, address: Address) -> Self {
19 Self {
20 provider,
21 address,
22 local_nonce: Arc::new(Mutex::new(None)),
23 }
24 }
25
26 pub async fn get_next_nonce(&self) -> Result<u64, AppError> {
27 let mut nonce_guard = self.local_nonce.lock().await;
28
29 if let Some(nonce) = *nonce_guard {
30 *nonce_guard = Some(nonce + 1);
31 return Ok(nonce);
32 }
33
34 let provider = self.provider.clone();
36 let address = self.address;
37 let on_chain_nonce: u64 = retry_async(
38 move |_| {
39 let provider = provider.clone();
40 async move { provider.get_transaction_count(address).await }
41 },
42 3,
43 Duration::from_millis(100),
44 )
45 .await
46 .map_err(|e| AppError::Connection(format!("Failed to fetch nonce: {}", e)))?;
47
48 *nonce_guard = Some(on_chain_nonce + 1);
49 Ok(on_chain_nonce)
50 }
51
52 pub async fn resync(&self) -> Result<(), AppError> {
53 let mut nonce_guard = self.local_nonce.lock().await;
54 let provider = self.provider.clone();
56 let address = self.address;
57 let on_chain_nonce: u64 = retry_async(
58 move |_| {
59 let provider = provider.clone();
60 async move { provider.get_transaction_count(address).await }
61 },
62 3,
63 Duration::from_millis(100),
64 )
65 .await
66 .map_err(|e| AppError::Connection(format!("Failed to resync nonce: {}", e)))?;
67
68 *nonce_guard = Some(on_chain_nonce);
69 tracing::info!("Nonce resynced to {}", on_chain_nonce);
70 Ok(())
71 }
72}