use alloy_primitives::I256;
use evm_fork_cache::cache::EvmCache;
use crate::{FeedRegistration, OracleError};
#[cfg(feature = "morpho")]
alloy_sol_types::sol! {
interface MorphoDerivedOracle {
function price() external view returns (uint256);
}
}
#[cfg(feature = "euler")]
alloy_sol_types::sol! {
interface EulerDerivedOracle {
function getQuote(uint256 inAmount, address base, address quote) external view returns (uint256 outAmount);
}
}
pub trait OracleDerivedReader {
fn read_derived_value(&mut self, registration: &FeedRegistration) -> Result<I256, OracleError>;
}
impl OracleDerivedReader for EvmCache {
fn read_derived_value(&mut self, registration: &FeedRegistration) -> Result<I256, OracleError> {
#[cfg(feature = "morpho")]
if let crate::FeedSource::MorphoChainlinkV2 { source, .. } = ®istration.source {
let price = self
.call_sol(*source, MorphoDerivedOracle::priceCall {})
.map_err(|error| {
OracleError::Provider(format!(
"Morpho price() read via {source:?} failed: {error}"
))
})?;
return i256_answer(price, "Morpho price()");
}
#[cfg(feature = "euler")]
if let crate::FeedSource::EulerQuote {
source,
base,
quote,
base_decimals,
..
}
| crate::FeedSource::EulerCross {
source,
base,
quote,
base_decimals,
..
} = ®istration.source
{
let in_amount = crate::euler::one_base_unit(*base_decimals)?;
let out = self
.call_sol(
*source,
EulerDerivedOracle::getQuoteCall {
inAmount: in_amount,
base: *base,
quote: *quote,
},
)
.map_err(|error| {
OracleError::Provider(format!(
"Euler getQuote read via {source:?} failed: {error}"
))
})?;
return i256_answer(out, "Euler getQuote outAmount");
}
Err(OracleError::Unsupported(format!(
"source for feed `{}` has no derived protocol read",
registration.id
)))
}
}
#[cfg(any(feature = "morpho", feature = "euler"))]
fn i256_answer(value: alloy_primitives::U256, field: &'static str) -> Result<I256, OracleError> {
I256::try_from(value)
.map_err(|_| OracleError::Unsupported(format!("{field} does not fit int256")))
}