Skip to main content

eth_prices/network/
time.rs

1use alloy::{primitives::BlockNumber, providers::Provider};
2
3use crate::{
4    EthPricesError,
5    network::{NetworkId, NetworkInstant},
6    provider::RpcProvider,
7};
8
9/// A single point-in-time on a specific network.
10///
11/// Each variant carries the information needed to query a rate at that moment:
12///
13/// | Variant | Use case | Payload |
14/// |---|---|---|
15/// | `EVM(chain_id, block, provider)` | On-chain asset quotes | chain ID, block height, RPC provider |
16/// | `Fiat(timestamp)` | ECB / off-chain fiat rates | Unix timestamp (seconds) |
17///
18/// # Converting to a [`NetworkInstant`]
19///
20/// Use [`instant()`](NetworkTime::instant) to wrap a single [`NetworkTime`] into a
21/// [`NetworkInstant`]
22///
23/// ```rust,ignore
24/// use eth_prices::network::NetworkTime;
25///
26/// let time = NetworkTime::EVM(1, 20_000_000, provider);
27/// let networks = time.instant();
28/// ```
29///
30/// For multi-network scenarios (e.g. different EVM chains + a fiat timestamp) build a
31/// [`NetworkInstant`] directly with its builder methods instead.
32#[derive(Debug, Clone)]
33pub enum NetworkTime {
34    /// An EVM chain at a specific block height.
35    ///
36    /// Fields: `(chain_id, block_number, provider)`
37    EVM(NetworkId, BlockNumber, RpcProvider),
38    /// An off-chain fiat timestamp (Unix seconds).
39    Fiat(u64),
40}
41
42impl NetworkTime {
43    /// Extract the EVM fields, if this is the `EVM` variant.
44    pub fn as_evm(&self) -> Option<(&NetworkId, &BlockNumber, &RpcProvider)> {
45        match self {
46            NetworkTime::EVM(chain_id, block_number, provider) => {
47                Some((chain_id, block_number, provider))
48            }
49            _ => None,
50        }
51    }
52
53    /// Extract the fiat timestamp, if this is the `Fiat` variant.
54    pub fn as_fiat(&self) -> Option<&u64> {
55        match self {
56            NetworkTime::Fiat(date_time) => Some(date_time),
57            _ => None,
58        }
59    }
60
61    /// Convert this single [`NetworkTime`] into a [`NetworkInstant`].
62    ///
63    /// This is the simplest way to create a [`NetworkInstant`] when only one network
64    /// is needed. For multi-network scenarios build the [`NetworkInstant`] directly
65    /// with its default + builder methods.
66    pub fn instant(self) -> NetworkInstant {
67        match self {
68            NetworkTime::EVM(network_id, block_number, provider) => {
69                NetworkInstant::default().with_evm_block(network_id, block_number, provider)
70            }
71            NetworkTime::Fiat(date_time) => {
72                NetworkInstant::default().with_fiat_timestamp(date_time)
73            }
74        }
75    }
76
77    pub async fn from_provider_latest(
78        provider: RpcProvider,
79        network_id: NetworkId,
80    ) -> Result<Self, EthPricesError> {
81        provider
82            .get_block_number()
83            .await
84            .map(|block_number| NetworkTime::EVM(network_id, block_number, provider))
85            .map_err(EthPricesError::from)
86    }
87
88    pub fn from_provider(
89        provider: RpcProvider,
90        network_id: NetworkId,
91        block_number: BlockNumber,
92    ) -> Self {
93        NetworkTime::EVM(network_id, block_number, provider)
94    }
95
96    /// Set a fiat timestamp to the current time.
97    #[cfg(feature = "time")]
98    pub fn with_fiat_now() -> Self {
99        use std::time::{SystemTime, UNIX_EPOCH};
100
101        let time = SystemTime::now()
102            .duration_since(UNIX_EPOCH)
103            .unwrap()
104            .as_secs();
105        NetworkTime::Fiat(time)
106    }
107}