evm_oracle_state/
adapter.rs1use std::{borrow::Cow, collections::BTreeMap, future::Future, pin::Pin, sync::Arc};
2
3use alloy_network::Ethereum;
4use alloy_primitives::{Address, I256};
5use evm_fork_cache::{cache::EvmCache, reactive::ReactiveHandler};
6
7use crate::{FeedRegistration, OracleAdapterFeedSkip, OracleError, OracleStorageSync, RoundData};
8
9pub type AdapterFuture<'a, T> = Pin<Box<dyn Future<Output = Result<T, OracleError>> + 'a>>;
11
12#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub struct OracleAdapterId(Cow<'static, str>);
15
16impl OracleAdapterId {
17 pub fn new(id: impl Into<Cow<'static, str>>) -> Self {
19 Self(id.into())
20 }
21
22 pub fn as_str(&self) -> &str {
24 self.0.as_ref()
25 }
26}
27
28impl std::fmt::Display for OracleAdapterId {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 self.0.fmt(f)
31 }
32}
33
34impl AsRef<str> for OracleAdapterId {
35 fn as_ref(&self) -> &str {
36 self.as_str()
37 }
38}
39
40#[non_exhaustive]
42#[derive(Clone, Debug, Default, PartialEq, Eq)]
43pub enum OracleTransformDescriptor {
44 #[default]
46 Identity,
47 PriceCap {
49 cap: I256,
51 },
52 Custom {
54 adapter_id: OracleAdapterId,
56 kind: Cow<'static, str>,
58 metadata: BTreeMap<String, String>,
60 },
61}
62
63#[non_exhaustive]
73#[derive(Clone, Debug, PartialEq, Eq)]
74pub struct OracleSourceDescriptor {
75 pub adapter_id: OracleAdapterId,
77 pub source_kind: Cow<'static, str>,
79 pub user_facing_proxy: Address,
81 pub read_proxy: Address,
85 pub event_source: Address,
87 pub transform: OracleTransformDescriptor,
89 pub metadata: BTreeMap<String, String>,
91}
92
93impl OracleSourceDescriptor {
94 pub fn new(
96 adapter_id: OracleAdapterId,
97 source_kind: impl Into<Cow<'static, str>>,
98 user_facing_proxy: Address,
99 read_proxy: Address,
100 event_source: Address,
101 ) -> Self {
102 Self {
103 adapter_id,
104 source_kind: source_kind.into(),
105 user_facing_proxy,
106 read_proxy,
107 event_source,
108 transform: OracleTransformDescriptor::Identity,
109 metadata: BTreeMap::new(),
110 }
111 }
112
113 pub fn transform(mut self, transform: OracleTransformDescriptor) -> Self {
115 self.transform = transform;
116 self
117 }
118
119 pub fn metadata(mut self, metadata: BTreeMap<String, String>) -> Self {
121 self.metadata = metadata;
122 self
123 }
124
125 pub fn metadata_entry(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
127 self.metadata.insert(key.into(), value.into());
128 self
129 }
130}
131
132#[non_exhaustive]
134#[derive(Clone, Debug)]
135pub struct OracleDiscoveredFeed {
136 pub registration: FeedRegistration,
138 pub round: RoundData,
140}
141
142impl OracleDiscoveredFeed {
143 pub fn new(registration: FeedRegistration, round: RoundData) -> Self {
145 Self {
146 registration,
147 round,
148 }
149 }
150}
151
152#[non_exhaustive]
154#[derive(Clone, Debug, Default)]
155pub struct OracleDiscoveryReport {
156 pub feeds: Vec<OracleDiscoveredFeed>,
158 pub skipped: Vec<OracleAdapterFeedSkip>,
160}
161
162impl OracleDiscoveryReport {
163 pub fn new() -> Self {
165 Self::default()
166 }
167
168 pub fn with_feed(mut self, feed: OracleDiscoveredFeed) -> Self {
170 self.feeds.push(feed);
171 self
172 }
173
174 pub fn with_skip(mut self, skip: OracleAdapterFeedSkip) -> Self {
176 self.skipped.push(skip);
177 self
178 }
179}
180
181pub struct OracleDiscoveryContext<'a> {
183 pub cache: &'a mut EvmCache,
185 pub now_timestamp: u64,
187}
188
189pub trait OracleAdapterPlugin: Send + Sync {
191 fn adapter_id(&self) -> OracleAdapterId;
193
194 fn discover<'a>(
196 &'a self,
197 ctx: OracleDiscoveryContext<'a>,
198 ) -> AdapterFuture<'a, OracleDiscoveryReport>;
199
200 fn reactive_handler(
202 &self,
203 registrations: Vec<FeedRegistration>,
204 storage_sync: OracleStorageSync,
205 ) -> Arc<dyn ReactiveHandler<Ethereum>>;
206}