difftreelog
refactor draft foreign assets as proxy to collections
in: master
18 files changed
node/cli/src/chain_spec.rsdiffbeforeafterboth--- 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),
},
pallets/balances-adapter/src/common.rsdiffbeforeafterboth--- 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<T>> {
- None
- }
-
fn set_allowance_for_all(
&self,
_owner: <T>::CrossAccountId,
pallets/common/src/dispatch.rsdiffbeforeafterboth--- 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<T::CrossAccountId>,
) -> Result<CollectionId, DispatchError>;
+ /// 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<T::CrossAccountId>,
+ ) -> Result<CollectionId, DispatchError>;
+
/// Delete the collection.
///
/// * `sender` - The owner of the collection.
pallets/common/src/lib.rsdiffbeforeafterboth--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -1132,23 +1132,37 @@
data: CreateCollectionData<T::CrossAccountId>,
) -> Result<CollectionId, DispatchError> {
ensure!(data.flags.is_allowed_for_user(), <Error<T>>::NoPermission);
- Self::init_collection_internal(owner, payer, data)
+
+ // Take a (non-refundable) deposit of collection creation
+ {
+ let mut imbalance = <Debt<T::AccountId, <T as Config>::Currency>>::zero();
+ imbalance.subsume(<T as Config>::Currency::deposit(
+ &T::TreasuryAccountId::get(),
+ T::CollectionCreationPrice::get(),
+ Precision::Exact,
+ )?);
+ let credit =
+ <T as Config>::Currency::settle(payer.as_sub(), imbalance, Preservation::Preserve)
+ .map_err(|_| Error::<T>::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<T::CrossAccountId>,
) -> Result<CollectionId, DispatchError> {
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<T::CrossAccountId>,
) -> Result<CollectionId, DispatchError> {
{
@@ -1224,21 +1238,6 @@
<Error<T>>::CollectionAdminCountExceeded,
);
<AdminAmount<T>>::insert(id, admin_amount);
-
- // Take a (non-refundable) deposit of collection creation
- {
- let mut imbalance = <Debt<T::AccountId, <T as Config>::Currency>>::zero();
- imbalance.subsume(<T as Config>::Currency::deposit(
- &T::TreasuryAccountId::get(),
- T::CollectionCreationPrice::get(),
- Precision::Exact,
- )?);
- let credit =
- <T as Config>::Currency::settle(payer.as_sub(), imbalance, Preservation::Preserve)
- .map_err(|_| Error::<T>::NotSufficientFounds)?;
-
- debug_assert!(credit.peek().is_zero())
- }
<CreatedCollectionCount<T>>::put(created_count);
<Pallet<T>>::deposit_event(Event::CollectionCreated(
@@ -2293,7 +2292,14 @@
) -> u128;
/// Get extension for RFT collection.
- fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>>;
+ fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>> {
+ None
+ }
+
+ /// Get XCM extensions.
+ fn xcm_extensions(&self) -> Option<&dyn XcmExtensions<T>> {
+ 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<T>
+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<TokenId, DispatchError>;
+
+ /// 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.
pallets/foreign-assets/src/impl_fungibles.rsdiffbeforeafterboth--- 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 <http://www.gnu.org/licenses/>.
-
-//! 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<T: Config> fungibles::Inspect<<T as SystemConfig>::AccountId> for Pallet<T>
-where
- T: orml_tokens::Config<CurrencyId = AssetId>,
- BalanceOf<T>: From<<T as pallet_balances::Config>::Balance>,
- BalanceOf<T>: From<<T as orml_tokens::Config>::Balance>,
- <T as pallet_balances::Config>::Balance: From<BalanceOf<T>>,
- <T as orml_tokens::Config>::Balance: From<BalanceOf<T>>,
-{
- type AssetId = AssetId;
- type Balance = BalanceOf<T>;
-
- 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) => {
- <pallet_balances::Pallet<T> as fungible::Inspect<T::AccountId>>::total_issuance()
- .into()
- }
- AssetId::NativeAssetId(NativeCurrency::Parent) => {
- <orml_tokens::Pallet<T> as fungibles::Inspect<T::AccountId>>::total_issuance(
- AssetId::NativeAssetId(NativeCurrency::Parent),
- )
- .into()
- }
- AssetId::ForeignAssetId(fid) => {
- let target_collection_id = match <AssetBinding<T>>::get(fid) {
- Some(v) => v,
- None => return Zero::zero(),
- };
- let collection_handle = match <CollectionHandle<T>>::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) => {
- <pallet_balances::Pallet<T> as fungible::Inspect<T::AccountId>>::minimum_balance()
- .into()
- }
- AssetId::NativeAssetId(NativeCurrency::Parent) => {
- <orml_tokens::Pallet<T> as fungibles::Inspect<T::AccountId>>::minimum_balance(
- AssetId::NativeAssetId(NativeCurrency::Parent),
- )
- .into()
- }
- AssetId::ForeignAssetId(fid) => AssetMetadatas::<T>::get(AssetId::ForeignAssetId(fid))
- .map(|x| x.minimal_balance)
- .unwrap_or_else(Zero::zero),
- }
- }
-
- fn balance(asset: Self::AssetId, who: &<T as SystemConfig>::AccountId) -> Self::Balance {
- log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible balance");
- match asset {
- AssetId::NativeAssetId(NativeCurrency::Here) => {
- <pallet_balances::Pallet<T> as fungible::Inspect<T::AccountId>>::balance(who).into()
- }
- AssetId::NativeAssetId(NativeCurrency::Parent) => {
- <orml_tokens::Pallet<T> as fungibles::Inspect<T::AccountId>>::balance(
- AssetId::NativeAssetId(NativeCurrency::Parent),
- who,
- )
- .into()
- }
- AssetId::ForeignAssetId(fid) => {
- let target_collection_id = match <AssetBinding<T>>::get(fid) {
- Some(v) => v,
- None => return Zero::zero(),
- };
- let collection_handle = match <CollectionHandle<T>>::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: &<T as SystemConfig>::AccountId) -> Self::Balance {
- Self::balance(asset, who)
- }
-
- fn reducible_balance(
- asset: Self::AssetId,
- who: &<T as SystemConfig>::AccountId,
- preservation: Preservation,
- fortitude: Fortitude,
- ) -> Self::Balance {
- log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible reducible_balance");
-
- match asset {
- AssetId::NativeAssetId(NativeCurrency::Here) => {
- <pallet_balances::Pallet<T> as fungible::Inspect<T::AccountId>>::reducible_balance(
- who,
- preservation,
- fortitude,
- )
- .into()
- }
- AssetId::NativeAssetId(NativeCurrency::Parent) => {
- <orml_tokens::Pallet<T> as fungibles::Inspect<T::AccountId>>::reducible_balance(
- AssetId::NativeAssetId(NativeCurrency::Parent),
- who,
- preservation,
- fortitude,
- )
- .into()
- }
- _ => Self::balance(asset, who),
- }
- }
-
- fn can_deposit(
- asset: Self::AssetId,
- who: &<T as SystemConfig>::AccountId,
- amount: Self::Balance,
- provenance: Provenance,
- ) -> DepositConsequence {
- log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible can_deposit");
-
- match asset {
- AssetId::NativeAssetId(NativeCurrency::Here) => {
- <pallet_balances::Pallet<T> as fungible::Inspect<T::AccountId>>::can_deposit(
- who,
- amount.into(),
- provenance,
- )
- }
- AssetId::NativeAssetId(NativeCurrency::Parent) => {
- <orml_tokens::Pallet<T> as fungibles::Inspect<T::AccountId>>::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: &<T as SystemConfig>::AccountId,
- amount: Self::Balance,
- ) -> WithdrawConsequence<Self::Balance> {
- 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: <T as pallet_balances::Config>::Balance = match value.try_into() {
- Ok(val) => val,
- Err(_) => {
- return WithdrawConsequence::UnknownAsset;
- }
- };
- match <pallet_balances::Pallet<T> as fungible::Inspect<T::AccountId>>::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: <T as orml_tokens::Config>::Balance = match value.try_into() {
- Ok(val) => val,
- Err(_) => {
- return WithdrawConsequence::UnknownAsset;
- }
- };
- match <orml_tokens::Pallet<T> as fungibles::Inspect<T::AccountId>>::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) => <AssetBinding<T>>::contains_key(fid),
- }
- }
-}
-
-impl<T: Config> fungibles::Mutate<<T as SystemConfig>::AccountId> for Pallet<T>
-where
- T: orml_tokens::Config<CurrencyId = AssetId>,
- BalanceOf<T>: From<<T as pallet_balances::Config>::Balance>,
- BalanceOf<T>: From<<T as orml_tokens::Config>::Balance>,
- <T as pallet_balances::Config>::Balance: From<BalanceOf<T>>,
- <T as orml_tokens::Config>::Balance: From<BalanceOf<T>>,
- u128: From<BalanceOf<T>>,
-{
- fn mint_into(
- asset: Self::AssetId,
- who: &<T as SystemConfig>::AccountId,
- amount: Self::Balance,
- ) -> Result<BalanceOf<T>, 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) => {
- <pallet_balances::Pallet<T> as fungible::Mutate<T::AccountId>>::mint_into(
- who,
- amount.into(),
- )
- .map(Into::into)
- }
- AssetId::NativeAssetId(NativeCurrency::Parent) => {
- <orml_tokens::Pallet<T> as fungibles::Mutate<T::AccountId>>::mint_into(
- AssetId::NativeAssetId(NativeCurrency::Parent),
- who,
- amount.into(),
- )
- .map(Into::into)
- }
- AssetId::ForeignAssetId(fid) => {
- let target_collection_id = match <AssetBinding<T>>::get(fid) {
- Some(v) => v,
- None => {
- return Err(DispatchError::Other(
- "Associated collection not found for asset",
- ))
- }
- };
- let collection =
- FungibleHandle::cast(<CollectionHandle<T>>::try_get(target_collection_id)?);
- let account = T::CrossAccountId::from_sub(who.clone());
-
- let amount_data: pallet_fungible::CreateItemData<T> =
- (account.clone(), amount.into());
-
- pallet_fungible::Pallet::<T>::create_item_foreign(
- &collection,
- &account,
- amount_data,
- &budget::Value::new(0),
- )?;
-
- Ok(amount)
- }
- }
- }
-
- fn burn_from(
- asset: Self::AssetId,
- who: &<T as SystemConfig>::AccountId,
- amount: Self::Balance,
- precision: Precision,
- fortitude: Fortitude,
- ) -> Result<Self::Balance, DispatchError> {
- // 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) => {
- <pallet_balances::Pallet<T> as fungible::Mutate<T::AccountId>>::burn_from(
- who,
- amount.into(),
- precision,
- fortitude,
- )
- .map(Into::into)
- }
- AssetId::NativeAssetId(NativeCurrency::Parent) => {
- <orml_tokens::Pallet<T> as fungibles::Mutate<T::AccountId>>::burn_from(
- AssetId::NativeAssetId(NativeCurrency::Parent),
- who,
- amount.into(),
- precision,
- fortitude,
- )
- .map(Into::into)
- }
- AssetId::ForeignAssetId(fid) => {
- let target_collection_id = match <AssetBinding<T>>::get(fid) {
- Some(v) => v,
- None => {
- return Err(DispatchError::Other(
- "Associated collection not found for asset",
- ))
- }
- };
- let collection =
- FungibleHandle::cast(<CollectionHandle<T>>::try_get(target_collection_id)?);
- pallet_fungible::Pallet::<T>::burn_foreign(
- &collection,
- &T::CrossAccountId::from_sub(who.clone()),
- amount.into(),
- )?;
-
- Ok(amount)
- }
- }
- }
-
- fn transfer(
- asset: Self::AssetId,
- source: &<T as SystemConfig>::AccountId,
- dest: &<T as SystemConfig>::AccountId,
- amount: Self::Balance,
- preservation: Preservation,
- ) -> Result<Self::Balance, DispatchError> {
- // 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 <pallet_balances::Pallet<T> as fungible::Mutate<T::AccountId>>::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 <orml_tokens::Pallet<T> as fungibles::Mutate<T::AccountId>>::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 <AssetBinding<T>>::get(fid) {
- Some(v) => v,
- None => {
- return Err(DispatchError::Other(
- "Associated collection not found for asset",
- ))
- }
- };
- let collection =
- FungibleHandle::cast(<CollectionHandle<T>>::try_get(target_collection_id)?);
-
- pallet_fungible::Pallet::<T>::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<T: Config> fungibles::Unbalanced<<T as SystemConfig>::AccountId> for Pallet<T>
-where
- T: orml_tokens::Config<CurrencyId = AssetId>,
- BalanceOf<T>: From<<T as pallet_balances::Config>::Balance>,
- BalanceOf<T>: From<<T as orml_tokens::Config>::Balance>,
- <T as pallet_balances::Config>::Balance: From<BalanceOf<T>>,
- <T as orml_tokens::Config>::Balance: From<BalanceOf<T>>,
- u128: From<BalanceOf<T>>,
-{
- fn handle_dust(_dust: fungibles::Dust<<T as SystemConfig>::AccountId, Self>) {
- ensure_balanced!();
- }
- fn write_balance(
- _asset: Self::AssetId,
- _who: &<T as SystemConfig>::AccountId,
- _amount: Self::Balance,
- ) -> Result<Option<Self::Balance>, DispatchError> {
- ensure_balanced!();
- }
- fn set_total_issuance(_asset: Self::AssetId, _amount: Self::Balance) {
- ensure_balanced!();
- }
-}
pallets/foreign-assets/src/lib.rsdiffbeforeafterboth--- 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<T, F> {
- fn try_as_foreign(asset: T) -> Option<F>;
-}
-
-impl TryAsForeign<AssetId, ForeignAssetId> for AssetId {
- fn try_as_foreign(asset: AssetId) -> Option<ForeignAssetId> {
- 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<T> =
- <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
-
-/// A mapping between ForeignAssetId and AssetMetadata.
-pub trait AssetIdMapping<ForeignAssetId, MultiLocation, AssetMetadata> {
- /// Returns the AssetMetadata associated with a given ForeignAssetId.
- fn get_asset_metadata(foreign_asset_id: ForeignAssetId) -> Option<AssetMetadata>;
- /// Returns the MultiLocation associated with a given ForeignAssetId.
- fn get_multi_location(foreign_asset_id: ForeignAssetId) -> Option<MultiLocation>;
- /// Returns the CurrencyId associated with a given MultiLocation.
- fn get_currency_id(multi_location: MultiLocation) -> Option<CurrencyId>;
-}
-
-pub struct XcmForeignAssetIdMapping<T>(sp_std::marker::PhantomData<T>);
-
-impl<T: Config> AssetIdMapping<ForeignAssetId, MultiLocation, AssetMetadata<BalanceOf<T>>>
- for XcmForeignAssetIdMapping<T>
-{
- fn get_asset_metadata(foreign_asset_id: ForeignAssetId) -> Option<AssetMetadata<BalanceOf<T>>> {
- log::trace!(target: "fassets::asset_metadatas", "call");
- Pallet::<T>::asset_metadatas(AssetId::ForeignAssetId(foreign_asset_id))
- }
-
- fn get_multi_location(foreign_asset_id: ForeignAssetId) -> Option<MultiLocation> {
- log::trace!(target: "fassets::get_multi_location", "call");
- Pallet::<T>::foreign_asset_locations(foreign_asset_id)
- }
- fn get_currency_id(multi_location: MultiLocation) -> Option<CurrencyId> {
- log::trace!(target: "fassets::get_currency_id", "call");
- Pallet::<T>::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<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
- /// Currency type for withdraw and balance storage.
- type Currency: Currency<Self::AccountId>;
+ /// Origin for force registering of a foreign asset.
+ type ForceRegisterOrigin: EnsureOrigin<Self::RuntimeOrigin>;
- /// Required origin for registering asset.
- type RegisterOrigin: EnsureOrigin<Self::RuntimeOrigin>;
+ /// The ID of the foreign assets pallet.
+ type PalletId: Get<PalletId>;
/// Weight information for the extrinsics in this module.
type WeightInfo: WeightInfo;
}
-
- pub type AssetName = BoundedVec<u8, ConstU32<32>>;
- pub type AssetSymbol = BoundedVec<u8, ConstU32<7>>;
- #[derive(Clone, Eq, PartialEq, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)]
- pub struct AssetMetadata<Balance> {
- pub name: AssetName,
- pub symbol: AssetSymbol,
- pub decimals: u8,
- pub minimal_balance: Balance,
- }
-
#[pallet::error]
pub enum Error<T> {
- /// 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<T: Config> {
/// The foreign asset registered.
ForeignAssetRegistered {
- asset_id: ForeignAssetId,
- asset_address: MultiLocation,
- metadata: AssetMetadata<BalanceOf<T>>,
- },
- /// The foreign asset updated.
- ForeignAssetUpdated {
- asset_id: ForeignAssetId,
- asset_address: MultiLocation,
- metadata: AssetMetadata<BalanceOf<T>>,
- },
- /// The asset registered.
- AssetRegistered {
- asset_id: AssetId,
- metadata: AssetMetadata<BalanceOf<T>>,
+ asset_id: CollectionId,
+ reserve_location: MultiLocation,
},
- /// The asset updated.
- AssetUpdated {
- asset_id: AssetId,
- metadata: AssetMetadata<BalanceOf<T>>,
- },
}
- /// Next available Foreign AssetId ID.
- ///
- /// NextForeignAssetId: ForeignAssetId
- #[pallet::storage]
- #[pallet::getter(fn next_foreign_asset_id)]
- pub type NextForeignAssetId<T: Config> = StorageValue<_, ForeignAssetId, ValueQuery>;
- /// The storages for MultiLocations.
- ///
- /// ForeignAssetLocations: map ForeignAssetId => Option<MultiLocation>
- #[pallet::storage]
- #[pallet::getter(fn foreign_asset_locations)]
- pub type ForeignAssetLocations<T: Config> =
- StorageMap<_, Twox64Concat, ForeignAssetId, staging_xcm::v3::MultiLocation, OptionQuery>;
-
- /// The storages for CurrencyIds.
- ///
- /// LocationToCurrencyIds: map MultiLocation => Option<ForeignAssetId>
+ /// The corresponding collections of reserve locations.
#[pallet::storage]
- #[pallet::getter(fn location_to_currency_ids)]
- pub type LocationToCurrencyIds<T: Config> =
- StorageMap<_, Twox64Concat, staging_xcm::v3::MultiLocation, ForeignAssetId, OptionQuery>;
+ #[pallet::getter(fn foreign_reserve_location_to_collection)]
+ pub type ForeignReserveLocationToCollection<T: Config> =
+ StorageMap<_, Twox64Concat, staging_xcm::v3::MultiLocation, CollectionId, OptionQuery>;
- /// The storages for AssetMetadatas.
- ///
- /// AssetMetadatas: map AssetIds => Option<AssetMetadata>
+ /// The correponding NFT token id of reserve NFTs
#[pallet::storage]
- #[pallet::getter(fn asset_metadatas)]
- pub type AssetMetadatas<T: Config> =
- StorageMap<_, Twox64Concat, AssetId, AssetMetadata<BalanceOf<T>>, OptionQuery>;
-
- /// The storages for assets to fungible collection binding
- ///
- #[pallet::storage]
- #[pallet::getter(fn asset_binding)]
- pub type AssetBinding<T: Config> =
- StorageMap<_, Twox64Concat, ForeignAssetId, CollectionId, OptionQuery>;
+ #[pallet::getter(fn foreign_reserve_asset_instance_to_token_id)]
+ pub type ForeignReserveAssetInstanceToTokenId<T: Config> = StorageDoubleMap<
+ Hasher1 = Twox64Concat,
+ Key1 = CollectionId,
+ Hasher2 = Twox64Concat,
+ Key2 = staging_xcm::v3::AssetInstance,
+ Value = TokenId,
+ QueryKind = OptionQuery,
+ >;
#[pallet::pallet]
pub struct Pallet<T>(_);
@@ -284,164 +132,152 @@
impl<T: Config> Pallet<T> {
#[pallet::call_index(0)]
#[pallet::weight(<T as Config>::WeightInfo::register_foreign_asset())]
- pub fn register_foreign_asset(
+ pub fn force_register_foreign_asset(
origin: OriginFor<T>,
- owner: T::AccountId,
- location: Box<VersionedMultiLocation>,
- metadata: Box<AssetMetadata<BalanceOf<T>>>,
+ 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::<T>::BadLocation)?;
+ let foreign_collection_owner = Self::pallet_account();
- let md = metadata.clone();
- let name: Vec<u16> = md.name.into_iter().map(|x| x as u16).collect::<Vec<u16>>();
- let mut description: Vec<u16> = "Foreign assets collection for "
+ let description: CollectionDescription = "Foreign Assets Collection"
.encode_utf16()
- .collect::<Vec<u16>>();
- description.append(&mut name.clone());
+ .collect::<Vec<_>>()
+ .try_into()
+ .expect("description length < max description length; qed");
- let data: CreateCollectionData<T::CrossAccountId> = 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 =
- <PalletFungible<T>>::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::<T>::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(<T as Config>::WeightInfo::update_foreign_asset())]
- pub fn update_foreign_asset(
- origin: OriginFor<T>,
- foreign_asset_id: ForeignAssetId,
- location: Box<VersionedMultiLocation>,
- metadata: Box<AssetMetadata<BalanceOf<T>>>,
- ) -> 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::<T>::BadLocation)?;
- Self::do_update_foreign_asset(foreign_asset_id, &location, &metadata)?;
+ <ForeignReserveLocationToCollection<T>>::insert(reserve_location, collection_id);
- Self::deposit_event(Event::<T>::ForeignAssetUpdated {
- asset_id: foreign_asset_id,
- asset_address: location,
- metadata: *metadata,
+ Self::deposit_event(Event::<T>::ForeignAssetRegistered {
+ asset_id: collection_id,
+ reserve_location,
});
+
Ok(())
}
}
}
impl<T: Config> Pallet<T> {
- fn get_next_foreign_asset_id() -> Result<ForeignAssetId, DispatchError> {
- NextForeignAssetId::<T>::try_mutate(|current| -> Result<ForeignAssetId, DispatchError> {
- 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<BalanceOf<T>>,
- bounded_collection_id: CollectionId,
- ) -> Result<ForeignAssetId, DispatchError> {
- let foreign_asset_id = Self::get_next_foreign_asset_id()?;
- LocationToCurrencyIds::<T>::try_mutate(location, |maybe_currency_ids| -> DispatchResult {
- ensure!(
- maybe_currency_ids.is_none(),
- Error::<T>::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::<T>::try_mutate(
- foreign_asset_id,
- |maybe_location| -> DispatchResult {
- ensure!(maybe_location.is_none(), Error::<T>::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::<T>::try_mutate(
- AssetId::ForeignAssetId(foreign_asset_id),
- |maybe_asset_metadatas| -> DispatchResult {
- ensure!(maybe_asset_metadatas.is_none(), Error::<T>::AssetIdExisted);
- *maybe_asset_metadatas = Some(metadata.clone());
- Ok(())
- },
- )
- },
- )?;
+impl<T: Config> TransactAsset for Pallet<T> {
+ fn can_check_in(
+ _origin: &MultiLocation,
+ _what: &MultiAsset,
+ _context: &XcmContext,
+ ) -> XcmResult {
+ Err(XcmError::Unimplemented)
+ }
- AssetBinding::<T>::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<staging_xcm_executor::Assets, XcmError> {
+ Err(XcmError::Unimplemented)
}
- fn do_update_foreign_asset(
- foreign_asset_id: ForeignAssetId,
- location: &MultiLocation,
- metadata: &AssetMetadata<BalanceOf<T>>,
- ) -> DispatchResult {
- ForeignAssetLocations::<T>::try_mutate(
- foreign_asset_id,
- |maybe_multi_locations| -> DispatchResult {
- let old_multi_locations = maybe_multi_locations
- .as_mut()
- .ok_or(Error::<T>::AssetIdNotExists)?;
+ fn internal_transfer_asset(
+ what: &MultiAsset,
+ from: &MultiLocation,
+ to: &MultiLocation,
+ _context: &XcmContext,
+ ) -> Result<staging_xcm_executor::Assets, XcmError> {
+ Err(XcmError::Unimplemented)
+ }
+}
- AssetMetadatas::<T>::try_mutate(
- AssetId::ForeignAssetId(foreign_asset_id),
- |maybe_asset_metadatas| -> DispatchResult {
- ensure!(
- maybe_asset_metadatas.is_some(),
- Error::<T>::AssetIdNotExists
- );
+pub struct CurrencyIdConvert<T: Config>(PhantomData<T>);
+impl<T: Config> sp_runtime::traits::Convert<CollectionId, Option<MultiLocation>>
+ for CurrencyIdConvert<T>
+{
+ fn convert(collection_id: CollectionId) -> Option<MultiLocation> {
+ 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::<T>::remove(*old_multi_locations);
- LocationToCurrencyIds::<T>::try_mutate(
- location,
- |maybe_currency_ids| -> DispatchResult {
- ensure!(
- maybe_currency_ids.is_none(),
- Error::<T>::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(&<Pallet<T>>::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<Balance = Currency::Balance>,
- AssetId: Get<MultiLocation>,
- AccountId,
- Currency: CurrencyT<AccountId>,
- OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
->(
- Weight,
- Currency::Balance,
- PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,
-);
+pub struct FreeForAll;
-impl<
- WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
- AssetId: Get<MultiLocation>,
- AccountId,
- Currency: CurrencyT<AccountId>,
- OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
- > WeightTrader for FreeForAll<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
-{
+impl WeightTrader for FreeForAll {
fn new() -> Self {
- Self(Weight::default(), Zero::zero(), PhantomData)
+ Self
}
fn buy_weight(
@@ -484,17 +303,5 @@
) -> Result<Assets, XcmError> {
log::trace!(target: "fassets::weight", "buy_weight weight: {:?}, payment: {:?}", weight, payment);
Ok(payment)
- }
-}
-impl<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced> Drop
- for FreeForAll<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
-where
- WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
- AssetId: Get<MultiLocation>,
- Currency: CurrencyT<AccountId>,
- OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
-{
- fn drop(&mut self) {
- OnUnbalanced::on_unbalanced(Currency::issue(self.1));
}
}
pallets/fungible/src/common.rsdiffbeforeafterboth--- a/pallets/fungible/src/common.rs
+++ b/pallets/fungible/src/common.rs
@@ -428,10 +428,6 @@
<Allowance<T>>::get((self.id, sender, spender))
}
- fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>> {
- None
- }
-
fn total_pieces(&self, token: TokenId) -> Option<u128> {
if token != TokenId::default() {
return None;
pallets/fungible/src/lib.rsdiffbeforeafterboth--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -212,24 +212,6 @@
/// Pallet implementation for fungible assets
impl<T: Config> Pallet<T> {
- /// Initializes the collection. Returns [CollectionId] on success, [DispatchError] otherwise.
- pub fn init_collection(
- owner: T::CrossAccountId,
- payer: T::CrossAccountId,
- data: CreateCollectionData<T::CrossAccountId>,
- ) -> Result<CollectionId, DispatchError> {
- <PalletCommon<T>>::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<T::CrossAccountId>,
- ) -> Result<CollectionId, DispatchError> {
- <PalletCommon<T>>::init_foreign_collection(owner, payer, data)
- }
-
/// Destroys a collection.
pub fn destroy_collection(
collection: FungibleHandle<T>,
pallets/nonfungible/src/common.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -535,10 +535,6 @@
}
}
- fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>> {
- None
- }
-
fn total_pieces(&self, token: TokenId) -> Option<u128> {
if <TokenData<T>>::contains_key((self.id, token)) {
Some(1)
pallets/nonfungible/src/lib.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # Nonfungible Pallet18//!19//! The Nonfungible pallet provides functionality for handling nonfungible collections and tokens.20//!21//! - [`Config`]22//! - [`NonfungibleHandle`]23//! - [`Pallet`]24//! - [`CommonWeights`](common::CommonWeights)25//!26//! ## Overview27//!28//! The Nonfungible pallet provides functions for:29//!30//! - NFT collection creation and removal31//! - Minting and burning of NFT tokens32//! - Retrieving account balances33//! - Transfering NFT tokens34//! - Setting and checking allowance for NFT tokens35//! - Setting properties and permissions for NFT collections and tokens36//! - Nesting and unnesting tokens37//!38//! ### Terminology39//!40//! - **NFT token:** Non fungible token.41//!42//! - **NFT Collection:** A collection of NFT tokens. All NFT tokens are part of a collection.43//! Each collection can define it's own properties, properties for it's tokens and set of permissions.44//!45//! - **Balance:** Number of NFT tokens owned by an account46//!47//! - **Allowance:** NFT tokens owned by one account that another account is allowed to make operations on48//!49//! - **Burning:** The process of “deleting” a token from a collection and from50//! an account balance of the owner.51//!52//! - **Nesting:** Setting up parent-child relationship between tokens. Nested tokens are inhereting53//! owner from their parent. There could be multiple levels of nesting. Token couldn't be nested in54//! it's child token i.e. parent-child relationship graph shouldn't have cycles.55//!56//! - **Properties:** Key-Values pairs. Token properties are attached to a token. Collection properties are57//! attached to a collection. Set of permissions could be defined for each property.58//!59//! ### Implementations60//!61//! The Nonfungible pallet provides implementations for the following traits. If these traits provide62//! the functionality that you need, then you can avoid coupling with the Nonfungible pallet.63//!64//! - [`CommonWeightInfo`](pallet_common::CommonWeightInfo): Functions for retrieval of transaction weight65//! - [`CommonCollectionOperations`](pallet_common::CommonCollectionOperations): Functions for dealing66//! with collections67//!68//! ## Interface69//!70//! ### Dispatchable Functions71//!72//! - `init_collection` - Create NFT collection. NFT collection can be configured to allow or deny access for73//! some accounts.74//! - `destroy_collection` - Destroy exising NFT collection. There should be no tokens in the collection.75//! - `burn` - Burn NFT token owned by account.76//! - `transfer` - Transfer NFT token. Transfers should be enabled for NFT collection.77//! Nests the NFT token if it is sent to another token.78//! - `create_item` - Mint NFT token in collection. Sender should have permission to mint tokens.79//! - `set_allowance` - Set allowance for another account.80//! - `set_token_property` - Set token property value.81//! - `delete_token_property` - Remove property from the token.82//! - `set_collection_properties` - Set collection properties.83//! - `delete_collection_properties` - Remove properties from the collection.84//! - `set_property_permission` - Set collection property permission.85//! - `set_token_property_permissions` - Set token property permissions.86//!87//! ## Assumptions88//!89//! * To perform operations on tokens sender should be in collection's allow list if collection access mode is `AllowList`.9091#![cfg_attr(not(feature = "std"), no_std)]9293use core::ops::Deref;9495use erc::ERC721Events;96use evm_coder::ToLog;97use frame_support::{98 dispatch::{Pays, PostDispatchInfo},99 ensure, fail,100 pallet_prelude::*,101 storage::with_transaction,102 transactional, BoundedVec,103};104pub use pallet::*;105use pallet_common::{106 eth::collection_id_to_address, helpers::add_weight_to_post_info,107 weights::WeightInfo as CommonWeightInfo, CollectionHandle, Error as CommonError,108 Event as CommonEvent, Pallet as PalletCommon, SelfWeightOf as PalletCommonWeightOf,109};110use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};111use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};112use pallet_structure::Pallet as PalletStructure;113use parity_scale_codec::{Decode, Encode, MaxEncodedLen};114use scale_info::TypeInfo;115use sp_core::{Get, H160};116use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};117use sp_std::{collections::btree_map::BTreeMap, vec, vec::Vec};118use up_data_structs::{119 budget::Budget, mapping::TokenAddressMapping, AccessMode, AuxPropertyValue, CollectionId,120 CreateCollectionData, CreateNftExData, CustomDataLimit, PropertiesPermissionMap, Property,121 PropertyKey, PropertyKeyPermission, PropertyScope, PropertyValue, TokenChild, TokenId,122 TokenProperties as TokenPropertiesT,123};124use weights::WeightInfo;125#[cfg(feature = "runtime-benchmarks")]126pub mod benchmarking;127pub mod common;128pub mod erc;129pub mod weights;130131pub type CreateItemData<T> = CreateNftExData<<T as pallet_evm::Config>::CrossAccountId>;132pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;133134/// Token data, stored independently from other data used to describe it135/// for the convenience of database access. Notably contains the owner account address.136#[struct_versioning::versioned(version = 2, upper)]137#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]138pub struct ItemData<CrossAccountId> {139 #[version(..2)]140 pub const_data: BoundedVec<u8, CustomDataLimit>,141142 #[version(..2)]143 pub variable_data: BoundedVec<u8, CustomDataLimit>,144145 pub owner: CrossAccountId,146}147148#[frame_support::pallet]149pub mod pallet {150 use frame_support::{151 pallet_prelude::*, storage::Key, traits::StorageVersion, Blake2_128Concat, Twox64Concat,152 };153 use up_data_structs::{CollectionId, TokenId};154155 use super::{weights::WeightInfo, *};156157 #[pallet::error]158 pub enum Error<T> {159 /// Not Nonfungible item data used to mint in Nonfungible collection.160 NotNonfungibleDataUsedToMintFungibleCollectionToken,161 /// Used amount > 1 with NFT162 NonfungibleItemsHaveNoAmount,163 /// Unable to burn NFT with children164 CantBurnNftWithChildren,165 }166167 #[pallet::config]168 pub trait Config:169 frame_system::Config + pallet_common::Config + pallet_structure::Config + pallet_evm::Config170 {171 type WeightInfo: WeightInfo;172 }173174 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);175176 #[pallet::pallet]177 #[pallet::storage_version(STORAGE_VERSION)]178 pub struct Pallet<T>(_);179180 /// Total amount of minted tokens in a collection.181 #[pallet::storage]182 pub type TokensMinted<T: Config> =183 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;184185 /// Amount of burnt tokens in a collection.186 #[pallet::storage]187 pub type TokensBurnt<T: Config> =188 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;189190 /// Token data, used to partially describe a token.191 #[pallet::storage]192 pub type TokenData<T: Config> = StorageNMap<193 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),194 Value = ItemData<T::CrossAccountId>,195 QueryKind = OptionQuery,196 >;197198 /// Map of key-value pairs, describing the metadata of a token.199 #[pallet::storage]200 #[pallet::getter(fn token_properties)]201 pub type TokenProperties<T: Config> = StorageNMap<202 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),203 Value = TokenPropertiesT,204 QueryKind = OptionQuery,205 >;206207 /// Custom data of a token that is serialized to bytes,208 /// primarily reserved for on-chain operations,209 /// normally obscured from the external users.210 ///211 /// Auxiliary properties are slightly different from212 /// usual [`TokenProperties`] due to an unlimited number213 /// and separately stored and written-to key-value pairs.214 ///215 /// Currently unused.216 #[pallet::storage]217 #[pallet::getter(fn token_aux_property)]218 pub type TokenAuxProperties<T: Config> = StorageNMap<219 Key = (220 Key<Twox64Concat, CollectionId>,221 Key<Twox64Concat, TokenId>,222 Key<Twox64Concat, PropertyScope>,223 Key<Twox64Concat, PropertyKey>,224 ),225 Value = AuxPropertyValue,226 QueryKind = OptionQuery,227 >;228229 /// Used to enumerate tokens owned by account.230 #[pallet::storage]231 pub type Owned<T: Config> = StorageNMap<232 Key = (233 Key<Twox64Concat, CollectionId>,234 Key<Blake2_128Concat, T::CrossAccountId>,235 Key<Twox64Concat, TokenId>,236 ),237 Value = bool,238 QueryKind = ValueQuery,239 >;240241 /// Used to enumerate token's children.242 #[pallet::storage]243 #[pallet::getter(fn token_children)]244 pub type TokenChildren<T: Config> = StorageNMap<245 Key = (246 Key<Twox64Concat, CollectionId>,247 Key<Twox64Concat, TokenId>,248 Key<Twox64Concat, (CollectionId, TokenId)>,249 ),250 Value = bool,251 QueryKind = ValueQuery,252 >;253254 /// Amount of tokens owned by an account in a collection.255 #[pallet::storage]256 pub type AccountBalance<T: Config> = StorageNMap<257 Key = (258 Key<Twox64Concat, CollectionId>,259 Key<Blake2_128Concat, T::CrossAccountId>,260 ),261 Value = u32,262 QueryKind = ValueQuery,263 >;264265 /// Allowance set by a token owner for another user to perform one of certain transactions on a token.266 #[pallet::storage]267 pub type Allowance<T: Config> = StorageNMap<268 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),269 Value = T::CrossAccountId,270 QueryKind = OptionQuery,271 >;272273 /// Operator set by a wallet owner that could perform certain transactions on all tokens in the wallet.274 #[pallet::storage]275 pub type CollectionAllowance<T: Config> = StorageNMap<276 Key = (277 Key<Twox64Concat, CollectionId>,278 Key<Blake2_128Concat, T::CrossAccountId>,279 Key<Blake2_128Concat, T::CrossAccountId>,280 ),281 Value = bool,282 QueryKind = ValueQuery,283 >;284285 #[pallet::genesis_config]286 pub struct GenesisConfig<T>(PhantomData<T>);287288 impl<T: Config> Default for GenesisConfig<T> {289 fn default() -> Self {290 Self(Default::default())291 }292 }293294 #[pallet::genesis_build]295 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {296 fn build(&self) {297 StorageVersion::new(1).put::<Pallet<T>>();298 }299 }300}301302pub struct NonfungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);303impl<T: Config> NonfungibleHandle<T> {304 pub fn cast(inner: pallet_common::CollectionHandle<T>) -> Self {305 Self(inner)306 }307 pub fn into_inner(self) -> pallet_common::CollectionHandle<T> {308 self.0309 }310 pub fn common_mut(&mut self) -> &mut pallet_common::CollectionHandle<T> {311 &mut self.0312 }313}314315impl<T: Config> WithRecorder<T> for NonfungibleHandle<T> {316 fn recorder(&self) -> &SubstrateRecorder<T> {317 self.0.recorder()318 }319 fn into_recorder(self) -> SubstrateRecorder<T> {320 self.0.into_recorder()321 }322}323impl<T: Config> Deref for NonfungibleHandle<T> {324 type Target = pallet_common::CollectionHandle<T>;325326 fn deref(&self) -> &Self::Target {327 &self.0328 }329}330331impl<T: Config> Pallet<T> {332 /// Get number of NFT tokens in collection.333 pub fn total_supply(collection: &NonfungibleHandle<T>) -> u32 {334 <TokensMinted<T>>::get(collection.id) - <TokensBurnt<T>>::get(collection.id)335 }336337 /// Check that NFT token exists.338 ///339 /// - `token`: Token ID.340 pub fn token_exists(collection: &NonfungibleHandle<T>, token: TokenId) -> bool {341 <TokenData<T>>::contains_key((collection.id, token))342 }343344 /// Add or edit auxiliary data for the property.345 ///346 /// - `f`: function that adds or edits auxiliary data.347 pub fn try_mutate_token_aux_property<R, E>(348 collection_id: CollectionId,349 token_id: TokenId,350 scope: PropertyScope,351 key: PropertyKey,352 f: impl FnOnce(&mut Option<AuxPropertyValue>) -> Result<R, E>,353 ) -> Result<R, E> {354 <TokenAuxProperties<T>>::try_mutate((collection_id, token_id, scope, key), f)355 }356357 /// Remove auxiliary data for the property.358 pub fn remove_token_aux_property(359 collection_id: CollectionId,360 token_id: TokenId,361 scope: PropertyScope,362 key: PropertyKey,363 ) {364 <TokenAuxProperties<T>>::remove((collection_id, token_id, scope, key));365 }366367 /// Get all auxiliary data in a given scope.368 ///369 /// Returns iterator over Property Key - Data pairs.370 pub fn iterate_token_aux_properties(371 collection_id: CollectionId,372 token_id: TokenId,373 scope: PropertyScope,374 ) -> impl Iterator<Item = (PropertyKey, AuxPropertyValue)> {375 <TokenAuxProperties<T>>::iter_prefix((collection_id, token_id, scope))376 }377378 /// Get ID of the last minted token379 pub fn current_token_id(collection_id: CollectionId) -> TokenId {380 TokenId(<TokensMinted<T>>::get(collection_id))381 }382}383384// unchecked calls skips any permission checks385impl<T: Config> Pallet<T> {386 /// Create NFT collection387 ///388 /// `init_collection` will take non-refundable deposit for collection creation.389 ///390 /// - `data`: Contains settings for collection limits and permissions.391 pub fn init_collection(392 owner: T::CrossAccountId,393 payer: T::CrossAccountId,394 data: CreateCollectionData<T::CrossAccountId>,395 ) -> Result<CollectionId, DispatchError> {396 <PalletCommon<T>>::init_collection(owner, payer, data)397 }398399 /// Destroy NFT collection400 ///401 /// `destroy_collection` will throw error if collection contains any tokens.402 /// Only owner can destroy collection.403 pub fn destroy_collection(404 collection: NonfungibleHandle<T>,405 sender: &T::CrossAccountId,406 ) -> DispatchResult {407 let id = collection.id;408409 if Self::collection_has_tokens(id) {410 return Err(<CommonError<T>>::CantDestroyNotEmptyCollection.into());411 }412413 // =========414415 PalletCommon::destroy_collection(collection.0, sender)?;416417 let _ = <TokenData<T>>::clear_prefix((id,), u32::MAX, None);418 let _ = <TokenChildren<T>>::clear_prefix((id,), u32::MAX, None);419 let _ = <Owned<T>>::clear_prefix((id,), u32::MAX, None);420 <TokensMinted<T>>::remove(id);421 <TokensBurnt<T>>::remove(id);422 let _ = <Allowance<T>>::clear_prefix((id,), u32::MAX, None);423 let _ = <AccountBalance<T>>::clear_prefix((id,), u32::MAX, None);424 let _ = <CollectionAllowance<T>>::clear_prefix((id,), u32::MAX, None);425 Ok(())426 }427428 /// Burn NFT token429 ///430 /// `burn` removes `token` from the `collection`, from it's owner and from the parent token431 /// if the token is nested.432 /// Only the owner can `burn` the token. The `token` shouldn't have any nested tokens.433 /// Also removes all corresponding properties and auxiliary properties.434 ///435 /// - `token`: Token that should be burned436 /// - `collection`: Collection that contains the token437 pub fn burn(438 collection: &NonfungibleHandle<T>,439 sender: &T::CrossAccountId,440 token: TokenId,441 ) -> DispatchResult {442 let token_data =443 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;444 ensure!(&token_data.owner == sender, <CommonError<T>>::NoPermission);445446 if collection.permissions.access() == AccessMode::AllowList {447 collection.check_allowlist(sender)?;448 }449450 if Self::token_has_children(collection.id, token) {451 return Err(<Error<T>>::CantBurnNftWithChildren.into());452 }453454 let burnt = <TokensBurnt<T>>::get(collection.id)455 .checked_add(1)456 .ok_or(ArithmeticError::Overflow)?;457458 let balance = <AccountBalance<T>>::get((collection.id, token_data.owner.clone()))459 .checked_sub(1)460 .ok_or(ArithmeticError::Overflow)?;461462 // =========463464 if balance == 0 {465 <AccountBalance<T>>::remove((collection.id, token_data.owner.clone()));466 } else {467 <AccountBalance<T>>::insert((collection.id, token_data.owner.clone()), balance);468 }469470 <PalletStructure<T>>::unnest_if_nested(&token_data.owner, collection.id, token);471472 <Owned<T>>::remove((collection.id, &token_data.owner, token));473 <TokensBurnt<T>>::insert(collection.id, burnt);474 <TokenData<T>>::remove((collection.id, token));475 <TokenProperties<T>>::remove((collection.id, token));476 let _ = <TokenAuxProperties<T>>::clear_prefix((collection.id, token), u32::MAX, None);477 let old_spender = <Allowance<T>>::take((collection.id, token));478479 if let Some(old_spender) = old_spender {480 <PalletCommon<T>>::deposit_event(CommonEvent::Approved(481 collection.id,482 token,483 token_data.owner.clone(),484 old_spender,485 0,486 ));487 }488489 <PalletEvm<T>>::deposit_log(490 ERC721Events::Transfer {491 from: *token_data.owner.as_eth(),492 to: H160::default(),493 token_id: token.into(),494 }495 .to_log(collection_id_to_address(collection.id)),496 );497 <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(498 collection.id,499 token,500 token_data.owner,501 1,502 ));503 Ok(())504 }505506 /// A batch operation to add, edit or remove properties for a token.507 ///508 /// - `nesting_budget`: Limit for searching parents in-depth to check ownership.509 ///510 /// All affected properties should have `mutable` permission511 /// to be **deleted** or to be **set more than once**,512 /// and the sender should have permission to edit those properties.513 ///514 /// This function fires an event for each property change.515 /// In case of an error, all the changes (including the events) will be reverted516 /// since the function is transactional.517 #[transactional]518 fn modify_token_properties(519 collection: &NonfungibleHandle<T>,520 sender: &T::CrossAccountId,521 token_id: TokenId,522 properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,523 nesting_budget: &dyn Budget,524 ) -> DispatchResult {525 let mut property_writer =526 pallet_common::ExistingTokenPropertyWriter::new(collection, sender);527528 property_writer.write_token_properties(529 sender,530 token_id,531 properties_updates,532 nesting_budget,533 erc::ERC721TokenEvent::TokenChanged {534 token_id: token_id.into(),535 }536 .to_log(T::ContractAddress::get()),537 )538 }539540 pub fn next_token_id(collection: &NonfungibleHandle<T>) -> Result<TokenId, DispatchError> {541 let next_token_id = <TokensMinted<T>>::get(collection.id)542 .checked_add(1)543 .ok_or(<CommonError<T>>::CollectionTokenLimitExceeded)?;544545 ensure!(546 collection.limits.token_limit() >= next_token_id,547 <CommonError<T>>::CollectionTokenLimitExceeded548 );549550 Ok(TokenId(next_token_id))551 }552553 /// Batch operation to add or edit properties for the token554 ///555 /// Same as [`modify_token_properties`] but doesn't allow to remove properties556 ///557 /// [`modify_token_properties`]: struct.Pallet.html#method.modify_token_properties558 pub fn set_token_properties(559 collection: &NonfungibleHandle<T>,560 sender: &T::CrossAccountId,561 token_id: TokenId,562 properties: impl Iterator<Item = Property>,563 nesting_budget: &dyn Budget,564 ) -> DispatchResult {565 Self::modify_token_properties(566 collection,567 sender,568 token_id,569 properties.map(|p| (p.key, Some(p.value))),570 nesting_budget,571 )572 }573574 /// Add or edit single property for the token575 ///576 /// Calls [`set_token_properties`] internally577 ///578 /// [`set_token_properties`]: struct.Pallet.html#method.set_token_properties579 pub fn set_token_property(580 collection: &NonfungibleHandle<T>,581 sender: &T::CrossAccountId,582 token_id: TokenId,583 property: Property,584 nesting_budget: &dyn Budget,585 ) -> DispatchResult {586 Self::set_token_properties(587 collection,588 sender,589 token_id,590 [property].into_iter(),591 nesting_budget,592 )593 }594595 /// Batch operation to remove properties from the token596 ///597 /// Same as [`modify_token_properties`] but doesn't allow to add or edit properties598 ///599 /// [`modify_token_properties`]: struct.Pallet.html#method.modify_token_properties600 pub fn delete_token_properties(601 collection: &NonfungibleHandle<T>,602 sender: &T::CrossAccountId,603 token_id: TokenId,604 property_keys: impl Iterator<Item = PropertyKey>,605 nesting_budget: &dyn Budget,606 ) -> DispatchResult {607 Self::modify_token_properties(608 collection,609 sender,610 token_id,611 property_keys.into_iter().map(|key| (key, None)),612 nesting_budget,613 )614 }615616 /// Remove single property from the token617 ///618 /// Calls [`delete_token_properties`] internally619 ///620 /// [`delete_token_properties`]: struct.Pallet.html#method.delete_token_properties621 pub fn delete_token_property(622 collection: &NonfungibleHandle<T>,623 sender: &T::CrossAccountId,624 token_id: TokenId,625 property_key: PropertyKey,626 nesting_budget: &dyn Budget,627 ) -> DispatchResult {628 Self::delete_token_properties(629 collection,630 sender,631 token_id,632 [property_key].into_iter(),633 nesting_budget,634 )635 }636637 /// Add or edit properties for the collection638 pub fn set_collection_properties(639 collection: &NonfungibleHandle<T>,640 sender: &T::CrossAccountId,641 properties: Vec<Property>,642 ) -> DispatchResult {643 <PalletCommon<T>>::set_collection_properties(collection, sender, properties.into_iter())644 }645646 /// Remove properties from the collection647 pub fn delete_collection_properties(648 collection: &CollectionHandle<T>,649 sender: &T::CrossAccountId,650 property_keys: Vec<PropertyKey>,651 ) -> DispatchResult {652 <PalletCommon<T>>::delete_collection_properties(653 collection,654 sender,655 property_keys.into_iter(),656 )657 }658659 /// Set property permissions for the token.660 ///661 /// Sender should be the owner or admin of token's collection.662 pub fn set_token_property_permissions(663 collection: &CollectionHandle<T>,664 sender: &T::CrossAccountId,665 property_permissions: Vec<PropertyKeyPermission>,666 ) -> DispatchResult {667 <PalletCommon<T>>::set_token_property_permissions(collection, sender, property_permissions)668 }669670 /// Set property permissions for the token with scope.671 ///672 /// Sender should be the owner or admin of token's collection.673 pub fn set_scoped_token_property_permissions(674 collection: &CollectionHandle<T>,675 sender: &T::CrossAccountId,676 scope: PropertyScope,677 property_permissions: Vec<PropertyKeyPermission>,678 ) -> DispatchResult {679 <PalletCommon<T>>::set_scoped_token_property_permissions(680 collection,681 sender,682 scope,683 property_permissions,684 )685 }686687 pub fn token_property_permission(collection_id: CollectionId) -> PropertiesPermissionMap {688 <PalletCommon<T>>::property_permissions(collection_id)689 }690691 pub fn check_token_immediate_ownership(692 collection: &NonfungibleHandle<T>,693 token: TokenId,694 possible_owner: &T::CrossAccountId,695 ) -> DispatchResult {696 let token_data =697 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;698 ensure!(699 &token_data.owner == possible_owner,700 <CommonError<T>>::NoPermission701 );702 Ok(())703 }704705 /// Transfer NFT token from one account to another.706 ///707 /// `from` account stops being the owner and `to` account becomes the owner of the token.708 /// If `to` is token than `to` becomes owner of the token and the token become nested.709 /// Unnests token from previous parent if it was nested before.710 /// Removes allowance for the token if there was any.711 /// Throws if transfers aren't allowed for collection or if receiver reached token ownership limit.712 ///713 /// - `nesting_budget`: Limit for token nesting depth714 pub fn transfer(715 collection: &NonfungibleHandle<T>,716 from: &T::CrossAccountId,717 to: &T::CrossAccountId,718 token: TokenId,719 nesting_budget: &dyn Budget,720 ) -> DispatchResultWithPostInfo {721 let depositor = from;722 Self::transfer_internal(collection, depositor, from, to, token, nesting_budget)723 }724725 /// Transfers an NFT from the `from` account to the `to` account.726 /// The `depositor` is the account who deposits the NFT.727 /// For instance, the nesting rules will be checked against the `depositor`'s permissions.728 pub fn transfer_internal(729 collection: &NonfungibleHandle<T>,730 depositor: &T::CrossAccountId,731 from: &T::CrossAccountId,732 to: &T::CrossAccountId,733 token: TokenId,734 nesting_budget: &dyn Budget,735 ) -> DispatchResultWithPostInfo {736 ensure!(737 collection.limits.transfers_enabled(),738 <CommonError<T>>::TransferNotAllowed739 );740741 let mut actual_weight = <SelfWeightOf<T>>::transfer_raw();742 let token_data =743 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;744 ensure!(&token_data.owner == from, <CommonError<T>>::NoPermission);745746 if collection.permissions.access() == AccessMode::AllowList {747 collection.check_allowlist(from)?;748 collection.check_allowlist(to)?;749 actual_weight += <PalletCommonWeightOf<T>>::check_accesslist() * 2;750 }751 <PalletCommon<T>>::ensure_correct_receiver(to)?;752753 let balance_from = <AccountBalance<T>>::get((collection.id, from))754 .checked_sub(1)755 .ok_or(<CommonError<T>>::TokenValueTooLow)?;756 let balance_to = if from != to {757 let balance_to = <AccountBalance<T>>::get((collection.id, to))758 .checked_add(1)759 .ok_or(ArithmeticError::Overflow)?;760761 ensure!(762 balance_to < collection.limits.account_token_ownership_limit(),763 <CommonError<T>>::AccountTokenLimitExceeded,764 );765766 Some(balance_to)767 } else {768 None769 };770771 <PalletStructure<T>>::nest_if_sent_to_token(772 depositor,773 to,774 collection.id,775 token,776 nesting_budget,777 )?;778779 // =========780781 <PalletStructure<T>>::unnest_if_nested(&token_data.owner, collection.id, token);782783 <TokenData<T>>::insert((collection.id, token), ItemData { owner: to.clone() });784785 if let Some(balance_to) = balance_to {786 // from != to787 if balance_from == 0 {788 <AccountBalance<T>>::remove((collection.id, from));789 } else {790 <AccountBalance<T>>::insert((collection.id, from), balance_from);791 }792 <AccountBalance<T>>::insert((collection.id, to), balance_to);793 <Owned<T>>::remove((collection.id, from, token));794 <Owned<T>>::insert((collection.id, to, token), true);795 }796 Self::set_allowance_unchecked(collection, from, token, None, true);797798 <PalletEvm<T>>::deposit_log(799 ERC721Events::Transfer {800 from: *from.as_eth(),801 to: *to.as_eth(),802 token_id: token.into(),803 }804 .to_log(collection_id_to_address(collection.id)),805 );806 <PalletCommon<T>>::deposit_event(CommonEvent::Transfer(807 collection.id,808 token,809 from.clone(),810 to.clone(),811 1,812 ));813814 Ok(PostDispatchInfo {815 actual_weight: Some(actual_weight),816 pays_fee: Pays::Yes,817 })818 }819820 /// Batch operation to mint multiple NFT tokens.821 ///822 /// The sender should be the owner/admin of the collection or collection should be configured823 /// to allow public minting.824 /// Throws if amount of tokens reached it's limit for the collection or if caller reached825 /// token ownership limit.826 ///827 /// - `data`: Contains list of token properties and users who will become the owners of the828 /// corresponging tokens.829 /// - `nesting_budget`: Limit for token nesting depth830 pub fn create_multiple_items(831 collection: &NonfungibleHandle<T>,832 sender: &T::CrossAccountId,833 data: Vec<CreateItemData<T>>,834 nesting_budget: &dyn Budget,835 ) -> DispatchResult {836 if !collection.is_owner_or_admin(sender) {837 ensure!(838 collection.permissions.mint_mode(),839 <CommonError<T>>::PublicMintingNotAllowed840 );841 collection.check_allowlist(sender)?;842843 for item in data.iter() {844 collection.check_allowlist(&item.owner)?;845 }846 }847848 for data in data.iter() {849 <PalletCommon<T>>::ensure_correct_receiver(&data.owner)?;850 }851852 let first_token = <TokensMinted<T>>::get(collection.id);853 let tokens_minted = first_token854 .checked_add(data.len() as u32)855 .ok_or(ArithmeticError::Overflow)?;856 ensure!(857 tokens_minted <= collection.limits.token_limit(),858 <CommonError<T>>::CollectionTokenLimitExceeded859 );860861 let mut balances = BTreeMap::new();862 for data in &data {863 let balance = balances864 .entry(&data.owner)865 .or_insert_with(|| <AccountBalance<T>>::get((collection.id, &data.owner)));866 *balance = balance.checked_add(1).ok_or(ArithmeticError::Overflow)?;867868 ensure!(869 *balance <= collection.limits.account_token_ownership_limit(),870 <CommonError<T>>::AccountTokenLimitExceeded,871 );872 }873874 for (i, data) in data.iter().enumerate() {875 let token = TokenId(first_token + i as u32 + 1);876877 <PalletStructure<T>>::check_nesting(878 sender,879 &data.owner,880 collection.id,881 token,882 nesting_budget,883 )?;884 }885886 // =========887888 let mut property_writer = pallet_common::NewTokenPropertyWriter::new(collection, sender);889890 with_transaction(|| {891 for (i, data) in data.iter().enumerate() {892 let token = first_token + i as u32 + 1;893894 <TokenData<T>>::insert(895 (collection.id, token),896 ItemData {897 // const_data: data.const_data.clone(),898 owner: data.owner.clone(),899 },900 );901902 let token = TokenId(token);903904 <PalletStructure<T>>::nest_if_sent_to_token_unchecked(905 &data.owner,906 collection.id,907 token,908 );909910 if let Err(e) = property_writer.write_token_properties(911 sender.conv_eq(&data.owner),912 token,913 data.properties.clone().into_iter(),914 erc::ERC721TokenEvent::TokenChanged {915 token_id: token.into(),916 }917 .to_log(T::ContractAddress::get()),918 ) {919 return TransactionOutcome::Rollback(Err(e));920 }921 }922 TransactionOutcome::Commit(Ok(()))923 })?;924925 <TokensMinted<T>>::insert(collection.id, tokens_minted);926 for (account, balance) in balances {927 <AccountBalance<T>>::insert((collection.id, account), balance);928 }929 for (i, data) in data.into_iter().enumerate() {930 let token = first_token + i as u32 + 1;931 <Owned<T>>::insert((collection.id, &data.owner, token), true);932933 <PalletEvm<T>>::deposit_log(934 ERC721Events::Transfer {935 from: H160::default(),936 to: *data.owner.as_eth(),937 token_id: token.into(),938 }939 .to_log(collection_id_to_address(collection.id)),940 );941 <PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(942 collection.id,943 TokenId(token),944 data.owner.clone(),945 1,946 ));947 }948 Ok(())949 }950951 pub fn set_allowance_unchecked(952 collection: &NonfungibleHandle<T>,953 sender: &T::CrossAccountId,954 token: TokenId,955 spender: Option<&T::CrossAccountId>,956 assume_implicit_eth: bool,957 ) {958 if let Some(spender) = spender {959 let old_spender = <Allowance<T>>::get((collection.id, token));960 <Allowance<T>>::insert((collection.id, token), spender);961 // In ERC721 there is only one possible approved user of token, so we set962 // approved user to spender963 <PalletEvm<T>>::deposit_log(964 ERC721Events::Approval {965 owner: *sender.as_eth(),966 approved: *spender.as_eth(),967 token_id: token.into(),968 }969 .to_log(collection_id_to_address(collection.id)),970 );971 // In Unique chain, any token can have any amount of approved users, so we need to972 // set allowance of old owner to 0, and allowance of new owner to 1973 if old_spender.as_ref() != Some(spender) {974 if let Some(old_owner) = old_spender {975 <PalletCommon<T>>::deposit_event(CommonEvent::Approved(976 collection.id,977 token,978 sender.clone(),979 old_owner,980 0,981 ));982 }983 <PalletCommon<T>>::deposit_event(CommonEvent::Approved(984 collection.id,985 token,986 sender.clone(),987 spender.clone(),988 1,989 ));990 }991 } else {992 let old_spender = <Allowance<T>>::take((collection.id, token));993 if !assume_implicit_eth {994 // In ERC721 there is only one possible approved user of token, so we set995 // approved user to zero address996 <PalletEvm<T>>::deposit_log(997 ERC721Events::Approval {998 owner: *sender.as_eth(),999 approved: H160::default(),1000 token_id: token.into(),1001 }1002 .to_log(collection_id_to_address(collection.id)),1003 );1004 }1005 // In Unique chain, any token can have any amount of approved users, so we need to1006 // set allowance of old owner to 01007 if let Some(old_spender) = old_spender {1008 <PalletCommon<T>>::deposit_event(CommonEvent::Approved(1009 collection.id,1010 token,1011 sender.clone(),1012 old_spender,1013 0,1014 ));1015 }1016 }1017 }10181019 pub fn get_allowance(1020 collection: &NonfungibleHandle<T>,1021 token_id: TokenId,1022 ) -> Result<Option<T::CrossAccountId>, DispatchError> {1023 ensure!(1024 <TokenData<T>>::get((collection.id, token_id)).is_some(),1025 <CommonError<T>>::TokenNotFound1026 );1027 Ok(<Allowance<T>>::get((collection.id, token_id)))1028 }10291030 /// Set allowance for the spender to `transfer` or `burn` sender's token.1031 ///1032 /// - `token`: Token the spender is allowed to `transfer` or `burn`.1033 pub fn set_allowance(1034 collection: &NonfungibleHandle<T>,1035 sender: &T::CrossAccountId,1036 token: TokenId,1037 spender: Option<&T::CrossAccountId>,1038 ) -> DispatchResult {1039 if collection.permissions.access() == AccessMode::AllowList {1040 collection.check_allowlist(sender)?;1041 if let Some(spender) = spender {1042 collection.check_allowlist(spender)?;1043 }1044 }10451046 if let Some(spender) = spender {1047 <PalletCommon<T>>::ensure_correct_receiver(spender)?;1048 }10491050 let token_data =1051 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;1052 if &token_data.owner != sender {1053 ensure!(1054 collection.ignores_owned_amount(sender),1055 <CommonError<T>>::CantApproveMoreThanOwned1056 );1057 }10581059 // =========10601061 Self::set_allowance_unchecked(collection, sender, token, spender, false);1062 Ok(())1063 }10641065 /// Set allowance for the spender to `transfer` or `burn` sender's token from eth mirror.1066 ///1067 /// - `from`: Address of sender's eth mirror.1068 /// - `to`: Adress of spender.1069 /// - `token`: Token the spender is allowed to `transfer` or `burn`.1070 pub fn set_allowance_from(1071 collection: &NonfungibleHandle<T>,1072 sender: &T::CrossAccountId,1073 from: &T::CrossAccountId,1074 token: TokenId,1075 to: Option<&T::CrossAccountId>,1076 ) -> DispatchResult {1077 if collection.permissions.access() == AccessMode::AllowList {1078 collection.check_allowlist(sender)?;1079 collection.check_allowlist(from)?;1080 if let Some(to) = to {1081 collection.check_allowlist(to)?;1082 }1083 }10841085 if let Some(to) = to {1086 <PalletCommon<T>>::ensure_correct_receiver(to)?;1087 }10881089 ensure!(1090 sender.conv_eq(from),1091 <CommonError<T>>::AddressIsNotEthMirror1092 );10931094 let token_data =1095 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;1096 if token_data.owner != *from {1097 ensure!(1098 collection.limits.owner_can_transfer()1099 && (collection.is_owner_or_admin(sender) || collection.is_owner_or_admin(from)),1100 <CommonError<T>>::CantApproveMoreThanOwned1101 );1102 }11031104 // =========11051106 Self::set_allowance_unchecked(collection, from, token, to, false);1107 Ok(())1108 }11091110 /// Checks allowance for the spender to use the token.1111 fn check_allowed(1112 collection: &NonfungibleHandle<T>,1113 spender: &T::CrossAccountId,1114 from: &T::CrossAccountId,1115 token: TokenId,1116 nesting_budget: &dyn Budget,1117 ) -> DispatchResult {1118 if spender.conv_eq(from) {1119 return Ok(());1120 }1121 if collection.permissions.access() == AccessMode::AllowList {1122 // `from`, `to` checked in [`transfer`]1123 collection.check_allowlist(spender)?;1124 }11251126 if collection.ignores_token_restrictions(spender) {1127 return Ok(());1128 }11291130 if let Some(source) = T::CrossTokenAddressMapping::address_to_token(from) {1131 ensure!(1132 <PalletStructure<T>>::check_indirectly_owned(1133 spender.clone(),1134 source.0,1135 source.1,1136 None,1137 nesting_budget1138 )?,1139 <CommonError<T>>::ApprovedValueTooLow,1140 );1141 return Ok(());1142 }1143 if <Allowance<T>>::get((collection.id, token)).as_ref() == Some(spender) {1144 return Ok(());1145 }1146 if <CollectionAllowance<T>>::get((collection.id, from, spender)) {1147 return Ok(());1148 }11491150 Err(<CommonError<T>>::ApprovedValueTooLow.into())1151 }11521153 /// Transfer NFT token from one account to another.1154 ///1155 /// Same as the [`transfer`] but spender doesn't needs to be the owner of the token.1156 /// The owner should set allowance for the spender to transfer token.1157 ///1158 /// [`transfer`]: struct.Pallet.html#method.transfer1159 pub fn transfer_from(1160 collection: &NonfungibleHandle<T>,1161 spender: &T::CrossAccountId,1162 from: &T::CrossAccountId,1163 to: &T::CrossAccountId,1164 token: TokenId,1165 nesting_budget: &dyn Budget,1166 ) -> DispatchResultWithPostInfo {1167 Self::check_allowed(collection, spender, from, token, nesting_budget)?;11681169 // =========11701171 // Allowance is reset in [`transfer`]1172 let mut result =1173 Self::transfer_internal(collection, spender, from, to, token, nesting_budget);1174 add_weight_to_post_info(&mut result, <SelfWeightOf<T>>::check_allowed_raw());1175 result1176 }11771178 /// Burn NFT token for `from` account.1179 ///1180 /// Same as the [`burn`] but spender doesn't need to be an owner of the token. The owner should1181 /// set allowance for the spender to burn token.1182 ///1183 /// [`burn`]: struct.Pallet.html#method.burn1184 pub fn burn_from(1185 collection: &NonfungibleHandle<T>,1186 spender: &T::CrossAccountId,1187 from: &T::CrossAccountId,1188 token: TokenId,1189 nesting_budget: &dyn Budget,1190 ) -> DispatchResult {1191 Self::check_allowed(collection, spender, from, token, nesting_budget)?;11921193 // =========11941195 Self::burn(collection, from, token)1196 }11971198 /// Check that `from` token could be nested in `under` token.1199 ///1200 pub fn check_nesting(1201 handle: &NonfungibleHandle<T>,1202 sender: &T::CrossAccountId,1203 from: (CollectionId, TokenId),1204 under: TokenId,1205 nesting_budget: &dyn Budget,1206 ) -> DispatchResult {1207 let nesting = handle.permissions.nesting();12081209 #[cfg(not(feature = "runtime-benchmarks"))]1210 let permissive = false;1211 #[cfg(feature = "runtime-benchmarks")]1212 let permissive = nesting.permissive;12131214 if permissive {1215 ensure!(1216 <TokenData<T>>::contains_key((handle.id, under)),1217 <CommonError<T>>::TokenNotFound1218 );1219 } else if nesting.token_owner1220 && <PalletStructure<T>>::check_indirectly_owned(1221 sender.clone(),1222 handle.id,1223 under,1224 Some(from),1225 nesting_budget,1226 )? {1227 // Pass, token existence and ouroboros checks are done in `check_indirectly_owned`1228 } else if nesting.collection_admin && handle.is_owner_or_admin(sender) {1229 // token existence and ouroboros checks are done in `get_checked_topmost_owner`1230 let _ = <PalletStructure<T>>::get_checked_topmost_owner(1231 handle.id,1232 under,1233 Some(from),1234 nesting_budget,1235 )?1236 .ok_or(<CommonError<T>>::TokenNotFound)?;1237 } else {1238 fail!(<CommonError<T>>::UserIsNotAllowedToNest);1239 }12401241 if let Some(whitelist) = &nesting.restricted {1242 ensure!(1243 whitelist.contains(&from.0),1244 <CommonError<T>>::SourceCollectionIsNotAllowedToNest1245 );1246 }1247 Ok(())1248 }12491250 fn nest(under: (CollectionId, TokenId), to_nest: (CollectionId, TokenId)) {1251 if to_nest.0 != pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {1252 <TokenChildren<T>>::insert((under.0, under.1, to_nest), true);1253 }1254 }12551256 fn unnest(under: (CollectionId, TokenId), to_unnest: (CollectionId, TokenId)) {1257 if to_unnest.0 != pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {1258 <TokenChildren<T>>::remove((under.0, under.1, to_unnest));1259 }1260 }12611262 fn collection_has_tokens(collection_id: CollectionId) -> bool {1263 <TokenData<T>>::iter_prefix((collection_id,))1264 .next()1265 .is_some()1266 }12671268 fn token_has_children(collection_id: CollectionId, token_id: TokenId) -> bool {1269 <TokenChildren<T>>::iter_prefix((collection_id, token_id))1270 .next()1271 .is_some()1272 }12731274 pub fn token_children_ids(collection_id: CollectionId, token_id: TokenId) -> Vec<TokenChild> {1275 <TokenChildren<T>>::iter_prefix((collection_id, token_id))1276 .map(|((child_collection_id, child_id), _)| TokenChild {1277 collection: child_collection_id,1278 token: child_id,1279 })1280 .collect()1281 }12821283 /// Mint single NFT token.1284 ///1285 /// Delegated to [`create_multiple_items`]1286 ///1287 /// [`create_multiple_items`]: struct.Pallet.html#method.create_multiple_items1288 pub fn create_item(1289 collection: &NonfungibleHandle<T>,1290 sender: &T::CrossAccountId,1291 data: CreateItemData<T>,1292 nesting_budget: &dyn Budget,1293 ) -> DispatchResult {1294 Self::create_multiple_items(collection, sender, vec![data], nesting_budget)1295 }12961297 /// Sets or unsets the approval of a given operator.1298 ///1299 /// The `operator` is allowed to transfer all token pieces of the `owner` on their behalf.1300 /// - `owner`: Token owner1301 /// - `operator`: Operator1302 /// - `approve`: Should operator status be granted or revoked?1303 pub fn set_allowance_for_all(1304 collection: &NonfungibleHandle<T>,1305 owner: &T::CrossAccountId,1306 operator: &T::CrossAccountId,1307 approve: bool,1308 ) -> DispatchResult {1309 <PalletCommon<T>>::set_allowance_for_all(1310 collection,1311 owner,1312 operator,1313 approve,1314 || <CollectionAllowance<T>>::insert((collection.id, owner, operator), approve),1315 ERC721Events::ApprovalForAll {1316 owner: *owner.as_eth(),1317 operator: *operator.as_eth(),1318 approved: approve,1319 }1320 .to_log(collection_id_to_address(collection.id)),1321 )1322 }13231324 /// Tells whether the given `owner` approves the `operator`.1325 pub fn allowance_for_all(1326 collection: &NonfungibleHandle<T>,1327 owner: &T::CrossAccountId,1328 operator: &T::CrossAccountId,1329 ) -> bool {1330 <CollectionAllowance<T>>::get((collection.id, owner, operator))1331 }13321333 pub fn repair_item(collection: &NonfungibleHandle<T>, token: TokenId) -> DispatchResult {1334 <TokenProperties<T>>::mutate((collection.id, token), |properties| {1335 if let Some(properties) = properties {1336 properties.recompute_consumed_space();1337 }1338 });13391340 Ok(())1341 }1342}runtime/common/config/orml.rsdiffbeforeafterboth--- 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 <http://www.gnu.org/licenses/>.
-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<AccountId> {
- vec![TreasuryAccountId::get()]
-}
-
-pub struct DustRemovalWhitelist;
-impl Contains<AccountId> for DustRemovalWhitelist {
- fn contains(a: &AccountId) -> bool {
- get_all_module_accounts().contains(a)
- }
-}
-
pub struct AccountIdToMultiLocation;
impl Convert<AccountId, MultiLocation> for AccountIdToMultiLocation {
fn convert(account: AccountId) -> MultiLocation {
@@ -91,18 +58,6 @@
})
.into()
}
-}
-
-pub struct CurrencyHooks;
-impl orml_traits::currency::MutationHooks<AccountId, CurrencyId, Balance> for CurrencyHooks {
- type OnDust = orml_tokens::TransferDust<Runtime, TreasuryAccountId>;
- 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<Runtime>;
-}
-
-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<Self>;
type AccountIdToMultiLocation = AccountIdToMultiLocation;
type SelfLocation = SelfLocation;
type XcmExecutor = XcmExecutor<XcmExecutorConfig<Self>>;
runtime/common/config/pallets/foreign_asset.rsdiffbeforeafterboth--- 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<AccountId>;
+ type ForceRegisterOrigin = governance::RootOrTechnicalCommitteeMember;
+ type PalletId = ForeignAssetPalletId;
type WeightInfo = pallet_foreign_assets::weights::SubstrateWeight<Self>;
}
runtime/common/config/xcm.rsdiffbeforeafterboth--- /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 <http://www.gnu.org/licenses/>.
+
+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<AccountId>,
+ // Sibling parachain origins convert to AccountId via the `ParaId::into`.
+ SiblingParachainConvertsVia<Sibling, AccountId>,
+ // Straight up local `AccountId32` origins just alias directly to `AccountId`.
+ AccountId32Aliases<RelayNetwork, AccountId>,
+);
+
+/// No local origins on this chain are allowed to dispatch XCM sends/executions.
+pub type LocalOriginToLocation = (SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>,);
+
+/// 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<ParachainSystem, PolkadotXcm, ()>,
+ // ..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<LocationToAccountId, RuntimeOrigin>,
+ // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when
+ // recognised.
+ RelayChainAsNative<RelayOrigin, RuntimeOrigin>,
+ // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when
+ // recognised.
+ SiblingParachainAsNative<cumulus_pallet_xcm::Origin, RuntimeOrigin>,
+ // Native signed account converter; this just converts an `AccountId32` origin into a normal
+ // `Origin::Signed` origin of the same 32-byte value.
+ SignedAccountId32AsNative<RelayNetwork, RuntimeOrigin>,
+ // Xcm origins can be represented natively under the Xcm pallet's Xcm origin.
+ XcmPassthrough<RuntimeOrigin>,
+);
+
+pub trait TryPass {
+ fn try_pass<Call>(
+ origin: &MultiLocation,
+ message: &mut [Instruction<Call>],
+ ) -> Result<(), ProcessMessageError>;
+}
+
+#[impl_trait_for_tuples::impl_for_tuples(30)]
+impl TryPass for Tuple {
+ fn try_pass<Call>(
+ origin: &MultiLocation,
+ message: &mut [Instruction<Call>],
+ ) -> 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<Deny, Allow>(PhantomData<Deny>, PhantomData<Allow>)
+where
+ Deny: TryPass,
+ Allow: ShouldExecute;
+
+impl<Deny, Allow> ShouldExecute for DenyThenTry<Deny, Allow>
+where
+ Deny: TryPass,
+ Allow: ShouldExecute,
+{
+ fn should_execute<Call>(
+ origin: &MultiLocation,
+ message: &mut [Instruction<Call>],
+ 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<UnitWeightCost, RuntimeCall, MaxInstructions>;
+
+pub type IsReserve = MultiNativeAsset<AbsoluteReserveProvider>;
+
+pub type Trader = FreeForAll;
+
+pub struct XcmExecutorConfig<T>(PhantomData<T>);
+impl<T> staging_xcm_executor::Config for XcmExecutorConfig<T>
+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<MultiLocation> = Some(Parent.into());
+}
+
+impl pallet_xcm::Config for Runtime {
+ type RuntimeEvent = RuntimeEvent;
+ type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, ()>;
+ type XcmRouter = XcmRouter;
+ type ExecuteXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
+ type XcmExecuteFilter = Everything;
+ type XcmExecutor = XcmExecutor<XcmExecutorConfig<Self>>;
+ type XcmTeleportFilter = Everything;
+ type XcmReserveTransferFilter = Everything;
+ type Weigher = FixedWeightBounds<UnitWeightCost, RuntimeCall, MaxInstructions>;
+ 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<Runtime>;
+ type AdminOrigin = EnsureRoot<AccountId>;
+ 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<XcmExecutorConfig<Self>>;
+}
+impl cumulus_pallet_xcmp_queue::Config for Runtime {
+ type WeightInfo = ();
+ type RuntimeEvent = RuntimeEvent;
+ type XcmExecutor = XcmExecutor<XcmExecutorConfig<Self>>;
+ type ChannelInfo = ParachainSystem;
+ type VersionWrapper = PolkadotXcm;
+ type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
+
+ #[cfg(feature = "governance")]
+ type ControllerOrigin = governance::RootOrTechnicalCommitteeMember;
+
+ #[cfg(not(feature = "governance"))]
+ type ControllerOrigin = frame_system::EnsureRoot<AccountId>;
+
+ type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
+ type PriceForSiblingDelivery = NoPriceForMessageDelivery<ParaId>;
+}
+
+impl cumulus_pallet_dmp_queue::Config for Runtime {
+ type RuntimeEvent = RuntimeEvent;
+ type XcmExecutor = XcmExecutor<XcmExecutorConfig<Self>>;
+ type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
+}
runtime/common/config/xcm/foreignassets.rsdiffbeforeafterboth--- 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 <http://www.gnu.org/licenses/>.
-
-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<ConvertAssetId>(PhantomData<(AssetId, ConvertAssetId)>);
-impl<ConvertAssetId: MaybeEquivalence<AssetId, AssetId>> MaybeEquivalence<MultiLocation, AssetId>
- for AsInnerId<ConvertAssetId>
-{
- fn convert(id: &MultiLocation) -> Option<AssetId> {
- 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::<Runtime>::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<MultiLocation> {
- 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 = <AssetId as TryAsForeign<AssetId, ForeignAssetId>>::try_as_foreign(*asset_id)?;
- XcmForeignAssetIdMapping::<Runtime>::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<AssetId, Balance, AsInnerId<JustTry>, 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<staging_xcm_executor::Assets, XcmError> {
- FungiblesTransactor::withdraw_asset(what, who, maybe_context)
- }
-
- fn internal_transfer_asset(
- what: &MultiAsset,
- from: &MultiLocation,
- to: &MultiLocation,
- context: &XcmContext,
- ) -> Result<staging_xcm_executor::Assets, XcmError> {
- FungiblesTransactor::internal_transfer_asset(what, from, to, context)
- }
-}
-
-pub type IsReserve = MultiNativeAsset<AbsoluteReserveProvider>;
-
-pub type Trader<T> = FreeForAll<
- pallet_configuration::WeightToFee<T, Balance>,
- RelayLocation,
- AccountId,
- Balances,
- (),
->;
-
-pub struct CurrencyIdConvert;
-impl Convert<AssetId, Option<MultiLocation>> for CurrencyIdConvert {
- fn convert(id: AssetId) -> Option<MultiLocation> {
- 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::<Runtime>::get_multi_location(foreign_asset_id)
- }
- }
- }
-}
-
-impl Convert<MultiLocation, Option<CurrencyId>> for CurrencyIdConvert {
- fn convert(location: MultiLocation) -> Option<CurrencyId> {
- 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::<Runtime>::get_currency_id(location) {
- return Some(currency_id);
- }
-
- None
- }
-}
runtime/common/config/xcm/mod.rsdiffbeforeafterboth--- 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 <http://www.gnu.org/licenses/>.
-
-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<AccountId>,
- // Sibling parachain origins convert to AccountId via the `ParaId::into`.
- SiblingParachainConvertsVia<Sibling, AccountId>,
- // Straight up local `AccountId32` origins just alias directly to `AccountId`.
- AccountId32Aliases<RelayNetwork, AccountId>,
-);
-
-/// No local origins on this chain are allowed to dispatch XCM sends/executions.
-pub type LocalOriginToLocation = (SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>,);
-
-/// 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<ParachainSystem, PolkadotXcm, ()>,
- // ..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<LocationToAccountId, RuntimeOrigin>,
- // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when
- // recognised.
- RelayChainAsNative<RelayOrigin, RuntimeOrigin>,
- // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when
- // recognised.
- SiblingParachainAsNative<cumulus_pallet_xcm::Origin, RuntimeOrigin>,
- // Native signed account converter; this just converts an `AccountId32` origin into a normal
- // `Origin::Signed` origin of the same 32-byte value.
- SignedAccountId32AsNative<RelayNetwork, RuntimeOrigin>,
- // Xcm origins can be represented natively under the Xcm pallet's Xcm origin.
- XcmPassthrough<RuntimeOrigin>,
-);
-
-pub trait TryPass {
- fn try_pass<Call>(
- origin: &MultiLocation,
- message: &mut [Instruction<Call>],
- ) -> Result<(), ProcessMessageError>;
-}
-
-#[impl_trait_for_tuples::impl_for_tuples(30)]
-impl TryPass for Tuple {
- fn try_pass<Call>(
- origin: &MultiLocation,
- message: &mut [Instruction<Call>],
- ) -> 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<Deny, Allow>(PhantomData<Deny>, PhantomData<Allow>)
-where
- Deny: TryPass,
- Allow: ShouldExecute;
-
-impl<Deny, Allow> ShouldExecute for DenyThenTry<Deny, Allow>
-where
- Deny: TryPass,
- Allow: ShouldExecute,
-{
- fn should_execute<Call>(
- origin: &MultiLocation,
- message: &mut [Instruction<Call>],
- 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<UnitWeightCost, RuntimeCall, MaxInstructions>;
-
-pub struct XcmExecutorConfig<T>(PhantomData<T>);
-impl<T> staging_xcm_executor::Config for XcmExecutorConfig<T>
-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<T>;
- 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<MultiLocation> = Some(Parent.into());
-}
-
-impl pallet_xcm::Config for Runtime {
- type RuntimeEvent = RuntimeEvent;
- type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, ()>;
- type XcmRouter = XcmRouter;
- type ExecuteXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
- type XcmExecuteFilter = Everything;
- type XcmExecutor = XcmExecutor<XcmExecutorConfig<Self>>;
- type XcmTeleportFilter = Everything;
- type XcmReserveTransferFilter = Everything;
- type Weigher = FixedWeightBounds<UnitWeightCost, RuntimeCall, MaxInstructions>;
- 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<Runtime>;
- type AdminOrigin = EnsureRoot<AccountId>;
- 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<XcmExecutorConfig<Self>>;
-}
-impl cumulus_pallet_xcmp_queue::Config for Runtime {
- type WeightInfo = ();
- type RuntimeEvent = RuntimeEvent;
- type XcmExecutor = XcmExecutor<XcmExecutorConfig<Self>>;
- type ChannelInfo = ParachainSystem;
- type VersionWrapper = PolkadotXcm;
- type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
-
- #[cfg(feature = "governance")]
- type ControllerOrigin = governance::RootOrTechnicalCommitteeMember;
-
- #[cfg(not(feature = "governance"))]
- type ControllerOrigin = frame_system::EnsureRoot<AccountId>;
-
- type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
- type PriceForSiblingDelivery = NoPriceForMessageDelivery<ParaId>;
-}
-
-impl cumulus_pallet_dmp_queue::Config for Runtime {
- type RuntimeEvent = RuntimeEvent;
- type XcmExecutor = XcmExecutor<XcmExecutorConfig<Self>>;
- type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
-}
runtime/common/config/xcm/nativeassets.rsdiffbeforeafterboth--- 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 <http://www.gnu.org/licenses/>.
-
-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<B: TryFrom<u128>> MatchesFungible<B> for OnlySelfCurrency {
- fn matches_fungible(a: &MultiAsset) -> Option<B> {
- 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<Balance = Currency::Balance>,
- AssetId: Get<MultiLocation>,
- AccountId,
- Currency: CurrencyT<AccountId>,
- OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
->(
- Weight,
- Currency::Balance,
- PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,
-);
-impl<
- WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
- AssetId: Get<MultiLocation>,
- AccountId,
- Currency: CurrencyT<AccountId>,
- OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
- > WeightTrader
- for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
-{
- 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<Assets, XcmError> {
- Ok(payment)
- }
-}
-impl<
- WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
- AssetId: Get<MultiLocation>,
- AccountId,
- Currency: CurrencyT<AccountId>,
- OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
- > Drop
- for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
-{
- fn drop(&mut self) {
- OnUnbalanced::on_unbalanced(Currency::issue(self.1));
- }
-}
-
-pub type Trader<T> = UsingOnlySelfCurrencyComponents<
- pallet_configuration::WeightToFee<T, Balance>,
- RelayLocation,
- AccountId,
- Balances,
- (),
->;
-
-pub struct CurrencyIdConvert;
-impl Convert<AssetIds, Option<MultiLocation>> for CurrencyIdConvert {
- fn convert(id: AssetIds) -> Option<MultiLocation> {
- match id {
- AssetIds::NativeAssetId(NativeCurrency::Here) => Some(MultiLocation::new(
- 1,
- X1(Parachain(ParachainInfo::get().into())),
- )),
- _ => None,
- }
- }
-}
runtime/common/construct_runtime.rsdiffbeforeafterboth--- 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<T>} = 38,
#[cfg(feature = "governance")]
runtime/common/dispatch.rsdiffbeforeafterboth--- 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<T::CrossAccountId>,
) -> Result<CollectionId, DispatchError> {
- let id = match data.mode {
- CollectionMode::NFT => <PalletNonfungible<T>>::init_collection(sender, payer, data)?,
+ match data.mode {
CollectionMode::Fungible(decimal_points) => {
// check params
ensure!(
decimal_points <= MAX_DECIMAL_POINTS,
pallet_unique::Error::<T>::CollectionDecimalPointLimitExceeded
);
- <PalletFungible<T>>::init_collection(sender, payer, data)?
}
- #[cfg(feature = "refungible")]
- CollectionMode::ReFungible => <PalletRefungible<T>>::init_collection(sender, payer, data)?,
+ #[cfg(not(feature = "refungible"))]
+ CollectionMode::ReFungible => return unsupported!(T),
+
+ _ => {}
+ };
+
+ <PalletCommon<T>>::init_collection(sender, payer, data)
+ }
+
+ fn create_foreign(
+ sender: <T>::CrossAccountId,
+ data: CreateCollectionData<<T>::CrossAccountId>,
+ ) -> Result<CollectionId, DispatchError> {
+ match data.mode {
+ CollectionMode::Fungible(decimal_points) => {
+ // check params
+ ensure!(
+ decimal_points <= MAX_DECIMAL_POINTS,
+ pallet_unique::Error::<T>::CollectionDecimalPointLimitExceeded
+ );
+ }
- #[cfg(not(feature = "refungible"))]
CollectionMode::ReFungible => return unsupported!(T),
+ _ => {}
};
- Ok(id)
+
+ <PalletCommon<T>>::init_foreign_collection(sender, data)
}
fn destroy(sender: T::CrossAccountId, collection_id: CollectionId) -> DispatchResult {