#![cfg_attr(not(feature = "std"), no_std)]
use frame_support::pallet;
pub use pallet::*;
#[cfg(any(test, feature = "runtime-benchmarks"))]
mod benchmarks;
pub mod migrations;
#[cfg(test)]
pub mod mock;
#[cfg(test)]
pub mod tests;
pub mod weights;
pub use crate::weights::WeightInfo;
#[pallet]
pub mod pallet {
use super::*;
use frame_support::{pallet_prelude::*, PalletId};
use frame_system::pallet_prelude::*;
use parity_scale_codec::HasCompact;
use sp_runtime::traits::{AccountIdConversion, AtLeast32BitUnsigned};
#[pallet::pallet]
#[pallet::without_storage_info]
pub struct Pallet<T>(PhantomData<T>);
pub const PALLET_ID: PalletId = PalletId(*b"asstmngr");
pub trait AssetRegistrar<T: Config> {
fn create_foreign_asset(
_asset: T::AssetId,
_min_balance: T::Balance,
_metadata: T::AssetRegistrarMetadata,
_is_sufficient: bool,
) -> DispatchResult {
unimplemented!()
}
fn destroy_foreign_asset(_asset: T::AssetId) -> DispatchResult {
unimplemented!()
}
fn destroy_asset_dispatch_info_weight(_asset: T::AssetId) -> Weight;
}
impl<T: Config> xcm_primitives::AssetTypeGetter<T::AssetId, T::ForeignAssetType> for Pallet<T> {
fn get_asset_type(asset_id: T::AssetId) -> Option<T::ForeignAssetType> {
AssetIdType::<T>::get(asset_id)
}
fn get_asset_id(asset_type: T::ForeignAssetType) -> Option<T::AssetId> {
AssetTypeId::<T>::get(asset_type)
}
#[cfg(feature = "runtime-benchmarks")]
fn set_asset_type_asset_id(asset_type: T::ForeignAssetType, asset_id: T::AssetId) {
AssetTypeId::<T>::insert(&asset_type, asset_id);
AssetIdType::<T>::insert(&asset_id, asset_type);
}
}
#[pallet::config]
pub trait Config: frame_system::Config {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
type AssetId: Member + Parameter + Default + Copy + HasCompact + MaxEncodedLen;
type AssetRegistrarMetadata: Member + Parameter + Default;
type ForeignAssetType: Parameter + Member + Ord + PartialOrd + Into<Self::AssetId> + Default;
type Balance: Member + Parameter + AtLeast32BitUnsigned + Default + Copy + MaxEncodedLen;
type AssetRegistrar: AssetRegistrar<Self>;
type ForeignAssetModifierOrigin: EnsureOrigin<Self::RuntimeOrigin>;
type WeightInfo: WeightInfo;
}
#[pallet::error]
pub enum Error<T> {
ErrorCreatingAsset,
AssetAlreadyExists,
AssetDoesNotExist,
TooLowNumAssetsWeightHint,
LocalAssetLimitReached,
ErrorDestroyingAsset,
NotSufficientDeposit,
NonExistentLocalAsset,
}
#[pallet::event]
#[pallet::generate_deposit(pub(crate) fn deposit_event)]
pub enum Event<T: Config> {
ForeignAssetRegistered {
asset_id: T::AssetId,
asset: T::ForeignAssetType,
metadata: T::AssetRegistrarMetadata,
},
#[deprecated(note = "Should not be used")]
UnitsPerSecondChanged,
ForeignAssetXcmLocationChanged {
asset_id: T::AssetId,
new_asset_type: T::ForeignAssetType,
},
ForeignAssetRemoved {
asset_id: T::AssetId,
asset_type: T::ForeignAssetType,
},
SupportedAssetRemoved { asset_type: T::ForeignAssetType },
ForeignAssetDestroyed {
asset_id: T::AssetId,
asset_type: T::ForeignAssetType,
},
LocalAssetDestroyed { asset_id: T::AssetId },
}
#[pallet::storage]
#[pallet::getter(fn asset_id_type)]
pub type AssetIdType<T: Config> =
StorageMap<_, Blake2_128Concat, T::AssetId, T::ForeignAssetType>;
#[pallet::storage]
#[pallet::getter(fn asset_type_id)]
pub type AssetTypeId<T: Config> =
StorageMap<_, Blake2_128Concat, T::ForeignAssetType, T::AssetId>;
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::call_index(0)]
#[pallet::weight(T::WeightInfo::register_foreign_asset())]
pub fn register_foreign_asset(
origin: OriginFor<T>,
asset: T::ForeignAssetType,
metadata: T::AssetRegistrarMetadata,
min_amount: T::Balance,
is_sufficient: bool,
) -> DispatchResult {
T::ForeignAssetModifierOrigin::ensure_origin(origin)?;
let asset_id: T::AssetId = asset.clone().into();
ensure!(
AssetIdType::<T>::get(&asset_id).is_none(),
Error::<T>::AssetAlreadyExists
);
T::AssetRegistrar::create_foreign_asset(
asset_id,
min_amount,
metadata.clone(),
is_sufficient,
)
.map_err(|_| Error::<T>::ErrorCreatingAsset)?;
AssetIdType::<T>::insert(&asset_id, &asset);
AssetTypeId::<T>::insert(&asset, &asset_id);
Self::deposit_event(Event::ForeignAssetRegistered {
asset_id,
asset,
metadata,
});
Ok(())
}
#[pallet::call_index(2)]
#[pallet::weight(T::WeightInfo::change_existing_asset_type())]
pub fn change_existing_asset_type(
origin: OriginFor<T>,
asset_id: T::AssetId,
new_asset_type: T::ForeignAssetType,
_num_assets_weight_hint: u32,
) -> DispatchResult {
T::ForeignAssetModifierOrigin::ensure_origin(origin)?;
let previous_asset_type =
AssetIdType::<T>::get(&asset_id).ok_or(Error::<T>::AssetDoesNotExist)?;
AssetIdType::<T>::insert(&asset_id, &new_asset_type);
AssetTypeId::<T>::insert(&new_asset_type, &asset_id);
AssetTypeId::<T>::remove(&previous_asset_type);
Self::deposit_event(Event::ForeignAssetXcmLocationChanged {
asset_id,
new_asset_type,
});
Ok(())
}
#[pallet::call_index(4)]
#[pallet::weight(T::WeightInfo::remove_existing_asset_type())]
pub fn remove_existing_asset_type(
origin: OriginFor<T>,
asset_id: T::AssetId,
_num_assets_weight_hint: u32,
) -> DispatchResult {
T::ForeignAssetModifierOrigin::ensure_origin(origin)?;
let asset_type =
AssetIdType::<T>::get(&asset_id).ok_or(Error::<T>::AssetDoesNotExist)?;
AssetIdType::<T>::remove(&asset_id);
AssetTypeId::<T>::remove(&asset_type);
Self::deposit_event(Event::ForeignAssetRemoved {
asset_id,
asset_type,
});
Ok(())
}
#[pallet::call_index(6)]
#[pallet::weight({
let dispatch_info_weight = T::AssetRegistrar::destroy_asset_dispatch_info_weight(
*asset_id
);
T::WeightInfo::remove_existing_asset_type()
.saturating_add(dispatch_info_weight)
})]
pub fn destroy_foreign_asset(
origin: OriginFor<T>,
asset_id: T::AssetId,
_num_assets_weight_hint: u32,
) -> DispatchResult {
T::ForeignAssetModifierOrigin::ensure_origin(origin)?;
T::AssetRegistrar::destroy_foreign_asset(asset_id)
.map_err(|_| Error::<T>::ErrorDestroyingAsset)?;
let asset_type =
AssetIdType::<T>::get(&asset_id).ok_or(Error::<T>::AssetDoesNotExist)?;
AssetIdType::<T>::remove(&asset_id);
AssetTypeId::<T>::remove(&asset_type);
Self::deposit_event(Event::ForeignAssetDestroyed {
asset_id,
asset_type,
});
Ok(())
}
}
impl<T: Config> Pallet<T> {
pub fn account_id() -> T::AccountId {
PALLET_ID.into_account_truncating()
}
}
}