Skip to main content

eth_prices/network/
instant.rs

1use std::collections::HashMap;
2
3use alloy::{primitives::BlockNumber, providers::Provider};
4
5use crate::{
6    EthPricesError,
7    network::{Network, NetworkId, NetworkTime},
8    provider::RpcProvider,
9};
10
11/// A snapshot of network states across multiple chains / data sources.
12///
13/// Internally a `HashMap<Network, NetworkTime>`, where:
14///
15/// - [`NetworkTime`] stores the actual point-in-time (block height or unix timestamp)
16///   together with the provider needed to query it.
17///
18/// ```rust,ignore
19/// use eth_prices::network::NetworkInstant;
20///
21/// let networks = NetworkInstant::default()
22///     .with_evm_provider_latest(eth_provider).await?
23///     .with_evm_provider_latest(sep_provider).await?
24///     .with_now();
25/// ```
26///
27/// Note that the above example makes a `eth_chainId` and `eth_blockNumber` query per provider supplied.
28///  
29/// # Quoting at a given network time
30///
31/// Start with [`Default::default()`] and chain builder methods. Each builder consumes
32/// and returns `self`, enabling a fluent style:
33///
34/// ```rust,ignore
35/// use eth_prices::network::NetworkInstant;
36///
37/// let networks = NetworkInstant::default()
38///     .with_evm_block(1.into(), 123_456_789, eth_provider)
39///     .with_evm_block(11155111.into(), 123_456_789, sep_provider)
40///     .with_fiat_timestamp(time);
41/// ```
42///
43/// For single-network convenience, start with [`NetworkTime::instant()`] instead.
44///
45#[derive(Default, Debug, Clone)]
46pub struct NetworkInstant(pub HashMap<Network, NetworkTime>);
47
48impl NetworkInstant {
49    /// Look up the [`NetworkTime`] for a given network.
50    pub fn get(&self, network_id: &Network) -> Option<&NetworkTime> {
51        self.0.get(network_id)
52    }
53
54    /// Convenience accessor: extract the EVM fields for a specific chain.
55    ///
56    /// Returns `(chain_id, block_number, provider)` if the network exists and is
57    /// an `EVM` variant.
58    pub fn get_evm_block(
59        &self,
60        network_id: Network,
61    ) -> Option<(&NetworkId, &BlockNumber, &RpcProvider)> {
62        self.0
63            .get(&network_id)
64            .and_then(|network_time| network_time.as_evm())
65    }
66
67    /// Convenience accessor: extract the fiat timestamp (network id `0`).
68    pub fn get_fiat_timestamp(&self) -> Option<&u64> {
69        self.0
70            .get(&Network::Fiat)
71            .and_then(|network_time| network_time.as_fiat())
72    }
73
74    // ── Builder methods ──────────────────────────────────────────────────────────
75
76    /// Set a fiat timestamp at network id `0`.
77    ///
78    /// Used by [`ecb`](crate::quoter::ecb) quoters to pick a date.
79    pub fn with_fiat_timestamp(mut self, timestamp: u64) -> Self {
80        self.0.insert(Network::Fiat, NetworkTime::Fiat(timestamp));
81        self
82    }
83
84    /// Set a fiat timestamp to the current time.
85    #[cfg(feature = "time")]
86    pub fn with_now(mut self) -> Result<Self, EthPricesError> {
87        self.0.insert(Network::Fiat, NetworkTime::with_fiat_now());
88        Ok(self)
89    }
90
91    /// Set an EVM network to a specific block number.
92    ///
93    /// Use this when you already know the block height (e.g. from a historical query
94    /// or configuration).
95    pub fn with_evm_block(
96        mut self,
97        network_id: NetworkId,
98        block_number: BlockNumber,
99        provider: RpcProvider,
100    ) -> Self {
101        self.0.insert(
102            network_id.clone().into(),
103            NetworkTime::EVM(network_id, block_number, provider),
104        );
105        self
106    }
107
108    /// Set an EVM network to the latest block, fetched from the RPC.
109    ///
110    /// This is an async builder — it must be `.await`ed before further chaining:
111    ///
112    /// ```rust,ignore
113    /// let networks = NetworkInstant::default()
114    ///     .with_evm_latest(1, eth_provider).await?
115    ///     .with_evm_latest(42161, arb_provider).await?;
116    /// ```
117    pub async fn with_evm_latest(
118        mut self,
119        network_id: NetworkId,
120        provider: RpcProvider,
121    ) -> Result<Self, EthPricesError> {
122        self.0.insert(
123            network_id.clone().into(),
124            NetworkTime::from_provider_latest(provider, network_id).await?,
125        );
126        Ok(self)
127    }
128
129    pub async fn with_evm_provider(
130        mut self,
131        provider: RpcProvider,
132    ) -> Result<Self, EthPricesError> {
133        let network_id = NetworkId::from_provider(&provider).await?;
134        let block_number = provider.get_block_number().await?;
135        let time = NetworkTime::from_provider(provider, network_id.clone(), block_number);
136
137        self.0.insert(network_id.into(), time);
138        Ok(self)
139    }
140}