oxidized_builder/core/
nonce.rs

1use 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        // FIX: Explicit U64 return type hint to help compiler
35        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        // FIX: Explicit U64 return type hint
55        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}