--- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -167,7 +167,6 @@ .map(|k| (k, 1 << 100)) .collect(), }, - tokens: TokensConfig { balances: vec![] }, sudo: SudoConfig { key: Some($root_key), }, --- a/pallets/balances-adapter/src/common.rs +++ b/pallets/balances-adapter/src/common.rs @@ -332,10 +332,6 @@ 0 } - fn refungible_extensions(&self) -> Option<&dyn pallet_common::RefungibleExtensions> { - None - } - fn set_allowance_for_all( &self, _owner: ::CrossAccountId, --- a/pallets/common/src/dispatch.rs +++ b/pallets/common/src/dispatch.rs @@ -72,6 +72,7 @@ /// Create a collection. The collection will be created according to the value of [`data.mode`](CreateCollectionData::mode). /// /// * `sender` - The user who will become the owner of the collection. + /// * `payer` - The user who pays the collection creation fee. /// * `data` - Description of the created collection. fn create( sender: T::CrossAccountId, @@ -79,6 +80,15 @@ data: CreateCollectionData, ) -> Result; + /// Create a foreign collection. The collection will be created according to the value of [`data.mode`](CreateCollectionData::mode). + /// + /// * `sender` - The user who will become the owner of the collection. + /// * `data` - Description of the created collection. + fn create_foreign( + sender: T::CrossAccountId, + data: CreateCollectionData, + ) -> Result; + /// Delete the collection. /// /// * `sender` - The owner of the collection. --- a/pallets/common/src/lib.rs +++ b/pallets/common/src/lib.rs @@ -1132,23 +1132,37 @@ data: CreateCollectionData, ) -> Result { ensure!(data.flags.is_allowed_for_user(), >::NoPermission); - Self::init_collection_internal(owner, payer, data) + + // Take a (non-refundable) deposit of collection creation + { + let mut imbalance = ::Currency>>::zero(); + imbalance.subsume(::Currency::deposit( + &T::TreasuryAccountId::get(), + T::CollectionCreationPrice::get(), + Precision::Exact, + )?); + let credit = + ::Currency::settle(payer.as_sub(), imbalance, Preservation::Preserve) + .map_err(|_| Error::::NotSufficientFounds)?; + + debug_assert!(credit.peek().is_zero()) + } + + Self::init_collection_internal(owner, data) } /// Initializes the collection with ForeignCollection flag. Returns [CollectionId] on success, [DispatchError] otherwise. pub fn init_foreign_collection( owner: T::CrossAccountId, - payer: T::CrossAccountId, mut data: CreateCollectionData, ) -> Result { data.flags.foreign = true; - let id = Self::init_collection_internal(owner, payer, data)?; + let id = Self::init_collection_internal(owner, data)?; Ok(id) } fn init_collection_internal( owner: T::CrossAccountId, - payer: T::CrossAccountId, data: CreateCollectionData, ) -> Result { { @@ -1224,21 +1238,6 @@ >::CollectionAdminCountExceeded, ); >::insert(id, admin_amount); - - // Take a (non-refundable) deposit of collection creation - { - let mut imbalance = ::Currency>>::zero(); - imbalance.subsume(::Currency::deposit( - &T::TreasuryAccountId::get(), - T::CollectionCreationPrice::get(), - Precision::Exact, - )?); - let credit = - ::Currency::settle(payer.as_sub(), imbalance, Preservation::Preserve) - .map_err(|_| Error::::NotSufficientFounds)?; - - debug_assert!(credit.peek().is_zero()) - } >::put(created_count); >::deposit_event(Event::CollectionCreated( @@ -2293,7 +2292,14 @@ ) -> u128; /// Get extension for RFT collection. - fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions>; + fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions> { + None + } + + /// Get XCM extensions. + fn xcm_extensions(&self) -> Option<&dyn XcmExtensions> { + None + } /// The `operator` is allowed to transfer all tokens of the `owner` on their behalf. /// * `owner` - Token owner @@ -2333,6 +2339,34 @@ ) -> DispatchResultWithPostInfo; } +/// XCM extensions for fungible and NFT collections +pub trait XcmExtensions +where + T: Config, +{ + /// Is the collection a foreign one? + fn is_foreign(&self) -> bool; + + /// Create a collection's item. + fn create_item( + &self, + to: T::CrossAccountId, + data: CreateItemData, + ) -> Result; + + /// Transfer an item from the `from` account to the `to` account. + fn transfer( + &self, + from: T::CrossAccountId, + to: T::CrossAccountId, + token: TokenId, + amount: u128, + ) -> DispatchResult; + + /// Burn a collection's item. + fn burn(&self, from: T::CrossAccountId, token: TokenId, amount: u128) -> DispatchResult; +} + /// Merge [`DispatchResult`] with [`Weight`] into [`DispatchResultWithPostInfo`]. /// /// Used for [`CommonCollectionOperations`] implementations and flexible enough to do so. --- a/pallets/foreign-assets/src/impl_fungibles.rs +++ /dev/null @@ -1,499 +0,0 @@ -// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. -// This file is part of Unique Network. - -// Unique Network is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Unique Network is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Unique Network. If not, see . - -//! Implementations for fungibles trait. - -use frame_support::traits::tokens::{ - DepositConsequence, Fortitude, Precision, Preservation, Provenance, WithdrawConsequence, -}; -use frame_system::Config as SystemConfig; -use pallet_common::{CollectionHandle, CommonCollectionOperations}; -use pallet_fungible::FungibleHandle; -use sp_runtime::traits::{CheckedAdd, CheckedSub}; -use up_data_structs::budget; - -use super::*; - -impl fungibles::Inspect<::AccountId> for Pallet -where - T: orml_tokens::Config, - BalanceOf: From<::Balance>, - BalanceOf: From<::Balance>, - ::Balance: From>, - ::Balance: From>, -{ - type AssetId = AssetId; - type Balance = BalanceOf; - - fn total_issuance(asset: Self::AssetId) -> Self::Balance { - log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible total_issuance"); - - match asset { - AssetId::NativeAssetId(NativeCurrency::Here) => { - as fungible::Inspect>::total_issuance() - .into() - } - AssetId::NativeAssetId(NativeCurrency::Parent) => { - as fungibles::Inspect>::total_issuance( - AssetId::NativeAssetId(NativeCurrency::Parent), - ) - .into() - } - AssetId::ForeignAssetId(fid) => { - let target_collection_id = match >::get(fid) { - Some(v) => v, - None => return Zero::zero(), - }; - let collection_handle = match >::try_get(target_collection_id) { - Ok(v) => v, - Err(_) => return Zero::zero(), - }; - let collection = FungibleHandle::cast(collection_handle); - Self::Balance::try_from(collection.total_supply()).unwrap_or(Zero::zero()) - } - } - } - - fn minimum_balance(asset: Self::AssetId) -> Self::Balance { - log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible minimum_balance"); - match asset { - AssetId::NativeAssetId(NativeCurrency::Here) => { - as fungible::Inspect>::minimum_balance() - .into() - } - AssetId::NativeAssetId(NativeCurrency::Parent) => { - as fungibles::Inspect>::minimum_balance( - AssetId::NativeAssetId(NativeCurrency::Parent), - ) - .into() - } - AssetId::ForeignAssetId(fid) => AssetMetadatas::::get(AssetId::ForeignAssetId(fid)) - .map(|x| x.minimal_balance) - .unwrap_or_else(Zero::zero), - } - } - - fn balance(asset: Self::AssetId, who: &::AccountId) -> Self::Balance { - log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible balance"); - match asset { - AssetId::NativeAssetId(NativeCurrency::Here) => { - as fungible::Inspect>::balance(who).into() - } - AssetId::NativeAssetId(NativeCurrency::Parent) => { - as fungibles::Inspect>::balance( - AssetId::NativeAssetId(NativeCurrency::Parent), - who, - ) - .into() - } - AssetId::ForeignAssetId(fid) => { - let target_collection_id = match >::get(fid) { - Some(v) => v, - None => return Zero::zero(), - }; - let collection_handle = match >::try_get(target_collection_id) { - Ok(v) => v, - Err(_) => return Zero::zero(), - }; - let collection = FungibleHandle::cast(collection_handle); - Self::Balance::try_from( - collection.balance(T::CrossAccountId::from_sub(who.clone()), TokenId(0)), - ) - .unwrap_or(Zero::zero()) - } - } - } - - fn total_balance(asset: Self::AssetId, who: &::AccountId) -> Self::Balance { - Self::balance(asset, who) - } - - fn reducible_balance( - asset: Self::AssetId, - who: &::AccountId, - preservation: Preservation, - fortitude: Fortitude, - ) -> Self::Balance { - log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible reducible_balance"); - - match asset { - AssetId::NativeAssetId(NativeCurrency::Here) => { - as fungible::Inspect>::reducible_balance( - who, - preservation, - fortitude, - ) - .into() - } - AssetId::NativeAssetId(NativeCurrency::Parent) => { - as fungibles::Inspect>::reducible_balance( - AssetId::NativeAssetId(NativeCurrency::Parent), - who, - preservation, - fortitude, - ) - .into() - } - _ => Self::balance(asset, who), - } - } - - fn can_deposit( - asset: Self::AssetId, - who: &::AccountId, - amount: Self::Balance, - provenance: Provenance, - ) -> DepositConsequence { - log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible can_deposit"); - - match asset { - AssetId::NativeAssetId(NativeCurrency::Here) => { - as fungible::Inspect>::can_deposit( - who, - amount.into(), - provenance, - ) - } - AssetId::NativeAssetId(NativeCurrency::Parent) => { - as fungibles::Inspect>::can_deposit( - AssetId::NativeAssetId(NativeCurrency::Parent), - who, - amount.into(), - provenance, - ) - } - _ => { - if amount.is_zero() { - return DepositConsequence::Success; - } - - let extential_deposit_value = T::ExistentialDeposit::get(); - let ed_value: u128 = match extential_deposit_value.try_into() { - Ok(val) => val, - Err(_) => return DepositConsequence::CannotCreate, - }; - let extential_deposit: Self::Balance = match ed_value.try_into() { - Ok(val) => val, - Err(_) => return DepositConsequence::CannotCreate, - }; - - let new_total_balance = match Self::balance(asset, who).checked_add(&amount) { - Some(x) => x, - None => return DepositConsequence::Overflow, - }; - - if new_total_balance < extential_deposit { - return DepositConsequence::BelowMinimum; - } - - DepositConsequence::Success - } - } - } - - fn can_withdraw( - asset: Self::AssetId, - who: &::AccountId, - amount: Self::Balance, - ) -> WithdrawConsequence { - log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible can_withdraw"); - let value: u128 = match amount.try_into() { - Ok(val) => val, - Err(_) => return WithdrawConsequence::UnknownAsset, - }; - - match asset { - AssetId::NativeAssetId(NativeCurrency::Here) => { - let this_amount: ::Balance = match value.try_into() { - Ok(val) => val, - Err(_) => { - return WithdrawConsequence::UnknownAsset; - } - }; - match as fungible::Inspect>::can_withdraw( - who, - this_amount, - ) { - WithdrawConsequence::BalanceLow => WithdrawConsequence::BalanceLow, - WithdrawConsequence::WouldDie => WithdrawConsequence::WouldDie, - WithdrawConsequence::UnknownAsset => WithdrawConsequence::UnknownAsset, - WithdrawConsequence::Underflow => WithdrawConsequence::Underflow, - WithdrawConsequence::Overflow => WithdrawConsequence::Overflow, - WithdrawConsequence::Frozen => WithdrawConsequence::Frozen, - WithdrawConsequence::Success => WithdrawConsequence::Success, - _ => WithdrawConsequence::BalanceLow, - } - } - AssetId::NativeAssetId(NativeCurrency::Parent) => { - let parent_amount: ::Balance = match value.try_into() { - Ok(val) => val, - Err(_) => { - return WithdrawConsequence::UnknownAsset; - } - }; - match as fungibles::Inspect>::can_withdraw( - AssetId::NativeAssetId(NativeCurrency::Parent), - who, - parent_amount, - ) { - WithdrawConsequence::BalanceLow => WithdrawConsequence::BalanceLow, - WithdrawConsequence::WouldDie => WithdrawConsequence::WouldDie, - WithdrawConsequence::UnknownAsset => WithdrawConsequence::UnknownAsset, - WithdrawConsequence::Underflow => WithdrawConsequence::Underflow, - WithdrawConsequence::Overflow => WithdrawConsequence::Overflow, - WithdrawConsequence::Frozen => WithdrawConsequence::Frozen, - WithdrawConsequence::Success => WithdrawConsequence::Success, - _ => WithdrawConsequence::BalanceLow, - } - } - _ => match Self::balance(asset, who).checked_sub(&amount) { - Some(_) => WithdrawConsequence::Success, - None => WithdrawConsequence::BalanceLow, - }, - } - } - - fn asset_exists(asset: AssetId) -> bool { - match asset { - AssetId::NativeAssetId(_) => true, - AssetId::ForeignAssetId(fid) => >::contains_key(fid), - } - } -} - -impl fungibles::Mutate<::AccountId> for Pallet -where - T: orml_tokens::Config, - BalanceOf: From<::Balance>, - BalanceOf: From<::Balance>, - ::Balance: From>, - ::Balance: From>, - u128: From>, -{ - fn mint_into( - asset: Self::AssetId, - who: &::AccountId, - amount: Self::Balance, - ) -> Result, DispatchError> { - //Self::do_mint(asset, who, amount, None) - log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible mint_into {:?}", asset); - - match asset { - AssetId::NativeAssetId(NativeCurrency::Here) => { - as fungible::Mutate>::mint_into( - who, - amount.into(), - ) - .map(Into::into) - } - AssetId::NativeAssetId(NativeCurrency::Parent) => { - as fungibles::Mutate>::mint_into( - AssetId::NativeAssetId(NativeCurrency::Parent), - who, - amount.into(), - ) - .map(Into::into) - } - AssetId::ForeignAssetId(fid) => { - let target_collection_id = match >::get(fid) { - Some(v) => v, - None => { - return Err(DispatchError::Other( - "Associated collection not found for asset", - )) - } - }; - let collection = - FungibleHandle::cast(>::try_get(target_collection_id)?); - let account = T::CrossAccountId::from_sub(who.clone()); - - let amount_data: pallet_fungible::CreateItemData = - (account.clone(), amount.into()); - - pallet_fungible::Pallet::::create_item_foreign( - &collection, - &account, - amount_data, - &budget::Value::new(0), - )?; - - Ok(amount) - } - } - } - - fn burn_from( - asset: Self::AssetId, - who: &::AccountId, - amount: Self::Balance, - precision: Precision, - fortitude: Fortitude, - ) -> Result { - // let f = DebitFlags { keep_alive: false, best_effort: false }; - log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible burn_from"); - - match asset { - AssetId::NativeAssetId(NativeCurrency::Here) => { - as fungible::Mutate>::burn_from( - who, - amount.into(), - precision, - fortitude, - ) - .map(Into::into) - } - AssetId::NativeAssetId(NativeCurrency::Parent) => { - as fungibles::Mutate>::burn_from( - AssetId::NativeAssetId(NativeCurrency::Parent), - who, - amount.into(), - precision, - fortitude, - ) - .map(Into::into) - } - AssetId::ForeignAssetId(fid) => { - let target_collection_id = match >::get(fid) { - Some(v) => v, - None => { - return Err(DispatchError::Other( - "Associated collection not found for asset", - )) - } - }; - let collection = - FungibleHandle::cast(>::try_get(target_collection_id)?); - pallet_fungible::Pallet::::burn_foreign( - &collection, - &T::CrossAccountId::from_sub(who.clone()), - amount.into(), - )?; - - Ok(amount) - } - } - } - - fn transfer( - asset: Self::AssetId, - source: &::AccountId, - dest: &::AccountId, - amount: Self::Balance, - preservation: Preservation, - ) -> Result { - // let f = TransferFlags { keep_alive, best_effort: false, burn_dust: false }; - log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible transfer"); - - match asset { - AssetId::NativeAssetId(NativeCurrency::Here) => { - match as fungible::Mutate>::transfer( - source, - dest, - amount.into(), - preservation, - ) { - Ok(_) => Ok(amount), - Err(_) => Err(DispatchError::Other( - "Bad amount to relay chain value conversion", - )), - } - } - AssetId::NativeAssetId(NativeCurrency::Parent) => { - match as fungibles::Mutate>::transfer( - AssetId::NativeAssetId(NativeCurrency::Parent), - source, - dest, - amount.into(), - preservation, - ) { - Ok(_) => Ok(amount), - Err(e) => Err(e), - } - } - AssetId::ForeignAssetId(fid) => { - let target_collection_id = match >::get(fid) { - Some(v) => v, - None => { - return Err(DispatchError::Other( - "Associated collection not found for asset", - )) - } - }; - let collection = - FungibleHandle::cast(>::try_get(target_collection_id)?); - - pallet_fungible::Pallet::::transfer( - &collection, - &T::CrossAccountId::from_sub(source.clone()), - &T::CrossAccountId::from_sub(dest.clone()), - amount.into(), - &budget::Value::new(0), - ) - .map_err(|e| e.error)?; - - Ok(amount) - } - } - } -} - -#[cfg(not(debug_assertions))] -extern "C" { - // This function does not exists, thus compilation will fail, if its call is - // not optimized away, which is only possible if it's not called at all. - // - // not(debug_assertions) is used to ensure compiler is dropping unused functions, as - // this option is enabled in release by defailt - // - // FIXME: maybe use build.rs, to ensure it will fail even in release with debug_assertions - // enabled? - fn unbalanced_fungible_is_called(); -} -macro_rules! ensure_balanced { - () => {{ - #[cfg(debug_assertions)] - panic!("unbalanced fungible methods should not be used"); - #[cfg(not(debug_assertions))] - { - unsafe { unbalanced_fungible_is_called() }; - unreachable!(); - } - }}; -} - -impl fungibles::Unbalanced<::AccountId> for Pallet -where - T: orml_tokens::Config, - BalanceOf: From<::Balance>, - BalanceOf: From<::Balance>, - ::Balance: From>, - ::Balance: From>, - u128: From>, -{ - fn handle_dust(_dust: fungibles::Dust<::AccountId, Self>) { - ensure_balanced!(); - } - fn write_balance( - _asset: Self::AssetId, - _who: &::AccountId, - _amount: Self::Balance, - ) -> Result, DispatchError> { - ensure_balanced!(); - } - fn set_total_issuance(_asset: Self::AssetId, _amount: Self::Balance) { - ensure_balanced!(); - } -} --- a/pallets/foreign-assets/src/lib.rs +++ b/pallets/foreign-assets/src/lib.rs @@ -34,93 +34,27 @@ #![cfg_attr(not(feature = "std"), no_std)] #![allow(clippy::unused_unit)] -use frame_support::{ - dispatch::DispatchResult, - ensure, - pallet_prelude::*, - traits::{fungible, fungibles, Currency, EnsureOrigin}, -}; +use frame_support::{dispatch::DispatchResult, pallet_prelude::*, traits::EnsureOrigin, PalletId}; use frame_system::pallet_prelude::*; -use pallet_common::erc::CrossAccountId; -use pallet_fungible::Pallet as PalletFungible; -use scale_info::TypeInfo; -use serde::{Deserialize, Serialize}; -use sp_runtime::{ - traits::{One, Zero}, - ArithmeticError, +use pallet_common::{ + dispatch::CollectionDispatch, erc::CrossAccountId, NATIVE_FUNGIBLE_COLLECTION_ID, }; -use sp_std::{boxed::Box, vec::Vec}; -use staging_xcm::{latest::MultiLocation, VersionedMultiLocation}; +use sp_runtime::traits::AccountIdConversion; +use sp_std::{vec, vec::Vec}; // NOTE: MultiLocation is used in storages, we will need to do migration if upgrade the // MultiLocation to the XCM v3. use staging_xcm::{ opaque::latest::{prelude::XcmError, Weight}, - v3::XcmContext, + v3::{prelude::*, MultiAsset, XcmContext}, +}; +use staging_xcm_executor::{ + traits::{TransactAsset, WeightTrader}, + Assets, }; -use staging_xcm_executor::{traits::WeightTrader, Assets}; -use up_data_structs::{CollectionId, CollectionMode, CreateCollectionData, TokenId}; - -// TODO: Move to primitives -// Id of native currency. -// 0 - QTZ\UNQ -// 1 - KSM\DOT -#[derive( - Clone, - Copy, - Eq, - PartialEq, - PartialOrd, - Ord, - MaxEncodedLen, - RuntimeDebug, - Encode, - Decode, - TypeInfo, - Serialize, - Deserialize, -)] -pub enum NativeCurrency { - Here = 0, - Parent = 1, -} - -#[derive( - Clone, - Copy, - Eq, - PartialEq, - PartialOrd, - Ord, - MaxEncodedLen, - RuntimeDebug, - Encode, - Decode, - TypeInfo, - Serialize, - Deserialize, -)] -pub enum AssetId { - ForeignAssetId(ForeignAssetId), - NativeAssetId(NativeCurrency), -} - -pub trait TryAsForeign { - fn try_as_foreign(asset: T) -> Option; -} - -impl TryAsForeign for AssetId { - fn try_as_foreign(asset: AssetId) -> Option { - match asset { - Self::ForeignAssetId(id) => Some(id), - _ => None, - } - } -} - -pub type ForeignAssetId = u32; -pub type CurrencyId = AssetId; +use up_data_structs::{ + CollectionId, CollectionMode, CollectionName, CreateCollectionData, PropertyKey, TokenId, +}; -mod impl_fungibles; pub mod weights; #[cfg(feature = "runtime-benchmarks")] @@ -128,44 +62,13 @@ pub use module::*; pub use weights::WeightInfo; - -/// Type alias for currency balance. -pub type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; - -/// A mapping between ForeignAssetId and AssetMetadata. -pub trait AssetIdMapping { - /// Returns the AssetMetadata associated with a given ForeignAssetId. - fn get_asset_metadata(foreign_asset_id: ForeignAssetId) -> Option; - /// Returns the MultiLocation associated with a given ForeignAssetId. - fn get_multi_location(foreign_asset_id: ForeignAssetId) -> Option; - /// Returns the CurrencyId associated with a given MultiLocation. - fn get_currency_id(multi_location: MultiLocation) -> Option; -} - -pub struct XcmForeignAssetIdMapping(sp_std::marker::PhantomData); - -impl AssetIdMapping>> - for XcmForeignAssetIdMapping -{ - fn get_asset_metadata(foreign_asset_id: ForeignAssetId) -> Option>> { - log::trace!(target: "fassets::asset_metadatas", "call"); - Pallet::::asset_metadatas(AssetId::ForeignAssetId(foreign_asset_id)) - } - - fn get_multi_location(foreign_asset_id: ForeignAssetId) -> Option { - log::trace!(target: "fassets::get_multi_location", "call"); - Pallet::::foreign_asset_locations(foreign_asset_id) - } - fn get_currency_id(multi_location: MultiLocation) -> Option { - log::trace!(target: "fassets::get_currency_id", "call"); - Pallet::::location_to_currency_ids(multi_location).map(AssetId::ForeignAssetId) - } -} - #[frame_support::pallet] pub mod module { + use up_data_structs::{ + CollectionDescription, Property, PropertyKeyPermission, PropertyPermission, + }; + use super::*; #[pallet::config] @@ -173,44 +76,25 @@ frame_system::Config + pallet_common::Config + pallet_fungible::Config - + orml_tokens::Config + pallet_balances::Config { /// The overarching event type. type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// Currency type for withdraw and balance storage. - type Currency: Currency; + /// Origin for force registering of a foreign asset. + type ForceRegisterOrigin: EnsureOrigin; - /// Required origin for registering asset. - type RegisterOrigin: EnsureOrigin; + /// The ID of the foreign assets pallet. + type PalletId: Get; /// Weight information for the extrinsics in this module. type WeightInfo: WeightInfo; } - - pub type AssetName = BoundedVec>; - pub type AssetSymbol = BoundedVec>; - #[derive(Clone, Eq, PartialEq, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] - pub struct AssetMetadata { - pub name: AssetName, - pub symbol: AssetSymbol, - pub decimals: u8, - pub minimal_balance: Balance, - } - #[pallet::error] pub enum Error { - /// The given location could not be used (e.g. because it cannot be expressed in the - /// desired version of XCM). - BadLocation, - /// MultiLocation existed - MultiLocationExisted, - /// AssetId not exists - AssetIdNotExists, - /// AssetId exists - AssetIdExisted, + /// The foreign asset is already registered + ForeignAssetAlreadyRegistered, } #[pallet::event] @@ -218,64 +102,28 @@ pub enum Event { /// The foreign asset registered. ForeignAssetRegistered { - asset_id: ForeignAssetId, - asset_address: MultiLocation, - metadata: AssetMetadata>, - }, - /// The foreign asset updated. - ForeignAssetUpdated { - asset_id: ForeignAssetId, - asset_address: MultiLocation, - metadata: AssetMetadata>, - }, - /// The asset registered. - AssetRegistered { - asset_id: AssetId, - metadata: AssetMetadata>, + asset_id: CollectionId, + reserve_location: MultiLocation, }, - /// The asset updated. - AssetUpdated { - asset_id: AssetId, - metadata: AssetMetadata>, - }, } - /// Next available Foreign AssetId ID. - /// - /// NextForeignAssetId: ForeignAssetId - #[pallet::storage] - #[pallet::getter(fn next_foreign_asset_id)] - pub type NextForeignAssetId = StorageValue<_, ForeignAssetId, ValueQuery>; - /// The storages for MultiLocations. - /// - /// ForeignAssetLocations: map ForeignAssetId => Option - #[pallet::storage] - #[pallet::getter(fn foreign_asset_locations)] - pub type ForeignAssetLocations = - StorageMap<_, Twox64Concat, ForeignAssetId, staging_xcm::v3::MultiLocation, OptionQuery>; - - /// The storages for CurrencyIds. - /// - /// LocationToCurrencyIds: map MultiLocation => Option + /// The corresponding collections of reserve locations. #[pallet::storage] - #[pallet::getter(fn location_to_currency_ids)] - pub type LocationToCurrencyIds = - StorageMap<_, Twox64Concat, staging_xcm::v3::MultiLocation, ForeignAssetId, OptionQuery>; + #[pallet::getter(fn foreign_reserve_location_to_collection)] + pub type ForeignReserveLocationToCollection = + StorageMap<_, Twox64Concat, staging_xcm::v3::MultiLocation, CollectionId, OptionQuery>; - /// The storages for AssetMetadatas. - /// - /// AssetMetadatas: map AssetIds => Option + /// The correponding NFT token id of reserve NFTs #[pallet::storage] - #[pallet::getter(fn asset_metadatas)] - pub type AssetMetadatas = - StorageMap<_, Twox64Concat, AssetId, AssetMetadata>, OptionQuery>; - - /// The storages for assets to fungible collection binding - /// - #[pallet::storage] - #[pallet::getter(fn asset_binding)] - pub type AssetBinding = - StorageMap<_, Twox64Concat, ForeignAssetId, CollectionId, OptionQuery>; + #[pallet::getter(fn foreign_reserve_asset_instance_to_token_id)] + pub type ForeignReserveAssetInstanceToTokenId = StorageDoubleMap< + Hasher1 = Twox64Concat, + Key1 = CollectionId, + Hasher2 = Twox64Concat, + Key2 = staging_xcm::v3::AssetInstance, + Value = TokenId, + QueryKind = OptionQuery, + >; #[pallet::pallet] pub struct Pallet(_); @@ -284,164 +132,152 @@ impl Pallet { #[pallet::call_index(0)] #[pallet::weight(::WeightInfo::register_foreign_asset())] - pub fn register_foreign_asset( + pub fn force_register_foreign_asset( origin: OriginFor, - owner: T::AccountId, - location: Box, - metadata: Box>>, + reserve_location: MultiLocation, + name: CollectionName, + mode: CollectionMode, ) -> DispatchResult { - T::RegisterOrigin::ensure_origin(origin.clone())?; + T::ForceRegisterOrigin::ensure_origin(origin.clone())?; - let location: MultiLocation = (*location) - .try_into() - .map_err(|()| Error::::BadLocation)?; + let foreign_collection_owner = Self::pallet_account(); - let md = metadata.clone(); - let name: Vec = md.name.into_iter().map(|x| x as u16).collect::>(); - let mut description: Vec = "Foreign assets collection for " + let description: CollectionDescription = "Foreign Assets Collection" .encode_utf16() - .collect::>(); - description.append(&mut name.clone()); + .collect::>() + .try_into() + .expect("description length < max description length; qed"); - let data: CreateCollectionData = CreateCollectionData { - name: name.try_into().unwrap(), - description: description.try_into().unwrap(), - mode: CollectionMode::Fungible(md.decimals), - ..Default::default() - }; - let owner = T::CrossAccountId::from_sub(owner); - let bounded_collection_id = - >::init_foreign_collection(owner.clone(), owner, data)?; - let foreign_asset_id = - Self::do_register_foreign_asset(&location, &metadata, bounded_collection_id)?; + let collection_id = T::CollectionDispatch::create_foreign( + foreign_collection_owner, + CreateCollectionData { + name, + description, + mode, - Self::deposit_event(Event::::ForeignAssetRegistered { - asset_id: foreign_asset_id, - asset_address: location, - metadata: *metadata, - }); - Ok(()) - } + properties: vec![Property { + key: Self::reserve_location_property_key(), + value: reserve_location + .encode() + .try_into() + .expect("multilocation is less than 32k; qed"), + }] + .try_into() + .expect("just one property can always be stored; qed"), - #[pallet::call_index(1)] - #[pallet::weight(::WeightInfo::update_foreign_asset())] - pub fn update_foreign_asset( - origin: OriginFor, - foreign_asset_id: ForeignAssetId, - location: Box, - metadata: Box>>, - ) -> DispatchResult { - T::RegisterOrigin::ensure_origin(origin)?; + token_property_permissions: vec![PropertyKeyPermission { + key: Self::reserve_asset_instance_property_key(), + permission: PropertyPermission { + mutable: false, + collection_admin: true, + token_owner: false, + }, + }] + .try_into() + .expect("just one property permission can always be stored; qed"), + ..Default::default() + }, + )?; - let location: MultiLocation = (*location) - .try_into() - .map_err(|()| Error::::BadLocation)?; - Self::do_update_foreign_asset(foreign_asset_id, &location, &metadata)?; + >::insert(reserve_location, collection_id); - Self::deposit_event(Event::::ForeignAssetUpdated { - asset_id: foreign_asset_id, - asset_address: location, - metadata: *metadata, + Self::deposit_event(Event::::ForeignAssetRegistered { + asset_id: collection_id, + reserve_location, }); + Ok(()) } } } impl Pallet { - fn get_next_foreign_asset_id() -> Result { - NextForeignAssetId::::try_mutate(|current| -> Result { - let id = *current; - *current = current - .checked_add(One::one()) - .ok_or(ArithmeticError::Overflow)?; - Ok(id) - }) + fn pallet_account() -> T::CrossAccountId { + let owner: T::AccountId = T::PalletId::get().into_account_truncating(); + T::CrossAccountId::from_sub(owner) } - fn do_register_foreign_asset( - location: &MultiLocation, - metadata: &AssetMetadata>, - bounded_collection_id: CollectionId, - ) -> Result { - let foreign_asset_id = Self::get_next_foreign_asset_id()?; - LocationToCurrencyIds::::try_mutate(location, |maybe_currency_ids| -> DispatchResult { - ensure!( - maybe_currency_ids.is_none(), - Error::::MultiLocationExisted - ); - *maybe_currency_ids = Some(foreign_asset_id); - // *maybe_currency_ids = Some(CurrencyId::ForeignAsset(foreign_asset_id)); + fn reserve_location_property_key() -> PropertyKey { + b"reserve-location" + .to_vec() + .try_into() + .expect("key length < max property key length; qed") + } - ForeignAssetLocations::::try_mutate( - foreign_asset_id, - |maybe_location| -> DispatchResult { - ensure!(maybe_location.is_none(), Error::::MultiLocationExisted); - *maybe_location = Some(*location); + fn reserve_asset_instance_property_key() -> PropertyKey { + b"reserve-asset-instance" + .to_vec() + .try_into() + .expect("key length < max property key length; qed") + } +} - AssetMetadatas::::try_mutate( - AssetId::ForeignAssetId(foreign_asset_id), - |maybe_asset_metadatas| -> DispatchResult { - ensure!(maybe_asset_metadatas.is_none(), Error::::AssetIdExisted); - *maybe_asset_metadatas = Some(metadata.clone()); - Ok(()) - }, - ) - }, - )?; +impl TransactAsset for Pallet { + fn can_check_in( + _origin: &MultiLocation, + _what: &MultiAsset, + _context: &XcmContext, + ) -> XcmResult { + Err(XcmError::Unimplemented) + } - AssetBinding::::try_mutate(foreign_asset_id, |collection_id| -> DispatchResult { - *collection_id = Some(bounded_collection_id); - Ok(()) - }) - })?; + fn check_in(_origin: &MultiLocation, _what: &MultiAsset, _context: &XcmContext) {} - Ok(foreign_asset_id) + fn can_check_out( + _dest: &MultiLocation, + _what: &MultiAsset, + _context: &XcmContext, + ) -> XcmResult { + Err(XcmError::Unimplemented) + } + + fn check_out(_dest: &MultiLocation, _what: &MultiAsset, _context: &XcmContext) {} + + fn deposit_asset(what: &MultiAsset, to: &MultiLocation, context: &XcmContext) -> XcmResult { + Err(XcmError::Unimplemented) + } + + fn withdraw_asset( + what: &MultiAsset, + from: &MultiLocation, + _maybe_context: Option<&XcmContext>, + ) -> Result { + Err(XcmError::Unimplemented) } - fn do_update_foreign_asset( - foreign_asset_id: ForeignAssetId, - location: &MultiLocation, - metadata: &AssetMetadata>, - ) -> DispatchResult { - ForeignAssetLocations::::try_mutate( - foreign_asset_id, - |maybe_multi_locations| -> DispatchResult { - let old_multi_locations = maybe_multi_locations - .as_mut() - .ok_or(Error::::AssetIdNotExists)?; + fn internal_transfer_asset( + what: &MultiAsset, + from: &MultiLocation, + to: &MultiLocation, + _context: &XcmContext, + ) -> Result { + Err(XcmError::Unimplemented) + } +} - AssetMetadatas::::try_mutate( - AssetId::ForeignAssetId(foreign_asset_id), - |maybe_asset_metadatas| -> DispatchResult { - ensure!( - maybe_asset_metadatas.is_some(), - Error::::AssetIdNotExists - ); +pub struct CurrencyIdConvert(PhantomData); +impl sp_runtime::traits::Convert> + for CurrencyIdConvert +{ + fn convert(collection_id: CollectionId) -> Option { + if collection_id == NATIVE_FUNGIBLE_COLLECTION_ID { + Some(Here.into()) + } else { + // let dispatch = T::CollectionDispatch::dispatch(collection_id).ok()?; + // let collection = dispatch.as_dyn(); + // let xcm_ext = collection.xcm_extensions()?; - // modify location - if location != old_multi_locations { - LocationToCurrencyIds::::remove(*old_multi_locations); - LocationToCurrencyIds::::try_mutate( - location, - |maybe_currency_ids| -> DispatchResult { - ensure!( - maybe_currency_ids.is_none(), - Error::::MultiLocationExisted - ); - // *maybe_currency_ids = Some(CurrencyId::ForeignAsset(foreign_asset_id)); - *maybe_currency_ids = Some(foreign_asset_id); - Ok(()) - }, - )?; - } - *maybe_asset_metadatas = Some(metadata.clone()); - *old_multi_locations = *location; - Ok(()) - }, - ) - }, - ) + // if xcm_ext.is_foreign() { + // let encoded_location = + // collection.property(&>::reserve_location_property_key())?; + // MultiLocation::decode(&mut &encoded_location[..]).ok() + // } else { + // T::SelfLocation::get() + // .pushed_with_interior(GeneralIndex(collection_id.0.into())) + // .ok() + // } + todo!() + } } } @@ -452,28 +288,11 @@ weights::{WeightToFee, WeightToFeePolynomial}, }; -pub struct FreeForAll< - WeightToFee: WeightToFeePolynomial, - AssetId: Get, - AccountId, - Currency: CurrencyT, - OnUnbalanced: OnUnbalancedT, ->( - Weight, - Currency::Balance, - PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>, -); +pub struct FreeForAll; -impl< - WeightToFee: WeightToFeePolynomial, - AssetId: Get, - AccountId, - Currency: CurrencyT, - OnUnbalanced: OnUnbalancedT, - > WeightTrader for FreeForAll -{ +impl WeightTrader for FreeForAll { fn new() -> Self { - Self(Weight::default(), Zero::zero(), PhantomData) + Self } fn buy_weight( @@ -484,17 +303,5 @@ ) -> Result { log::trace!(target: "fassets::weight", "buy_weight weight: {:?}, payment: {:?}", weight, payment); Ok(payment) - } -} -impl Drop - for FreeForAll -where - WeightToFee: WeightToFeePolynomial, - AssetId: Get, - Currency: CurrencyT, - OnUnbalanced: OnUnbalancedT, -{ - fn drop(&mut self) { - OnUnbalanced::on_unbalanced(Currency::issue(self.1)); } } --- a/pallets/fungible/src/common.rs +++ b/pallets/fungible/src/common.rs @@ -428,10 +428,6 @@ >::get((self.id, sender, spender)) } - fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions> { - None - } - fn total_pieces(&self, token: TokenId) -> Option { if token != TokenId::default() { return None; --- a/pallets/fungible/src/lib.rs +++ b/pallets/fungible/src/lib.rs @@ -212,24 +212,6 @@ /// Pallet implementation for fungible assets impl Pallet { - /// Initializes the collection. Returns [CollectionId] on success, [DispatchError] otherwise. - pub fn init_collection( - owner: T::CrossAccountId, - payer: T::CrossAccountId, - data: CreateCollectionData, - ) -> Result { - >::init_collection(owner, payer, data) - } - - /// Initializes the collection with ForeignCollection flag. Returns [CollectionId] on success, [DispatchError] otherwise. - pub fn init_foreign_collection( - owner: T::CrossAccountId, - payer: T::CrossAccountId, - data: CreateCollectionData, - ) -> Result { - >::init_foreign_collection(owner, payer, data) - } - /// Destroys a collection. pub fn destroy_collection( collection: FungibleHandle, --- a/pallets/nonfungible/src/common.rs +++ b/pallets/nonfungible/src/common.rs @@ -535,10 +535,6 @@ } } - fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions> { - None - } - fn total_pieces(&self, token: TokenId) -> Option { if >::contains_key((self.id, token)) { Some(1) --- a/pallets/nonfungible/src/lib.rs +++ b/pallets/nonfungible/src/lib.rs @@ -383,19 +383,6 @@ // unchecked calls skips any permission checks impl Pallet { - /// Create NFT collection - /// - /// `init_collection` will take non-refundable deposit for collection creation. - /// - /// - `data`: Contains settings for collection limits and permissions. - pub fn init_collection( - owner: T::CrossAccountId, - payer: T::CrossAccountId, - data: CreateCollectionData, - ) -> Result { - >::init_collection(owner, payer, data) - } - /// Destroy NFT collection /// /// `destroy_collection` will throw error if collection contains any tokens. --- a/runtime/common/config/orml.rs +++ b/runtime/common/config/orml.rs @@ -14,31 +14,21 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . -use frame_support::{ - parameter_types, - traits::{Contains, Everything}, -}; +use frame_support::{parameter_types, traits::Everything}; use frame_system::EnsureSigned; use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key}; -use pallet_foreign_assets::{CurrencyId, NativeCurrency}; +use pallet_foreign_assets::CurrencyIdConvert; use sp_runtime::traits::Convert; -use sp_std::{vec, vec::Vec}; use staging_xcm::latest::{Junction::*, Junctions::*, MultiLocation, Weight}; use staging_xcm_executor::XcmExecutor; use up_common::{ constants::*, types::{AccountId, Balance}, }; +use up_data_structs::CollectionId; use crate::{ - runtime_common::config::{ - pallets::TreasuryAccountId, - substrate::{MaxLocks, MaxReserves}, - xcm::{ - xcm_assets::CurrencyIdConvert, SelfLocation, UniversalLocation, Weigher, - XcmExecutorConfig, - }, - }, + runtime_common::config::xcm::{SelfLocation, UniversalLocation, Weigher, XcmExecutorConfig}, RelayChainBlockNumberProvider, Runtime, RuntimeEvent, }; @@ -59,29 +49,6 @@ }; } -parameter_type_with_key! { - pub ExistentialDeposits: |currency_id: CurrencyId| -> Balance { - match currency_id { - CurrencyId::NativeAssetId(symbol) => match symbol { - NativeCurrency::Here => 0, - NativeCurrency::Parent=> 0, - }, - _ => 100_000 - } - }; -} - -pub fn get_all_module_accounts() -> Vec { - vec![TreasuryAccountId::get()] -} - -pub struct DustRemovalWhitelist; -impl Contains for DustRemovalWhitelist { - fn contains(a: &AccountId) -> bool { - get_all_module_accounts().contains(a) - } -} - pub struct AccountIdToMultiLocation; impl Convert for AccountIdToMultiLocation { fn convert(account: AccountId) -> MultiLocation { @@ -91,18 +58,6 @@ }) .into() } -} - -pub struct CurrencyHooks; -impl orml_traits::currency::MutationHooks for CurrencyHooks { - type OnDust = orml_tokens::TransferDust; - type OnSlash = (); - type PreTransfer = (); - type PostTransfer = (); - type PreDeposit = (); - type PostDeposit = (); - type OnNewTokenAccount = (); - type OnKilledTokenAccount = (); } impl orml_vesting::Config for Runtime { @@ -113,29 +68,13 @@ type WeightInfo = (); type MaxVestingSchedules = MaxVestingSchedules; type BlockNumberProvider = RelayChainBlockNumberProvider; -} - -impl orml_tokens::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Balance = Balance; - type Amount = Amount; - type CurrencyId = CurrencyId; - type WeightInfo = (); - type ExistentialDeposits = ExistentialDeposits; - type CurrencyHooks = CurrencyHooks; - type MaxLocks = MaxLocks; - type MaxReserves = MaxReserves; - // TODO: Add all module accounts - type DustRemovalWhitelist = DustRemovalWhitelist; - /// The id type for named reserves. - type ReserveIdentifier = (); } impl orml_xtokens::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; - type CurrencyId = CurrencyId; - type CurrencyIdConvert = CurrencyIdConvert; + type CurrencyId = CollectionId; + type CurrencyIdConvert = CurrencyIdConvert; type AccountIdToMultiLocation = AccountIdToMultiLocation; type SelfLocation = SelfLocation; type XcmExecutor = XcmExecutor>; --- a/runtime/common/config/pallets/foreign_asset.rs +++ b/runtime/common/config/pallets/foreign_asset.rs @@ -1,10 +1,14 @@ -use up_common::types::AccountId; +use frame_support::{parameter_types, PalletId}; + +use crate::{runtime_common::config::governance, Runtime, RuntimeEvent}; -use crate::{Balances, Runtime, RuntimeEvent}; +parameter_types! { + pub ForeignAssetPalletId: PalletId = PalletId(*b"frgnasts"); +} impl pallet_foreign_assets::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type RegisterOrigin = frame_system::EnsureRoot; + type ForceRegisterOrigin = governance::RootOrTechnicalCommitteeMember; + type PalletId = ForeignAssetPalletId; type WeightInfo = pallet_foreign_assets::weights::SubstrateWeight; } --- /dev/null +++ b/runtime/common/config/xcm.rs @@ -0,0 +1,254 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +use cumulus_primitives_core::ParaId; +use frame_support::{ + parameter_types, + traits::{ConstU32, Everything, Get, Nothing, ProcessMessageError}, +}; +use frame_system::EnsureRoot; +use orml_traits::location::AbsoluteReserveProvider; +use orml_xcm_support::MultiNativeAsset; +use pallet_foreign_assets::FreeForAll; +use pallet_xcm::XcmPassthrough; +use polkadot_parachain_primitives::primitives::Sibling; +use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; +use sp_std::marker::PhantomData; +use staging_xcm::{ + latest::{prelude::*, MultiLocation, Weight}, + v3::Instruction, +}; +use staging_xcm_builder::{ + AccountId32Aliases, EnsureXcmOrigin, FixedWeightBounds, ParentIsPreset, RelayChainAsNative, + SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, +}; +use staging_xcm_executor::{ + traits::{Properties, ShouldExecute}, + XcmExecutor, +}; +use up_common::types::AccountId; + +#[cfg(feature = "governance")] +use crate::runtime_common::config::governance; +use crate::{ + xcm_barrier::Barrier, AllPalletsWithSystem, Balances, ForeignAssets, ParachainInfo, + ParachainSystem, PolkadotXcm, RelayNetwork, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, + XcmpQueue, +}; + +parameter_types! { + pub const RelayLocation: MultiLocation = MultiLocation::parent(); + pub RelayOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UniversalLocation: InteriorMultiLocation = ( + GlobalConsensus(crate::RelayNetwork::get()), + Parachain(ParachainInfo::get().into()), + ).into(); + pub SelfLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(ParachainInfo::get().into()))); + + // One XCM operation is 1_000_000 weight - almost certainly a conservative estimate. + pub UnitWeightCost: Weight = Weight::from_parts(1_000_000, 1000); // ? + pub const MaxInstructions: u32 = 100; +} + +/// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the default `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + // Straight up local `AccountId32` origins just alias directly to `AccountId`. + AccountId32Aliases, +); + +/// No local origins on this chain are allowed to dispatch XCM sends/executions. +pub type LocalOriginToLocation = (SignedToAccountId32,); + +/// The means for routing XCM messages which are not for local execution into the right message +/// queues. +pub type XcmRouter = ( + // Two routers - use UMP to communicate with the relay chain: + cumulus_primitives_utility::ParentAsUmp, + // ..and XCMP to communicate with the sibling chains. + XcmpQueue, +); + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Native signed account converter; this just converts an `AccountId32` origin into a normal + // `Origin::Signed` origin of the same 32-byte value. + SignedAccountId32AsNative, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + XcmPassthrough, +); + +pub trait TryPass { + fn try_pass( + origin: &MultiLocation, + message: &mut [Instruction], + ) -> Result<(), ProcessMessageError>; +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl TryPass for Tuple { + fn try_pass( + origin: &MultiLocation, + message: &mut [Instruction], + ) -> Result<(), ProcessMessageError> { + for_tuples!( #( + Tuple::try_pass(origin, message)?; + )* ); + + Ok(()) + } +} + +/// Deny executing the XCM if it matches any of the Deny filter regardless of anything else. +/// If it passes the Deny, and matches one of the Allow cases then it is let through. +pub struct DenyThenTry(PhantomData, PhantomData) +where + Deny: TryPass, + Allow: ShouldExecute; + +impl ShouldExecute for DenyThenTry +where + Deny: TryPass, + Allow: ShouldExecute, +{ + fn should_execute( + origin: &MultiLocation, + message: &mut [Instruction], + max_weight: Weight, + properties: &mut Properties, + ) -> Result<(), ProcessMessageError> { + Deny::try_pass(origin, message)?; + Allow::should_execute(origin, message, max_weight, properties) + } +} + +pub type Weigher = FixedWeightBounds; + +pub type IsReserve = MultiNativeAsset; + +pub type Trader = FreeForAll; + +pub struct XcmExecutorConfig(PhantomData); +impl staging_xcm_executor::Config for XcmExecutorConfig +where + T: pallet_configuration::Config, +{ + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + // How to withdraw and deposit an asset. + type AssetTransactor = ForeignAssets; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type IsReserve = IsReserve; + type IsTeleporter = (); // Teleportation is disabled + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = Weigher; + type Trader = Trader; + type ResponseHandler = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type PalletInstancesInfo = AllPalletsWithSystem; + type MaxAssetsIntoHolding = ConstU32<8>; + + type AssetTrap = PolkadotXcm; + type AssetClaims = PolkadotXcm; + type AssetLocker = (); + type AssetExchanger = (); + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Nothing; + type Aliasers = Nothing; +} + +#[cfg(feature = "runtime-benchmarks")] +parameter_types! { + pub ReachableDest: Option = Some(Parent.into()); +} + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Everything; + type XcmExecutor = XcmExecutor>; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type UniversalLocation = UniversalLocation; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = LocationToAccountId; + type MaxLockers = ConstU32<8>; + type WeightInfo = crate::weights::xcm::SubstrateWeight; + type AdminOrigin = EnsureRoot; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor>; +} +impl cumulus_pallet_xcmp_queue::Config for Runtime { + type WeightInfo = (); + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor>; + type ChannelInfo = ParachainSystem; + type VersionWrapper = PolkadotXcm; + type ExecuteOverweightOrigin = frame_system::EnsureRoot; + + #[cfg(feature = "governance")] + type ControllerOrigin = governance::RootOrTechnicalCommitteeMember; + + #[cfg(not(feature = "governance"))] + type ControllerOrigin = frame_system::EnsureRoot; + + type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; + type PriceForSiblingDelivery = NoPriceForMessageDelivery; +} + +impl cumulus_pallet_dmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor>; + type ExecuteOverweightOrigin = frame_system::EnsureRoot; +} --- a/runtime/common/config/xcm/foreignassets.rs +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. -// This file is part of Unique Network. - -// Unique Network is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Unique Network is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Unique Network. If not, see . - -use frame_support::{parameter_types, traits::Get}; -use orml_traits::location::AbsoluteReserveProvider; -use orml_xcm_support::MultiNativeAsset; -use pallet_foreign_assets::{ - AssetId, AssetIdMapping, CurrencyId, ForeignAssetId, FreeForAll, NativeCurrency, TryAsForeign, - XcmForeignAssetIdMapping, -}; -use sp_runtime::traits::{Convert, MaybeEquivalence}; -use sp_std::marker::PhantomData; -use staging_xcm::latest::{prelude::*, MultiAsset, MultiLocation}; -use staging_xcm_builder::{ConvertedConcreteId, FungiblesAdapter, NoChecking}; -use staging_xcm_executor::traits::{JustTry, TransactAsset}; -use up_common::types::{AccountId, Balance}; - -use super::{LocationToAccountId, RelayLocation}; -use crate::{Balances, ForeignAssets, ParachainInfo, PolkadotXcm, Runtime}; - -parameter_types! { - pub CheckingAccount: AccountId = PolkadotXcm::check_account(); -} - -pub struct AsInnerId(PhantomData<(AssetId, ConvertAssetId)>); -impl> MaybeEquivalence - for AsInnerId -{ - fn convert(id: &MultiLocation) -> Option { - log::trace!( - target: "xcm::AsInnerId::Convert", - "AsInnerId {:?}", - id - ); - - let parent = MultiLocation::parent(); - let here = MultiLocation::here(); - let self_location = MultiLocation::new(1, X1(Parachain(ParachainInfo::get().into()))); - - if *id == parent { - return ConvertAssetId::convert(&AssetId::NativeAssetId(NativeCurrency::Parent)); - } - - if *id == here || *id == self_location { - return ConvertAssetId::convert(&AssetId::NativeAssetId(NativeCurrency::Here)); - } - - match XcmForeignAssetIdMapping::::get_currency_id(*id) { - Some(AssetId::ForeignAssetId(foreign_asset_id)) => { - ConvertAssetId::convert(&AssetId::ForeignAssetId(foreign_asset_id)) - } - _ => None, - } - } - - fn convert_back(asset_id: &AssetId) -> Option { - log::trace!( - target: "xcm::AsInnerId::Reverse", - "AsInnerId", - ); - - let parent_id = - ConvertAssetId::convert(&AssetId::NativeAssetId(NativeCurrency::Parent)).unwrap(); - let here_id = - ConvertAssetId::convert(&AssetId::NativeAssetId(NativeCurrency::Here)).unwrap(); - - if *asset_id == parent_id { - return Some(MultiLocation::parent()); - } - - if *asset_id == here_id { - return Some(MultiLocation::new( - 1, - X1(Parachain(ParachainInfo::get().into())), - )); - } - - let fid = >::try_as_foreign(*asset_id)?; - XcmForeignAssetIdMapping::::get_multi_location(fid) - } -} - -/// Means for transacting assets besides the native currency on this chain. -pub type FungiblesTransactor = FungiblesAdapter< - // Use this fungibles implementation: - ForeignAssets, - // Use this currency when it is a fungible asset matching the given location or name: - ConvertedConcreteId, JustTry>, - // Convert an XCM MultiLocation into a local account id: - LocationToAccountId, - // Our chain's account ID type (we can't get away without mentioning it explicitly): - AccountId, - // No Checking for teleported assets since we disallow teleports at all. - NoChecking, - // The account to use for tracking teleports. - CheckingAccount, ->; - -/// Means for transacting assets on this chain. -pub struct AssetTransactor; -impl TransactAsset for AssetTransactor { - fn can_check_in( - _origin: &MultiLocation, - _what: &MultiAsset, - _context: &XcmContext, - ) -> XcmResult { - Err(XcmError::Unimplemented) - } - - fn check_in(_origin: &MultiLocation, _what: &MultiAsset, _context: &XcmContext) {} - - fn can_check_out( - _dest: &MultiLocation, - _what: &MultiAsset, - _context: &XcmContext, - ) -> XcmResult { - Err(XcmError::Unimplemented) - } - - fn check_out(_dest: &MultiLocation, _what: &MultiAsset, _context: &XcmContext) {} - - fn deposit_asset( - what: &MultiAsset, - who: &MultiLocation, - context: Option<&XcmContext>, - ) -> XcmResult { - FungiblesTransactor::deposit_asset(what, who, context) - } - - fn withdraw_asset( - what: &MultiAsset, - who: &MultiLocation, - maybe_context: Option<&XcmContext>, - ) -> Result { - FungiblesTransactor::withdraw_asset(what, who, maybe_context) - } - - fn internal_transfer_asset( - what: &MultiAsset, - from: &MultiLocation, - to: &MultiLocation, - context: &XcmContext, - ) -> Result { - FungiblesTransactor::internal_transfer_asset(what, from, to, context) - } -} - -pub type IsReserve = MultiNativeAsset; - -pub type Trader = FreeForAll< - pallet_configuration::WeightToFee, - RelayLocation, - AccountId, - Balances, - (), ->; - -pub struct CurrencyIdConvert; -impl Convert> for CurrencyIdConvert { - fn convert(id: AssetId) -> Option { - match id { - AssetId::NativeAssetId(NativeCurrency::Here) => Some(MultiLocation::new( - 1, - X1(Parachain(ParachainInfo::get().into())), - )), - AssetId::NativeAssetId(NativeCurrency::Parent) => Some(MultiLocation::parent()), - AssetId::ForeignAssetId(foreign_asset_id) => { - XcmForeignAssetIdMapping::::get_multi_location(foreign_asset_id) - } - } - } -} - -impl Convert> for CurrencyIdConvert { - fn convert(location: MultiLocation) -> Option { - if location == MultiLocation::here() - || location == MultiLocation::new(1, X1(Parachain(ParachainInfo::get().into()))) - { - return Some(AssetId::NativeAssetId(NativeCurrency::Here)); - } - - if location == MultiLocation::parent() { - return Some(AssetId::NativeAssetId(NativeCurrency::Parent)); - } - - if let Some(currency_id) = XcmForeignAssetIdMapping::::get_currency_id(location) { - return Some(currency_id); - } - - None - } -} --- a/runtime/common/config/xcm/mod.rs +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. -// This file is part of Unique Network. - -// Unique Network is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Unique Network is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Unique Network. If not, see . - -use cumulus_primitives_core::ParaId; -use frame_support::{ - parameter_types, - traits::{ConstU32, Everything, Get, Nothing, ProcessMessageError}, -}; -use frame_system::EnsureRoot; -use pallet_xcm::XcmPassthrough; -use polkadot_parachain_primitives::primitives::Sibling; -use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; -use sp_std::marker::PhantomData; -use staging_xcm::{ - latest::{prelude::*, MultiLocation, Weight}, - v3::Instruction, -}; -use staging_xcm_builder::{ - AccountId32Aliases, EnsureXcmOrigin, FixedWeightBounds, ParentIsPreset, RelayChainAsNative, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, -}; -use staging_xcm_executor::{ - traits::{Properties, ShouldExecute}, - XcmExecutor, -}; -use up_common::types::AccountId; - -use crate::{ - xcm_barrier::Barrier, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, - PolkadotXcm, RelayNetwork, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, XcmpQueue, -}; - -#[cfg(feature = "foreign-assets")] -pub mod foreignassets; - -#[cfg(not(feature = "foreign-assets"))] -pub mod nativeassets; - -#[cfg(feature = "foreign-assets")] -pub use foreignassets as xcm_assets; -#[cfg(not(feature = "foreign-assets"))] -pub use nativeassets as xcm_assets; -use xcm_assets::{AssetTransactor, IsReserve, Trader}; - -#[cfg(feature = "governance")] -use crate::runtime_common::config::governance; - -parameter_types! { - pub const RelayLocation: MultiLocation = MultiLocation::parent(); - pub RelayOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); - pub UniversalLocation: InteriorMultiLocation = ( - GlobalConsensus(crate::RelayNetwork::get()), - Parachain(ParachainInfo::get().into()), - ).into(); - pub SelfLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(ParachainInfo::get().into()))); - - // One XCM operation is 1_000_000 weight - almost certainly a conservative estimate. - pub UnitWeightCost: Weight = Weight::from_parts(1_000_000, 1000); // ? - pub const MaxInstructions: u32 = 100; -} - -/// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used -/// when determining ownership of accounts for asset transacting and when attempting to use XCM -/// `Transact` in order to determine the dispatch Origin. -pub type LocationToAccountId = ( - // The parent (Relay-chain) origin converts to the default `AccountId`. - ParentIsPreset, - // Sibling parachain origins convert to AccountId via the `ParaId::into`. - SiblingParachainConvertsVia, - // Straight up local `AccountId32` origins just alias directly to `AccountId`. - AccountId32Aliases, -); - -/// No local origins on this chain are allowed to dispatch XCM sends/executions. -pub type LocalOriginToLocation = (SignedToAccountId32,); - -/// The means for routing XCM messages which are not for local execution into the right message -/// queues. -pub type XcmRouter = ( - // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, - // ..and XCMP to communicate with the sibling chains. - XcmpQueue, -); - -/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, -/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can -/// biases the kind of local `Origin` it will become. -pub type XcmOriginToTransactDispatchOrigin = ( - // Sovereign account converter; this attempts to derive an `AccountId` from the origin location - // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for - // foreign chains who want to have a local sovereign account on this chain which they control. - SovereignSignedViaLocation, - // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when - // recognised. - RelayChainAsNative, - // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when - // recognised. - SiblingParachainAsNative, - // Native signed account converter; this just converts an `AccountId32` origin into a normal - // `Origin::Signed` origin of the same 32-byte value. - SignedAccountId32AsNative, - // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. - XcmPassthrough, -); - -pub trait TryPass { - fn try_pass( - origin: &MultiLocation, - message: &mut [Instruction], - ) -> Result<(), ProcessMessageError>; -} - -#[impl_trait_for_tuples::impl_for_tuples(30)] -impl TryPass for Tuple { - fn try_pass( - origin: &MultiLocation, - message: &mut [Instruction], - ) -> Result<(), ProcessMessageError> { - for_tuples!( #( - Tuple::try_pass(origin, message)?; - )* ); - - Ok(()) - } -} - -/// Deny executing the XCM if it matches any of the Deny filter regardless of anything else. -/// If it passes the Deny, and matches one of the Allow cases then it is let through. -pub struct DenyThenTry(PhantomData, PhantomData) -where - Deny: TryPass, - Allow: ShouldExecute; - -impl ShouldExecute for DenyThenTry -where - Deny: TryPass, - Allow: ShouldExecute, -{ - fn should_execute( - origin: &MultiLocation, - message: &mut [Instruction], - max_weight: Weight, - properties: &mut Properties, - ) -> Result<(), ProcessMessageError> { - Deny::try_pass(origin, message)?; - Allow::should_execute(origin, message, max_weight, properties) - } -} - -pub type Weigher = FixedWeightBounds; - -pub struct XcmExecutorConfig(PhantomData); -impl staging_xcm_executor::Config for XcmExecutorConfig -where - T: pallet_configuration::Config, -{ - type RuntimeCall = RuntimeCall; - type XcmSender = XcmRouter; - // How to withdraw and deposit an asset. - type AssetTransactor = AssetTransactor; - type OriginConverter = XcmOriginToTransactDispatchOrigin; - type IsReserve = IsReserve; - type IsTeleporter = (); // Teleportation is disabled - type UniversalLocation = UniversalLocation; - type Barrier = Barrier; - type Weigher = Weigher; - type Trader = Trader; - type ResponseHandler = PolkadotXcm; - type SubscriptionService = PolkadotXcm; - type PalletInstancesInfo = AllPalletsWithSystem; - type MaxAssetsIntoHolding = ConstU32<8>; - - type AssetTrap = PolkadotXcm; - type AssetClaims = PolkadotXcm; - type AssetLocker = (); - type AssetExchanger = (); - type FeeManager = (); - type MessageExporter = (); - type UniversalAliases = Nothing; - type CallDispatcher = RuntimeCall; - type SafeCallFilter = Nothing; - type Aliasers = Nothing; -} - -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); -} - -impl pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type SendXcmOrigin = EnsureXcmOrigin; - type XcmRouter = XcmRouter; - type ExecuteXcmOrigin = EnsureXcmOrigin; - type XcmExecuteFilter = Everything; - type XcmExecutor = XcmExecutor>; - type XcmTeleportFilter = Everything; - type XcmReserveTransferFilter = Everything; - type Weigher = FixedWeightBounds; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; - type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; - type UniversalLocation = UniversalLocation; - type Currency = Balances; - type CurrencyMatcher = (); - type TrustedLockers = (); - type SovereignAccountOf = LocationToAccountId; - type MaxLockers = ConstU32<8>; - type WeightInfo = crate::weights::xcm::SubstrateWeight; - type AdminOrigin = EnsureRoot; - type MaxRemoteLockConsumers = ConstU32<0>; - type RemoteLockConsumerIdentifier = (); - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; -} - -impl cumulus_pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor>; -} -impl cumulus_pallet_xcmp_queue::Config for Runtime { - type WeightInfo = (); - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor>; - type ChannelInfo = ParachainSystem; - type VersionWrapper = PolkadotXcm; - type ExecuteOverweightOrigin = frame_system::EnsureRoot; - - #[cfg(feature = "governance")] - type ControllerOrigin = governance::RootOrTechnicalCommitteeMember; - - #[cfg(not(feature = "governance"))] - type ControllerOrigin = frame_system::EnsureRoot; - - type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; - type PriceForSiblingDelivery = NoPriceForMessageDelivery; -} - -impl cumulus_pallet_dmp_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor>; - type ExecuteOverweightOrigin = frame_system::EnsureRoot; -} --- a/runtime/common/config/xcm/nativeassets.rs +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. -// This file is part of Unique Network. - -// Unique Network is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Unique Network is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Unique Network. If not, see . - -use cumulus_primitives_core::XcmContext; -use frame_support::{ - traits::{tokens::currency::Currency as CurrencyT, Get, OnUnbalanced as OnUnbalancedT}, - weights::WeightToFeePolynomial, -}; -use pallet_foreign_assets::{AssetIds, NativeCurrency}; -use sp_runtime::traits::{CheckedConversion, Convert, Zero}; -use sp_std::marker::PhantomData; -use staging_xcm::latest::{ - AssetId::Concrete, Error as XcmError, Fungibility::Fungible as XcmFungible, Junction::*, - Junctions::*, MultiAsset, MultiLocation, Weight, -}; -use staging_xcm_builder::{CurrencyAdapter, NativeAsset}; -use staging_xcm_executor::{ - traits::{MatchesFungible, WeightTrader}, - Assets, -}; -use up_common::types::{AccountId, Balance}; - -use super::{LocationToAccountId, RelayLocation}; -use crate::{Balances, ParachainInfo}; - -pub struct OnlySelfCurrency; -impl> MatchesFungible for OnlySelfCurrency { - fn matches_fungible(a: &MultiAsset) -> Option { - let paraid = Parachain(ParachainInfo::parachain_id().into()); - match (&a.id, &a.fun) { - ( - Concrete(MultiLocation { - parents: 1, - interior: X1(loc), - }), - XcmFungible(ref amount), - ) if paraid == *loc => CheckedConversion::checked_from(*amount), - ( - Concrete(MultiLocation { - parents: 0, - interior: Here, - }), - XcmFungible(ref amount), - ) => CheckedConversion::checked_from(*amount), - _ => None, - } - } -} - -/// Means for transacting assets on this chain. -pub type LocalAssetTransactor = CurrencyAdapter< - // Use this currency: - Balances, - // Use this currency when it is a fungible asset matching the given location or name: - OnlySelfCurrency, - // Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID: - LocationToAccountId, - // Our chain's account ID type (we can't get away without mentioning it explicitly): - AccountId, - // We don't track any teleports. - (), ->; - -pub type AssetTransactor = LocalAssetTransactor; - -pub type IsReserve = NativeAsset; - -pub struct UsingOnlySelfCurrencyComponents< - WeightToFee: WeightToFeePolynomial, - AssetId: Get, - AccountId, - Currency: CurrencyT, - OnUnbalanced: OnUnbalancedT, ->( - Weight, - Currency::Balance, - PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>, -); -impl< - WeightToFee: WeightToFeePolynomial, - AssetId: Get, - AccountId, - Currency: CurrencyT, - OnUnbalanced: OnUnbalancedT, - > WeightTrader - for UsingOnlySelfCurrencyComponents -{ - fn new() -> Self { - // FIXME: benchmark - Self(Weight::from_parts(0, 0), Zero::zero(), PhantomData) - } - - fn buy_weight( - &mut self, - _weight: Weight, - payment: Assets, - _xcm: &XcmContext, - ) -> Result { - Ok(payment) - } -} -impl< - WeightToFee: WeightToFeePolynomial, - AssetId: Get, - AccountId, - Currency: CurrencyT, - OnUnbalanced: OnUnbalancedT, - > Drop - for UsingOnlySelfCurrencyComponents -{ - fn drop(&mut self) { - OnUnbalanced::on_unbalanced(Currency::issue(self.1)); - } -} - -pub type Trader = UsingOnlySelfCurrencyComponents< - pallet_configuration::WeightToFee, - RelayLocation, - AccountId, - Balances, - (), ->; - -pub struct CurrencyIdConvert; -impl Convert> for CurrencyIdConvert { - fn convert(id: AssetIds) -> Option { - match id { - AssetIds::NativeAssetId(NativeCurrency::Here) => Some(MultiLocation::new( - 1, - X1(Parachain(ParachainInfo::get().into())), - )), - _ => None, - } - } -} --- a/runtime/common/construct_runtime.rs +++ b/runtime/common/construct_runtime.rs @@ -47,7 +47,7 @@ Vesting: orml_vesting = 37, XTokens: orml_xtokens = 38, - Tokens: orml_tokens = 39, + // [REMOVED] Tokens: orml_tokens = 39, // Contracts: pallet_contracts::{Pallet, Call, Storage, Event} = 38, #[cfg(feature = "governance")] --- a/runtime/common/dispatch.rs +++ b/runtime/common/dispatch.rs @@ -17,11 +17,9 @@ use frame_support::{dispatch::DispatchResult, ensure, fail}; use pallet_balances_adapter::NativeFungibleHandle; pub use pallet_common::dispatch::CollectionDispatch; -#[cfg(not(feature = "refungible"))] -use pallet_common::unsupported; use pallet_common::{ - erc::CommonEvmHandler, eth::map_eth_to_id, CollectionById, CollectionHandle, - CommonCollectionOperations, + erc::CommonEvmHandler, eth::map_eth_to_id, unsupported, CollectionById, CollectionHandle, + CommonCollectionOperations, Pallet as PalletCommon, }; use pallet_evm::{PrecompileHandle, PrecompileResult}; use pallet_fungible::{FungibleHandle, Pallet as PalletFungible}; @@ -73,24 +71,42 @@ payer: T::CrossAccountId, data: CreateCollectionData, ) -> Result { - let id = match data.mode { - CollectionMode::NFT => >::init_collection(sender, payer, data)?, + match data.mode { CollectionMode::Fungible(decimal_points) => { // check params ensure!( decimal_points <= MAX_DECIMAL_POINTS, pallet_unique::Error::::CollectionDecimalPointLimitExceeded ); - >::init_collection(sender, payer, data)? } - #[cfg(feature = "refungible")] - CollectionMode::ReFungible => >::init_collection(sender, payer, data)?, + #[cfg(not(feature = "refungible"))] + CollectionMode::ReFungible => return unsupported!(T), + + _ => {} + }; + + >::init_collection(sender, payer, data) + } + + fn create_foreign( + sender: ::CrossAccountId, + data: CreateCollectionData<::CrossAccountId>, + ) -> Result { + match data.mode { + CollectionMode::Fungible(decimal_points) => { + // check params + ensure!( + decimal_points <= MAX_DECIMAL_POINTS, + pallet_unique::Error::::CollectionDecimalPointLimitExceeded + ); + } - #[cfg(not(feature = "refungible"))] CollectionMode::ReFungible => return unsupported!(T), + _ => {} }; - Ok(id) + + >::init_foreign_collection(sender, data) } fn destroy(sender: T::CrossAccountId, collection_id: CollectionId) -> DispatchResult {