use evm_fork_cache::reactive::HookSignal;
use crate::{
AggregatorChange, OracleHookEvent, OraclePriceConfirmed, OraclePriceCorrected,
OraclePriceStale, OraclePriceUpdate, OracleSignalDecodeError, OracleUpdate,
};
pub const ORACLE_SIGNAL_NAMESPACE: &str = "evm-oracle-state";
pub const ORACLE_LEGACY_ANSWER_UPDATED_KIND: &str = "oracle.answer_updated";
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum OracleSignalKind {
PriceUpdate,
PriceConfirmed,
PriceCorrected,
PriceStale,
AggregatorChanged,
}
impl OracleSignalKind {
pub const fn as_str(self) -> &'static str {
match self {
Self::PriceUpdate => "oracle.price_update",
Self::PriceConfirmed => "oracle.price_confirmed",
Self::PriceCorrected => "oracle.price_corrected",
Self::PriceStale => "oracle.price_stale",
Self::AggregatorChanged => "oracle.aggregator_changed",
}
}
pub fn parse(kind: &str) -> Option<Self> {
match kind {
"oracle.price_update" => Some(Self::PriceUpdate),
"oracle.price_confirmed" => Some(Self::PriceConfirmed),
"oracle.price_corrected" => Some(Self::PriceCorrected),
"oracle.price_stale" => Some(Self::PriceStale),
"oracle.aggregator_changed" => Some(Self::AggregatorChanged),
_ => None,
}
}
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum OracleSignal<'a> {
PriceUpdate(&'a OraclePriceUpdate),
PriceConfirmed(&'a OraclePriceConfirmed),
PriceCorrected(&'a OraclePriceCorrected),
PriceStale(&'a OraclePriceStale),
AggregatorChanged(&'a AggregatorChange),
}
impl<'a> OracleSignal<'a> {
pub fn from_hook(signal: &'a HookSignal) -> Result<Option<Self>, OracleSignalDecodeError> {
if signal.namespace.as_ref() != ORACLE_SIGNAL_NAMESPACE {
return Ok(None);
}
let Some(kind) = OracleSignalKind::parse(signal.kind.as_ref()) else {
return Ok(None);
};
let payload =
signal
.payload
.as_ref()
.ok_or_else(|| OracleSignalDecodeError::MissingPayload {
kind: signal.kind.to_string(),
})?;
if let Some(event) = payload.downcast_ref::<OracleHookEvent>() {
return event
.as_signal()
.ok_or_else(|| OracleSignalDecodeError::WrongPayloadType {
kind: signal.kind.to_string(),
})
.map(Some);
}
match kind {
OracleSignalKind::PriceUpdate => payload
.downcast_ref::<OraclePriceUpdate>()
.map(Self::PriceUpdate),
OracleSignalKind::PriceConfirmed => payload
.downcast_ref::<OraclePriceConfirmed>()
.map(Self::PriceConfirmed),
OracleSignalKind::PriceCorrected => payload
.downcast_ref::<OraclePriceCorrected>()
.map(Self::PriceCorrected),
OracleSignalKind::PriceStale => payload
.downcast_ref::<OraclePriceStale>()
.map(Self::PriceStale),
OracleSignalKind::AggregatorChanged => payload
.downcast_ref::<AggregatorChange>()
.map(Self::AggregatorChanged),
}
.ok_or_else(|| OracleSignalDecodeError::WrongPayloadType {
kind: signal.kind.to_string(),
})
.map(Some)
}
pub fn to_event(self) -> OracleHookEvent {
match self {
Self::PriceUpdate(update) => OracleHookEvent::PriceUpdate(update.clone()),
Self::PriceConfirmed(confirmed) => OracleHookEvent::PriceConfirmed(confirmed.clone()),
Self::PriceCorrected(corrected) => OracleHookEvent::PriceCorrected(corrected.clone()),
Self::PriceStale(stale) => OracleHookEvent::PriceStale(stale.clone()),
Self::AggregatorChanged(change) => OracleHookEvent::AggregatorChanged(change.clone()),
}
}
}
impl OracleHookEvent {
pub fn signal_kind(&self) -> OracleSignalKind {
match self {
Self::PriceUpdate(_) => OracleSignalKind::PriceUpdate,
Self::PriceConfirmed(_) => OracleSignalKind::PriceConfirmed,
Self::PriceCorrected(_) => OracleSignalKind::PriceCorrected,
Self::PriceStale(_) => OracleSignalKind::PriceStale,
Self::AggregatorChanged(_) => OracleSignalKind::AggregatorChanged,
}
}
pub fn kind_str(&self) -> &'static str {
self.signal_kind().as_str()
}
pub(crate) fn as_signal(&self) -> Option<OracleSignal<'_>> {
match self {
Self::PriceUpdate(update) => Some(OracleSignal::PriceUpdate(update)),
Self::PriceConfirmed(confirmed) => Some(OracleSignal::PriceConfirmed(confirmed)),
Self::PriceCorrected(corrected) => Some(OracleSignal::PriceCorrected(corrected)),
Self::PriceStale(stale) => Some(OracleSignal::PriceStale(stale)),
Self::AggregatorChanged(change) => Some(OracleSignal::AggregatorChanged(change)),
}
}
}
impl OracleUpdate {
pub const KIND: &'static str = ORACLE_LEGACY_ANSWER_UPDATED_KIND;
}