#![recursion_limit = "256"]
#![cfg_attr(not(feature = "std"), no_std)]
use frame_support::{
pallet_prelude::*,
traits::tokens::asset_ops::{
common_strategies::{DeriveAndReportId, NoParams},
AssetDefinition, Create, Destroy,
},
};
use frame_system::pallet_prelude::*;
use sp_runtime::DispatchResult;
pub use pallet::*;
pub mod misc;
pub use misc::*;
#[cfg(feature = "runtime-benchmarks")]
pub mod benchmarking;
#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;
pub const LOG_TARGET: &'static str = "runtime::xcm::derivatives";
pub struct SaveMappingTo<Derivative>(pub Derivative);
type OriginalOf<T, I> = <T as Config<I>>::Original;
type DerivativeOf<T, I> = <T as Config<I>>::Derivative;
type DerivativeExtraOf<T, I> = <T as Config<I>>::DerivativeExtra;
#[frame_support::pallet]
pub mod pallet {
use super::*;
#[pallet::pallet]
pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
#[pallet::config]
pub trait Config<I: 'static = ()>: frame_system::Config {
type WeightInfo: WeightInfo;
type Original: Member + Parameter + MaxEncodedLen;
type Derivative: Member + Parameter + MaxEncodedLen;
type DerivativeExtra: Member + Parameter + MaxEncodedLen;
type CreateOrigin: EnsureOrigin<Self::RuntimeOrigin>;
type CreateOp: Create<
DeriveAndReportId<Self::Original, Option<SaveMappingTo<Self::Derivative>>>,
>;
type DestroyOrigin: EnsureOrigin<Self::RuntimeOrigin>;
type DestroyOp: AssetDefinition<Id = Self::Original> + Destroy<NoParams>;
}
#[pallet::storage]
#[pallet::getter(fn original_to_derivative)]
pub type OriginalToDerivative<T: Config<I>, I: 'static = ()> =
StorageMap<_, Blake2_128Concat, OriginalOf<T, I>, DerivativeOf<T, I>, OptionQuery>;
#[pallet::storage]
#[pallet::getter(fn derivative_to_original)]
pub type DerivativeToOriginal<T: Config<I>, I: 'static = ()> =
StorageMap<_, Blake2_128Concat, DerivativeOf<T, I>, OriginalOf<T, I>, OptionQuery>;
#[pallet::storage]
#[pallet::getter(fn derivative_extra)]
pub type DerivativeExtra<T: Config<I>, I: 'static = ()> =
StorageMap<_, Blake2_128Concat, DerivativeOf<T, I>, DerivativeExtraOf<T, I>, OptionQuery>;
#[pallet::event]
#[pallet::generate_deposit(pub(crate) fn deposit_event)]
pub enum Event<T: Config<I>, I: 'static = ()> {
DerivativeCreated { original: OriginalOf<T, I> },
DerivativeMappingCreated { original: OriginalOf<T, I>, derivative_id: DerivativeOf<T, I> },
DerivativeDestroyed { original: OriginalOf<T, I> },
}
#[pallet::error]
pub enum Error<T, I = ()> {
DerivativeAlreadyExists,
NoDerivativeToDeregister,
DerivativeNotFound,
DerivativeExtraDataNotFound,
OriginalNotFound,
InvalidAsset,
}
#[pallet::call(weight(T::WeightInfo))]
impl<T: Config<I>, I: 'static> Pallet<T, I> {
#[pallet::call_index(0)]
pub fn create_derivative(
origin: OriginFor<T>,
original: OriginalOf<T, I>,
) -> DispatchResult {
T::CreateOrigin::ensure_origin(origin)?;
let maybe_save_mapping =
T::CreateOp::create(DeriveAndReportId::from(original.clone()))?;
if let Some(SaveMappingTo(derivative)) = maybe_save_mapping {
Self::try_register_derivative(&original, &derivative)?;
}
Self::deposit_event(Event::<T, I>::DerivativeCreated { original });
Ok(())
}
#[pallet::call_index(1)]
pub fn destroy_derivative(
origin: OriginFor<T>,
original: OriginalOf<T, I>,
) -> DispatchResult {
T::DestroyOrigin::ensure_origin(origin)?;
T::DestroyOp::destroy(&original, NoParams)?;
if Self::get_derivative(&original).is_ok() {
Self::try_deregister_derivative_of(&original)?;
}
Ok(())
}
}
}
impl<T: Config<I>, I: 'static> DerivativesRegistry<OriginalOf<T, I>, DerivativeOf<T, I>>
for Pallet<T, I>
{
fn try_register_derivative(
original: &OriginalOf<T, I>,
derivative: &DerivativeOf<T, I>,
) -> DispatchResult {
ensure!(
Self::original_to_derivative(original).is_none(),
Error::<T, I>::DerivativeAlreadyExists,
);
<OriginalToDerivative<T, I>>::insert(original, derivative);
<DerivativeToOriginal<T, I>>::insert(derivative, original);
Self::deposit_event(Event::<T, I>::DerivativeCreated { original: original.clone() });
Ok(())
}
fn try_deregister_derivative_of(original: &OriginalOf<T, I>) -> DispatchResult {
let derivative = <OriginalToDerivative<T, I>>::take(&original)
.ok_or(Error::<T, I>::NoDerivativeToDeregister)?;
<DerivativeToOriginal<T, I>>::remove(&derivative);
<DerivativeExtra<T, I>>::remove(&derivative);
Self::deposit_event(Event::<T, I>::DerivativeDestroyed { original: original.clone() });
Ok(())
}
fn get_derivative(original: &OriginalOf<T, I>) -> Result<DerivativeOf<T, I>, DispatchError> {
<OriginalToDerivative<T, I>>::get(original).ok_or(Error::<T, I>::DerivativeNotFound.into())
}
fn get_original(derivative: &DerivativeOf<T, I>) -> Result<OriginalOf<T, I>, DispatchError> {
<DerivativeToOriginal<T, I>>::get(derivative).ok_or(Error::<T, I>::OriginalNotFound.into())
}
}
impl<T: Config<I>, I: 'static> IterDerivativesRegistry<OriginalOf<T, I>, DerivativeOf<T, I>>
for Pallet<T, I>
{
fn iter_originals() -> impl Iterator<Item = OriginalOf<T, I>> {
<OriginalToDerivative<T, I>>::iter_keys()
}
fn iter_derivatives() -> impl Iterator<Item = DerivativeOf<T, I>> {
<OriginalToDerivative<T, I>>::iter_values()
}
fn iter() -> impl Iterator<Item = (OriginalOf<T, I>, DerivativeOf<T, I>)> {
<OriginalToDerivative<T, I>>::iter()
}
}
impl<T: Config<I>, I: 'static> DerivativesExtra<DerivativeOf<T, I>, DerivativeExtraOf<T, I>>
for Pallet<T, I>
{
fn get_derivative_extra(derivative: &DerivativeOf<T, I>) -> Option<DerivativeExtraOf<T, I>> {
<DerivativeExtra<T, I>>::get(derivative)
}
fn set_derivative_extra(
derivative: &DerivativeOf<T, I>,
extra: Option<DerivativeExtraOf<T, I>>,
) -> DispatchResult {
ensure!(
<DerivativeToOriginal<T, I>>::contains_key(derivative),
Error::<T, I>::DerivativeNotFound,
);
<DerivativeExtra<T, I>>::set(derivative, extra);
Ok(())
}
}
pub trait WeightInfo {
fn create_derivative() -> Weight;
fn destroy_derivative() -> Weight;
}
pub struct TestWeightInfo;
impl WeightInfo for TestWeightInfo {
fn create_derivative() -> Weight {
Weight::from_parts(100_000_000, 0)
}
fn destroy_derivative() -> Weight {
Weight::from_parts(100_000_000, 0)
}
}
pub struct NoStoredMapping<CreateOp>(PhantomData<CreateOp>);
impl<CreateOp, Original, Derivative>
Create<DeriveAndReportId<Original, Option<SaveMappingTo<Derivative>>>>
for NoStoredMapping<CreateOp>
where
CreateOp: Create<DeriveAndReportId<Original, Derivative>>,
{
fn create(
strategy: DeriveAndReportId<Original, Option<SaveMappingTo<Derivative>>>,
) -> Result<Option<SaveMappingTo<Derivative>>, DispatchError> {
CreateOp::create(DeriveAndReportId::from(strategy.params))?;
Ok(None)
}
}
pub struct StoreMapping<CreateOp>(PhantomData<CreateOp>);
impl<CreateOp, Original, Derivative>
Create<DeriveAndReportId<Original, Option<SaveMappingTo<Derivative>>>> for StoreMapping<CreateOp>
where
CreateOp: Create<DeriveAndReportId<Original, Derivative>>,
{
fn create(
strategy: DeriveAndReportId<Original, Option<SaveMappingTo<Derivative>>>,
) -> Result<Option<SaveMappingTo<Derivative>>, DispatchError> {
let derivative = CreateOp::create(DeriveAndReportId::from(strategy.params))?;
Ok(Some(SaveMappingTo(derivative)))
}
}
pub struct InvalidAssetError<Pallet>(PhantomData<Pallet>);
impl<T: Config<I>, I: 'static> TypedGet for InvalidAssetError<Pallet<T, I>> {
type Type = Error<T, I>;
fn get() -> Self::Type {
Error::<T, I>::InvalidAsset
}
}