Skip to main content

evm_oracle_state/
provider.rs

1use std::{future::Future, pin::Pin};
2
3use alloy_primitives::{Address, B256, U256};
4
5use crate::{OracleError, RoundData};
6
7/// Boxed future used by the provider seam.
8pub type ProviderFuture<'a, T> = Pin<Box<dyn Future<Output = Result<T, OracleError>> + Send + 'a>>;
9
10/// Block identity for hash-pinned oracle reconciliation reads.
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12pub struct OracleBlockRef {
13    /// Block number.
14    pub number: u64,
15    /// Block hash.
16    pub hash: B256,
17}
18
19/// Minimal read seam for Chainlink-compatible proxy feeds.
20///
21/// The trait is intentionally small so tests and downstream systems can provide
22/// their own provider, cache, or batched multicall implementation.
23pub trait ChainlinkFeedProvider {
24    /// Read `decimals()` from the proxy.
25    fn decimals(&self, proxy: Address) -> ProviderFuture<'_, u8>;
26
27    /// Read `description()` from the proxy.
28    fn description(&self, proxy: Address) -> ProviderFuture<'_, String>;
29
30    /// Read `version()` from the proxy.
31    fn version(&self, proxy: Address) -> ProviderFuture<'_, U256>;
32
33    /// Read `latestRoundData()` from the proxy.
34    fn latest_round_data(&self, proxy: Address) -> ProviderFuture<'_, RoundData>;
35
36    /// Read `latestRoundData()` from the proxy at a specific block, when supported.
37    ///
38    /// Providers that cannot pin by block may fall back to the unpinned read.
39    fn latest_round_data_at(
40        &self,
41        proxy: Address,
42        _block: Option<OracleBlockRef>,
43    ) -> ProviderFuture<'_, RoundData> {
44        self.latest_round_data(proxy)
45    }
46
47    /// Best-effort read of the current underlying aggregator address.
48    fn aggregator(&self, proxy: Address) -> ProviderFuture<'_, Option<Address>>;
49
50    /// Best-effort read of the underlying aggregator address at a specific block.
51    ///
52    /// Providers that cannot pin by block may fall back to the unpinned read.
53    fn aggregator_at(
54        &self,
55        proxy: Address,
56        _block: Option<OracleBlockRef>,
57    ) -> ProviderFuture<'_, Option<Address>> {
58        self.aggregator(proxy)
59    }
60
61    /// Best-effort read of the aggregator implementation `typeAndVersion()`.
62    ///
63    /// Providers that do not support implementation introspection may return
64    /// `Ok(None)`. Registration and reconciliation treat missing or failed
65    /// introspection as an unsupported layout and fall back to purge/refetch.
66    fn aggregator_type_and_version(
67        &self,
68        _aggregator: Address,
69    ) -> ProviderFuture<'_, Option<String>> {
70        Box::pin(async { Ok(None) })
71    }
72
73    /// Best-effort block-pinned read of the aggregator `typeAndVersion()`.
74    fn aggregator_type_and_version_at(
75        &self,
76        aggregator: Address,
77        _block: Option<OracleBlockRef>,
78    ) -> ProviderFuture<'_, Option<String>> {
79        self.aggregator_type_and_version(aggregator)
80    }
81
82    /// Best-effort read of the aggregator runtime code hash.
83    fn aggregator_code_hash(&self, _aggregator: Address) -> ProviderFuture<'_, Option<B256>> {
84        Box::pin(async { Ok(None) })
85    }
86
87    /// Best-effort block-pinned read of the aggregator runtime code hash.
88    fn aggregator_code_hash_at(
89        &self,
90        aggregator: Address,
91        _block: Option<OracleBlockRef>,
92    ) -> ProviderFuture<'_, Option<B256>> {
93        self.aggregator_code_hash(aggregator)
94    }
95}