From 1d8485c2a5c2efad92280099f4f23b16bdd8b9d0 Mon Sep 17 00:00:00 2001 From: Daanvdplas Date: Fri, 21 Feb 2025 09:12:34 +0100 Subject: [PATCH 1/7] feat: asset manager moonbeam --- pallets/asset-manager/Cargo.toml | 49 ++++ pallets/asset-manager/src/benchmarks.rs | 97 +++++++ pallets/asset-manager/src/lib.rs | 335 ++++++++++++++++++++++++ pallets/asset-manager/src/migrations.rs | 15 ++ pallets/asset-manager/src/mock.rs | 230 ++++++++++++++++ pallets/asset-manager/src/tests.rs | 267 +++++++++++++++++++ pallets/asset-manager/src/weights.rs | 185 +++++++++++++ 7 files changed, 1178 insertions(+) create mode 100644 pallets/asset-manager/Cargo.toml create mode 100644 pallets/asset-manager/src/benchmarks.rs create mode 100644 pallets/asset-manager/src/lib.rs create mode 100644 pallets/asset-manager/src/migrations.rs create mode 100644 pallets/asset-manager/src/mock.rs create mode 100644 pallets/asset-manager/src/tests.rs create mode 100644 pallets/asset-manager/src/weights.rs diff --git a/pallets/asset-manager/Cargo.toml b/pallets/asset-manager/Cargo.toml new file mode 100644 index 000000000..c6f429b2a --- /dev/null +++ b/pallets/asset-manager/Cargo.toml @@ -0,0 +1,49 @@ +[package] +name = "pallet-asset-manager" +authors = { workspace = true } +edition = "2021" +version = "0.1.0" + +[dependencies] +log = { workspace = true } +serde = { workspace = true, optional = true } + +# Moonbeam +xcm-primitives = { workspace = true } + +# Substrate +frame-support = { workspace = true } +frame-system = { workspace = true } +parity-scale-codec = { workspace = true, features = [ "derive" ] } +scale-info = { workspace = true, features = [ "derive" ] } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } + +# Polkadot +xcm = { workspace = true } + +# Benchmarks +frame-benchmarking = { workspace = true, optional = true } + +[dev-dependencies] +pallet-balances = { workspace = true, features = [ "insecure_zero_ed", "std" ] } +sp-core = { workspace = true, features = [ "std" ] } + +[features] +default = [ "std" ] +std = [ + "frame-support/std", + "frame-system/std", + "parity-scale-codec/std", + "scale-info/std", + "serde", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", + "xcm-primitives/std", + "xcm/std", +] + +runtime-benchmarks = [ "frame-benchmarking", "xcm-primitives/runtime-benchmarks" ] +try-runtime = [ "frame-support/try-runtime" ] diff --git a/pallets/asset-manager/src/benchmarks.rs b/pallets/asset-manager/src/benchmarks.rs new file mode 100644 index 000000000..27cb259d7 --- /dev/null +++ b/pallets/asset-manager/src/benchmarks.rs @@ -0,0 +1,97 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#![cfg(feature = "runtime-benchmarks")] + +use crate::{Call, Config, Pallet}; +use frame_benchmarking::{benchmarks, impl_benchmark_test_suite}; +use frame_system::RawOrigin; +use xcm::v3::prelude::*; + +benchmarks! { + // This where clause allows us to create ForeignAssetTypes + where_clause { where T::ForeignAssetType: From } + register_foreign_asset { + // does not really matter what we register + let asset_type = T::ForeignAssetType::default(); + let metadata = T::AssetRegistrarMetadata::default(); + let amount = 1u32.into(); + let asset_id: T::AssetId = asset_type.clone().into(); + + }: _(RawOrigin::Root, asset_type.clone(), metadata, amount, true) + verify { + assert_eq!(Pallet::::asset_id_type(asset_id), Some(asset_type)); + } + + change_existing_asset_type { + let asset_type: T::ForeignAssetType = Location::new(0, X1(GeneralIndex(1 as u128))).into(); + let metadata = T::AssetRegistrarMetadata::default(); + let amount = 1u32.into(); + Pallet::::register_foreign_asset( + RawOrigin::Root.into(), + asset_type.clone(), + metadata, + amount, + true + )?; + + let new_asset_type = T::ForeignAssetType::default(); + let asset_id_to_be_changed = asset_type.clone().into(); + }: _(RawOrigin::Root, asset_id_to_be_changed, new_asset_type.clone(), 1) + verify { + assert_eq!(Pallet::::asset_id_type(asset_id_to_be_changed), Some(new_asset_type.clone())); + assert_eq!(Pallet::::asset_type_id(new_asset_type.clone()), Some(asset_id_to_be_changed)); + assert!(Pallet::::asset_type_id(asset_type).is_none()); + } + + remove_existing_asset_type { + let asset_type: T::ForeignAssetType = Location::new(0, X1(GeneralIndex(1 as u128))).into(); + let metadata = T::AssetRegistrarMetadata::default(); + let amount = 1u32.into(); + Pallet::::register_foreign_asset( + RawOrigin::Root.into(), + asset_type.clone(), + metadata, + amount, + true + )?; + let asset_id: T::AssetId = asset_type.clone().into(); + }: _(RawOrigin::Root, asset_id, 1) + verify { + assert!(Pallet::::asset_id_type(asset_id).is_none()); + assert!(Pallet::::asset_type_id(asset_type).is_none()); + } +} + +#[cfg(test)] +mod tests { + use crate::mock::Test; + use sp_io::TestExternalities; + use sp_runtime::BuildStorage; + + pub fn new_test_ext() -> TestExternalities { + let t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + TestExternalities::new(t) + } +} + +impl_benchmark_test_suite!( + Pallet, + crate::benchmarks::tests::new_test_ext(), + crate::mock::Test +); diff --git a/pallets/asset-manager/src/lib.rs b/pallets/asset-manager/src/lib.rs new file mode 100644 index 000000000..4d5813a32 --- /dev/null +++ b/pallets/asset-manager/src/lib.rs @@ -0,0 +1,335 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! # Asset Manager Pallet +//! +//! This pallet allows to register new assets if certain conditions are met +//! The main goal of this pallet is to allow moonbeam to register XCM assets +//! The assumption is we work with AssetTypes, which can then be compared to AssetIds +//! +//! This pallet has five storage items: AssetIdType, which holds a mapping from AssetId->AssetType +//! AssetTypeUnitsPerSecond: an AssetType->u128 mapping that holds how much each AssetType should +//! be charged per unit of second, in the case such an Asset is received as a XCM asset. Finally, +//! AssetTypeId holds a mapping from AssetType -> AssetId. +//! +//! This pallet has eight extrinsics: register_foreign_asset, which registers a foreign +//! asset in this pallet and creates the asset as dictated by the AssetRegistrar trait. +//! change_existing_asset_type: which allows to update the correspondence between AssetId and +//! AssetType +//! remove_supported_asset: which removes an asset from the supported assets for fee payment +//! remove_existing_asset_type: which removes a mapping from a foreign asset to an assetId +//! destroy_foreign_asset: which destroys a foreign asset and all its associated data + +#![cfg_attr(not(feature = "std"), no_std)] + +use frame_support::pallet; +pub use pallet::*; +#[cfg(any(test, feature = "runtime-benchmarks"))] +mod benchmarks; +pub mod migrations; +#[cfg(test)] +pub mod mock; +#[cfg(test)] +pub mod tests; +pub mod weights; + +pub use crate::weights::WeightInfo; + +#[pallet] +pub mod pallet { + use super::*; + use frame_support::{pallet_prelude::*, PalletId}; + use frame_system::pallet_prelude::*; + use parity_scale_codec::HasCompact; + use sp_runtime::traits::{AccountIdConversion, AtLeast32BitUnsigned}; + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(PhantomData); + + /// The AssetManagers's pallet id + pub const PALLET_ID: PalletId = PalletId(*b"asstmngr"); + + // The registrar trait. We need to comply with this + pub trait AssetRegistrar { + // How to create a foreign asset, meaning an asset whose reserve chain + // is not our chain + fn create_foreign_asset( + _asset: T::AssetId, + _min_balance: T::Balance, + _metadata: T::AssetRegistrarMetadata, + // Wether or not an asset-receiving account increments the sufficient counter + _is_sufficient: bool, + ) -> DispatchResult { + unimplemented!() + } + + // How to destroy a foreign asset + fn destroy_foreign_asset(_asset: T::AssetId) -> DispatchResult { + unimplemented!() + } + + // Get destroy asset weight dispatch info + fn destroy_asset_dispatch_info_weight(_asset: T::AssetId) -> Weight; + } + + // We implement this trait to be able to get the AssetType and units per second registered + impl xcm_primitives::AssetTypeGetter for Pallet { + fn get_asset_type(asset_id: T::AssetId) -> Option { + AssetIdType::::get(asset_id) + } + + fn get_asset_id(asset_type: T::ForeignAssetType) -> Option { + AssetTypeId::::get(asset_type) + } + #[cfg(feature = "runtime-benchmarks")] + fn set_asset_type_asset_id(asset_type: T::ForeignAssetType, asset_id: T::AssetId) { + AssetTypeId::::insert(&asset_type, asset_id); + AssetIdType::::insert(&asset_id, asset_type); + } + } + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// The Asset Id. This will be used to create the asset and to associate it with + /// a assetType + type AssetId: Member + Parameter + Default + Copy + HasCompact + MaxEncodedLen; + + /// The Asset Metadata we want to store + type AssetRegistrarMetadata: Member + Parameter + Default; + + /// The Foreign Asset Kind. + type ForeignAssetType: Parameter + Member + Ord + PartialOrd + Into + Default; + + /// The units in which we record balances. + type Balance: Member + Parameter + AtLeast32BitUnsigned + Default + Copy + MaxEncodedLen; + + /// The asset Registrar. + /// The trait we use to register Assets + type AssetRegistrar: AssetRegistrar; + + /// Origin that is allowed to create and modify asset information for foreign assets + type ForeignAssetModifierOrigin: EnsureOrigin; + + type WeightInfo: WeightInfo; + } + + /// An error that can occur while executing the mapping pallet's logic. + #[pallet::error] + pub enum Error { + ErrorCreatingAsset, + AssetAlreadyExists, + AssetDoesNotExist, + TooLowNumAssetsWeightHint, + LocalAssetLimitReached, + ErrorDestroyingAsset, + NotSufficientDeposit, + NonExistentLocalAsset, + } + + #[pallet::event] + #[pallet::generate_deposit(pub(crate) fn deposit_event)] + pub enum Event { + /// New asset with the asset manager is registered + ForeignAssetRegistered { + asset_id: T::AssetId, + asset: T::ForeignAssetType, + metadata: T::AssetRegistrarMetadata, + }, + /// Changed the amount of units we are charging per execution second for a given asset + #[deprecated(note = "Should not be used")] + UnitsPerSecondChanged, + /// Changed the xcm type mapping for a given asset id + ForeignAssetXcmLocationChanged { + asset_id: T::AssetId, + new_asset_type: T::ForeignAssetType, + }, + /// Removed all information related to an assetId + ForeignAssetRemoved { + asset_id: T::AssetId, + asset_type: T::ForeignAssetType, + }, + /// Supported asset type for fee payment removed + SupportedAssetRemoved { asset_type: T::ForeignAssetType }, + /// Removed all information related to an assetId and destroyed asset + ForeignAssetDestroyed { + asset_id: T::AssetId, + asset_type: T::ForeignAssetType, + }, + /// Removed all information related to an assetId and destroyed asset + LocalAssetDestroyed { asset_id: T::AssetId }, + } + + /// Mapping from an asset id to asset type. + /// This is mostly used when receiving transaction specifying an asset directly, + /// like transferring an asset from this chain to another. + #[pallet::storage] + #[pallet::getter(fn asset_id_type)] + pub type AssetIdType = + StorageMap<_, Blake2_128Concat, T::AssetId, T::ForeignAssetType>; + + /// Reverse mapping of AssetIdType. Mapping from an asset type to an asset id. + /// This is mostly used when receiving a multilocation XCM message to retrieve + /// the corresponding asset in which tokens should me minted. + #[pallet::storage] + #[pallet::getter(fn asset_type_id)] + pub type AssetTypeId = + StorageMap<_, Blake2_128Concat, T::ForeignAssetType, T::AssetId>; + + #[pallet::call] + impl Pallet { + /// Register new asset with the asset manager + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::register_foreign_asset())] + pub fn register_foreign_asset( + origin: OriginFor, + asset: T::ForeignAssetType, + metadata: T::AssetRegistrarMetadata, + min_amount: T::Balance, + is_sufficient: bool, + ) -> DispatchResult { + T::ForeignAssetModifierOrigin::ensure_origin(origin)?; + + // Compute assetId from asset + let asset_id: T::AssetId = asset.clone().into(); + + // Ensure such an assetId does not exist + ensure!( + AssetIdType::::get(&asset_id).is_none(), + Error::::AssetAlreadyExists + ); + T::AssetRegistrar::create_foreign_asset( + asset_id, + min_amount, + metadata.clone(), + is_sufficient, + ) + .map_err(|_| Error::::ErrorCreatingAsset)?; + + // Insert the association assetId->assetType + AssetIdType::::insert(&asset_id, &asset); + AssetTypeId::::insert(&asset, &asset_id); + + Self::deposit_event(Event::ForeignAssetRegistered { + asset_id, + asset, + metadata, + }); + Ok(()) + } + + /// Change the xcm type mapping for a given assetId + /// We also change this if the previous units per second where pointing at the old + /// assetType + #[pallet::call_index(2)] + #[pallet::weight(T::WeightInfo::change_existing_asset_type())] + pub fn change_existing_asset_type( + origin: OriginFor, + asset_id: T::AssetId, + new_asset_type: T::ForeignAssetType, + _num_assets_weight_hint: u32, + ) -> DispatchResult { + T::ForeignAssetModifierOrigin::ensure_origin(origin)?; + + let previous_asset_type = + AssetIdType::::get(&asset_id).ok_or(Error::::AssetDoesNotExist)?; + + // Insert new asset type info + AssetIdType::::insert(&asset_id, &new_asset_type); + AssetTypeId::::insert(&new_asset_type, &asset_id); + + // Remove previous asset type info + AssetTypeId::::remove(&previous_asset_type); + + Self::deposit_event(Event::ForeignAssetXcmLocationChanged { + asset_id, + new_asset_type, + }); + Ok(()) + } + + /// Remove a given assetId -> assetType association + #[pallet::call_index(4)] + #[pallet::weight(T::WeightInfo::remove_existing_asset_type())] + pub fn remove_existing_asset_type( + origin: OriginFor, + asset_id: T::AssetId, + _num_assets_weight_hint: u32, + ) -> DispatchResult { + T::ForeignAssetModifierOrigin::ensure_origin(origin)?; + + let asset_type = + AssetIdType::::get(&asset_id).ok_or(Error::::AssetDoesNotExist)?; + + // Remove from AssetIdType + AssetIdType::::remove(&asset_id); + // Remove from AssetTypeId + AssetTypeId::::remove(&asset_type); + + Self::deposit_event(Event::ForeignAssetRemoved { + asset_id, + asset_type, + }); + Ok(()) + } + + /// Destroy a given foreign assetId + /// The weight in this case is the one returned by the trait + /// plus the db writes and reads from removing all the associated + /// data + #[pallet::call_index(6)] + #[pallet::weight({ + let dispatch_info_weight = T::AssetRegistrar::destroy_asset_dispatch_info_weight( + *asset_id + ); + T::WeightInfo::remove_existing_asset_type() + .saturating_add(dispatch_info_weight) + })] + pub fn destroy_foreign_asset( + origin: OriginFor, + asset_id: T::AssetId, + _num_assets_weight_hint: u32, + ) -> DispatchResult { + T::ForeignAssetModifierOrigin::ensure_origin(origin)?; + + T::AssetRegistrar::destroy_foreign_asset(asset_id) + .map_err(|_| Error::::ErrorDestroyingAsset)?; + + let asset_type = + AssetIdType::::get(&asset_id).ok_or(Error::::AssetDoesNotExist)?; + + // Remove from AssetIdType + AssetIdType::::remove(&asset_id); + // Remove from AssetTypeId + AssetTypeId::::remove(&asset_type); + + Self::deposit_event(Event::ForeignAssetDestroyed { + asset_id, + asset_type, + }); + Ok(()) + } + } + + impl Pallet { + /// The account ID of AssetManager + pub fn account_id() -> T::AccountId { + PALLET_ID.into_account_truncating() + } + } +} diff --git a/pallets/asset-manager/src/migrations.rs b/pallets/asset-manager/src/migrations.rs new file mode 100644 index 000000000..2e08649a7 --- /dev/null +++ b/pallets/asset-manager/src/migrations.rs @@ -0,0 +1,15 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . diff --git a/pallets/asset-manager/src/mock.rs b/pallets/asset-manager/src/mock.rs new file mode 100644 index 000000000..64def3515 --- /dev/null +++ b/pallets/asset-manager/src/mock.rs @@ -0,0 +1,230 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +use super::*; +use crate as pallet_asset_manager; +use parity_scale_codec::{Decode, Encode}; + +use frame_support::{construct_runtime, parameter_types, traits::Everything, weights::Weight}; +use frame_system::EnsureRoot; +use scale_info::TypeInfo; +use sp_core::{RuntimeDebug, H256}; +use sp_runtime::traits::Hash as THash; +use sp_runtime::traits::{BlakeTwo256, IdentityLookup}; +use sp_runtime::{BuildStorage, DispatchError}; +use xcm::v3::prelude::*; + +type Block = frame_system::mocking::MockBlock; + +pub type AccountId = u64; +pub type Balance = u64; + +construct_runtime!( + pub enum Test + { + System: frame_system, + Balances: pallet_balances, + AssetManager: pallet_asset_manager, + } +); + +parameter_types! { + pub const BlockHashCount: u32 = 250; +} +impl frame_system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +parameter_types! { + pub const ExistentialDeposit: u64 = 0; +} + +impl pallet_balances::Config for Test { + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeFreezeReason = (); +} + +parameter_types! { + pub const AssetDeposit: u64 = 1; + pub const ApprovalDeposit: u64 = 1; + pub const StringLimit: u32 = 50; + pub const MetadataDepositBase: u64 = 1; + pub const MetadataDepositPerByte: u64 = 1; +} + +parameter_types! { + pub const StatemineParaIdInfo: u32 = 1000u32; + pub const StatemineAssetsInstanceInfo: u8 = 50u8; +} + +pub type AssetId = u128; +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum MockAssetType { + Xcm(Location), + MockAsset(AssetId), +} + +impl Default for MockAssetType { + fn default() -> Self { + Self::MockAsset(0) + } +} + +impl From for AssetId { + fn from(asset: MockAssetType) -> AssetId { + match asset { + MockAssetType::MockAsset(id) => id, + MockAssetType::Xcm(id) => { + let mut result: [u8; 16] = [0u8; 16]; + let hash: H256 = id.using_encoded(::Hashing::hash); + result.copy_from_slice(&hash.as_fixed_bytes()[0..16]); + u128::from_le_bytes(result) + } + } + } +} + +impl From for MockAssetType { + fn from(location: Location) -> Self { + Self::Xcm(location) + } +} + +impl Into> for MockAssetType { + fn into(self) -> Option { + match self { + Self::Xcm(location) => Some(location), + _ => None, + } + } +} + +pub struct MockAssetPalletRegistrar; + +impl AssetRegistrar for MockAssetPalletRegistrar { + fn create_foreign_asset( + _asset: u128, + _min_balance: u64, + _metadata: u32, + _is_sufficient: bool, + ) -> Result<(), DispatchError> { + Ok(()) + } + + fn destroy_foreign_asset(_asset: u128) -> Result<(), DispatchError> { + Ok(()) + } + + fn destroy_asset_dispatch_info_weight(_asset: u128) -> Weight { + Weight::from_parts(0, 0) + } +} + +impl Config for Test { + type RuntimeEvent = RuntimeEvent; + type Balance = u64; + type AssetId = u128; + type AssetRegistrarMetadata = u32; + type ForeignAssetType = MockAssetType; + type AssetRegistrar = MockAssetPalletRegistrar; + type ForeignAssetModifierOrigin = EnsureRoot; + type WeightInfo = (); +} + +pub(crate) struct ExtBuilder { + // endowed accounts with balances + balances: Vec<(AccountId, Balance)>, +} + +impl Default for ExtBuilder { + fn default() -> ExtBuilder { + ExtBuilder { balances: vec![] } + } +} + +impl ExtBuilder { + pub(crate) fn build(self) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .expect("Frame system builds valid default genesis config"); + + pallet_balances::GenesisConfig:: { + balances: self.balances, + } + .assimilate_storage(&mut t) + .expect("Pallet balances storage can be assimilated"); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext + } +} + +pub(crate) fn events() -> Vec> { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| { + if let RuntimeEvent::AssetManager(inner) = e { + Some(inner) + } else { + None + } + }) + .collect::>() +} + +pub fn expect_events(e: Vec>) { + assert_eq!(events(), e); +} diff --git a/pallets/asset-manager/src/tests.rs b/pallets/asset-manager/src/tests.rs new file mode 100644 index 000000000..aa2037b72 --- /dev/null +++ b/pallets/asset-manager/src/tests.rs @@ -0,0 +1,267 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +// Tests for AssetManager Pallet +use crate::*; +use mock::*; + +use frame_support::{assert_noop, assert_ok}; + +#[test] +fn registering_foreign_works() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + RuntimeOrigin::root(), + MockAssetType::MockAsset(1), + 0u32.into(), + 1u32.into(), + true + )); + + assert_eq!( + AssetManager::asset_id_type(1).unwrap(), + MockAssetType::MockAsset(1) + ); + assert_eq!( + AssetManager::asset_type_id(MockAssetType::MockAsset(1)).unwrap(), + 1 + ); + expect_events(vec![crate::Event::ForeignAssetRegistered { + asset_id: 1, + asset: MockAssetType::MockAsset(1), + metadata: 0u32, + }]) + }); +} + +#[test] +fn test_asset_exists_error() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + RuntimeOrigin::root(), + MockAssetType::MockAsset(1), + 0u32.into(), + 1u32.into(), + true + )); + + assert_eq!( + AssetManager::asset_id_type(1).unwrap(), + MockAssetType::MockAsset(1) + ); + assert_noop!( + AssetManager::register_foreign_asset( + RuntimeOrigin::root(), + MockAssetType::MockAsset(1), + 0u32.into(), + 1u32.into(), + true + ), + Error::::AssetAlreadyExists + ); + }); +} + +#[test] +fn test_regular_user_cannot_call_extrinsics() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + AssetManager::register_foreign_asset( + RuntimeOrigin::signed(1), + MockAssetType::MockAsset(1), + 0u32.into(), + 1u32.into(), + true + ), + sp_runtime::DispatchError::BadOrigin + ); + + assert_noop!( + AssetManager::change_existing_asset_type( + RuntimeOrigin::signed(1), + 1, + MockAssetType::MockAsset(2), + 1 + ), + sp_runtime::DispatchError::BadOrigin + ); + }); +} + +#[test] +fn test_root_can_change_asset_id_type() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + RuntimeOrigin::root(), + MockAssetType::MockAsset(1), + 0u32.into(), + 1u32.into(), + true + )); + + assert_ok!(AssetManager::change_existing_asset_type( + RuntimeOrigin::root(), + 1, + MockAssetType::MockAsset(2), + 1 + )); + + // New associations are established + assert_eq!( + AssetManager::asset_id_type(1).unwrap(), + MockAssetType::MockAsset(2) + ); + assert_eq!( + AssetManager::asset_type_id(MockAssetType::MockAsset(2)).unwrap(), + 1 + ); + + // Old ones are deleted + assert!(AssetManager::asset_type_id(MockAssetType::MockAsset(1)).is_none()); + + expect_events(vec![ + crate::Event::ForeignAssetRegistered { + asset_id: 1, + asset: MockAssetType::MockAsset(1), + metadata: 0, + }, + crate::Event::ForeignAssetXcmLocationChanged { + asset_id: 1, + new_asset_type: MockAssetType::MockAsset(2), + }, + ]) + }); +} + +#[test] +fn test_asset_id_non_existent_error() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + AssetManager::change_existing_asset_type( + RuntimeOrigin::root(), + 1, + MockAssetType::MockAsset(2), + 1 + ), + Error::::AssetDoesNotExist + ); + }); +} + +#[test] +fn test_root_can_remove_asset_association() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + RuntimeOrigin::root(), + MockAssetType::MockAsset(1), + 0u32.into(), + 1u32.into(), + true + )); + + assert_ok!(AssetManager::remove_existing_asset_type( + RuntimeOrigin::root(), + 1, + 1 + )); + + // Mappings are deleted + assert!(AssetManager::asset_type_id(MockAssetType::MockAsset(1)).is_none()); + assert!(AssetManager::asset_id_type(1).is_none()); + + expect_events(vec![ + crate::Event::ForeignAssetRegistered { + asset_id: 1, + asset: MockAssetType::MockAsset(1), + metadata: 0, + }, + crate::Event::ForeignAssetRemoved { + asset_id: 1, + asset_type: MockAssetType::MockAsset(1), + }, + ]) + }); +} + +#[test] +fn test_removing_without_asset_units_per_second_does_not_panic() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + RuntimeOrigin::root(), + MockAssetType::MockAsset(1), + 0u32.into(), + 1u32.into(), + true + )); + + assert_ok!(AssetManager::remove_existing_asset_type( + RuntimeOrigin::root(), + 1, + 0 + )); + + // Mappings are deleted + assert!(AssetManager::asset_type_id(MockAssetType::MockAsset(1)).is_none()); + assert!(AssetManager::asset_id_type(1).is_none()); + + expect_events(vec![ + crate::Event::ForeignAssetRegistered { + asset_id: 1, + asset: MockAssetType::MockAsset(1), + metadata: 0, + }, + crate::Event::ForeignAssetRemoved { + asset_id: 1, + asset_type: MockAssetType::MockAsset(1), + }, + ]) + }); +} + +#[test] +fn test_destroy_foreign_asset_also_removes_everything() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + RuntimeOrigin::root(), + MockAssetType::MockAsset(1), + 0u32.into(), + 1u32.into(), + true + )); + + assert_ok!(AssetManager::destroy_foreign_asset( + RuntimeOrigin::root(), + 1, + 0, + )); + + // Mappings are deleted + assert!(AssetManager::asset_type_id(MockAssetType::MockAsset(1)).is_none()); + assert!(AssetManager::asset_id_type(1).is_none()); + + expect_events(vec![ + crate::Event::ForeignAssetRegistered { + asset_id: 1, + asset: MockAssetType::MockAsset(1), + metadata: 0, + }, + crate::Event::ForeignAssetDestroyed { + asset_id: 1, + asset_type: MockAssetType::MockAsset(1), + }, + ]) + }); +} diff --git a/pallets/asset-manager/src/weights.rs b/pallets/asset-manager/src/weights.rs new file mode 100644 index 000000000..5bab822ae --- /dev/null +++ b/pallets/asset-manager/src/weights.rs @@ -0,0 +1,185 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + + +//! Autogenerated weights for pallet_asset_manager +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-04-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `benchmarker`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 + +// Executed Command: +// ./target/release/moonbeam +// benchmark +// pallet +// --execution=wasm +// --wasm-execution=compiled +// --pallet +// * +// --extrinsic +// * +// --steps +// 50 +// --repeat +// 20 +// --template=./benchmarking/frame-weight-template.hbs +// --json-file +// raw.json +// --output +// weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_asset_manager. +pub trait WeightInfo { + fn register_foreign_asset() -> Weight; + fn change_existing_asset_type() -> Weight; + fn remove_existing_asset_type() -> Weight; +} + +/// Weights for pallet_asset_manager using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: AssetManager AssetIdType (r:1 w:1) + /// Proof Skipped: AssetManager AssetIdType (max_values: None, max_size: None, mode: Measured) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(174), added: 2649, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:1) + /// Proof: Assets Metadata (max_values: None, max_size: Some(152), added: 2627, mode: MaxEncodedLen) + /// Storage: AssetManager AssetTypeId (r:0 w:1) + /// Proof Skipped: AssetManager AssetTypeId (max_values: None, max_size: None, mode: Measured) + fn register_foreign_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `82` + // Estimated: `10885` + // Minimum execution time: 51_631_000 picoseconds. + Weight::from_parts(52_681_000, 10885) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: AssetManager SupportedFeePaymentAssets (r:1 w:1) + /// Proof Skipped: AssetManager SupportedFeePaymentAssets (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AssetManager AssetIdType (r:1 w:1) + /// Proof Skipped: AssetManager AssetIdType (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetManager AssetTypeUnitsPerSecond (r:1 w:2) + /// Proof Skipped: AssetManager AssetTypeUnitsPerSecond (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetManager AssetTypeId (r:0 w:2) + /// Proof Skipped: AssetManager AssetTypeId (max_values: None, max_size: None, mode: Measured) + /// The range of component `x` is `[5, 100]`. + fn change_existing_asset_type() -> Weight { + // Proof Size summary in bytes: + // Measured: `926 + x * (13 ±0)` + // Estimated: `11791 + x * (60 ±0)` + // Minimum execution time: 42_959_000 picoseconds. + Weight::from_parts(43_255_055, 11791) + // Standard Error: 3_394 + .saturating_add(Weight::from_parts(543_897, 0)) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + .saturating_add(Weight::from_parts(0, 60)) + } + /// Storage: AssetManager SupportedFeePaymentAssets (r:1 w:1) + /// Proof Skipped: AssetManager SupportedFeePaymentAssets (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AssetManager AssetIdType (r:1 w:1) + /// Proof Skipped: AssetManager AssetIdType (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetManager AssetTypeUnitsPerSecond (r:0 w:1) + /// Proof Skipped: AssetManager AssetTypeUnitsPerSecond (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetManager AssetTypeId (r:0 w:1) + /// Proof Skipped: AssetManager AssetTypeId (max_values: None, max_size: None, mode: Measured) + /// The range of component `x` is `[5, 100]`. + fn remove_existing_asset_type() -> Weight { + // Proof Size summary in bytes: + // Measured: `482 + x * (10 ±0)` + // Estimated: `6910 + x * (40 ±0)` + // Minimum execution time: 32_960_000 picoseconds. + Weight::from_parts(33_257_599, 6910) + // Standard Error: 2_430 + .saturating_add(Weight::from_parts(421_651, 0)) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 40)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: AssetManager AssetIdType (r:1 w:1) + /// Proof Skipped: AssetManager AssetIdType (max_values: None, max_size: None, mode: Measured) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(174), added: 2649, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:1) + /// Proof: Assets Metadata (max_values: None, max_size: Some(152), added: 2627, mode: MaxEncodedLen) + /// Storage: AssetManager AssetTypeId (r:0 w:1) + /// Proof Skipped: AssetManager AssetTypeId (max_values: None, max_size: None, mode: Measured) + fn register_foreign_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `82` + // Estimated: `10885` + // Minimum execution time: 51_631_000 picoseconds. + Weight::from_parts(52_681_000, 10885) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: AssetManager SupportedFeePaymentAssets (r:1 w:1) + /// Proof Skipped: AssetManager SupportedFeePaymentAssets (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AssetManager AssetIdType (r:1 w:1) + /// Proof Skipped: AssetManager AssetIdType (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetManager AssetTypeUnitsPerSecond (r:1 w:2) + /// Proof Skipped: AssetManager AssetTypeUnitsPerSecond (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetManager AssetTypeId (r:0 w:2) + /// Proof Skipped: AssetManager AssetTypeId (max_values: None, max_size: None, mode: Measured) + /// The range of component `x` is `[5, 100]`. + fn change_existing_asset_type() -> Weight { + // Proof Size summary in bytes: + // Measured: `926 + x * (13 ±0)` + // Estimated: `11791 + x * (60 ±0)` + // Minimum execution time: 42_959_000 picoseconds. + Weight::from_parts(43_255_055, 11791) + // Standard Error: 3_394 + .saturating_add(Weight::from_parts(543_897, 0)) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + .saturating_add(Weight::from_parts(0, 60)) + } + /// Storage: AssetManager SupportedFeePaymentAssets (r:1 w:1) + /// Proof Skipped: AssetManager SupportedFeePaymentAssets (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AssetManager AssetIdType (r:1 w:1) + /// Proof Skipped: AssetManager AssetIdType (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetManager AssetTypeUnitsPerSecond (r:0 w:1) + /// Proof Skipped: AssetManager AssetTypeUnitsPerSecond (max_values: None, max_size: None, mode: Measured) + /// Storage: AssetManager AssetTypeId (r:0 w:1) + /// Proof Skipped: AssetManager AssetTypeId (max_values: None, max_size: None, mode: Measured) + /// The range of component `x` is `[5, 100]`. + fn remove_existing_asset_type() -> Weight { + // Proof Size summary in bytes: + // Measured: `482 + x * (10 ±0)` + // Estimated: `6910 + x * (40 ±0)` + // Minimum execution time: 32_960_000 picoseconds. + Weight::from_parts(33_257_599, 6910) + // Standard Error: 2_430 + .saturating_add(Weight::from_parts(421_651, 0)) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 40)) + } +} \ No newline at end of file From 693f0051b13e082d12cb3977ff2778710cfb6843 Mon Sep 17 00:00:00 2001 From: Daanvdplas Date: Fri, 21 Feb 2025 09:13:50 +0100 Subject: [PATCH 2/7] refactor: assset manager --- Cargo.lock | 21 ++++++ pallets/asset-manager/Cargo.toml | 40 +++++------ pallets/asset-manager/src/lib.rs | 55 +++++---------- pallets/asset-manager/src/mock.rs | 104 +++++++++++++++-------------- pallets/asset-manager/src/tests.rs | 73 +++++++------------- 5 files changed, 133 insertions(+), 160 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac3eda25f..3875d6fc1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8948,6 +8948,27 @@ dependencies = [ "sp-runtime 40.0.0", ] +[[package]] +name = "pallet-asset-manager" +version = "0.1.0" +dependencies = [ + "frame-benchmarking 39.0.0", + "frame-support 39.0.0", + "frame-system 39.0.0", + "log", + "pallet-balances 40.0.0", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core 35.0.0", + "sp-io 39.0.0", + "sp-runtime 40.0.0", + "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk?branch=stable2412)", + "staging-xcm 15.0.1", + "staging-xcm-builder 18.0.0", + "staging-xcm-executor 18.0.0", +] + [[package]] name = "pallet-asset-rate" version = "15.0.0" diff --git a/pallets/asset-manager/Cargo.toml b/pallets/asset-manager/Cargo.toml index c6f429b2a..6e1dfbbb5 100644 --- a/pallets/asset-manager/Cargo.toml +++ b/pallets/asset-manager/Cargo.toml @@ -8,42 +8,42 @@ version = "0.1.0" log = { workspace = true } serde = { workspace = true, optional = true } -# Moonbeam -xcm-primitives = { workspace = true } - # Substrate frame-support = { workspace = true } frame-system = { workspace = true } -parity-scale-codec = { workspace = true, features = [ "derive" ] } -scale-info = { workspace = true, features = [ "derive" ] } +codec = { workspace = true, features = ["derive"] } +scale-info = { workspace = true, features = ["derive"] } sp-io = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } # Polkadot xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } # Benchmarks frame-benchmarking = { workspace = true, optional = true } [dev-dependencies] -pallet-balances = { workspace = true, features = [ "insecure_zero_ed", "std" ] } -sp-core = { workspace = true, features = [ "std" ] } +pallet-balances = { workspace = true, features = ["insecure_zero_ed", "std"] } +sp-core = { workspace = true, features = ["std"] } [features] -default = [ "std" ] +default = ["std"] std = [ - "frame-support/std", - "frame-system/std", - "parity-scale-codec/std", - "scale-info/std", - "serde", - "sp-io/std", - "sp-runtime/std", - "sp-std/std", - "xcm-primitives/std", - "xcm/std", + "frame-support/std", + "frame-system/std", + "codec/std", + "scale-info/std", + "serde", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", + "xcm/std", + "xcm-builder/std", + "xcm-executor/std", ] -runtime-benchmarks = [ "frame-benchmarking", "xcm-primitives/runtime-benchmarks" ] -try-runtime = [ "frame-support/try-runtime" ] +runtime-benchmarks = ["frame-benchmarking"] +try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/asset-manager/src/lib.rs b/pallets/asset-manager/src/lib.rs index 4d5813a32..52e19fc7e 100644 --- a/pallets/asset-manager/src/lib.rs +++ b/pallets/asset-manager/src/lib.rs @@ -45,17 +45,19 @@ pub mod mock; #[cfg(test)] pub mod tests; pub mod weights; +mod xcm_primitives; pub use crate::weights::WeightInfo; #[pallet] pub mod pallet { - use super::*; + use codec::HasCompact; use frame_support::{pallet_prelude::*, PalletId}; use frame_system::pallet_prelude::*; - use parity_scale_codec::HasCompact; use sp_runtime::traits::{AccountIdConversion, AtLeast32BitUnsigned}; + use super::*; + #[pallet::pallet] #[pallet::without_storage_info] pub struct Pallet(PhantomData); @@ -65,6 +67,7 @@ pub mod pallet { // The registrar trait. We need to comply with this pub trait AssetRegistrar { + fn next_asset_id() -> T::AssetId; // How to create a foreign asset, meaning an asset whose reserve chain // is not our chain fn create_foreign_asset( @@ -95,6 +98,7 @@ pub mod pallet { fn get_asset_id(asset_type: T::ForeignAssetType) -> Option { AssetTypeId::::get(asset_type) } + #[cfg(feature = "runtime-benchmarks")] fn set_asset_type_asset_id(asset_type: T::ForeignAssetType, asset_id: T::AssetId) { AssetTypeId::::insert(&asset_type, asset_id); @@ -114,7 +118,7 @@ pub mod pallet { type AssetRegistrarMetadata: Member + Parameter + Default; /// The Foreign Asset Kind. - type ForeignAssetType: Parameter + Member + Ord + PartialOrd + Into + Default; + type ForeignAssetType: Parameter + Member + Ord + PartialOrd + Default; /// The units in which we record balances. type Balance: Member + Parameter + AtLeast32BitUnsigned + Default + Copy + MaxEncodedLen; @@ -155,22 +159,13 @@ pub mod pallet { #[deprecated(note = "Should not be used")] UnitsPerSecondChanged, /// Changed the xcm type mapping for a given asset id - ForeignAssetXcmLocationChanged { - asset_id: T::AssetId, - new_asset_type: T::ForeignAssetType, - }, + ForeignAssetXcmLocationChanged { asset_id: T::AssetId, new_asset_type: T::ForeignAssetType }, /// Removed all information related to an assetId - ForeignAssetRemoved { - asset_id: T::AssetId, - asset_type: T::ForeignAssetType, - }, + ForeignAssetRemoved { asset_id: T::AssetId, asset_type: T::ForeignAssetType }, /// Supported asset type for fee payment removed SupportedAssetRemoved { asset_type: T::ForeignAssetType }, /// Removed all information related to an assetId and destroyed asset - ForeignAssetDestroyed { - asset_id: T::AssetId, - asset_type: T::ForeignAssetType, - }, + ForeignAssetDestroyed { asset_id: T::AssetId, asset_type: T::ForeignAssetType }, /// Removed all information related to an assetId and destroyed asset LocalAssetDestroyed { asset_id: T::AssetId }, } @@ -205,14 +200,9 @@ pub mod pallet { ) -> DispatchResult { T::ForeignAssetModifierOrigin::ensure_origin(origin)?; - // Compute assetId from asset - let asset_id: T::AssetId = asset.clone().into(); - + let asset_id = T::AssetRegistrar::next_asset_id(); // Ensure such an assetId does not exist - ensure!( - AssetIdType::::get(&asset_id).is_none(), - Error::::AssetAlreadyExists - ); + ensure!(AssetIdType::::get(&asset_id).is_none(), Error::::AssetAlreadyExists); T::AssetRegistrar::create_foreign_asset( asset_id, min_amount, @@ -225,11 +215,7 @@ pub mod pallet { AssetIdType::::insert(&asset_id, &asset); AssetTypeId::::insert(&asset, &asset_id); - Self::deposit_event(Event::ForeignAssetRegistered { - asset_id, - asset, - metadata, - }); + Self::deposit_event(Event::ForeignAssetRegistered { asset_id, asset, metadata }); Ok(()) } @@ -256,10 +242,7 @@ pub mod pallet { // Remove previous asset type info AssetTypeId::::remove(&previous_asset_type); - Self::deposit_event(Event::ForeignAssetXcmLocationChanged { - asset_id, - new_asset_type, - }); + Self::deposit_event(Event::ForeignAssetXcmLocationChanged { asset_id, new_asset_type }); Ok(()) } @@ -281,10 +264,7 @@ pub mod pallet { // Remove from AssetTypeId AssetTypeId::::remove(&asset_type); - Self::deposit_event(Event::ForeignAssetRemoved { - asset_id, - asset_type, - }); + Self::deposit_event(Event::ForeignAssetRemoved { asset_id, asset_type }); Ok(()) } @@ -318,10 +298,7 @@ pub mod pallet { // Remove from AssetTypeId AssetTypeId::::remove(&asset_type); - Self::deposit_event(Event::ForeignAssetDestroyed { - asset_id, - asset_type, - }); + Self::deposit_event(Event::ForeignAssetDestroyed { asset_id, asset_type }); Ok(()) } } diff --git a/pallets/asset-manager/src/mock.rs b/pallets/asset-manager/src/mock.rs index 64def3515..9a4fca559 100644 --- a/pallets/asset-manager/src/mock.rs +++ b/pallets/asset-manager/src/mock.rs @@ -14,19 +14,22 @@ // You should have received a copy of the GNU General Public License // along with Moonbeam. If not, see . -use super::*; -use crate as pallet_asset_manager; -use parity_scale_codec::{Decode, Encode}; - -use frame_support::{construct_runtime, parameter_types, traits::Everything, weights::Weight}; +use codec::{Decode, Encode}; +use frame_support::{ + construct_runtime, derive_impl, parameter_types, traits::Everything, weights::Weight, +}; use frame_system::EnsureRoot; use scale_info::TypeInfo; use sp_core::{RuntimeDebug, H256}; -use sp_runtime::traits::Hash as THash; -use sp_runtime::traits::{BlakeTwo256, IdentityLookup}; -use sp_runtime::{BuildStorage, DispatchError}; +use sp_runtime::{ + traits::{BlakeTwo256, Hash as THash, IdentityLookup}, + BuildStorage, DispatchError, +}; use xcm::v3::prelude::*; +use super::*; +use crate as pallet_asset_manager; + type Block = frame_system::mocking::MockBlock; pub type AccountId = u64; @@ -44,36 +47,38 @@ construct_runtime!( parameter_types! { pub const BlockHashCount: u32 = 250; } + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { + type AccountData = pallet_balances::AccountData; + type AccountId = AccountId; type BaseCallFilter = Everything; - type BlockWeights = (); - type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type RuntimeTask = RuntimeTask; - type Nonce = u64; type Block = Block; + type BlockHashCount = BlockHashCount; + type BlockLength = (); + type BlockWeights = (); + type DbWeight = (); type Hash = H256; type Hashing = BlakeTwo256; - type AccountId = AccountId; type Lookup = IdentityLookup; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type DbWeight = (); - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); type MaxConsumers = frame_support::traits::ConstU32<16>; - type SingleBlockMigrations = (); type MultiBlockMigrator = (); - type PreInherents = (); + type Nonce = u64; + type OnKilledAccount = (); + type OnNewAccount = (); + type OnSetCode = (); + type PalletInfo = PalletInfo; type PostInherents = (); type PostTransactions = (); + type PreInherents = (); + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeTask = RuntimeTask; + type SS58Prefix = (); + type SingleBlockMigrations = (); + type SystemWeightInfo = (); + type Version = (); } parameter_types! { @@ -81,19 +86,20 @@ parameter_types! { } impl pallet_balances::Config for Test { + type AccountStore = System; type Balance = Balance; + type DoneSlashHandler = (); type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); type MaxLocks = (); type MaxReserves = (); type ReserveIdentifier = [u8; 8]; - type RuntimeHoldReason = (); - type FreezeIdentifier = (); - type MaxFreezes = (); + type RuntimeEvent = RuntimeEvent; type RuntimeFreezeReason = (); + type RuntimeHoldReason = (); + type WeightInfo = (); } parameter_types! { @@ -131,7 +137,7 @@ impl From for AssetId { let hash: H256 = id.using_encoded(::Hashing::hash); result.copy_from_slice(&hash.as_fixed_bytes()[0..16]); u128::from_le_bytes(result) - } + }, } } } @@ -154,6 +160,10 @@ impl Into> for MockAssetType { pub struct MockAssetPalletRegistrar; impl AssetRegistrar for MockAssetPalletRegistrar { + fn next_asset_id() -> AssetId { + 42u128 + } + fn create_foreign_asset( _asset: u128, _min_balance: u64, @@ -173,13 +183,13 @@ impl AssetRegistrar for MockAssetPalletRegistrar { } impl Config for Test { - type RuntimeEvent = RuntimeEvent; - type Balance = u64; type AssetId = u128; - type AssetRegistrarMetadata = u32; - type ForeignAssetType = MockAssetType; type AssetRegistrar = MockAssetPalletRegistrar; + type AssetRegistrarMetadata = u32; + type Balance = u64; type ForeignAssetModifierOrigin = EnsureRoot; + type ForeignAssetType = MockAssetType; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } @@ -200,11 +210,9 @@ impl ExtBuilder { .build_storage() .expect("Frame system builds valid default genesis config"); - pallet_balances::GenesisConfig:: { - balances: self.balances, - } - .assimilate_storage(&mut t) - .expect("Pallet balances storage can be assimilated"); + pallet_balances::GenesisConfig:: { balances: self.balances } + .assimilate_storage(&mut t) + .expect("Pallet balances storage can be assimilated"); let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| System::set_block_number(1)); ext @@ -215,13 +223,7 @@ pub(crate) fn events() -> Vec> { System::events() .into_iter() .map(|r| r.event) - .filter_map(|e| { - if let RuntimeEvent::AssetManager(inner) = e { - Some(inner) - } else { - None - } - }) + .filter_map(|e| if let RuntimeEvent::AssetManager(inner) = e { Some(inner) } else { None }) .collect::>() } diff --git a/pallets/asset-manager/src/tests.rs b/pallets/asset-manager/src/tests.rs index aa2037b72..d1d670a82 100644 --- a/pallets/asset-manager/src/tests.rs +++ b/pallets/asset-manager/src/tests.rs @@ -15,10 +15,10 @@ // along with Moonbeam. If not, see . // Tests for AssetManager Pallet -use crate::*; +use frame_support::{assert_noop, assert_ok}; use mock::*; -use frame_support::{assert_noop, assert_ok}; +use crate::*; #[test] fn registering_foreign_works() { @@ -31,16 +31,10 @@ fn registering_foreign_works() { true )); - assert_eq!( - AssetManager::asset_id_type(1).unwrap(), - MockAssetType::MockAsset(1) - ); - assert_eq!( - AssetManager::asset_type_id(MockAssetType::MockAsset(1)).unwrap(), - 1 - ); + assert_eq!(AssetManager::asset_id_type(42).unwrap(), MockAssetType::MockAsset(1)); + assert_eq!(AssetManager::asset_type_id(MockAssetType::MockAsset(1)).unwrap(), 42); expect_events(vec![crate::Event::ForeignAssetRegistered { - asset_id: 1, + asset_id: 42, asset: MockAssetType::MockAsset(1), metadata: 0u32, }]) @@ -58,10 +52,7 @@ fn test_asset_exists_error() { true )); - assert_eq!( - AssetManager::asset_id_type(1).unwrap(), - MockAssetType::MockAsset(1) - ); + assert_eq!(AssetManager::asset_id_type(42).unwrap(), MockAssetType::MockAsset(1)); assert_noop!( AssetManager::register_foreign_asset( RuntimeOrigin::root(), @@ -114,32 +105,26 @@ fn test_root_can_change_asset_id_type() { assert_ok!(AssetManager::change_existing_asset_type( RuntimeOrigin::root(), - 1, + 42, MockAssetType::MockAsset(2), 1 )); // New associations are established - assert_eq!( - AssetManager::asset_id_type(1).unwrap(), - MockAssetType::MockAsset(2) - ); - assert_eq!( - AssetManager::asset_type_id(MockAssetType::MockAsset(2)).unwrap(), - 1 - ); + assert_eq!(AssetManager::asset_id_type(42).unwrap(), MockAssetType::MockAsset(2)); + assert_eq!(AssetManager::asset_type_id(MockAssetType::MockAsset(2)).unwrap(), 42); // Old ones are deleted assert!(AssetManager::asset_type_id(MockAssetType::MockAsset(1)).is_none()); expect_events(vec![ crate::Event::ForeignAssetRegistered { - asset_id: 1, + asset_id: 42, asset: MockAssetType::MockAsset(1), metadata: 0, }, crate::Event::ForeignAssetXcmLocationChanged { - asset_id: 1, + asset_id: 42, new_asset_type: MockAssetType::MockAsset(2), }, ]) @@ -172,24 +157,20 @@ fn test_root_can_remove_asset_association() { true )); - assert_ok!(AssetManager::remove_existing_asset_type( - RuntimeOrigin::root(), - 1, - 1 - )); + assert_ok!(AssetManager::remove_existing_asset_type(RuntimeOrigin::root(), 42, 1)); // Mappings are deleted assert!(AssetManager::asset_type_id(MockAssetType::MockAsset(1)).is_none()); - assert!(AssetManager::asset_id_type(1).is_none()); + assert!(AssetManager::asset_id_type(42).is_none()); expect_events(vec![ crate::Event::ForeignAssetRegistered { - asset_id: 1, + asset_id: 42, asset: MockAssetType::MockAsset(1), metadata: 0, }, crate::Event::ForeignAssetRemoved { - asset_id: 1, + asset_id: 42, asset_type: MockAssetType::MockAsset(1), }, ]) @@ -207,24 +188,20 @@ fn test_removing_without_asset_units_per_second_does_not_panic() { true )); - assert_ok!(AssetManager::remove_existing_asset_type( - RuntimeOrigin::root(), - 1, - 0 - )); + assert_ok!(AssetManager::remove_existing_asset_type(RuntimeOrigin::root(), 42, 0)); // Mappings are deleted assert!(AssetManager::asset_type_id(MockAssetType::MockAsset(1)).is_none()); - assert!(AssetManager::asset_id_type(1).is_none()); + assert!(AssetManager::asset_id_type(42).is_none()); expect_events(vec![ crate::Event::ForeignAssetRegistered { - asset_id: 1, + asset_id: 42, asset: MockAssetType::MockAsset(1), metadata: 0, }, crate::Event::ForeignAssetRemoved { - asset_id: 1, + asset_id: 42, asset_type: MockAssetType::MockAsset(1), }, ]) @@ -242,24 +219,20 @@ fn test_destroy_foreign_asset_also_removes_everything() { true )); - assert_ok!(AssetManager::destroy_foreign_asset( - RuntimeOrigin::root(), - 1, - 0, - )); + assert_ok!(AssetManager::destroy_foreign_asset(RuntimeOrigin::root(), 42, 0,)); // Mappings are deleted assert!(AssetManager::asset_type_id(MockAssetType::MockAsset(1)).is_none()); - assert!(AssetManager::asset_id_type(1).is_none()); + assert!(AssetManager::asset_id_type(42).is_none()); expect_events(vec![ crate::Event::ForeignAssetRegistered { - asset_id: 1, + asset_id: 42, asset: MockAssetType::MockAsset(1), metadata: 0, }, crate::Event::ForeignAssetDestroyed { - asset_id: 1, + asset_id: 42, asset_type: MockAssetType::MockAsset(1), }, ]) From 3ae1fcde3b74a69d25d7eb81cb7185bf0418495d Mon Sep 17 00:00:00 2001 From: Daanvdplas Date: Fri, 21 Feb 2025 09:15:07 +0100 Subject: [PATCH 3/7] feat: asset manager devnet --- Cargo.lock | 1 + Cargo.toml | 35 +-- pallets/asset-manager/src/xcm_primitives.rs | 97 +++++++ runtime/devnet/Cargo.toml | 292 ++++++++++---------- runtime/devnet/src/config/assets.rs | 73 ++++- runtime/devnet/src/lib.rs | 2 + 6 files changed, 335 insertions(+), 165 deletions(-) create mode 100644 pallets/asset-manager/src/xcm_primitives.rs diff --git a/Cargo.lock b/Cargo.lock index 3875d6fc1..37b9bad5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13811,6 +13811,7 @@ dependencies = [ "ismp-parachain-runtime-api", "log", "pallet-api", + "pallet-asset-manager", "pallet-assets 41.0.0", "pallet-aura 38.0.0", "pallet-authorship 39.0.0", diff --git a/Cargo.toml b/Cargo.toml index d1109b76c..4eb341741 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ inherits = "release" lto = true [workspace.package] -authors = [ "R0GUE " ] +authors = ["R0GUE "] description = "Pop Network makes it easy for smart contract developers to use the Power of Polkadot." edition = "2021" homepage = "https://r0gue.io" @@ -16,28 +16,28 @@ repository = "https://github.com/r0gue-io/pop-node/" [workspace] exclude = [ - "extension/contract", - "pop-api", - "tests/contracts", + "extension/contract", + "pop-api", + "tests/contracts", ] members = [ - "integration-tests", - "node", - "pallets/*", - "pop-api/integration-tests", - "primitives", - "runtime/devnet", - "runtime/mainnet", - "runtime/testnet", + "integration-tests", + "node", + "pallets/*", + "pop-api/integration-tests", + "primitives", + "runtime/devnet", + "runtime/mainnet", + "runtime/testnet", ] resolver = "2" [workspace.dependencies] anyhow = { version = "1.0", default-features = false } -clap = { version = "4.5.10", features = [ "derive" ] } +clap = { version = "4.5.10", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ - "derive", + "derive", ] } color-print = "0.3.4" contract-build = "5.0.2" @@ -48,18 +48,18 @@ futures = "0.3.30" hex = "0.4.3" hex-literal = "0.4.1" impl-trait-for-tuples = "0.2.2" -jsonrpsee = { version = "0.24.3", features = [ "server" ] } +jsonrpsee = { version = "0.24.3", features = ["server"] } log = { version = "0.4.22", default-features = false } rand = "0.8.5" scale-info = { version = "2.11.1", default-features = false, features = [ - "derive", + "derive", ] } serde = "1.0.209" serde_json = "1.0.127" smallvec = "1.11.2" subxt = "0.38.0" subxt-signer = "0.38.0" -tokio = { version = "1.36", features = [ "macros", "rt-multi-thread", "time" ] } +tokio = { version = "1.36", features = ["macros", "rt-multi-thread", "time"] } tracing-subscriber = { version = "0.3.18", default-features = false } # Build @@ -68,6 +68,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/polkadot-sdk", b # Local pallet-api = { path = "pallets/api", default-features = false } +pallet-asset-manager = { path = "pallets/asset-manager", default-features = false } pallet-nfts = { path = "pallets/nfts", default-features = false } pop-chain-extension = { path = "./extension", default-features = false } pop-primitives = { path = "./primitives", default-features = false } diff --git a/pallets/asset-manager/src/xcm_primitives.rs b/pallets/asset-manager/src/xcm_primitives.rs new file mode 100644 index 000000000..0b8540b56 --- /dev/null +++ b/pallets/asset-manager/src/xcm_primitives.rs @@ -0,0 +1,97 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +use sp_runtime::traits::MaybeEquivalence; +use sp_std::marker::PhantomData; +use xcm::v5::Location; +use xcm_executor::traits::ConvertLocation; + +/// Converter struct implementing `AssetIdConversion` converting a numeric asset ID +/// (must be `TryFrom/TryInto`) into a Location Value and vice versa through +/// an intermediate generic type AssetType. +/// The trait bounds enforce is that the AssetTypeGetter trait is also implemented for +/// AssetIdInfoGetter +pub struct AsAssetType( + PhantomData<(AssetId, AssetType, AssetIdInfoGetter)>, +); +impl MaybeEquivalence + for AsAssetType +where + AssetId: Clone, + AssetType: From + Into> + Clone, + AssetIdInfoGetter: AssetTypeGetter, +{ + fn convert(id: &Location) -> Option { + AssetIdInfoGetter::get_asset_id(id.clone().into()) + } + + fn convert_back(what: &AssetId) -> Option { + AssetIdInfoGetter::get_asset_type(what.clone()).and_then(Into::into) + } +} + +// impl MaybeEquivalence +// for AsAssetType +// where +// AssetId: Clone, +// AssetType: From + Into> + Clone, +// AssetIdInfoGetter: AssetTypeGetter, +// { +// fn convert(id: &xcm::v4::Location) -> Option { +// let v3_location = +// xcm_builder::WithLatestLocationConverter::::convert(id)?; +// AssetIdInfoGetter::get_asset_id(v3_location.clone().into()) +// } +// +// fn convert_back(what: &AssetId) -> Option { +// let v3_location: Location = +// AssetIdInfoGetter::get_asset_type(what.clone()).and_then(Into::into)?; +// xcm_builder::WithLatestLocationConverter::convert_back(&v3_location) +// } +// } + +impl ConvertLocation + for AsAssetType +where + AssetId: Clone, + AssetType: From + Into> + Clone, + AssetIdInfoGetter: AssetTypeGetter, +{ + fn convert_location(id: &Location) -> Option { + let v5_location = xcm_builder::WithLatestLocationConverter::::convert(id)?; + AssetIdInfoGetter::get_asset_id(v5_location.clone().into()) + } +} + +/// Defines the trait to obtain a generic AssetType from a generic AssetId and vice versa +pub trait AssetTypeGetter { + // Get asset type from assetId + fn get_asset_type(asset_id: AssetId) -> Option; + + // Get assetId from assetType + fn get_asset_id(asset_type: AssetType) -> Option; + + // Set assetId and assetType + #[cfg(feature = "runtime-benchmarks")] + fn set_asset_type_asset_id(asset_type: AssetType, asset_id: AssetId); +} + +/// This trait ensure we can convert AccountIds to CurrencyIds +/// We will require Runtime to have this trait implemented +pub trait AccountIdToCurrencyId { + // Get assetId from account + fn account_to_currency_id(account: Account) -> Option; +} diff --git a/runtime/devnet/Cargo.toml b/runtime/devnet/Cargo.toml index 41e875184..261ca26fa 100644 --- a/runtime/devnet/Cargo.toml +++ b/runtime/devnet/Cargo.toml @@ -9,7 +9,7 @@ repository.workspace = true version = "0.1.0" [package.metadata.docs.rs] -targets = [ "x86_64-unknown-linux-gnu" ] +targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] substrate-wasm-builder = { workspace = true, optional = true } @@ -25,6 +25,7 @@ smallvec.workspace = true # Local pallet-api.workspace = true +pallet-asset-manager.workspace = true pallet-nfts.workspace = true pop-chain-extension.workspace = true pop-primitives.workspace = true @@ -97,7 +98,7 @@ parachains-common.workspace = true ismp.workspace = true ismp-parachain.workspace = true ismp-parachain-runtime-api.workspace = true -pallet-ismp = { workspace = true, features = [ "unsigned" ] } +pallet-ismp = { workspace = true, features = ["unsigned"] } pallet-ismp-runtime-api.workspace = true [dev-dependencies] @@ -106,154 +107,155 @@ env_logger.workspace = true hex.workspace = true [features] -default = [ "std" ] +default = ["std"] std = [ - "codec/std", - "cumulus-pallet-aura-ext/std", - "cumulus-pallet-parachain-system/std", - "cumulus-pallet-session-benchmarking/std", - "cumulus-pallet-xcm/std", - "cumulus-pallet-xcmp-queue/std", - "cumulus-primitives-aura/std", - "cumulus-primitives-core/std", - "cumulus-primitives-storage-weight-reclaim/std", - "cumulus-primitives-utility/std", - "enumflags2/std", - "frame-benchmarking/std", - "frame-executive/std", - "frame-metadata-hash-extension/std", - "frame-support/std", - "frame-system-benchmarking/std", - "frame-system-rpc-runtime-api/std", - "frame-system/std", - "frame-try-runtime/std", - "ismp-parachain-runtime-api/std", - "ismp-parachain/std", - "ismp/std", - "log/std", - "pallet-api/std", - "pallet-assets/std", - "pallet-aura/std", - "pallet-authorship/std", - "pallet-balances/std", - "pallet-collator-selection/std", - "pallet-contracts/std", - "pallet-ismp-runtime-api/std", - "pallet-ismp/std", - "pallet-message-queue/std", - "pallet-multisig/std", - "pallet-nft-fractionalization/std", - "pallet-nfts-runtime-api/std", - "pallet-nfts/std", - "pallet-preimage/std", - "pallet-proxy/std", - "pallet-scheduler/std", - "pallet-session/std", - "pallet-sudo/std", - "pallet-timestamp/std", - "pallet-transaction-payment-rpc-runtime-api/std", - "pallet-transaction-payment/std", - "pallet-utility/std", - "pallet-xcm/std", - "parachain-info/std", - "parachains-common/std", - "polkadot-parachain-primitives/std", - "polkadot-runtime-common/std", - "pop-chain-extension/std", - "pop-primitives/std", - "pop-runtime-common/std", - "scale-info/std", - "sp-api/std", - "sp-block-builder/std", - "sp-consensus-aura/std", - "sp-core/std", - "sp-genesis-builder/std", - "sp-inherents/std", - "sp-io/std", - "sp-mmr-primitives/std", - "sp-offchain/std", - "sp-runtime/std", - "sp-session/std", - "sp-transaction-pool/std", - "sp-version/std", - "substrate-wasm-builder", - "xcm-builder/std", - "xcm-executor/std", - "xcm/std", + "codec/std", + "cumulus-pallet-aura-ext/std", + "cumulus-pallet-parachain-system/std", + "cumulus-pallet-session-benchmarking/std", + "cumulus-pallet-xcm/std", + "cumulus-pallet-xcmp-queue/std", + "cumulus-primitives-aura/std", + "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", + "cumulus-primitives-utility/std", + "enumflags2/std", + "frame-benchmarking/std", + "frame-executive/std", + "frame-metadata-hash-extension/std", + "frame-support/std", + "frame-system-benchmarking/std", + "frame-system-rpc-runtime-api/std", + "frame-system/std", + "frame-try-runtime/std", + "ismp-parachain-runtime-api/std", + "ismp-parachain/std", + "ismp/std", + "log/std", + "pallet-api/std", + "pallet-assets/std", + "pallet-asset-manager/std", + "pallet-aura/std", + "pallet-authorship/std", + "pallet-balances/std", + "pallet-collator-selection/std", + "pallet-contracts/std", + "pallet-ismp-runtime-api/std", + "pallet-ismp/std", + "pallet-message-queue/std", + "pallet-multisig/std", + "pallet-nft-fractionalization/std", + "pallet-nfts-runtime-api/std", + "pallet-nfts/std", + "pallet-preimage/std", + "pallet-proxy/std", + "pallet-scheduler/std", + "pallet-session/std", + "pallet-sudo/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + "pallet-utility/std", + "pallet-xcm/std", + "parachain-info/std", + "parachains-common/std", + "polkadot-parachain-primitives/std", + "polkadot-runtime-common/std", + "pop-chain-extension/std", + "pop-primitives/std", + "pop-runtime-common/std", + "scale-info/std", + "sp-api/std", + "sp-block-builder/std", + "sp-consensus-aura/std", + "sp-core/std", + "sp-genesis-builder/std", + "sp-inherents/std", + "sp-io/std", + "sp-mmr-primitives/std", + "sp-offchain/std", + "sp-runtime/std", + "sp-session/std", + "sp-transaction-pool/std", + "sp-version/std", + "substrate-wasm-builder", + "xcm-builder/std", + "xcm-executor/std", + "xcm/std", ] runtime-benchmarks = [ - "cumulus-pallet-parachain-system/runtime-benchmarks", - "cumulus-pallet-session-benchmarking/runtime-benchmarks", - "cumulus-pallet-xcmp-queue/runtime-benchmarks", - "cumulus-primitives-core/runtime-benchmarks", - "cumulus-primitives-utility/runtime-benchmarks", - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system-benchmarking/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "pallet-api/runtime-benchmarks", - "pallet-assets/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "pallet-collator-selection/runtime-benchmarks", - "pallet-contracts/runtime-benchmarks", - "pallet-ismp/runtime-benchmarks", - "pallet-message-queue/runtime-benchmarks", - "pallet-multisig/runtime-benchmarks", - "pallet-nft-fractionalization/runtime-benchmarks", - "pallet-nfts/runtime-benchmarks", - "pallet-preimage/runtime-benchmarks", - "pallet-proxy/runtime-benchmarks", - "pallet-scheduler/runtime-benchmarks", - "pallet-sudo/runtime-benchmarks", - "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", - "pallet-utility/runtime-benchmarks", - "pallet-xcm/runtime-benchmarks", - "parachains-common/runtime-benchmarks", - "polkadot-parachain-primitives/runtime-benchmarks", - "polkadot-runtime-common/runtime-benchmarks", - "pop-chain-extension/runtime-benchmarks", - "pop-runtime-common/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", - "xcm-builder/runtime-benchmarks", - "xcm-executor/runtime-benchmarks", + "cumulus-pallet-parachain-system/runtime-benchmarks", + "cumulus-pallet-session-benchmarking/runtime-benchmarks", + "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", + "cumulus-primitives-utility/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system-benchmarking/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-api/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-collator-selection/runtime-benchmarks", + "pallet-contracts/runtime-benchmarks", + "pallet-ismp/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", + "pallet-multisig/runtime-benchmarks", + "pallet-nft-fractionalization/runtime-benchmarks", + "pallet-nfts/runtime-benchmarks", + "pallet-preimage/runtime-benchmarks", + "pallet-proxy/runtime-benchmarks", + "pallet-scheduler/runtime-benchmarks", + "pallet-sudo/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", + "pallet-utility/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "parachains-common/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", + "polkadot-runtime-common/runtime-benchmarks", + "pop-chain-extension/runtime-benchmarks", + "pop-runtime-common/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", ] try-runtime = [ - "cumulus-pallet-aura-ext/try-runtime", - "cumulus-pallet-parachain-system/try-runtime", - "cumulus-pallet-xcm/try-runtime", - "cumulus-pallet-xcmp-queue/try-runtime", - "frame-executive/try-runtime", - "frame-support/try-runtime", - "frame-system/try-runtime", - "frame-try-runtime/try-runtime", - "ismp-parachain/try-runtime", - "pallet-api/try-runtime", - "pallet-assets/try-runtime", - "pallet-aura/try-runtime", - "pallet-authorship/try-runtime", - "pallet-balances/try-runtime", - "pallet-collator-selection/try-runtime", - "pallet-contracts/try-runtime", - "pallet-ismp/try-runtime", - "pallet-message-queue/try-runtime", - "pallet-multisig/try-runtime", - "pallet-nft-fractionalization/try-runtime", - "pallet-nfts/try-runtime", - "pallet-preimage/try-runtime", - "pallet-proxy/try-runtime", - "pallet-scheduler/try-runtime", - "pallet-session/try-runtime", - "pallet-sudo/try-runtime", - "pallet-timestamp/try-runtime", - "pallet-transaction-payment/try-runtime", - "pallet-utility/try-runtime", - "pallet-xcm/try-runtime", - "parachain-info/try-runtime", - "polkadot-runtime-common/try-runtime", - "sp-runtime/try-runtime", + "cumulus-pallet-aura-ext/try-runtime", + "cumulus-pallet-parachain-system/try-runtime", + "cumulus-pallet-xcm/try-runtime", + "cumulus-pallet-xcmp-queue/try-runtime", + "frame-executive/try-runtime", + "frame-support/try-runtime", + "frame-system/try-runtime", + "frame-try-runtime/try-runtime", + "ismp-parachain/try-runtime", + "pallet-api/try-runtime", + "pallet-assets/try-runtime", + "pallet-aura/try-runtime", + "pallet-authorship/try-runtime", + "pallet-balances/try-runtime", + "pallet-collator-selection/try-runtime", + "pallet-contracts/try-runtime", + "pallet-ismp/try-runtime", + "pallet-message-queue/try-runtime", + "pallet-multisig/try-runtime", + "pallet-nft-fractionalization/try-runtime", + "pallet-nfts/try-runtime", + "pallet-preimage/try-runtime", + "pallet-proxy/try-runtime", + "pallet-scheduler/try-runtime", + "pallet-session/try-runtime", + "pallet-sudo/try-runtime", + "pallet-timestamp/try-runtime", + "pallet-transaction-payment/try-runtime", + "pallet-utility/try-runtime", + "pallet-xcm/try-runtime", + "parachain-info/try-runtime", + "polkadot-runtime-common/try-runtime", + "sp-runtime/try-runtime", ] # Enable the metadata hash generation. @@ -263,8 +265,8 @@ try-runtime = [ # generate the metadata hash and then a second time with the # `RUNTIME_METADATA_HASH` environment variable set for the `CheckMetadataHash` # extension. -metadata-hash = [ "substrate-wasm-builder/metadata-hash" ] +metadata-hash = ["substrate-wasm-builder/metadata-hash"] # A convenience feature for enabling things when doing a build # for an on-chain release. -on-chain-release-build = [ "metadata-hash" ] +on-chain-release-build = ["metadata-hash"] diff --git a/runtime/devnet/src/config/assets.rs b/runtime/devnet/src/config/assets.rs index 704cf4c37..28fe0e762 100644 --- a/runtime/devnet/src/config/assets.rs +++ b/runtime/devnet/src/config/assets.rs @@ -1,3 +1,4 @@ +use codec::{Decode, Encode}; use frame_support::{ pallet_prelude::Get, parameter_types, @@ -7,11 +8,12 @@ use frame_support::{ use frame_system::{EnsureRoot, EnsureSigned}; use pallet_nfts::PalletFeatures; use parachains_common::{AssetIdForTrustBackedAssets, CollectionId, ItemId, Signature}; -use sp_runtime::traits::Verify; +use sp_runtime::traits::{StaticLookup, Verify}; use crate::{ - deposit, AccountId, Assets, Balance, Balances, BlockNumber, Nfts, Runtime, RuntimeEvent, - RuntimeHoldReason, DAYS, EXISTENTIAL_DEPOSIT, UNIT, + deposit, AccountId, AssetManager, Assets, Balance, Balances, BlockNumber, Nfts, Runtime, + RuntimeCall, RuntimeEvent, RuntimeHoldReason, RuntimeOrigin, Vec, Weight, DAYS, + EXISTENTIAL_DEPOSIT, UNIT, }; /// We allow root to execute privileged asset operations. @@ -146,6 +148,71 @@ impl pallet_assets::Config for Runtime { type WeightInfo = pallet_assets::weights::SubstrateWeight; } +pub struct AssetRegistrar; +use frame_support::{dispatch::GetDispatchInfo, pallet_prelude::DispatchResult, transactional}; + +impl pallet_asset_manager::AssetRegistrar for AssetRegistrar { + fn next_asset_id() -> AssetIdForTrustBackedAssets { + pallet_assets::NextAssetId::::get().unwrap() + } + + #[transactional] + fn create_foreign_asset( + asset: AssetIdForTrustBackedAssets, + min_balance: Balance, + metadata: AssetRegistrarMetadata, + is_sufficient: bool, + ) -> DispatchResult { + // Create the asset. + Assets::force_create( + RuntimeOrigin::root(), + asset.into(), + ::Lookup::unlookup(AssetManager::account_id()), + is_sufficient, + min_balance, + )?; + // Set metadata for created asset. + Assets::force_set_metadata( + RuntimeOrigin::root(), + asset.into(), + metadata.name, + metadata.symbol, + metadata.decimals, + metadata.is_frozen, + ) + } + + #[transactional] + fn destroy_foreign_asset(asset: AssetIdForTrustBackedAssets) -> DispatchResult { + Assets::start_destroy(RuntimeOrigin::root(), asset.into()) + } + + fn destroy_asset_dispatch_info_weight(asset: AssetIdForTrustBackedAssets) -> Weight { + use pallet_assets::WeightInfo; + >::WeightInfo::start_destroy() + } +} + +use frame_support::pallet_prelude::TypeInfo; +#[derive(Clone, Default, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub struct AssetRegistrarMetadata { + pub name: Vec, + pub symbol: Vec, + pub decimals: u8, + pub is_frozen: bool, +} + +impl pallet_asset_manager::Config for Runtime { + type AssetId = >::AssetId; + type AssetRegistrar = AssetRegistrar; + type AssetRegistrarMetadata = AssetRegistrarMetadata; + type Balance = Balance; + type ForeignAssetModifierOrigin = EnsureRoot; + type ForeignAssetType = xcm::v5::Location; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_asset_manager::weights::SubstrateWeight; +} + #[cfg(test)] mod tests { use frame_support::traits::StorageInfoTrait; diff --git a/runtime/devnet/src/lib.rs b/runtime/devnet/src/lib.rs index aca3c865a..d1ab10df0 100644 --- a/runtime/devnet/src/lib.rs +++ b/runtime/devnet/src/lib.rs @@ -648,6 +648,8 @@ mod runtime { pub type NftFractionalization = pallet_nft_fractionalization::Pallet; #[runtime::pallet_index(52)] pub type Assets = pallet_assets::Pallet; + #[runtime::pallet_index(53)] + pub type AssetManager = pallet_asset_manager::Pallet; // Pop API #[runtime::pallet_index(150)] From 012ed2e930ddc01f9844afd860ce74efc0dfb645 Mon Sep 17 00:00:00 2001 From: Daanvdplas Date: Fri, 21 Feb 2025 10:13:56 +0100 Subject: [PATCH 4/7] test: foreign asset creation The CallbackHandle also had to be configured to have the NextAssetId increment --- Cargo.lock | 1 + runtime/devnet/Cargo.toml | 1 + runtime/devnet/src/config/assets.rs | 84 +++++++++++++++++++++++++++-- 3 files changed, 82 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 37b9bad5d..35231b451 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13851,6 +13851,7 @@ dependencies = [ "sp-genesis-builder 0.16.0", "sp-inherents 35.0.0", "sp-io 39.0.0", + "sp-keyring 40.0.0", "sp-mmr-primitives 35.0.0", "sp-offchain 35.0.0", "sp-runtime 40.0.0", diff --git a/runtime/devnet/Cargo.toml b/runtime/devnet/Cargo.toml index 261ca26fa..28b987fe9 100644 --- a/runtime/devnet/Cargo.toml +++ b/runtime/devnet/Cargo.toml @@ -105,6 +105,7 @@ pallet-ismp-runtime-api.workspace = true enumflags2.workspace = true env_logger.workspace = true hex.workspace = true +sp-keyring.workspace = true [features] default = ["std"] diff --git a/runtime/devnet/src/config/assets.rs b/runtime/devnet/src/config/assets.rs index 28fe0e762..0f8a58cc2 100644 --- a/runtime/devnet/src/config/assets.rs +++ b/runtime/devnet/src/config/assets.rs @@ -134,7 +134,7 @@ impl pallet_assets::Config for Runtime { type Balance = Balance; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = (); - type CallbackHandle = (); + type CallbackHandle = pallet_assets::AutoIncAssetId; type CreateOrigin = AsEnsureOriginWithArg>; type Currency = Balances; type Extra = (); @@ -163,15 +163,19 @@ impl pallet_asset_manager::AssetRegistrar for AssetRegistrar { metadata: AssetRegistrarMetadata, is_sufficient: bool, ) -> DispatchResult { - // Create the asset. + // Create the asset. Unlike `create`, no funds are reserved. Assets::force_create( RuntimeOrigin::root(), asset.into(), + // Asset manager pallet is the owner of the asset. This means changes to the asset can + // only be made through this pallet. ::Lookup::unlookup(AssetManager::account_id()), is_sufficient, min_balance, )?; - // Set metadata for created asset. + // Set metadata for created asset. Deposit is left alone, meaning that also no deposit will + // be taken unless metadata was already set for this asset which in this case wouldn't be + // the case. Assets::force_set_metadata( RuntimeOrigin::root(), asset.into(), @@ -215,9 +219,81 @@ impl pallet_asset_manager::Config for Runtime { #[cfg(test)] mod tests { - use frame_support::traits::StorageInfoTrait; + use frame_support::{ + assert_ok, + traits::{fungibles::Inspect, StorageInfoTrait}, + }; + use sp_keyring::AccountKeyring as Keyring; + use sp_runtime::BuildStorage; use super::*; + use crate::{config::xcm::AssetHub, ExistentialDeposit, System}; + + fn new_test_ext() -> sp_io::TestExternalities { + let initial_balance = 100_000_000 * UNIT; + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + pallet_balances::GenesisConfig:: { + balances: vec![(Keyring::Alice.to_account_id(), initial_balance)], + } + .assimilate_storage(&mut t) + .unwrap(); + pallet_assets::GenesisConfig:: { + next_asset_id: Some(1), + ..Default::default() + } + .assimilate_storage(&mut t) + .unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext + } + + #[test] + fn test_foreign_asset_creation() { + new_test_ext().execute_with(|| { + let metadata = AssetRegistrarMetadata { + name: "DOT".encode(), + symbol: "DOT".encode(), + decimals: 10, + is_frozen: false, + }; + // Obtain the next asset id from pallet assets. + let asset_id = + pallet_assets::NextAssetId::::get().unwrap(); + // Register a foreign asset in the asset manager pallet. + assert_ok!(AssetManager::register_foreign_asset( + RuntimeOrigin::root(), + xcm::v5::Parent.into(), + metadata, + ExistentialDeposit::get(), + true + )); + // Foreign asset has been created with the next asset id queried. + assert!(Assets::asset_exists(asset_id)); + // Next asset id is incremented for the next foreign asset created. + let next_asset_id = + pallet_assets::NextAssetId::::get().unwrap(); + assert_eq!(next_asset_id, asset_id + 1); + let metadata = AssetRegistrarMetadata { + name: "AH".encode(), + symbol: "AH".encode(), + decimals: 12, + is_frozen: false, + }; + assert_ok!(AssetManager::register_foreign_asset( + RuntimeOrigin::root(), + AssetHub::get(), + metadata, + ExistentialDeposit::get(), + true + )); + assert!(Assets::asset_exists(next_asset_id)); + + // There is no way to modify the assets metadata, mint or burn tokens or any other + // action with owner privileges because the asset manager pallet is the owner and + // doesn't have this functionality. + }); + } #[test] fn ensure_account_balance_deposit() { From d8664d016d005111ccc76e39ea0e9e1f7d487a91 Mon Sep 17 00:00:00 2001 From: Daanvdplas Date: Tue, 25 Feb 2025 18:51:28 +0100 Subject: [PATCH 5/7] test: integration test --- Cargo.lock | 1 + integration-tests/Cargo.toml | 147 +++++++++--------- .../src/chains/asset_hub/genesis.rs | 16 ++ integration-tests/src/chains/asset_hub/mod.rs | 3 + integration-tests/src/chains/mod.rs | 2 + .../src/chains/pop_network/genesis.rs | 1 + .../src/chains/pop_network/mod.rs | 2 + integration-tests/src/lib.rs | 119 +++++++++++++- pallets/asset-manager/src/lib.rs | 2 +- pallets/asset-manager/src/xcm_primitives.rs | 20 ++- runtime/devnet/src/config/xcm.rs | 50 ++++-- 11 files changed, 265 insertions(+), 98 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 35231b451..5e1b268d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6570,6 +6570,7 @@ dependencies = [ "sp-consensus-beefy 23.0.0", "sp-consensus-grandpa 22.0.0", "sp-core 35.0.0", + "sp-keyring 40.0.0", "sp-runtime 40.0.0", "staging-xcm 15.0.1", "staging-xcm-executor 18.0.0", diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index 93d37669b..0847664d6 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -9,10 +9,10 @@ repository.workspace = true [dependencies] codec.workspace = true tracing-subscriber = { workspace = true, features = [ - "env-filter", - "fmt", - "std", - "tracing-log", + "env-filter", + "fmt", + "std", + "tracing-log", ] } # Substrate @@ -26,6 +26,7 @@ sp-consensus-babe.workspace = true sp-consensus-beefy.workspace = true sp-consensus-grandpa.workspace = true sp-core.workspace = true +sp-keyring.workspace = true sp-runtime.workspace = true # Polkadot @@ -55,82 +56,82 @@ pop-runtime-mainnet.workspace = true pop-runtime-testnet.workspace = true [features] -default = [ "std" ] -devnet = [ "pop-runtime-devnet/std" ] -mainnet = [ "pop-runtime-mainnet/std" ] +default = ["std"] +devnet = ["pop-runtime-devnet/std"] +mainnet = ["pop-runtime-mainnet/std"] paseo = [ - "asset-hub-paseo-runtime", - "paseo-runtime", - "paseo-runtime-constants", + "asset-hub-paseo-runtime", + "paseo-runtime", + "paseo-runtime-constants", ] runtime-benchmarks = [ - "asset-hub-paseo-runtime?/runtime-benchmarks", - "asset-hub-westend-runtime?/runtime-benchmarks", - "cumulus-primitives-core/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "pallet-assets/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "pallet-message-queue/runtime-benchmarks", - "pallet-xcm/runtime-benchmarks", - "paseo-runtime?/runtime-benchmarks", - "polkadot-primitives/runtime-benchmarks", - "polkadot-runtime-parachains/runtime-benchmarks", - "pop-runtime-common/runtime-benchmarks", - "pop-runtime-devnet/runtime-benchmarks", - "pop-runtime-mainnet/runtime-benchmarks", - "pop-runtime-testnet/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", - "westend-runtime?/runtime-benchmarks", - "xcm-executor/runtime-benchmarks", + "asset-hub-paseo-runtime?/runtime-benchmarks", + "asset-hub-westend-runtime?/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "paseo-runtime?/runtime-benchmarks", + "polkadot-primitives/runtime-benchmarks", + "polkadot-runtime-parachains/runtime-benchmarks", + "pop-runtime-common/runtime-benchmarks", + "pop-runtime-devnet/runtime-benchmarks", + "pop-runtime-mainnet/runtime-benchmarks", + "pop-runtime-testnet/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "westend-runtime?/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", ] std = [ - "asset-hub-paseo-runtime?/std", - "asset-hub-westend-runtime?/std", - "asset-test-utils/std", - "codec/std", - "cumulus-primitives-core/std", - "frame-support/std", - "pallet-assets/std", - "pallet-balances/std", - "pallet-message-queue/std", - "pallet-xcm/std", - "paseo-runtime-constants?/std", - "paseo-runtime?/std", - "polkadot-primitives/std", - "polkadot-runtime-parachains/std", - "pop-runtime-common/std", - "pop-runtime-devnet/std", - "pop-runtime-mainnet/std", - "sp-authority-discovery/std", - "sp-consensus-aura/std", - "sp-consensus-babe/std", - "sp-consensus-beefy/std", - "sp-consensus-grandpa/std", - "sp-core/std", - "sp-runtime/std", - "tracing-subscriber/std", - "westend-runtime-constants?/std", - "westend-runtime?/std", - "xcm-executor/std", - "xcm/std", + "asset-hub-paseo-runtime?/std", + "asset-hub-westend-runtime?/std", + "asset-test-utils/std", + "codec/std", + "cumulus-primitives-core/std", + "frame-support/std", + "pallet-assets/std", + "pallet-balances/std", + "pallet-message-queue/std", + "pallet-xcm/std", + "paseo-runtime-constants?/std", + "paseo-runtime?/std", + "polkadot-primitives/std", + "polkadot-runtime-parachains/std", + "pop-runtime-common/std", + "pop-runtime-devnet/std", + "pop-runtime-mainnet/std", + "sp-authority-discovery/std", + "sp-consensus-aura/std", + "sp-consensus-babe/std", + "sp-consensus-beefy/std", + "sp-consensus-grandpa/std", + "sp-core/std", + "sp-runtime/std", + "tracing-subscriber/std", + "westend-runtime-constants?/std", + "westend-runtime?/std", + "xcm-executor/std", + "xcm/std", ] -testnet = [ "pop-runtime-testnet/std" ] +testnet = ["pop-runtime-testnet/std"] try-runtime = [ - "asset-hub-paseo-runtime?/try-runtime", - "asset-hub-westend-runtime?/try-runtime", - "frame-support/try-runtime", - "pallet-assets/try-runtime", - "pallet-balances/std", - "pallet-message-queue/try-runtime", - "paseo-runtime?/try-runtime", - "pop-runtime-devnet/try-runtime", - "pop-runtime-mainnet/try-runtime", - "pop-runtime-testnet/try-runtime", - "sp-runtime/try-runtime", - "westend-runtime?/try-runtime", + "asset-hub-paseo-runtime?/try-runtime", + "asset-hub-westend-runtime?/try-runtime", + "frame-support/try-runtime", + "pallet-assets/try-runtime", + "pallet-balances/std", + "pallet-message-queue/try-runtime", + "paseo-runtime?/try-runtime", + "pop-runtime-devnet/try-runtime", + "pop-runtime-mainnet/try-runtime", + "pop-runtime-testnet/try-runtime", + "sp-runtime/try-runtime", + "westend-runtime?/try-runtime", ] westend = [ - "asset-hub-westend-runtime", - "westend-runtime", - "westend-runtime-constants", + "asset-hub-westend-runtime", + "westend-runtime", + "westend-runtime-constants", ] diff --git a/integration-tests/src/chains/asset_hub/genesis.rs b/integration-tests/src/chains/asset_hub/genesis.rs index b61d2308f..955f63f7e 100644 --- a/integration-tests/src/chains/asset_hub/genesis.rs +++ b/integration-tests/src/chains/asset_hub/genesis.rs @@ -2,8 +2,10 @@ use cumulus_primitives_core::relay_chain::Balance; use emulated_integration_tests_common::{ accounts, build_genesis_storage, collators::invulnerables, SAFE_XCM_VERSION, }; +use frame_support::parameter_types; use sp_core::storage::Storage; +use super::*; use crate::chains::asset_hub::{ constants::currency::EXISTENTIAL_DEPOSIT, runtime::{ @@ -14,10 +16,24 @@ use crate::chains::asset_hub::{ pub(crate) const ED: Balance = EXISTENTIAL_DEPOSIT; pub(crate) const PARA_ID: u32 = 1000; +pub(crate) const USDC: u32 = 1337; +pub(crate) const USDT: u32 = 1984; +pub(crate) const USD_MIN_BALANCE: Balance = 70_000; + +parameter_types! { + pub AssetOwner: AccountId = Keyring::Alice.to_account_id(); +} pub(crate) fn genesis() -> Storage { let genesis_config = RuntimeGenesisConfig { system: SystemConfig::default(), + assets: AssetsConfig { + assets: vec![ + // Stablecoins + (USDC, AssetOwner::get(), true, USD_MIN_BALANCE), + (USDT, AssetOwner::get(), true, USD_MIN_BALANCE), + ], + }, balances: BalancesConfig { balances: accounts::init_balances() .iter() diff --git a/integration-tests/src/chains/asset_hub/mod.rs b/integration-tests/src/chains/asset_hub/mod.rs index b15a86657..039904be2 100644 --- a/integration-tests/src/chains/asset_hub/mod.rs +++ b/integration-tests/src/chains/asset_hub/mod.rs @@ -9,7 +9,10 @@ pub(crate) use {asset_hub_paseo_runtime as runtime, paseo_runtime_constants as c #[cfg(feature = "westend")] pub(crate) use {asset_hub_westend_runtime as runtime, westend_runtime_constants as constants}; +use super::*; + pub(crate) mod genesis; +use genesis::*; // AssetHub Parachain declaration. decl_test_parachains! { diff --git a/integration-tests/src/chains/mod.rs b/integration-tests/src/chains/mod.rs index 604bbeef0..84c11eaa1 100644 --- a/integration-tests/src/chains/mod.rs +++ b/integration-tests/src/chains/mod.rs @@ -1,3 +1,5 @@ +use sp_keyring::Sr25519Keyring as Keyring; + pub(crate) mod asset_hub; pub(crate) mod pop_network; pub(crate) mod relay; diff --git a/integration-tests/src/chains/pop_network/genesis.rs b/integration-tests/src/chains/pop_network/genesis.rs index d4ecf0904..f86db5e24 100644 --- a/integration-tests/src/chains/pop_network/genesis.rs +++ b/integration-tests/src/chains/pop_network/genesis.rs @@ -10,6 +10,7 @@ const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; pub(crate) fn genesis() -> Storage { let genesis_config = runtime::RuntimeGenesisConfig { system: runtime::SystemConfig::default(), + assets: runtime::AssetsConfig { next_asset_id: Some(1), ..Default::default() }, balances: runtime::BalancesConfig { ..Default::default() }, parachain_info: runtime::ParachainInfoConfig { parachain_id: PARA_ID.into(), diff --git a/integration-tests/src/chains/pop_network/mod.rs b/integration-tests/src/chains/pop_network/mod.rs index 7c579defd..b8ff3c60e 100644 --- a/integration-tests/src/chains/pop_network/mod.rs +++ b/integration-tests/src/chains/pop_network/mod.rs @@ -29,6 +29,8 @@ decl_test_parachains! { pallets = { PolkadotXcm: runtime::PolkadotXcm, Balances: runtime::Balances, + Assets: runtime::Assets, + AssetManager: runtime::AssetManager, } }, } diff --git a/integration-tests/src/lib.rs b/integration-tests/src/lib.rs index fce13ea9c..06c8abdda 100644 --- a/integration-tests/src/lib.rs +++ b/integration-tests/src/lib.rs @@ -3,10 +3,12 @@ use asset_test_utils::xcm_helpers; use chains::{ asset_hub::{ - genesis::ED as ASSET_HUB_ED, runtime::xcm_config::XcmConfig as AssetHubXcmConfig, AssetHub, - AssetHubParaPallet, + self, + genesis::{ED as ASSET_HUB_ED, USDC}, + runtime::xcm_config::XcmConfig as AssetHubXcmConfig, + AssetHub, AssetHubParaPallet, }, - pop_network::{PopNetwork, PopNetworkParaPallet}, + pop_network::{genesis, runtime, PopNetwork, PopNetworkParaPallet}, relay::{ genesis::ED as RELAY_ED, runtime::xcm_config::XcmConfig as RelayXcmConfig, Relay, RelayRelayPallet as RelayPallet, @@ -198,6 +200,117 @@ fn fund_pop_from_system_para( test.assert(); } +/// Asset Hub. +pub const ASSET_HUB: Junction = Parachain(1000); +/// Assets on Asset Hub. +pub const ASSET_HUB_ASSETS: Junction = PalletInstance(50); + +#[cfg(feature = "devnet")] +#[test] +fn receive_usdc_on_pop() { + use codec::Encode; + use pop_runtime_devnet::{config::assets::AssetRegistrarMetadata, RuntimeOrigin}; + init_tracing(); + + // Create a foreign asset for usdc on Pop. + // ------ + let usdc = AssetId([ASSET_HUB_ASSETS, GeneralIndex(USDC.into())].into()); + let metadata = AssetRegistrarMetadata { + name: "USDC".encode(), + symbol: "USDC".encode(), + decimals: 10, + is_frozen: false, + }; + PopNetwork::::execute_with(|| { + as PopNetworkParaPallet>::AssetManager::register_foreign_asset( + RuntimeOrigin::root(), + usdc.clone(), + metadata, + 1, + true, + ) + }); + // Cheating but for now easy. + let usdc_pop_asset_id = 1u32; + // ------ + + // Provide sender on AH with usdc to transfer. + // ------ + let sender = AssetHubSender::get(); + let usdc_owner = asset_hub::AssetOwner::get(); + let usdc_owner_signer = ::RuntimeOrigin::signed(usdc_owner.clone()); + let usdc_amount_to_send = asset_hub::USD_MIN_BALANCE * 100_000; + AssetHub::mint_asset( + usdc_owner_signer.clone(), + USDC, + sender.clone(), + usdc_amount_to_send + asset_hub::USD_MIN_BALANCE, + ); + let usdc_asset = (usdc, usdc_amount_to_send).into(); + // ------ + + // Setup test to transfer usdc to receiver. + // ------ + let fee_amount_to_send = runtime::UNIT / 2; + let fee_asset = (Parent, fee_amount_to_send).into(); + let assets: Assets = vec![usdc_asset, fee_asset].into(); + let destination = AssetHub::sibling_location_of(PopNetwork::para_id()); + let receiver = PopNetworkParaReceiver::get(); + let location_usdc = Location::new(1, [ASSET_HUB, ASSET_HUB_ASSETS, GeneralIndex(USDC)]); + // Init Test + let test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para( + destination, + receiver.clone(), + usdc_amount_to_send, + assets, + Some(USDC), + 1, + ), + }; + let mut test = Test::::new(test_args); + // ------ + + // Query balances before. + // ------ + let sender_usdc_balance_before = AssetHub::execute_with(|| { + <::Assets as Inspect<_>>::balance(USDC, &sender) + }); + let receiver_usdc_balance_before = Para::execute_with(|| { + <::Assets as Inspect<_>>::balance( + usdc_pop_asset_id, + &receiver, + ) + }); + // ------ + + // Set assertions and dispatchables. + // ------ + test.set_assertion::(asset_hub_to_para_assets_sender_assertions); + test.set_assertion::(asset_hub_to_para_assets_receiver_assertions); + test.set_dispatchable::(asset_hub_to_para_transfer_assets); + test.assert(); + // ------ + + // Query balances after. + // ------ + let sender_usdc_balance_after = AssetHub::execute_with(|| { + <::Assets as Inspect<_>>::balance(USDC, &sender) + }); + let receiver_usdc_balance_after = Para::execute_with(|| { + <::Assets as Inspect<_>>::balance( + usdc_pop_asset_id, + &receiver, + ) + }); + // ------ + + assert_eq!(sender_usdc_balance_after, sender_usdc_balance_before - usdc_amount_to_send); + assert_eq!(receiver_usdc_balance_after, receiver_usdc_balance_before + usdc_amount_to_send); +} + /// Reserve Transfers of native asset from Relay to Parachain should work #[test] #[should_panic] diff --git a/pallets/asset-manager/src/lib.rs b/pallets/asset-manager/src/lib.rs index 52e19fc7e..903da4811 100644 --- a/pallets/asset-manager/src/lib.rs +++ b/pallets/asset-manager/src/lib.rs @@ -45,7 +45,7 @@ pub mod mock; #[cfg(test)] pub mod tests; pub mod weights; -mod xcm_primitives; +pub mod xcm_primitives; pub use crate::weights::WeightInfo; diff --git a/pallets/asset-manager/src/xcm_primitives.rs b/pallets/asset-manager/src/xcm_primitives.rs index 0b8540b56..201efebf8 100644 --- a/pallets/asset-manager/src/xcm_primitives.rs +++ b/pallets/asset-manager/src/xcm_primitives.rs @@ -24,15 +24,13 @@ use xcm_executor::traits::ConvertLocation; /// an intermediate generic type AssetType. /// The trait bounds enforce is that the AssetTypeGetter trait is also implemented for /// AssetIdInfoGetter -pub struct AsAssetType( - PhantomData<(AssetId, AssetType, AssetIdInfoGetter)>, -); -impl MaybeEquivalence - for AsAssetType +pub struct AsAssetType(PhantomData<(AssetId, AssetIdInfoGetter)>); +impl MaybeEquivalence + for AsAssetType where AssetId: Clone, - AssetType: From + Into> + Clone, - AssetIdInfoGetter: AssetTypeGetter, + // AssetType: From + Into> + Clone, + AssetIdInfoGetter: AssetTypeGetter, { fn convert(id: &Location) -> Option { AssetIdInfoGetter::get_asset_id(id.clone().into()) @@ -63,12 +61,12 @@ where // } // } -impl ConvertLocation - for AsAssetType +impl ConvertLocation + for AsAssetType where AssetId: Clone, - AssetType: From + Into> + Clone, - AssetIdInfoGetter: AssetTypeGetter, + // AssetType: From + Into> + Clone, + AssetIdInfoGetter: AssetTypeGetter, { fn convert_location(id: &Location) -> Option { let v5_location = xcm_builder::WithLatestLocationConverter::::convert(id)?; diff --git a/runtime/devnet/src/config/xcm.rs b/runtime/devnet/src/config/xcm.rs index 555ec4ad6..a61745009 100644 --- a/runtime/devnet/src/config/xcm.rs +++ b/runtime/devnet/src/config/xcm.rs @@ -7,22 +7,24 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; +use parachains_common::{AssetIdForTrustBackedAssets, Balance}; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::impls::ToAuthor; -use xcm::latest::prelude::*; +use xcm::{latest::prelude::*, VersionedLocation}; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowTopLevelPaidExecutionFrom, EnsureXcmOrigin, FixedWeightBounds, - FrameTransactionalProcessor, FungibleAdapter, IsConcrete, ParentIsPreset, RelayChainAsNative, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WithComputedOrigin, WithUniqueTopic, + AllowTopLevelPaidExecutionFrom, ConvertedConcreteId, EnsureXcmOrigin, FixedWeightBounds, + FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, IsConcrete, NoChecking, + ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, }; -use xcm_executor::XcmExecutor; +use xcm_executor::{traits::JustTry, XcmExecutor}; use crate::{ - AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, - Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, + AccountId, AllPalletsWithSystem, AssetManager, Assets, Balances, ParachainInfo, + ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, + XcmpQueue, }; parameter_types! { @@ -34,6 +36,7 @@ parameter_types! { // For the real deployment, it is recommended to set `RelayNetwork` according to the relay chain // and prepend `UniversalLocation` with `GlobalConsensus(RelayNetwork::get())`. pub UniversalLocation: InteriorLocation = Parachain(ParachainInfo::parachain_id().into()).into(); + pub CheckAccount: AccountId = crate::PolkadotXcm::check_account(); } /// Type for specifying how a `Location` can be converted into an `AccountId`. This is used @@ -63,6 +66,33 @@ pub type LocalAssetTransactor = FungibleAdapter< (), >; +// The non-reserve fungible transactor type +// It will use pallet-assets, and the Id will be matched against AsAssetType +pub type ForeignFungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + crate::Assets, + // Use this currency when it is a fungible asset matching the given location or name: + ( + ConvertedConcreteId< + AssetIdForTrustBackedAssets, + Balance, + pallet_asset_manager::xcm_primitives::AsAssetType< + AssetIdForTrustBackedAssets, + AssetManager, + >, + JustTry, + >, + ), + // Do a simple punn to convert an AccountId32 Location into a native chain account ID: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleports. + NoChecking, + // We dont track any teleports + CheckAccount, +>; + /// 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. @@ -152,7 +182,7 @@ impl xcm_executor::Config for XcmConfig { type AssetExchanger = (); type AssetLocker = (); // How to withdraw and deposit an asset. - type AssetTransactor = LocalAssetTransactor; + type AssetTransactor = (LocalAssetTransactor, ForeignFungiblesTransactor); type AssetTrap = PolkadotXcm; type Barrier = Barrier; type CallDispatcher = RuntimeCall; From 6549df5fb7a9073b1fd492a37aeee5519399399a Mon Sep 17 00:00:00 2001 From: Daanvdplas Date: Tue, 4 Mar 2025 14:00:26 +0100 Subject: [PATCH 6/7] test: integration test usdc cross chain transfers --- Cargo.lock | 3 + integration-tests/Cargo.toml | 7 + .../src/chains/asset_hub/genesis.rs | 8 +- integration-tests/src/chains/asset_hub/mod.rs | 2 +- .../src/chains/pop_network/mod.rs | 7 +- integration-tests/src/lib.rs | 290 +++++++++++++++--- pallets/asset-manager/src/benchmarks.rs | 16 +- pop-api/Cargo.toml | 21 +- pop-api/examples/foreign_fungibles/Cargo.toml | 28 ++ pop-api/examples/foreign_fungibles/lib.rs | 109 +++++++ runtime/devnet/src/config/xcm.rs | 19 +- 11 files changed, 436 insertions(+), 74 deletions(-) create mode 100644 pop-api/examples/foreign_fungibles/Cargo.toml create mode 100644 pop-api/examples/foreign_fungibles/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 5e1b268d3..0a1229be8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6551,8 +6551,10 @@ dependencies = [ "cumulus-primitives-core 0.17.0", "emulated-integration-tests-common", "frame-support 39.0.0", + "log", "pallet-assets 41.0.0", "pallet-balances 40.0.0", + "pallet-contracts", "pallet-message-queue 42.0.0", "pallet-xcm 18.0.0", "parity-scale-codec", @@ -6570,6 +6572,7 @@ dependencies = [ "sp-consensus-beefy 23.0.0", "sp-consensus-grandpa 22.0.0", "sp-core 35.0.0", + "sp-io 39.0.0", "sp-keyring 40.0.0", "sp-runtime 40.0.0", "staging-xcm 15.0.1", diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index 0847664d6..a46913b15 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -14,11 +14,13 @@ tracing-subscriber = { workspace = true, features = [ "std", "tracing-log", ] } +log.workspace = true # Substrate frame-support.workspace = true pallet-assets.workspace = true pallet-balances.workspace = true +pallet-contracts.workspace = true pallet-message-queue.workspace = true sp-authority-discovery.workspace = true sp-consensus-aura.workspace = true @@ -28,6 +30,7 @@ sp-consensus-grandpa.workspace = true sp-core.workspace = true sp-keyring.workspace = true sp-runtime.workspace = true +sp-io.workspace = true # Polkadot pallet-xcm.workspace = true @@ -71,6 +74,7 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-contracts/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "paseo-runtime?/runtime-benchmarks", @@ -93,6 +97,7 @@ std = [ "frame-support/std", "pallet-assets/std", "pallet-balances/std", + "pallet-contracts/std", "pallet-message-queue/std", "pallet-xcm/std", "paseo-runtime-constants?/std", @@ -108,6 +113,7 @@ std = [ "sp-consensus-beefy/std", "sp-consensus-grandpa/std", "sp-core/std", + "sp-io/std", "sp-runtime/std", "tracing-subscriber/std", "westend-runtime-constants?/std", @@ -122,6 +128,7 @@ try-runtime = [ "frame-support/try-runtime", "pallet-assets/try-runtime", "pallet-balances/std", + "pallet-contracts/try-runtime", "pallet-message-queue/try-runtime", "paseo-runtime?/try-runtime", "pop-runtime-devnet/try-runtime", diff --git a/integration-tests/src/chains/asset_hub/genesis.rs b/integration-tests/src/chains/asset_hub/genesis.rs index 955f63f7e..c91ea45f5 100644 --- a/integration-tests/src/chains/asset_hub/genesis.rs +++ b/integration-tests/src/chains/asset_hub/genesis.rs @@ -3,14 +3,16 @@ use emulated_integration_tests_common::{ accounts, build_genesis_storage, collators::invulnerables, SAFE_XCM_VERSION, }; use frame_support::parameter_types; +use polkadot_primitives::AccountId; use sp_core::storage::Storage; use super::*; use crate::chains::asset_hub::{ constants::currency::EXISTENTIAL_DEPOSIT, runtime::{ - BalancesConfig, CollatorSelectionConfig, ParachainInfoConfig, PolkadotXcmConfig, - RuntimeGenesisConfig, SessionConfig, SessionKeys, SystemConfig, WASM_BINARY, + AssetsConfig, BalancesConfig, CollatorSelectionConfig, ParachainInfoConfig, + PolkadotXcmConfig, RuntimeGenesisConfig, SessionConfig, SessionKeys, SystemConfig, + WASM_BINARY, }, }; @@ -33,6 +35,8 @@ pub(crate) fn genesis() -> Storage { (USDC, AssetOwner::get(), true, USD_MIN_BALANCE), (USDT, AssetOwner::get(), true, USD_MIN_BALANCE), ], + next_asset_id: Some(USDC), + ..Default::default() }, balances: BalancesConfig { balances: accounts::init_balances() diff --git a/integration-tests/src/chains/asset_hub/mod.rs b/integration-tests/src/chains/asset_hub/mod.rs index 039904be2..985ad4934 100644 --- a/integration-tests/src/chains/asset_hub/mod.rs +++ b/integration-tests/src/chains/asset_hub/mod.rs @@ -12,7 +12,7 @@ pub(crate) use {asset_hub_westend_runtime as runtime, westend_runtime_constants use super::*; pub(crate) mod genesis; -use genesis::*; +pub(crate) use genesis::*; // AssetHub Parachain declaration. decl_test_parachains! { diff --git a/integration-tests/src/chains/pop_network/mod.rs b/integration-tests/src/chains/pop_network/mod.rs index b8ff3c60e..7e31bda7d 100644 --- a/integration-tests/src/chains/pop_network/mod.rs +++ b/integration-tests/src/chains/pop_network/mod.rs @@ -6,11 +6,11 @@ use emulated_integration_tests_common::{ }; use frame_support::traits::OnInitialize; #[cfg(feature = "devnet")] -use pop_runtime_devnet as runtime; +pub(crate) use pop_runtime_devnet as runtime; #[cfg(feature = "mainnet")] -use pop_runtime_mainnet as runtime; +pub(crate) use pop_runtime_mainnet as runtime; #[cfg(feature = "testnet")] -use pop_runtime_testnet as runtime; +pub(crate) use pop_runtime_testnet as runtime; // PopNetwork Parachain declaration decl_test_parachains! { @@ -31,6 +31,7 @@ decl_test_parachains! { Balances: runtime::Balances, Assets: runtime::Assets, AssetManager: runtime::AssetManager, + Contracts: runtime::Contracts, } }, } diff --git a/integration-tests/src/lib.rs b/integration-tests/src/lib.rs index 06c8abdda..0421f1e5d 100644 --- a/integration-tests/src/lib.rs +++ b/integration-tests/src/lib.rs @@ -22,7 +22,10 @@ use emulated_integration_tests_common::{ Test, TestArgs, TestContext, TestExt, }, }; -use frame_support::{pallet_prelude::Weight, sp_runtime::DispatchResult}; +use frame_support::{ + pallet_prelude::Weight, sp_runtime::DispatchResult, traits::fungibles::Inspect, +}; +use polkadot_primitives::AccountId; use pop_runtime_common::Balance; use pop_runtime_devnet::config::xcm::XcmConfig as PopNetworkXcmConfig; use xcm::prelude::*; @@ -183,9 +186,9 @@ fn para_to_system_para_reserve_transfer_assets(t: ParaToSystemParaTest) -> Dispa // Funds Pop with relay tokens from system para fn fund_pop_from_system_para( - sender: sp_runtime::AccountId32, + sender: AccountId, amount_to_send: Balance, - beneficiary: sp_runtime::AccountId32, + beneficiary: AccountId, assets: Assets, ) { let destination = AssetHubPara::sibling_location_of(PopNetworkPara::para_id()); @@ -200,47 +203,88 @@ fn fund_pop_from_system_para( test.assert(); } +use pop_runtime_devnet::{config::assets::AssetRegistrarMetadata, RuntimeOrigin}; + /// Asset Hub. pub const ASSET_HUB: Junction = Parachain(1000); /// Assets on Asset Hub. pub const ASSET_HUB_ASSETS: Junction = PalletInstance(50); +pub const USDC_POP_ASSET_ID: u32 = 1; #[cfg(feature = "devnet")] #[test] fn receive_usdc_on_pop() { use codec::Encode; - use pop_runtime_devnet::{config::assets::AssetRegistrarMetadata, RuntimeOrigin}; + use pallet_contracts::{Code, CollectEvents, Determinism}; + const GAS_LIMIT: Weight = Weight::from_parts(100_000_000_000, 3 * 1024 * 1024); + const DEBUG_OUTPUT: pallet_contracts::DebugInfo = pallet_contracts::DebugInfo::UnsafeDebug; init_tracing(); + // Provide bob DOT. + let amount: Balance = ASSET_HUB_ED * 1000; + let bob_on_pop = PopNetworkParaReceiver::get(); + fund_pop_from_system_para( + AssetHubParaSender::get(), + amount * 20, + bob_on_pop.clone(), + (Parent, amount * 20).into(), + ); + // Fund Pop Network's SA on AH with DOT. + let pop_net_location_as_seen_by_ahr = + AssetHubPara::sibling_location_of(PopNetworkPara::para_id()); + let sov_pop_net_on_ahr = AssetHubPara::sovereign_account_id_of(pop_net_location_as_seen_by_ahr); + AssetHubPara::fund_accounts(vec![(sov_pop_net_on_ahr.into(), amount * 2)]); + // Amounts used for doing transfers. + let transfer_amount = amount / 2; + // Create a foreign asset for usdc on Pop. // ------ let usdc = AssetId([ASSET_HUB_ASSETS, GeneralIndex(USDC.into())].into()); + let usdc_location = Location::new(1, [ASSET_HUB, ASSET_HUB_ASSETS, GeneralIndex(USDC.into())]); let metadata = AssetRegistrarMetadata { name: "USDC".encode(), symbol: "USDC".encode(), decimals: 10, is_frozen: false, }; + let mut contract = AccountId::from([0u8; 32]); PopNetwork::::execute_with(|| { as PopNetworkParaPallet>::AssetManager::register_foreign_asset( RuntimeOrigin::root(), - usdc.clone(), + usdc_location, metadata, 1, true, - ) + ); + + let path = "../pop-api/examples/foreign_fungibles/target/ink/foreign_fungibles.wasm"; + let wasm_binary = std::fs::read(path).expect("could not read .wasm file"); + let instantiate_result = + as PopNetworkParaPallet>::Contracts::bare_instantiate( + bob_on_pop.clone(), + amount * 5, + GAS_LIMIT, + None, + Code::Upload(wasm_binary), + function_selector("new"), + vec![], + DEBUG_OUTPUT, + CollectEvents::Skip, + ) + .result + .expect("Contract instantiation failed"); + assert!(!instantiate_result.result.did_revert()); + contract = instantiate_result.account_id; }); - // Cheating but for now easy. - let usdc_pop_asset_id = 1u32; // ------ // Provide sender on AH with usdc to transfer. // ------ - let sender = AssetHubSender::get(); + let sender = AssetHubParaSender::get(); let usdc_owner = asset_hub::AssetOwner::get(); - let usdc_owner_signer = ::RuntimeOrigin::signed(usdc_owner.clone()); + let usdc_owner_signer = ::RuntimeOrigin::signed(usdc_owner.clone()); let usdc_amount_to_send = asset_hub::USD_MIN_BALANCE * 100_000; - AssetHub::mint_asset( + AssetHubPara::mint_asset( usdc_owner_signer.clone(), USDC, sender.clone(), @@ -249,20 +293,18 @@ fn receive_usdc_on_pop() { let usdc_asset = (usdc, usdc_amount_to_send).into(); // ------ - // Setup test to transfer usdc to receiver. - // ------ + // Transfer usdc to contract. let fee_amount_to_send = runtime::UNIT / 2; let fee_asset = (Parent, fee_amount_to_send).into(); let assets: Assets = vec![usdc_asset, fee_asset].into(); - let destination = AssetHub::sibling_location_of(PopNetwork::para_id()); - let receiver = PopNetworkParaReceiver::get(); - let location_usdc = Location::new(1, [ASSET_HUB, ASSET_HUB_ASSETS, GeneralIndex(USDC)]); - // Init Test + let destination = AssetHubPara::sibling_location_of(PopNetworkPara::para_id()); + let receiver = contract.clone(); + let location_usdc = Location::new(1, [ASSET_HUB, ASSET_HUB_ASSETS, GeneralIndex(USDC.into())]); // Init Test let test_args = TestContext { sender: sender.clone(), receiver: receiver.clone(), args: TestArgs::new_para( - destination, + destination.clone(), receiver.clone(), usdc_amount_to_send, assets, @@ -270,45 +312,136 @@ fn receive_usdc_on_pop() { 1, ), }; - let mut test = Test::::new(test_args); - // ------ - - // Query balances before. - // ------ - let sender_usdc_balance_before = AssetHub::execute_with(|| { - <::Assets as Inspect<_>>::balance(USDC, &sender) + let mut test = Test::::new(test_args); + // ---- Assertions + let sender_usdc_balance_before = AssetHubPara::execute_with(|| { + <::Assets as Inspect<_>>::balance(USDC, &sender) }); - let receiver_usdc_balance_before = Para::execute_with(|| { - <::Assets as Inspect<_>>::balance( - usdc_pop_asset_id, + let receiver_usdc_balance_before = PopNetworkPara::execute_with(|| { + <::Assets as Inspect<_>>::balance( + USDC_POP_ASSET_ID, &receiver, ) }); - // ------ - - // Set assertions and dispatchables. - // ------ - test.set_assertion::(asset_hub_to_para_assets_sender_assertions); - test.set_assertion::(asset_hub_to_para_assets_receiver_assertions); - test.set_dispatchable::(asset_hub_to_para_transfer_assets); + test.set_assertion::(asset_hub_to_para_assets_sender_assertions); + test.set_assertion::(asset_hub_to_para_assets_receiver_assertions); + test.set_dispatchable::(asset_hub_to_para_transfer_assets); test.assert(); - // ------ - - // Query balances after. - // ------ - let sender_usdc_balance_after = AssetHub::execute_with(|| { - <::Assets as Inspect<_>>::balance(USDC, &sender) + let sender_usdc_balance_after = AssetHubPara::execute_with(|| { + <::Assets as Inspect<_>>::balance(USDC, &sender) }); - let receiver_usdc_balance_after = Para::execute_with(|| { - <::Assets as Inspect<_>>::balance( - usdc_pop_asset_id, + let receiver_usdc_balance_after = PopNetworkPara::execute_with(|| { + <::Assets as Inspect<_>>::balance( + USDC_POP_ASSET_ID, &receiver, ) }); - // ------ assert_eq!(sender_usdc_balance_after, sender_usdc_balance_before - usdc_amount_to_send); assert_eq!(receiver_usdc_balance_after, receiver_usdc_balance_before + usdc_amount_to_send); + + // ------ + + let ah_transfer_amount = usdc_amount_to_send / 2; + // Step 4: Interact with the contract on Pop Network + PopNetworkPara::execute_with(|| { + // Call contract to transfer half USDC to another account on Pop. + let local_transfer_amount = usdc_amount_to_send / 2; + let local_receiver = AccountId::from([2u8; 32]); + let function = function_selector("transfer"); + let params = [local_receiver.encode(), local_transfer_amount.encode()].concat(); + let input = [function, params].concat(); + let call_result = as PopNetworkParaPallet>::Contracts::bare_call( + bob_on_pop.clone(), + contract.clone(), + 0, + GAS_LIMIT, + None, + input, + DEBUG_OUTPUT, + CollectEvents::Skip, + Determinism::Enforced, + ); + let result = decoded::>(call_result.result.unwrap()).unwrap(); + assert!(result.is_ok()); + // Verify local transfer + let local_receiver_balance = + < as PopNetworkParaPallet>::Assets as Inspect<_>>::balance( + USDC_POP_ASSET_ID, + &local_receiver, + ); + assert_eq!(local_receiver_balance, local_transfer_amount); + let contract_usdc_balance_after_local = + < as PopNetworkParaPallet>::Assets as Inspect<_>>::balance( + USDC_POP_ASSET_ID, + &contract, + ); + assert_eq!(contract_usdc_balance_after_local, usdc_amount_to_send - local_transfer_amount); + + // Call contract to transfer remaining USDC back to AH + let ah_receiver = AssetHubParaReceiver::get(); + let function = function_selector("ah_transfer"); + let params = + [ah_receiver.encode(), ah_transfer_amount.encode(), 2500000000000u128.encode()] + .concat(); + let input = [function, params].concat(); + let call_result = as PopNetworkParaPallet>::Contracts::bare_call( + bob_on_pop.clone(), + contract.clone(), + 0, + GAS_LIMIT, + None, + input, + DEBUG_OUTPUT, + CollectEvents::Skip, + Determinism::Enforced, + ); + let result = decoded::>(call_result.result.unwrap()).unwrap(); + assert!(result.is_ok()); + + // Check Pop Network events for USDC burn + type RuntimeEvent = ::RuntimeEvent; + let events = PopNetworkPara::events(); + println!("\nPopNetwork events after contract calls: {:?}", events); + assert_event_matches!( + events, + RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) + if *asset_id == USDC_POP_ASSET_ID && *owner == contract && *balance == + ah_transfer_amount ); + }); + + // Step 5: Verify the transfer back to Asset Hub + AssetHubPara::execute_with(|| { + // Check AH events for USDC mint + type RuntimeEventAH = ::RuntimeEvent; + let sov_pop_net_on_ahr = AssetHubPara::sovereign_account_id_of(destination); + let ah_receiver = AssetHubParaReceiver::get(); + let events = AssetHubPara::events(); + println!("\nAssetHub events after contract call: {:?}", events); + assert_event_matches!( + events, + RuntimeEventAH::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) + if *asset_id == USDC && *owner == sov_pop_net_on_ahr && *balance == ah_transfer_amount + ); + assert_event_matches!( + events, + RuntimeEventAH::Assets(pallet_assets::Event::Issued { asset_id, owner, amount }) + if *asset_id == USDC && *owner == ah_receiver && *amount <= ah_transfer_amount && + *amount > 0 ); + assert_event_matches!( + events, + RuntimeEventAH::MessageQueue(pallet_message_queue::Event::Processed { success, .. }) + if *success == true + ); + + // Verify receiver’s USDC balance on AH + let receiver_usdc_balance = + <::Assets as Inspect<_>>::balance( + USDC, + &ah_receiver, + ); + assert!(receiver_usdc_balance == ah_transfer_amount); + }); } /// Reserve Transfers of native asset from Relay to Parachain should work @@ -477,7 +610,7 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { // fn place_coretime_spot_order_from_para_to_relay() { // init_tracing(); // -// let beneficiary: sp_runtime::AccountId32 = [1u8; 32].into(); +// let beneficiary: AccountId = [1u8; 32].into(); // // // Setup: reserve transfer from relay to Pop, so that sovereign account accurate for return // transfer let amount_to_send: Balance = pop_runtime::UNIT * 1000; @@ -485,7 +618,7 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { // // let message = { // let assets: Asset = (Here, 10 * pop_runtime::UNIT).into(); -// let beneficiary = AccountId32 { id: beneficiary.clone().into(), network: None }.into(); +// let beneficiary = AccountId { id: beneficiary.clone().into(), network: None }.into(); // let spot_order = ::RuntimeCall::OnDemandAssignmentProvider( // assigner_on_demand::Call::<::Runtime>::place_order_keep_alive { // max_amount: 1 * pop_runtime::UNIT, @@ -587,3 +720,66 @@ fn init_tracing() { .init(); }); } + +/// Asserts that an event has been emitted using pattern matching. +macro_rules! assert_event_matches { + ($expression:expr, $pattern:pat $(if $guard:expr)? $(,)?) => { + assert!($expression.iter().any(|e| matches!(e, $pattern $(if $guard)?)), "expected event not found in {:#?}", $expression); + }; +} +pub(crate) use assert_event_matches; + +fn asset_hub_to_para_transfer_assets(t: Test) -> DispatchResult { + ::PolkadotXcm::limited_reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + +fn asset_hub_to_para_assets_sender_assertions(t: Test) { + type RuntimeEvent = ::RuntimeEvent; + AssetHubPara::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( + 864_610_000, + 8_799, + ))); + let sovereign_account = AssetHubPara::sovereign_account_id_of(t.args.dest.clone()); + assert_event_matches!( + AssetHubPara::events(), + RuntimeEvent::Assets(pallet_assets::Event::Transferred { asset_id, from, to, amount }) + if *asset_id == USDC && *from == t.sender.account_id && *to == sovereign_account && *amount == t.args.amount + ); +} + +fn asset_hub_to_para_assets_receiver_assertions(t: Test) { + type RuntimeEvent = ::RuntimeEvent; + let events = PopNetworkPara::events(); + println!("PopNetwork events: {:?}", events); // Debug output + assert_event_matches!( + events, + RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, owner, amount }) + if *asset_id == USDC_POP_ASSET_ID && *owner == t.receiver.account_id && *amount == t.args.amount + ); + assert_event_matches!( + events, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success, .. }) + if *success == true + ); +} + +use codec::Decode; +use pallet_contracts::{Code, CollectEvents}; + +fn function_selector(name: &str) -> Vec { + let hash = sp_io::hashing::blake2_256(name.as_bytes()); + [hash[0..4].to_vec()].concat() +} + +fn decoded( + result: pallet_contracts::ExecReturnValue, +) -> Result { + ::decode(&mut &result.data[1..]).map_err(|_| result) +} diff --git a/pallets/asset-manager/src/benchmarks.rs b/pallets/asset-manager/src/benchmarks.rs index 27cb259d7..bc515335d 100644 --- a/pallets/asset-manager/src/benchmarks.rs +++ b/pallets/asset-manager/src/benchmarks.rs @@ -16,11 +16,12 @@ #![cfg(feature = "runtime-benchmarks")] -use crate::{Call, Config, Pallet}; use frame_benchmarking::{benchmarks, impl_benchmark_test_suite}; use frame_system::RawOrigin; use xcm::v3::prelude::*; +use crate::{Call, Config, Pallet}; + benchmarks! { // This where clause allows us to create ForeignAssetTypes where_clause { where T::ForeignAssetType: From } @@ -78,20 +79,15 @@ benchmarks! { #[cfg(test)] mod tests { - use crate::mock::Test; use sp_io::TestExternalities; use sp_runtime::BuildStorage; + use crate::mock::Test; + pub fn new_test_ext() -> TestExternalities { - let t = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap(); + let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); TestExternalities::new(t) } } -impl_benchmark_test_suite!( - Pallet, - crate::benchmarks::tests::new_test_ext(), - crate::mock::Test -); +impl_benchmark_test_suite!(Pallet, crate::benchmarks::tests::new_test_ext(), crate::mock::Test); diff --git a/pop-api/Cargo.toml b/pop-api/Cargo.toml index e3597236a..d62cc21fe 100644 --- a/pop-api/Cargo.toml +++ b/pop-api/Cargo.toml @@ -14,29 +14,30 @@ pop-primitives = { path = "../primitives", default-features = false } # Substrate. sp-io = { version = "38.0.0", default-features = false, features = [ - "disable_allocator", - "disable_oom", - "disable_panic_handler", + "disable_allocator", + "disable_oom", + "disable_panic_handler", ] } # ink! dependencies. ink = { version = "5.1.0", default-features = false } +#ink = { git = "https://github.com/use-ink/ink", branch = "xcm", default-features = false } [dev-dependencies] pallet-nfts = { path = "../pallets/nfts" } scale = { package = "parity-scale-codec", version = "3" } [lib] -crate-type = [ "rlib" ] +crate-type = ["rlib"] name = "pop_api" path = "src/lib.rs" [features] -default = [ "std" ] -fungibles = [ ] -nonfungibles = [ ] +default = ["std"] +fungibles = [] +nonfungibles = [] std = [ - "ink/std", - "pop-primitives/std", - "sp-io/std", + "ink/std", + "pop-primitives/std", + "sp-io/std", ] diff --git a/pop-api/examples/foreign_fungibles/Cargo.toml b/pop-api/examples/foreign_fungibles/Cargo.toml new file mode 100644 index 000000000..1121b143b --- /dev/null +++ b/pop-api/examples/foreign_fungibles/Cargo.toml @@ -0,0 +1,28 @@ +[package] +authors = ["R0GUE "] +edition = "2021" +name = "foreign_fungibles" +version = "0.1.0" + +[dependencies] +ink = { version = "5.1.0", default-features = false, features = ["ink-debug"] } +#ink = { git = "https://github.com/use-ink/ink", branch = "xcm", default-features = false } +pop-api = { path = "../../../pop-api", default-features = false, features = [ + "fungibles", +] } + +[dev-dependencies] +env_logger = { version = "0.11.3" } +serde_json = "1.0.114" + +[lib] +path = "lib.rs" + +[features] +default = ["std"] +e2e-tests = [] +ink-as-dependency = [] +std = [ + "ink/std", + "pop-api/std", +] diff --git a/pop-api/examples/foreign_fungibles/lib.rs b/pop-api/examples/foreign_fungibles/lib.rs new file mode 100644 index 000000000..a1bc6996c --- /dev/null +++ b/pop-api/examples/foreign_fungibles/lib.rs @@ -0,0 +1,109 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +use ink::{prelude::vec, xcm::prelude::*}; +use pop_api::{ + primitives::{AccountId, TokenId}, + v0::fungibles as api, +}; + +#[cfg(test)] +mod tests; + +#[ink::contract] +mod fungibles { + use ink::env::Error as EnvError; + + use super::*; + + #[ink(storage)] + pub struct Fungible { + id: TokenId, + } + + #[derive(Debug, PartialEq, Eq)] + #[ink::scale_derive(Encode, Decode, TypeInfo)] + pub enum Error { + TransferFailed, + AHTransferFailed, + } + + // Constants for USDC and Asset Hub + const ASSET_HUB_PARA_ID: u32 = 1000; + const ASSET_HUB_ASSETS_PALLET: u8 = 50; + const USDC_ASSET_ID_ON_AH: u128 = 1337; + const USDC_ASSET_ID_ON_POP: TokenId = 1; + + impl Fungible { + #[ink(constructor, payable)] + pub fn new() -> Self { + Self { id: USDC_ASSET_ID_ON_POP } + } + + #[ink(message)] + pub fn ah_transfer( + &mut self, + to: AccountId, + value: Balance, + fee: Balance, + ) -> Result<(), Error> { + // Define the destination (Asset Hub) + let destination = Location::new(1, [Parachain(ASSET_HUB_PARA_ID)]); + + // Define the beneficiary (the 'to' account on Asset Hub) + let beneficiary = Location::new(0, [AccountId32 { network: None, id: to.0.into() }]); + + // Define USDC asset location as seen from Pop Network (foreign asset from Asset Hub) + let usdc_location_on_pop = Location::new( + 1, + [ + Parachain(ASSET_HUB_PARA_ID), + PalletInstance(ASSET_HUB_ASSETS_PALLET), + GeneralIndex(USDC_ASSET_ID_ON_AH), + ], + ); + let usdc_asset_on_pop: Asset = (AssetId(usdc_location_on_pop.clone()), value).into(); + + // Define USDC asset location as seen from Asset Hub (local asset) + let usdc_location_on_ah = Location::new( + 0, + [PalletInstance(ASSET_HUB_ASSETS_PALLET), GeneralIndex(USDC_ASSET_ID_ON_AH)], + ); + let usdc_asset_on_ah: Asset = (AssetId(usdc_location_on_ah.clone()), value).into(); + + let fee_asset: Asset = (AssetId(Location::parent()), fee).into(); + + // XCM instructions to be executed on Asset Hub + let xcm_on_destination = Xcm(vec![ + // Buy execution with the DOT + BuyExecution { fees: fee_asset.clone(), weight_limit: WeightLimit::Unlimited }, + // Deposit USDC to the beneficiary + DepositAsset { assets: Wild(All.into()), beneficiary: beneficiary.clone() }, + ]); + + // Construct the full XCM message from Pop Network + let message: Xcm<()> = Xcm(vec![ + // Withdraw the USDC and DOT. + WithdrawAsset((vec![usdc_asset_on_pop.clone(), fee_asset.clone()]).into()), + // Initiate the reserve-based transfer to Asset Hub + InitiateReserveWithdraw { + assets: vec![usdc_asset_on_pop.clone(), fee_asset].into(), + reserve: destination.clone(), + xcm: xcm_on_destination, + }, + ]); + + // Execute the XCM message + self.env() + .xcm_execute(&VersionedXcm::V4(message)) + .map_err(|_| Error::AHTransferFailed)?; + + Ok(()) + } + + #[ink(message)] + pub fn transfer(&mut self, to: AccountId, value: Balance) -> Result<(), Error> { + api::transfer(self.id, to, value).map_err(|_| Error::TransferFailed)?; + Ok(()) + } + } +} diff --git a/runtime/devnet/src/config/xcm.rs b/runtime/devnet/src/config/xcm.rs index a61745009..01458db5f 100644 --- a/runtime/devnet/src/config/xcm.rs +++ b/runtime/devnet/src/config/xcm.rs @@ -27,6 +27,10 @@ use crate::{ XcmpQueue, }; +pub const ASSET_HUB: Junction = Parachain(1000); +/// Assets on Asset Hub. +pub const ASSET_HUB_ASSETS: Junction = PalletInstance(50); + parameter_types! { pub const RelayLocation: Location = Location::parent(); pub AssetHub: Location = Location::new(1, [Parachain(1000)]); @@ -37,6 +41,7 @@ parameter_types! { // and prepend `UniversalLocation` with `GlobalConsensus(RelayNetwork::get())`. pub UniversalLocation: InteriorLocation = Parachain(ParachainInfo::parachain_id().into()).into(); pub CheckAccount: AccountId = crate::PolkadotXcm::check_account(); + pub USDCAssetReserve: Location = Location::new(1, [ASSET_HUB, ASSET_HUB_ASSETS, GeneralIndex(1337)]); } /// Type for specifying how a `Location` can be converted into an `AccountId`. This is used @@ -172,8 +177,20 @@ impl ContainsPair for NativeAssetExceptRelay { } } +/// Asset filter that allows specific asset if coming from a certain location. +pub struct AssetFrom(PhantomData<(Asset, Origin)>); +impl, Origin: Get> ContainsPair + for AssetFrom +{ + fn contains(asset: &xcm::prelude::Asset, origin: &Location) -> bool { + log::trace!(target: "xcm::contains", "AssetFrom asset: {:?}, origin: {:?}", asset, origin); + *origin == Origin::get() && matches!(asset.id.clone(), AssetId(id) if id == Asset::get()) + } +} + /// Combinations of (Asset, Location) pairs which we trust as reserves. -pub type TrustedReserves = (NativeAssetFrom, NativeAssetExceptRelay); +pub type TrustedReserves = + (NativeAssetFrom, NativeAssetExceptRelay, AssetFrom); pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { From 79068d4e2a3b1763dcfd37c586d6e587af0ab1a4 Mon Sep 17 00:00:00 2001 From: Daanvdplas Date: Tue, 4 Mar 2025 14:01:13 +0100 Subject: [PATCH 7/7] fmt taplo --- Cargo.toml | 40 +-- integration-tests/Cargo.toml | 158 +++++----- pallets/asset-manager/Cargo.toml | 38 +-- pop-api/Cargo.toml | 20 +- pop-api/examples/foreign_fungibles/Cargo.toml | 16 +- runtime/devnet/Cargo.toml | 292 +++++++++--------- 6 files changed, 282 insertions(+), 282 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4eb341741..540809762 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ inherits = "release" lto = true [workspace.package] -authors = ["R0GUE "] +authors = [ "R0GUE " ] description = "Pop Network makes it easy for smart contract developers to use the Power of Polkadot." edition = "2021" homepage = "https://r0gue.io" @@ -16,28 +16,28 @@ repository = "https://github.com/r0gue-io/pop-node/" [workspace] exclude = [ - "extension/contract", - "pop-api", - "tests/contracts", + "extension/contract", + "pop-api", + "tests/contracts", ] members = [ - "integration-tests", - "node", - "pallets/*", - "pop-api/integration-tests", - "primitives", - "runtime/devnet", - "runtime/mainnet", - "runtime/testnet", + "integration-tests", + "node", + "pallets/*", + "pop-api/integration-tests", + "primitives", + "runtime/devnet", + "runtime/mainnet", + "runtime/testnet", ] resolver = "2" [workspace.dependencies] anyhow = { version = "1.0", default-features = false } -clap = { version = "4.5.10", features = ["derive"] } +clap = { version = "4.5.10", features = [ "derive" ] } codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ - "derive", + "derive", ] } color-print = "0.3.4" contract-build = "5.0.2" @@ -48,18 +48,18 @@ futures = "0.3.30" hex = "0.4.3" hex-literal = "0.4.1" impl-trait-for-tuples = "0.2.2" -jsonrpsee = { version = "0.24.3", features = ["server"] } +jsonrpsee = { version = "0.24.3", features = [ "server" ] } log = { version = "0.4.22", default-features = false } rand = "0.8.5" scale-info = { version = "2.11.1", default-features = false, features = [ - "derive", + "derive", ] } serde = "1.0.209" serde_json = "1.0.127" smallvec = "1.11.2" subxt = "0.38.0" subxt-signer = "0.38.0" -tokio = { version = "1.36", features = ["macros", "rt-multi-thread", "time"] } +tokio = { version = "1.36", features = [ "macros", "rt-multi-thread", "time" ] } tracing-subscriber = { version = "0.3.18", default-features = false } # Build @@ -73,9 +73,9 @@ pallet-nfts = { path = "pallets/nfts", default-features = false } pop-chain-extension = { path = "./extension", default-features = false } pop-primitives = { path = "./primitives", default-features = false } pop-runtime-common = { path = "runtime/common", default-features = false } -pop-runtime-devnet = { path = "runtime/devnet", default-features = true } # default-features=true required for `-p pop-node` builds -pop-runtime-mainnet = { path = "runtime/mainnet", default-features = true } # default-features=true required for `-p pop-node` builds -pop-runtime-testnet = { path = "runtime/testnet", default-features = true } # default-features=true required for `-p pop-node` builds +pop-runtime-devnet = { path = "runtime/devnet", default-features = true } # default-features=true required for `-p pop-node` builds +pop-runtime-mainnet = { path = "runtime/mainnet", default-features = true } # default-features=true required for `-p pop-node` builds +pop-runtime-testnet = { path = "runtime/testnet", default-features = true } # default-features=true required for `-p pop-node` builds # Substrate frame-benchmarking = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false } diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index a46913b15..eefd46477 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -8,13 +8,13 @@ repository.workspace = true [dependencies] codec.workspace = true +log.workspace = true tracing-subscriber = { workspace = true, features = [ - "env-filter", - "fmt", - "std", - "tracing-log", + "env-filter", + "fmt", + "std", + "tracing-log", ] } -log.workspace = true # Substrate frame-support.workspace = true @@ -28,9 +28,9 @@ sp-consensus-babe.workspace = true sp-consensus-beefy.workspace = true sp-consensus-grandpa.workspace = true sp-core.workspace = true +sp-io.workspace = true sp-keyring.workspace = true sp-runtime.workspace = true -sp-io.workspace = true # Polkadot pallet-xcm.workspace = true @@ -59,86 +59,86 @@ pop-runtime-mainnet.workspace = true pop-runtime-testnet.workspace = true [features] -default = ["std"] -devnet = ["pop-runtime-devnet/std"] -mainnet = ["pop-runtime-mainnet/std"] +default = [ "std" ] +devnet = [ "pop-runtime-devnet/std" ] +mainnet = [ "pop-runtime-mainnet/std" ] paseo = [ - "asset-hub-paseo-runtime", - "paseo-runtime", - "paseo-runtime-constants", + "asset-hub-paseo-runtime", + "paseo-runtime", + "paseo-runtime-constants", ] runtime-benchmarks = [ - "asset-hub-paseo-runtime?/runtime-benchmarks", - "asset-hub-westend-runtime?/runtime-benchmarks", - "cumulus-primitives-core/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "pallet-assets/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "pallet-contracts/runtime-benchmarks", - "pallet-message-queue/runtime-benchmarks", - "pallet-xcm/runtime-benchmarks", - "paseo-runtime?/runtime-benchmarks", - "polkadot-primitives/runtime-benchmarks", - "polkadot-runtime-parachains/runtime-benchmarks", - "pop-runtime-common/runtime-benchmarks", - "pop-runtime-devnet/runtime-benchmarks", - "pop-runtime-mainnet/runtime-benchmarks", - "pop-runtime-testnet/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", - "westend-runtime?/runtime-benchmarks", - "xcm-executor/runtime-benchmarks", + "asset-hub-paseo-runtime?/runtime-benchmarks", + "asset-hub-westend-runtime?/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-contracts/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "paseo-runtime?/runtime-benchmarks", + "polkadot-primitives/runtime-benchmarks", + "polkadot-runtime-parachains/runtime-benchmarks", + "pop-runtime-common/runtime-benchmarks", + "pop-runtime-devnet/runtime-benchmarks", + "pop-runtime-mainnet/runtime-benchmarks", + "pop-runtime-testnet/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "westend-runtime?/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", ] std = [ - "asset-hub-paseo-runtime?/std", - "asset-hub-westend-runtime?/std", - "asset-test-utils/std", - "codec/std", - "cumulus-primitives-core/std", - "frame-support/std", - "pallet-assets/std", - "pallet-balances/std", - "pallet-contracts/std", - "pallet-message-queue/std", - "pallet-xcm/std", - "paseo-runtime-constants?/std", - "paseo-runtime?/std", - "polkadot-primitives/std", - "polkadot-runtime-parachains/std", - "pop-runtime-common/std", - "pop-runtime-devnet/std", - "pop-runtime-mainnet/std", - "sp-authority-discovery/std", - "sp-consensus-aura/std", - "sp-consensus-babe/std", - "sp-consensus-beefy/std", - "sp-consensus-grandpa/std", - "sp-core/std", - "sp-io/std", - "sp-runtime/std", - "tracing-subscriber/std", - "westend-runtime-constants?/std", - "westend-runtime?/std", - "xcm-executor/std", - "xcm/std", + "asset-hub-paseo-runtime?/std", + "asset-hub-westend-runtime?/std", + "asset-test-utils/std", + "codec/std", + "cumulus-primitives-core/std", + "frame-support/std", + "pallet-assets/std", + "pallet-balances/std", + "pallet-contracts/std", + "pallet-message-queue/std", + "pallet-xcm/std", + "paseo-runtime-constants?/std", + "paseo-runtime?/std", + "polkadot-primitives/std", + "polkadot-runtime-parachains/std", + "pop-runtime-common/std", + "pop-runtime-devnet/std", + "pop-runtime-mainnet/std", + "sp-authority-discovery/std", + "sp-consensus-aura/std", + "sp-consensus-babe/std", + "sp-consensus-beefy/std", + "sp-consensus-grandpa/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "tracing-subscriber/std", + "westend-runtime-constants?/std", + "westend-runtime?/std", + "xcm-executor/std", + "xcm/std", ] -testnet = ["pop-runtime-testnet/std"] +testnet = [ "pop-runtime-testnet/std" ] try-runtime = [ - "asset-hub-paseo-runtime?/try-runtime", - "asset-hub-westend-runtime?/try-runtime", - "frame-support/try-runtime", - "pallet-assets/try-runtime", - "pallet-balances/std", - "pallet-contracts/try-runtime", - "pallet-message-queue/try-runtime", - "paseo-runtime?/try-runtime", - "pop-runtime-devnet/try-runtime", - "pop-runtime-mainnet/try-runtime", - "pop-runtime-testnet/try-runtime", - "sp-runtime/try-runtime", - "westend-runtime?/try-runtime", + "asset-hub-paseo-runtime?/try-runtime", + "asset-hub-westend-runtime?/try-runtime", + "frame-support/try-runtime", + "pallet-assets/try-runtime", + "pallet-balances/std", + "pallet-contracts/try-runtime", + "pallet-message-queue/try-runtime", + "paseo-runtime?/try-runtime", + "pop-runtime-devnet/try-runtime", + "pop-runtime-mainnet/try-runtime", + "pop-runtime-testnet/try-runtime", + "sp-runtime/try-runtime", + "westend-runtime?/try-runtime", ] westend = [ - "asset-hub-westend-runtime", - "westend-runtime", - "westend-runtime-constants", + "asset-hub-westend-runtime", + "westend-runtime", + "westend-runtime-constants", ] diff --git a/pallets/asset-manager/Cargo.toml b/pallets/asset-manager/Cargo.toml index 6e1dfbbb5..d9550b5b4 100644 --- a/pallets/asset-manager/Cargo.toml +++ b/pallets/asset-manager/Cargo.toml @@ -1,7 +1,7 @@ [package] -name = "pallet-asset-manager" authors = { workspace = true } edition = "2021" +name = "pallet-asset-manager" version = "0.1.0" [dependencies] @@ -9,10 +9,10 @@ log = { workspace = true } serde = { workspace = true, optional = true } # Substrate +codec = { workspace = true, features = [ "derive" ] } frame-support = { workspace = true } frame-system = { workspace = true } -codec = { workspace = true, features = ["derive"] } -scale-info = { workspace = true, features = ["derive"] } +scale-info = { workspace = true, features = [ "derive" ] } sp-io = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } @@ -26,24 +26,24 @@ xcm-executor = { workspace = true } frame-benchmarking = { workspace = true, optional = true } [dev-dependencies] -pallet-balances = { workspace = true, features = ["insecure_zero_ed", "std"] } -sp-core = { workspace = true, features = ["std"] } +pallet-balances = { workspace = true, features = [ "insecure_zero_ed", "std" ] } +sp-core = { workspace = true, features = [ "std" ] } [features] -default = ["std"] +default = [ "std" ] std = [ - "frame-support/std", - "frame-system/std", - "codec/std", - "scale-info/std", - "serde", - "sp-io/std", - "sp-runtime/std", - "sp-std/std", - "xcm/std", - "xcm-builder/std", - "xcm-executor/std", + "codec/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "serde", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", + "xcm-builder/std", + "xcm-executor/std", + "xcm/std", ] -runtime-benchmarks = ["frame-benchmarking"] -try-runtime = ["frame-support/try-runtime"] +runtime-benchmarks = [ "frame-benchmarking" ] +try-runtime = [ "frame-support/try-runtime" ] diff --git a/pop-api/Cargo.toml b/pop-api/Cargo.toml index d62cc21fe..80962774f 100644 --- a/pop-api/Cargo.toml +++ b/pop-api/Cargo.toml @@ -14,9 +14,9 @@ pop-primitives = { path = "../primitives", default-features = false } # Substrate. sp-io = { version = "38.0.0", default-features = false, features = [ - "disable_allocator", - "disable_oom", - "disable_panic_handler", + "disable_allocator", + "disable_oom", + "disable_panic_handler", ] } # ink! dependencies. @@ -28,16 +28,16 @@ pallet-nfts = { path = "../pallets/nfts" } scale = { package = "parity-scale-codec", version = "3" } [lib] -crate-type = ["rlib"] +crate-type = [ "rlib" ] name = "pop_api" path = "src/lib.rs" [features] -default = ["std"] -fungibles = [] -nonfungibles = [] +default = [ "std" ] +fungibles = [ ] +nonfungibles = [ ] std = [ - "ink/std", - "pop-primitives/std", - "sp-io/std", + "ink/std", + "pop-primitives/std", + "sp-io/std", ] diff --git a/pop-api/examples/foreign_fungibles/Cargo.toml b/pop-api/examples/foreign_fungibles/Cargo.toml index 1121b143b..130e535d5 100644 --- a/pop-api/examples/foreign_fungibles/Cargo.toml +++ b/pop-api/examples/foreign_fungibles/Cargo.toml @@ -1,14 +1,14 @@ [package] -authors = ["R0GUE "] +authors = [ "R0GUE " ] edition = "2021" name = "foreign_fungibles" version = "0.1.0" [dependencies] -ink = { version = "5.1.0", default-features = false, features = ["ink-debug"] } +ink = { version = "5.1.0", default-features = false, features = [ "ink-debug" ] } #ink = { git = "https://github.com/use-ink/ink", branch = "xcm", default-features = false } pop-api = { path = "../../../pop-api", default-features = false, features = [ - "fungibles", + "fungibles", ] } [dev-dependencies] @@ -19,10 +19,10 @@ serde_json = "1.0.114" path = "lib.rs" [features] -default = ["std"] -e2e-tests = [] -ink-as-dependency = [] +default = [ "std" ] +e2e-tests = [ ] +ink-as-dependency = [ ] std = [ - "ink/std", - "pop-api/std", + "ink/std", + "pop-api/std", ] diff --git a/runtime/devnet/Cargo.toml b/runtime/devnet/Cargo.toml index 28b987fe9..dd3f93ef0 100644 --- a/runtime/devnet/Cargo.toml +++ b/runtime/devnet/Cargo.toml @@ -9,7 +9,7 @@ repository.workspace = true version = "0.1.0" [package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] +targets = [ "x86_64-unknown-linux-gnu" ] [build-dependencies] substrate-wasm-builder = { workspace = true, optional = true } @@ -98,7 +98,7 @@ parachains-common.workspace = true ismp.workspace = true ismp-parachain.workspace = true ismp-parachain-runtime-api.workspace = true -pallet-ismp = { workspace = true, features = ["unsigned"] } +pallet-ismp = { workspace = true, features = [ "unsigned" ] } pallet-ismp-runtime-api.workspace = true [dev-dependencies] @@ -108,155 +108,155 @@ hex.workspace = true sp-keyring.workspace = true [features] -default = ["std"] +default = [ "std" ] std = [ - "codec/std", - "cumulus-pallet-aura-ext/std", - "cumulus-pallet-parachain-system/std", - "cumulus-pallet-session-benchmarking/std", - "cumulus-pallet-xcm/std", - "cumulus-pallet-xcmp-queue/std", - "cumulus-primitives-aura/std", - "cumulus-primitives-core/std", - "cumulus-primitives-storage-weight-reclaim/std", - "cumulus-primitives-utility/std", - "enumflags2/std", - "frame-benchmarking/std", - "frame-executive/std", - "frame-metadata-hash-extension/std", - "frame-support/std", - "frame-system-benchmarking/std", - "frame-system-rpc-runtime-api/std", - "frame-system/std", - "frame-try-runtime/std", - "ismp-parachain-runtime-api/std", - "ismp-parachain/std", - "ismp/std", - "log/std", - "pallet-api/std", - "pallet-assets/std", - "pallet-asset-manager/std", - "pallet-aura/std", - "pallet-authorship/std", - "pallet-balances/std", - "pallet-collator-selection/std", - "pallet-contracts/std", - "pallet-ismp-runtime-api/std", - "pallet-ismp/std", - "pallet-message-queue/std", - "pallet-multisig/std", - "pallet-nft-fractionalization/std", - "pallet-nfts-runtime-api/std", - "pallet-nfts/std", - "pallet-preimage/std", - "pallet-proxy/std", - "pallet-scheduler/std", - "pallet-session/std", - "pallet-sudo/std", - "pallet-timestamp/std", - "pallet-transaction-payment-rpc-runtime-api/std", - "pallet-transaction-payment/std", - "pallet-utility/std", - "pallet-xcm/std", - "parachain-info/std", - "parachains-common/std", - "polkadot-parachain-primitives/std", - "polkadot-runtime-common/std", - "pop-chain-extension/std", - "pop-primitives/std", - "pop-runtime-common/std", - "scale-info/std", - "sp-api/std", - "sp-block-builder/std", - "sp-consensus-aura/std", - "sp-core/std", - "sp-genesis-builder/std", - "sp-inherents/std", - "sp-io/std", - "sp-mmr-primitives/std", - "sp-offchain/std", - "sp-runtime/std", - "sp-session/std", - "sp-transaction-pool/std", - "sp-version/std", - "substrate-wasm-builder", - "xcm-builder/std", - "xcm-executor/std", - "xcm/std", + "codec/std", + "cumulus-pallet-aura-ext/std", + "cumulus-pallet-parachain-system/std", + "cumulus-pallet-session-benchmarking/std", + "cumulus-pallet-xcm/std", + "cumulus-pallet-xcmp-queue/std", + "cumulus-primitives-aura/std", + "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", + "cumulus-primitives-utility/std", + "enumflags2/std", + "frame-benchmarking/std", + "frame-executive/std", + "frame-metadata-hash-extension/std", + "frame-support/std", + "frame-system-benchmarking/std", + "frame-system-rpc-runtime-api/std", + "frame-system/std", + "frame-try-runtime/std", + "ismp-parachain-runtime-api/std", + "ismp-parachain/std", + "ismp/std", + "log/std", + "pallet-api/std", + "pallet-asset-manager/std", + "pallet-assets/std", + "pallet-aura/std", + "pallet-authorship/std", + "pallet-balances/std", + "pallet-collator-selection/std", + "pallet-contracts/std", + "pallet-ismp-runtime-api/std", + "pallet-ismp/std", + "pallet-message-queue/std", + "pallet-multisig/std", + "pallet-nft-fractionalization/std", + "pallet-nfts-runtime-api/std", + "pallet-nfts/std", + "pallet-preimage/std", + "pallet-proxy/std", + "pallet-scheduler/std", + "pallet-session/std", + "pallet-sudo/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + "pallet-utility/std", + "pallet-xcm/std", + "parachain-info/std", + "parachains-common/std", + "polkadot-parachain-primitives/std", + "polkadot-runtime-common/std", + "pop-chain-extension/std", + "pop-primitives/std", + "pop-runtime-common/std", + "scale-info/std", + "sp-api/std", + "sp-block-builder/std", + "sp-consensus-aura/std", + "sp-core/std", + "sp-genesis-builder/std", + "sp-inherents/std", + "sp-io/std", + "sp-mmr-primitives/std", + "sp-offchain/std", + "sp-runtime/std", + "sp-session/std", + "sp-transaction-pool/std", + "sp-version/std", + "substrate-wasm-builder", + "xcm-builder/std", + "xcm-executor/std", + "xcm/std", ] runtime-benchmarks = [ - "cumulus-pallet-parachain-system/runtime-benchmarks", - "cumulus-pallet-session-benchmarking/runtime-benchmarks", - "cumulus-pallet-xcmp-queue/runtime-benchmarks", - "cumulus-primitives-core/runtime-benchmarks", - "cumulus-primitives-utility/runtime-benchmarks", - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system-benchmarking/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "pallet-api/runtime-benchmarks", - "pallet-assets/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "pallet-collator-selection/runtime-benchmarks", - "pallet-contracts/runtime-benchmarks", - "pallet-ismp/runtime-benchmarks", - "pallet-message-queue/runtime-benchmarks", - "pallet-multisig/runtime-benchmarks", - "pallet-nft-fractionalization/runtime-benchmarks", - "pallet-nfts/runtime-benchmarks", - "pallet-preimage/runtime-benchmarks", - "pallet-proxy/runtime-benchmarks", - "pallet-scheduler/runtime-benchmarks", - "pallet-sudo/runtime-benchmarks", - "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", - "pallet-utility/runtime-benchmarks", - "pallet-xcm/runtime-benchmarks", - "parachains-common/runtime-benchmarks", - "polkadot-parachain-primitives/runtime-benchmarks", - "polkadot-runtime-common/runtime-benchmarks", - "pop-chain-extension/runtime-benchmarks", - "pop-runtime-common/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", - "xcm-builder/runtime-benchmarks", - "xcm-executor/runtime-benchmarks", + "cumulus-pallet-parachain-system/runtime-benchmarks", + "cumulus-pallet-session-benchmarking/runtime-benchmarks", + "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", + "cumulus-primitives-utility/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system-benchmarking/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-api/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-collator-selection/runtime-benchmarks", + "pallet-contracts/runtime-benchmarks", + "pallet-ismp/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", + "pallet-multisig/runtime-benchmarks", + "pallet-nft-fractionalization/runtime-benchmarks", + "pallet-nfts/runtime-benchmarks", + "pallet-preimage/runtime-benchmarks", + "pallet-proxy/runtime-benchmarks", + "pallet-scheduler/runtime-benchmarks", + "pallet-sudo/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", + "pallet-utility/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "parachains-common/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", + "polkadot-runtime-common/runtime-benchmarks", + "pop-chain-extension/runtime-benchmarks", + "pop-runtime-common/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", ] try-runtime = [ - "cumulus-pallet-aura-ext/try-runtime", - "cumulus-pallet-parachain-system/try-runtime", - "cumulus-pallet-xcm/try-runtime", - "cumulus-pallet-xcmp-queue/try-runtime", - "frame-executive/try-runtime", - "frame-support/try-runtime", - "frame-system/try-runtime", - "frame-try-runtime/try-runtime", - "ismp-parachain/try-runtime", - "pallet-api/try-runtime", - "pallet-assets/try-runtime", - "pallet-aura/try-runtime", - "pallet-authorship/try-runtime", - "pallet-balances/try-runtime", - "pallet-collator-selection/try-runtime", - "pallet-contracts/try-runtime", - "pallet-ismp/try-runtime", - "pallet-message-queue/try-runtime", - "pallet-multisig/try-runtime", - "pallet-nft-fractionalization/try-runtime", - "pallet-nfts/try-runtime", - "pallet-preimage/try-runtime", - "pallet-proxy/try-runtime", - "pallet-scheduler/try-runtime", - "pallet-session/try-runtime", - "pallet-sudo/try-runtime", - "pallet-timestamp/try-runtime", - "pallet-transaction-payment/try-runtime", - "pallet-utility/try-runtime", - "pallet-xcm/try-runtime", - "parachain-info/try-runtime", - "polkadot-runtime-common/try-runtime", - "sp-runtime/try-runtime", + "cumulus-pallet-aura-ext/try-runtime", + "cumulus-pallet-parachain-system/try-runtime", + "cumulus-pallet-xcm/try-runtime", + "cumulus-pallet-xcmp-queue/try-runtime", + "frame-executive/try-runtime", + "frame-support/try-runtime", + "frame-system/try-runtime", + "frame-try-runtime/try-runtime", + "ismp-parachain/try-runtime", + "pallet-api/try-runtime", + "pallet-assets/try-runtime", + "pallet-aura/try-runtime", + "pallet-authorship/try-runtime", + "pallet-balances/try-runtime", + "pallet-collator-selection/try-runtime", + "pallet-contracts/try-runtime", + "pallet-ismp/try-runtime", + "pallet-message-queue/try-runtime", + "pallet-multisig/try-runtime", + "pallet-nft-fractionalization/try-runtime", + "pallet-nfts/try-runtime", + "pallet-preimage/try-runtime", + "pallet-proxy/try-runtime", + "pallet-scheduler/try-runtime", + "pallet-session/try-runtime", + "pallet-sudo/try-runtime", + "pallet-timestamp/try-runtime", + "pallet-transaction-payment/try-runtime", + "pallet-utility/try-runtime", + "pallet-xcm/try-runtime", + "parachain-info/try-runtime", + "polkadot-runtime-common/try-runtime", + "sp-runtime/try-runtime", ] # Enable the metadata hash generation. @@ -266,8 +266,8 @@ try-runtime = [ # generate the metadata hash and then a second time with the # `RUNTIME_METADATA_HASH` environment variable set for the `CheckMetadataHash` # extension. -metadata-hash = ["substrate-wasm-builder/metadata-hash"] +metadata-hash = [ "substrate-wasm-builder/metadata-hash" ] # A convenience feature for enabling things when doing a build # for an on-chain release. -on-chain-release-build = ["metadata-hash"] +on-chain-release-build = [ "metadata-hash" ]