use alloc::vec;
use miden_protocol::account::component::{
AccountComponentCode,
AccountComponentMetadata,
SchemaType,
StorageSchema,
StorageSlotSchema,
};
use miden_protocol::account::{
AccountComponent,
AccountComponentName,
AccountProcedureRoot,
StorageSlot,
StorageSlotName,
};
use miden_protocol::utils::sync::LazyLock;
use crate::account::account_component_code;
use crate::procedure_root;
account_component_code!(PRICE_ORACLE_CODE, "miden-standards-oracle-price-oracle.masp");
const PRICE_ORACLE_LIBRARY_PATH: &str = "miden::standards::components::oracle::price_oracle";
procedure_root!(
PRICE_ORACLE_GET_CONVERSION_RATE_ROOT,
PRICE_ORACLE_LIBRARY_PATH,
PriceOracle::GET_CONVERSION_RATE_PROC_NAME,
PriceOracle::code()
);
procedure_root!(
PRICE_ORACLE_SET_RATE_PROVIDER_ROOT,
PRICE_ORACLE_LIBRARY_PATH,
PriceOracle::SET_RATE_PROVIDER_PROC_NAME,
PriceOracle::code()
);
static ACTIVE_RATE_PROVIDER_SLOT_NAME: LazyLock<StorageSlotName> = LazyLock::new(|| {
StorageSlotName::new("miden::standards::oracle::price_oracle::active_rate_provider_proc_root")
.expect("storage slot name should be valid")
});
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PriceOracle {
rate_provider: AccountProcedureRoot,
}
impl PriceOracle {
pub const NAME: &'static str = "miden::standards::oracle::price_oracle";
pub(crate) const GET_CONVERSION_RATE_PROC_NAME: &'static str = "get_conversion_rate";
const SET_RATE_PROVIDER_PROC_NAME: &'static str = "set_rate_provider";
pub const fn new(rate_provider: AccountProcedureRoot) -> Self {
Self { rate_provider }
}
pub const fn name() -> AccountComponentName {
AccountComponentName::from_static_str(Self::NAME)
}
pub fn code() -> &'static AccountComponentCode {
&PRICE_ORACLE_CODE
}
pub fn get_conversion_rate_root() -> AccountProcedureRoot {
*PRICE_ORACLE_GET_CONVERSION_RATE_ROOT
}
pub fn set_rate_provider_root() -> AccountProcedureRoot {
*PRICE_ORACLE_SET_RATE_PROVIDER_ROOT
}
pub fn active_rate_provider_slot() -> &'static StorageSlotName {
&ACTIVE_RATE_PROVIDER_SLOT_NAME
}
pub const fn rate_provider(&self) -> AccountProcedureRoot {
self.rate_provider
}
pub fn active_rate_provider_slot_schema() -> (StorageSlotName, StorageSlotSchema) {
(
Self::active_rate_provider_slot().clone(),
StorageSlotSchema::value(
"Procedure root of the active rate provider",
SchemaType::native_word(),
),
)
}
pub fn component_metadata() -> AccountComponentMetadata {
let storage_schema = StorageSchema::new([Self::active_rate_provider_slot_schema()])
.expect("storage schema should be valid");
AccountComponentMetadata::new(Self::NAME)
.with_description("Reports the conversion rate between two assets")
.with_storage_schema(storage_schema)
}
}
impl From<PriceOracle> for AccountComponent {
fn from(oracle: PriceOracle) -> Self {
AccountComponent::new(
PriceOracle::code().clone(),
vec![StorageSlot::with_value(
PriceOracle::active_rate_provider_slot().clone(),
*oracle.rate_provider.mast_root(),
)],
PriceOracle::component_metadata(),
)
.expect(
"price oracle component should satisfy the requirements of a valid account component",
)
}
}