#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
pub mod weights;
pub use pallet::*;
pub use weights::WeightInfo;
#[frame_support::pallet]
pub mod pallet {
use cfg_traits::{fees::PayFee, ValueProvider};
use frame_support::{
pallet_prelude::*,
traits::{OriginTrait, Time},
};
use frame_system::pallet_prelude::*;
use crate::weights::WeightInfo;
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
pub type MomentOf<T> = <<T as Config>::Time as Time>::Moment;
pub type Feeder<T> = <<T as frame_system::Config>::RuntimeOrigin as OriginTrait>::PalletsOrigin;
#[pallet::pallet]
#[pallet::storage_version(STORAGE_VERSION)]
pub struct Pallet<T>(_);
#[pallet::config]
pub trait Config: frame_system::Config {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
type OracleKey: Parameter + Member + Copy + MaxEncodedLen;
type OracleValue: Parameter + Member + Copy + MaxEncodedLen + Default;
type Time: Time;
type FirstValuePayFee: PayFee<<Self::RuntimeOrigin as OriginTrait>::AccountId>;
type WeightInfo: WeightInfo;
type FeederOrigin: EnsureOrigin<Self::RuntimeOrigin>;
}
#[pallet::storage]
pub(crate) type FedValues<T: Config> = StorageDoubleMap<
_,
Blake2_128Concat,
Feeder<T>,
Blake2_128Concat,
T::OracleKey,
(T::OracleValue, MomentOf<T>),
>;
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
Fed {
feeder: Feeder<T>,
key: T::OracleKey,
value: T::OracleValue,
},
}
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::weight(T::WeightInfo::feed_with_fee())]
#[pallet::call_index(0)]
pub fn feed(
origin: OriginFor<T>,
key: T::OracleKey,
value: T::OracleValue,
) -> DispatchResultWithPostInfo {
let _ = T::FeederOrigin::ensure_origin(origin.clone())?;
let feeder = origin.clone().into_caller();
let signed_account = origin.into_signer();
FedValues::<T>::mutate(&feeder, key, |prev_value| {
let new_weight = match (&prev_value, signed_account) {
(None, Some(account_id)) => {
T::FirstValuePayFee::pay(&account_id)?;
None
}
_ => {
Some(T::WeightInfo::feed_without_fee())
}
};
*prev_value = Some((value, T::Time::now()));
Self::deposit_event(Event::<T>::Fed {
feeder: feeder.clone(),
key,
value,
});
Ok(new_weight.into())
})
}
}
impl<T: Config> ValueProvider<T::RuntimeOrigin, T::OracleKey> for Pallet<T> {
type Value = (T::OracleValue, MomentOf<T>);
fn get(
source: &T::RuntimeOrigin,
id: &T::OracleKey,
) -> Result<Option<Self::Value>, DispatchError> {
Ok(FedValues::<T>::get(source.caller(), id))
}
#[cfg(feature = "runtime-benchmarks")]
fn set(source: &T::RuntimeOrigin, key: &T::OracleKey, value: Self::Value) {
FedValues::<T>::insert(source.caller(), key, value)
}
}
}
pub mod util {
use parity_scale_codec::MaxEncodedLen;
use crate::pallet::{Config, MomentOf};
pub fn size_of_feed<T: Config>() -> u32 {
let max_len = <(T::OracleKey, T::OracleValue, MomentOf<T>)>::max_encoded_len();
match max_len.try_into() {
Ok(size) => size,
Err(_) => u32::MAX,
}
}
}