12345678910111213141516171819202122232425262728293031323334#![cfg_attr(not(feature = "std"), no_std)]35#![allow(clippy::unused_unit)]3637use frame_support::{dispatch::DispatchResult, pallet_prelude::*, traits::EnsureOrigin, PalletId};38use frame_system::pallet_prelude::*;39use pallet_common::{40 dispatch::CollectionDispatch, erc::CrossAccountId, NATIVE_FUNGIBLE_COLLECTION_ID,41};42use sp_runtime::traits::AccountIdConversion;43use sp_std::{vec, vec::Vec};444546use staging_xcm::{47 opaque::latest::{prelude::XcmError, Weight},48 v3::{prelude::*, MultiAsset, XcmContext},49};50use staging_xcm_executor::{51 traits::{TransactAsset, WeightTrader},52 Assets,53};54use up_data_structs::{55 CollectionId, CollectionMode, CollectionName, CreateCollectionData, PropertyKey, TokenId,56};5758pub mod weights;5960#[cfg(feature = "runtime-benchmarks")]61mod benchmarking;6263pub use module::*;64pub use weights::WeightInfo;6566#[frame_support::pallet]67pub mod module {68 use up_data_structs::{69 CollectionDescription, Property, PropertyKeyPermission, PropertyPermission,70 };7172 use super::*;7374 #[pallet::config]75 pub trait Config:76 frame_system::Config77 + pallet_common::Config78 + pallet_fungible::Config79 + pallet_balances::Config80 {81 82 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;8384 85 type ForceRegisterOrigin: EnsureOrigin<Self::RuntimeOrigin>;8687 88 type PalletId: Get<PalletId>;8990 91 type WeightInfo: WeightInfo;92 }9394 #[pallet::error]95 pub enum Error<T> {96 97 ForeignAssetAlreadyRegistered,98 }99100 #[pallet::event]101 #[pallet::generate_deposit(fn deposit_event)]102 pub enum Event<T: Config> {103 104 ForeignAssetRegistered {105 asset_id: CollectionId,106 reserve_location: MultiLocation,107 },108 }109110 111 #[pallet::storage]112 #[pallet::getter(fn foreign_reserve_location_to_collection)]113 pub type ForeignReserveLocationToCollection<T: Config> =114 StorageMap<_, Twox64Concat, staging_xcm::v3::MultiLocation, CollectionId, OptionQuery>;115116 117 #[pallet::storage]118 #[pallet::getter(fn foreign_reserve_asset_instance_to_token_id)]119 pub type ForeignReserveAssetInstanceToTokenId<T: Config> = StorageDoubleMap<120 Hasher1 = Twox64Concat,121 Key1 = CollectionId,122 Hasher2 = Twox64Concat,123 Key2 = staging_xcm::v3::AssetInstance,124 Value = TokenId,125 QueryKind = OptionQuery,126 >;127128 #[pallet::pallet]129 pub struct Pallet<T>(_);130131 #[pallet::call]132 impl<T: Config> Pallet<T> {133 #[pallet::call_index(0)]134 #[pallet::weight(<T as Config>::WeightInfo::register_foreign_asset())]135 pub fn force_register_foreign_asset(136 origin: OriginFor<T>,137 reserve_location: MultiLocation,138 name: CollectionName,139 mode: CollectionMode,140 ) -> DispatchResult {141 T::ForceRegisterOrigin::ensure_origin(origin.clone())?;142143 let foreign_collection_owner = Self::pallet_account();144145 let description: CollectionDescription = "Foreign Assets Collection"146 .encode_utf16()147 .collect::<Vec<_>>()148 .try_into()149 .expect("description length < max description length; qed");150151 let collection_id = T::CollectionDispatch::create_foreign(152 foreign_collection_owner,153 CreateCollectionData {154 name,155 description,156 mode,157158 properties: vec![Property {159 key: Self::reserve_location_property_key(),160 value: reserve_location161 .encode()162 .try_into()163 .expect("multilocation is less than 32k; qed"),164 }]165 .try_into()166 .expect("just one property can always be stored; qed"),167168 token_property_permissions: vec![PropertyKeyPermission {169 key: Self::reserve_asset_instance_property_key(),170 permission: PropertyPermission {171 mutable: false,172 collection_admin: true,173 token_owner: false,174 },175 }]176 .try_into()177 .expect("just one property permission can always be stored; qed"),178 ..Default::default()179 },180 )?;181182 <ForeignReserveLocationToCollection<T>>::insert(reserve_location, collection_id);183184 Self::deposit_event(Event::<T>::ForeignAssetRegistered {185 asset_id: collection_id,186 reserve_location,187 });188189 Ok(())190 }191 }192}193194impl<T: Config> Pallet<T> {195 fn pallet_account() -> T::CrossAccountId {196 let owner: T::AccountId = T::PalletId::get().into_account_truncating();197 T::CrossAccountId::from_sub(owner)198 }199200 fn reserve_location_property_key() -> PropertyKey {201 b"reserve-location"202 .to_vec()203 .try_into()204 .expect("key length < max property key length; qed")205 }206207 fn reserve_asset_instance_property_key() -> PropertyKey {208 b"reserve-asset-instance"209 .to_vec()210 .try_into()211 .expect("key length < max property key length; qed")212 }213}214215impl<T: Config> TransactAsset for Pallet<T> {216 fn can_check_in(217 _origin: &MultiLocation,218 _what: &MultiAsset,219 _context: &XcmContext,220 ) -> XcmResult {221 Err(XcmError::Unimplemented)222 }223224 fn check_in(_origin: &MultiLocation, _what: &MultiAsset, _context: &XcmContext) {}225226 fn can_check_out(227 _dest: &MultiLocation,228 _what: &MultiAsset,229 _context: &XcmContext,230 ) -> XcmResult {231 Err(XcmError::Unimplemented)232 }233234 fn check_out(_dest: &MultiLocation, _what: &MultiAsset, _context: &XcmContext) {}235236 fn deposit_asset(what: &MultiAsset, to: &MultiLocation, context: &XcmContext) -> XcmResult {237 Err(XcmError::Unimplemented)238 }239240 fn withdraw_asset(241 what: &MultiAsset,242 from: &MultiLocation,243 _maybe_context: Option<&XcmContext>,244 ) -> Result<staging_xcm_executor::Assets, XcmError> {245 Err(XcmError::Unimplemented)246 }247248 fn internal_transfer_asset(249 what: &MultiAsset,250 from: &MultiLocation,251 to: &MultiLocation,252 _context: &XcmContext,253 ) -> Result<staging_xcm_executor::Assets, XcmError> {254 Err(XcmError::Unimplemented)255 }256}257258pub struct CurrencyIdConvert<T: Config>(PhantomData<T>);259impl<T: Config> sp_runtime::traits::Convert<CollectionId, Option<MultiLocation>>260 for CurrencyIdConvert<T>261{262 fn convert(collection_id: CollectionId) -> Option<MultiLocation> {263 if collection_id == NATIVE_FUNGIBLE_COLLECTION_ID {264 Some(Here.into())265 } else {266 267 268 269270 271 272 273 274 275 276 277 278 279 todo!()280 }281 }282}283284pub use frame_support::{285 traits::{286 fungibles::Balanced, tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT,287 },288 weights::{WeightToFee, WeightToFeePolynomial},289};290291pub struct FreeForAll;292293impl WeightTrader for FreeForAll {294 fn new() -> Self {295 Self296 }297298 fn buy_weight(299 &mut self,300 weight: Weight,301 payment: Assets,302 _xcm: &XcmContext,303 ) -> Result<Assets, XcmError> {304 log::trace!(target: "fassets::weight", "buy_weight weight: {:?}, payment: {:?}", weight, payment);305 Ok(payment)306 }307}