Skip to main content

evm_oracle_state/
lib.rs

1//! A real-time oracle state engine built on a forked-EVM state cache
2//! ([`evm_fork_cache`]).
3//!
4//! `evm-oracle-state` is the oracle domain crate layered over
5//! [`evm_fork_cache`]: the companion crate owns generic cache invalidation,
6//! reactive batching, and reorg reporting, while this crate owns
7//! oracle-specific metadata, event decoding, typed snapshots, staleness
8//! policy, reconciliation, and feed lookup. Chainlink-compatible feeds are
9//! registered through their proxy addresses; adapter-owned oracle families
10//! (Aave, Morpho, Euler, Pyth, RedStone) plug into the same typed state,
11//! hook, and overlay surfaces behind feature flags.
12//!
13//! The central contract:
14//!
15//! > Events are fast-path hints; proxy reads are authoritative.
16//!
17//! Oracle log events update typed state immediately, so simulations can
18//! observe a new answer with no RPC on the hot path; authoritative proxy
19//! reads confirm, correct, or repair that state afterwards:
20//!
21//! ```text
22//! oracle log event (AnswerUpdated / OCR1+OCR2 NewTransmission / adapter event)
23//!   -> reactive handler decodes it; an OraclePriceUpdate hook fires immediately
24//!   -> OracleTracker stores an EventPending typed snapshot
25//!   -> OracleReadOverlay serves registered oracle view calls from typed state
26//!   -> OracleReconciler reads the proxy latestRoundData()
27//!   -> the snapshot becomes Confirmed or Corrected (or Stale / RequiresRepair)
28//! ```
29//!
30//! # Main types
31//!
32//! The internal modules are private; everything below is re-exported at the
33//! crate root:
34//!
35//! - [`OracleRuntime`] — the high-level runtime, built from a provider
36//!   ([`OracleRuntime::builder`]) or an existing cache
37//!   ([`OracleRuntime::cache_builder`]): [`ChainlinkFeed`] registrations,
38//!   typed event callbacks, storage/code warmup, and the reactive
39//!   install / refresh / uninstall lifecycle.
40//! - [`OracleAdapter`] — the cache-native registration path over an
41//!   [`evm_fork_cache::cache::EvmCache`]: [`Feed`] builders,
42//!   Multicall3-batched discovery reads, and skip-aware build reports.
43//! - [`OracleTracker`] — the typed state store: [`OracleSnapshot`] lookup
44//!   with freshness classification, [`OraclePriceUpdate`] hook payloads, and
45//!   reconciliation through [`OracleReconciler`].
46//! - [`OracleRegistry`] — feed registrations ([`FeedRegistration`],
47//!   [`FeedId`]), aggregator and dependency bookkeeping, and feed-readiness
48//!   reporting.
49//! - [`OracleReactiveHandler`] — dependency-aware log routing bridged into
50//!   the [`evm_fork_cache`] reactive runtime; detected OCR1/OCR2 layouts get
51//!   exact direct storage writes, everything else takes the conservative
52//!   purge/refetch fallback.
53//! - [`OracleReadOverlay`] — serves registered oracle view calls
54//!   (`latestRoundData()`, adapter reads such as Morpho `price()`, Euler
55//!   `getQuote(...)`, Pyth `getPriceUnsafe(...)`) from typed state, so
56//!   simulations see event prices before a follow-up RPC read completes.
57//! - [`PricePolicy`] / [`CheckedPrice`] — the typed price vocabulary
58//!   ([`AssetId`], [`Denomination`], [`TokenAmount`]): promote raw oracle
59//!   answers into policy-vetted values before liquidation or valuation
60//!   decisions.
61//! - [`OracleAdapterPlugin`] — the extension seam for oracle families that
62//!   are not plain Chainlink proxies: adapter-owned discovery plus an
63//!   adapter-owned reactive handler over the same runtime.
64//! - Feature-gated adapters — [`AaveV3OracleAdapter`] (`aave`),
65//!   [`MorphoBlueOracleAdapter`] (`morpho`), [`EulerOracleAdapter`]
66//!   (`euler`), [`PythOracleAdapter`] (`pyth`), and
67//!   [`RedstoneOracleAdapter`] (`redstone`).
68//!
69//! See the crate's `examples/local_oracle_lifecycle.rs` for the
70//! compile-checked quickstart: a deterministic, RPC-free walk through
71//! register → synthetic event → hook → overlay read → reconciliation.
72
73#![warn(missing_docs)]
74// docs.rs builds with `--cfg docsrs` (see `[package.metadata.docs.rs]`), which
75// enables nightly `doc_cfg`: every feature-gated item renders with its
76// "Available on crate feature … only" badge, derived automatically from the
77// existing `#[cfg]`s with no per-item annotations (auto-cfg is part of
78// `doc_cfg` since 1.92, rust-lang/rust#138907). Inert on stable builds.
79#![cfg_attr(docsrs, feature(doc_cfg))]
80
81/// Re-export of [`alloy_primitives`]: the `Address` / `U256` / `B256` / `Log`
82/// vocabulary this crate's API speaks.
83///
84/// Import from here (`evm_oracle_state::alloy_primitives`) to use exactly the
85/// version this crate's signatures expect without pinning `alloy-primitives`
86/// yourself.
87pub use alloy_primitives;
88/// Re-export of the [`evm_fork_cache`] companion crate: `EvmCache`, the
89/// reactive runtime, storage programs, and the typed errors that appear on
90/// this crate's cache and reactive seams.
91///
92/// `evm-fork-cache` is a 0.x **public dependency**: a semver-breaking bump
93/// there (e.g. 0.2 → 0.3) is necessarily a breaking release of this crate too,
94/// and the two are released in lockstep. Importing it through this re-export
95/// (`evm_oracle_state::evm_fork_cache`) guarantees the versions match.
96pub use evm_fork_cache;
97
98#[cfg(feature = "aave")]
99mod aave;
100mod adapter;
101mod cache_reader;
102mod code;
103mod config;
104mod derived;
105mod error;
106#[cfg(feature = "euler")]
107mod euler;
108mod events;
109mod feed;
110mod layout;
111mod mocking;
112#[cfg(feature = "morpho")]
113mod morpho;
114mod overlay;
115mod price;
116mod provider;
117#[cfg(feature = "pyth")]
118mod pyth;
119mod reactive;
120#[cfg(feature = "redstone")]
121mod redstone;
122mod registry;
123mod report;
124mod runtime;
125mod signal;
126mod state;
127mod storage;
128mod tracker;
129mod types;
130
131#[cfg(feature = "aave")]
132pub use aave::{AaveAsset, AaveV3OracleAdapter};
133pub use adapter::{
134    AdapterFuture, OracleAdapterId, OracleAdapterPlugin, OracleDiscoveredFeed,
135    OracleDiscoveryContext, OracleDiscoveryReport, OracleSourceDescriptor,
136    OracleTransformDescriptor,
137};
138pub use cache_reader::{
139    EvmCacheChainlinkReader, OracleAdapter, OracleAdapterBuildReport, OracleAdapterBuilder,
140    OracleAdapterFeedSkip, OracleAdapterSkipReason, OracleFeedSkip,
141};
142pub use code::{
143    OracleCodeInstall, OracleCodeInstallError, OracleCodeInstallMode, OracleCodeMismatch,
144    OracleCodePolicyViolation, OracleCodeRegistry, OracleCodeSeed, OracleCodeUnverifiable,
145    OracleCodeWarmupPolicy, OracleCodeWarmupReport,
146};
147pub use config::{FeedConfig, StalenessPolicy};
148pub use derived::OracleDerivedReader;
149pub use error::{
150    ChainlinkEventDecodeError, OracleConfigError, OracleError, OracleSignalDecodeError,
151};
152#[cfg(feature = "euler")]
153pub use euler::{EulerOracleAdapter, EulerQuotePair};
154pub use events::{
155    ANSWER_UPDATED_TOPIC, AnswerUpdated, NEW_ROUND_TOPIC, NewRound, OCR1_NEW_TRANSMISSION_TOPIC,
156    OCR2_NEW_TRANSMISSION_TOPIC, Ocr1NewTransmission, Ocr2NewTransmission, decode_answer_updated,
157    decode_new_round, decode_ocr1_new_transmission, decode_ocr2_new_transmission,
158};
159#[cfg(feature = "pyth")]
160pub use events::{
161    PYTH_PRICE_FEED_UPDATE_TOPIC, PythPriceFeedUpdate, decode_pyth_price_feed_update,
162};
163#[cfg(feature = "redstone")]
164pub use events::{REDSTONE_VALUE_UPDATE_TOPIC, RedstoneValueUpdate, decode_redstone_value_update};
165pub use feed::{Feed, FeedAccess, FeedBuilder, FeedBuilderState, FeedReady};
166pub use layout::{
167    AggregatorLayout, AggregatorLayoutConfidence, AggregatorLayoutEvidence,
168    classify_type_and_version,
169};
170pub use mocking::{OracleMockError, OracleMockReport, OracleOverlayMockExt, OraclePriceMock};
171#[cfg(feature = "morpho")]
172pub use morpho::{MorphoBlueMarket, MorphoBlueOracleAdapter, MorphoMarketParams};
173pub use overlay::OracleReadOverlay;
174pub use price::{CheckedPrice, OraclePrice, PricePolicy, PricePolicyViolation};
175pub use provider::{ChainlinkFeedProvider, OracleBlockRef, ProviderFuture};
176#[cfg(feature = "pyth")]
177pub use pyth::{PythFeed, PythOracleAdapter, PythReactiveHandler};
178pub use reactive::OracleReactiveHandler;
179#[cfg(feature = "redstone")]
180pub use redstone::{
181    RedstoneFeed, RedstoneMultiFeedStorageAdapter, RedstoneOracleAdapter,
182    RedstonePriceFeedsStorageAdapter, RedstoneReactiveHandler,
183};
184pub use registry::{
185    AggregatorChange, EulerQuoteLeg, FeedId, FeedRegistration, FeedSource, MorphoChainlinkFeed,
186    MorphoChainlinkFeedRole, OracleDependency, OracleFeedReadinessReport, OracleRegistry,
187};
188pub use report::{
189    OracleBatchReport, OracleChangeImpact, OracleFeedChange, OracleFeedChangeKind, OracleIncident,
190};
191pub use runtime::{
192    ChainlinkFeed, OracleCacheRuntimeBuildReport, OracleCacheRuntimeBuilder,
193    OracleColdStartWarmupReport, OracleReactiveInstallReport, OracleReactiveRefreshReport,
194    OracleReactiveUninstallReport, OracleRuntime, OracleRuntimeBuilder,
195    OracleRuntimeMutationReport, OracleStorageWarmupFailure, OracleStorageWarmupMode,
196    OracleStorageWarmupReport,
197};
198pub use signal::{
199    ORACLE_LEGACY_ANSWER_UPDATED_KIND, ORACLE_SIGNAL_NAMESPACE, OracleSignal, OracleSignalKind,
200};
201pub use state::{
202    FeedMetadata, OracleFeedStatus, OracleRoundStatus, OracleSnapshot, OracleValueSource,
203    OracleValueStatus, RoundData,
204};
205pub use storage::{
206    ChainlinkOcr1StorageAdapter, ChainlinkOcr2StorageAdapter, Ocr1TransmissionStorageUpdate,
207    Ocr2TransmissionStorageUpdate, OracleStorageAdapter, OracleStorageEffect, OracleStorageError,
208    OracleStorageSync,
209};
210pub use tracker::{
211    DerivedReconcileFailure, DerivedReconcileReport, OracleAggregatorChanged, OracleHookEvent,
212    OraclePriceConfirmed, OraclePriceCorrected, OraclePriceStale, OraclePriceUpdate,
213    OracleReconciler, OracleReconciliationKind, OracleReconciliationRequest,
214    OracleReconciliationResult, OracleTracker, OracleUpdate, ReconcileReport,
215};
216pub use types::{AssetId, Denomination, TokenAmount, ValuedAmount};
217
218/// Compiles the README's code samples as doctests so the documented snippets
219/// cannot drift from the real API. Exists only under `cfg(doctest)` — it is
220/// never part of the built crate or the rendered docs. Gated on every adapter
221/// feature because the README demonstrates the Aave / Morpho / Euler / Pyth /
222/// RedStone surfaces; the adapter-features test run (local + CI) compiles it.
223#[cfg(all(
224    doctest,
225    feature = "aave",
226    feature = "morpho",
227    feature = "euler",
228    feature = "pyth",
229    feature = "redstone"
230))]
231#[doc = include_str!("../README.md")]
232pub struct ReadmeDoctests;