mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 08:11:03 +00:00
Add Support for Foreign Assets (#2133)
* add foreign assets to westmint * add foreign assets to statemine * use updated api for ensure origin trait * Assets/ForeignAssets tests and fixes (#2167) * Test for create and transfer `TrustBackedAssets` with AssetTransactor * Test for transfer `local Currency` with AssetTransactor * Test for create foreign assets (covers foreign relaychain currency) * Added `ForeignFungiblesTransactor` and test for transfer `ForeignAssets` with AssetTransactor * Removed unused `pub const Local: MultiLocation` * Changed `ParaId -> Sibling` for `SiblingParachainConvertsVia` * Test for create foreign assets (covers local sibling parachain assets) * Reverted stuff for ForeignCreators from different global consensus (moved to transfer asset branch) * Refactor `weight_limit` for `execute_xcm` * Added test for `set_metadata` by ForeignCreator with `xcm::Transact(set_metadata)` * Renamed `receive_teleported_asset_works` -> `receive_teleported_asset_for_native_asset_works` * Allow `ForeignCreators` only for sibling parachains * Unify ReservedDmpWeight/ReservedXcmpWeight usage * Removed hack - replaced with `MatchedConvertedConcreteId` * Refactor `ForeignCreators` to assets-common * Add `ReceiveTeleportedAsset` test * Change test - `Utility::batch` -> Multiple `xcm::Transact` * Reusing the same deposits as for TrustBackedAssets * missing `try_successful_origin` ? * Finished `ForeignAssets` for westmint (converter, FungiblesApi, tests) * Refactoring tests - receive_teleported_asset_for_native_asset_works * ForeignAssets for statemine + refactored `receive_teleported_asset_from_foreign_creator_works` * Add `ForeignAssets` to statemine `FungiblesApi` * Add `asset_transactor_transfer_with_local_consensus_currency_works` to all runtimes * Added `asset_transactor_transfer_with_trust_backed_assets_works` test * Added `asset_transactor_transfer_with_foreign_assets_works` * Fix `missing `try_successful_origin` in implementation` * Added `create_and_manage_foreign_assets_for_local_consensus_parachain_assets_works` * Added `ExpectTransactStatus` check * Small rename * Extended `test_assets_balances_api_works` with ForeignAssets for `statemine` * PR fixes * Update parachains/runtimes/assets/test-utils/src/test_cases.rs --------- Co-authored-by: parity-processbot <> Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Added `StartsWithExplicitGlobalConsensus` to ignores (#2338) * Update parachains/runtimes/assets/common/src/lib.rs Co-authored-by: Gavin Wood <gavin@parity.io> * include mint and burn in SafeCallFilter * include mint and burn in SafeCallFilter (statemine) * clarify doc * Fix compilation (moved trait `InspectMetadata`) * Fix test * Extended test for `teleport` from/to relaychain + `CheckingAccount` (Part I) * Extended test for `teleport` from/to foreign parachain + `CheckingAccount` (Part II) * Fixed TODO - `NonLocal` for `ForeignAssets` * Changed `NonLocal` to `NoChecking` * Fix weight in test --------- Co-authored-by: parity-processbot <> Co-authored-by: muharem <ismailov.m.h@gmail.com> Co-authored-by: Branislav Kontur <bkontur@gmail.com> Co-authored-by: Gavin Wood <gavin@parity.io>
This commit is contained in:
Generated
+16
@@ -334,26 +334,42 @@ checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9"
|
|||||||
name = "asset-test-utils"
|
name = "asset-test-utils"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"assets-common",
|
||||||
|
"cumulus-pallet-parachain-system",
|
||||||
|
"cumulus-pallet-xcmp-queue",
|
||||||
|
"cumulus-primitives-core",
|
||||||
|
"cumulus-primitives-parachain-inherent",
|
||||||
|
"cumulus-test-relay-sproof-builder",
|
||||||
"frame-support",
|
"frame-support",
|
||||||
"frame-system",
|
"frame-system",
|
||||||
"hex-literal",
|
"hex-literal",
|
||||||
|
"pallet-assets",
|
||||||
"pallet-balances",
|
"pallet-balances",
|
||||||
"pallet-collator-selection",
|
"pallet-collator-selection",
|
||||||
"pallet-session",
|
"pallet-session",
|
||||||
|
"pallet-xcm",
|
||||||
|
"parachain-info",
|
||||||
"parachains-common",
|
"parachains-common",
|
||||||
|
"parity-scale-codec",
|
||||||
|
"polkadot-parachain",
|
||||||
"sp-consensus-aura",
|
"sp-consensus-aura",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-io",
|
"sp-io",
|
||||||
"sp-runtime",
|
"sp-runtime",
|
||||||
"sp-std",
|
"sp-std",
|
||||||
"substrate-wasm-builder",
|
"substrate-wasm-builder",
|
||||||
|
"xcm",
|
||||||
|
"xcm-executor",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "assets-common"
|
name = "assets-common"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cumulus-primitives-core",
|
||||||
"frame-support",
|
"frame-support",
|
||||||
|
"log",
|
||||||
|
"pallet-xcm",
|
||||||
"parachains-common",
|
"parachains-common",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"sp-api",
|
"sp-api",
|
||||||
|
|||||||
@@ -95,6 +95,18 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Allow checking in assets that exists.
|
||||||
|
pub struct AssetExists<AccountId, Assets>(PhantomData<(AccountId, Assets)>);
|
||||||
|
impl<AccountId, Assets> Contains<<Assets as fungibles::Inspect<AccountId>>::AssetId>
|
||||||
|
for AssetExists<AccountId, Assets>
|
||||||
|
where
|
||||||
|
Assets: fungibles::Inspect<AccountId>,
|
||||||
|
{
|
||||||
|
fn contains(id: &<Assets as fungibles::Inspect<AccountId>>::AssetId) -> bool {
|
||||||
|
Assets::asset_exists(*id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Asset filter that allows all assets from a certain location.
|
/// Asset filter that allows all assets from a certain location.
|
||||||
pub struct AssetsFrom<T>(PhantomData<T>);
|
pub struct AssetsFrom<T>(PhantomData<T>);
|
||||||
impl<T: Get<MultiLocation>> ContainsPair<MultiAsset, MultiLocation> for AssetsFrom<T> {
|
impl<T: Get<MultiLocation>> ContainsPair<MultiAsset, MultiLocation> for AssetsFrom<T> {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ description = "Assets common utilities"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] }
|
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] }
|
||||||
|
log = { version = "0.4.17", default-features = false }
|
||||||
|
|
||||||
# Substrate
|
# Substrate
|
||||||
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||||
@@ -14,12 +15,14 @@ sp-api = { git = "https://github.com/paritytech/substrate", default-features = f
|
|||||||
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||||
|
|
||||||
# Polkadot
|
# Polkadot
|
||||||
|
pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
|
||||||
xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
|
xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
|
||||||
xcm-builder = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
|
xcm-builder = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
|
||||||
xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
|
xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
|
||||||
|
|
||||||
# Cumulus
|
# Cumulus
|
||||||
parachains-common = { path = "../../../common", default-features = false }
|
parachains-common = { path = "../../../common", default-features = false }
|
||||||
|
cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
@@ -28,11 +31,20 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran
|
|||||||
default = [ "std" ]
|
default = [ "std" ]
|
||||||
std = [
|
std = [
|
||||||
"codec/std",
|
"codec/std",
|
||||||
|
"log/std",
|
||||||
"frame-support/std",
|
"frame-support/std",
|
||||||
"parachains-common/std",
|
"parachains-common/std",
|
||||||
|
"cumulus-primitives-core/std",
|
||||||
"sp-api/std",
|
"sp-api/std",
|
||||||
"sp-std/std",
|
"sp-std/std",
|
||||||
|
"pallet-xcm/std",
|
||||||
"xcm/std",
|
"xcm/std",
|
||||||
"xcm-builder/std",
|
"xcm-builder/std",
|
||||||
"xcm-executor/std",
|
"xcm-executor/std",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
runtime-benchmarks = [
|
||||||
|
"frame-support/runtime-benchmarks",
|
||||||
|
"pallet-xcm/runtime-benchmarks",
|
||||||
|
"xcm-builder/runtime-benchmarks",
|
||||||
|
]
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
// Copyright (C) 2023 Parity Technologies (UK) Ltd.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
use frame_support::traits::{
|
||||||
|
ContainsPair, EnsureOrigin, EnsureOriginWithArg, Everything, OriginTrait,
|
||||||
|
};
|
||||||
|
use pallet_xcm::{EnsureXcm, Origin as XcmOrigin};
|
||||||
|
use xcm::latest::MultiLocation;
|
||||||
|
use xcm_executor::traits::Convert;
|
||||||
|
|
||||||
|
// `EnsureOriginWithArg` impl for `CreateOrigin` that allows only XCM origins that are locations
|
||||||
|
// containing the class location.
|
||||||
|
pub struct ForeignCreators<IsForeign, AccountOf, AccountId>(
|
||||||
|
sp_std::marker::PhantomData<(IsForeign, AccountOf, AccountId)>,
|
||||||
|
);
|
||||||
|
impl<
|
||||||
|
IsForeign: ContainsPair<MultiLocation, MultiLocation>,
|
||||||
|
AccountOf: Convert<MultiLocation, AccountId>,
|
||||||
|
AccountId: Clone,
|
||||||
|
RuntimeOrigin: From<XcmOrigin> + OriginTrait + Clone,
|
||||||
|
> EnsureOriginWithArg<RuntimeOrigin, MultiLocation>
|
||||||
|
for ForeignCreators<IsForeign, AccountOf, AccountId>
|
||||||
|
where
|
||||||
|
RuntimeOrigin::PalletsOrigin:
|
||||||
|
From<XcmOrigin> + TryInto<XcmOrigin, Error = RuntimeOrigin::PalletsOrigin>,
|
||||||
|
{
|
||||||
|
type Success = AccountId;
|
||||||
|
|
||||||
|
fn try_origin(
|
||||||
|
origin: RuntimeOrigin,
|
||||||
|
asset_location: &MultiLocation,
|
||||||
|
) -> sp_std::result::Result<Self::Success, RuntimeOrigin> {
|
||||||
|
let origin_location = EnsureXcm::<Everything>::try_origin(origin.clone())?;
|
||||||
|
if !IsForeign::contains(&asset_location, &origin_location) {
|
||||||
|
return Err(origin)
|
||||||
|
}
|
||||||
|
AccountOf::convert(origin_location).map_err(|_| origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "runtime-benchmarks")]
|
||||||
|
fn try_successful_origin(a: &MultiLocation) -> Result<RuntimeOrigin, ()> {
|
||||||
|
Ok(pallet_xcm::Origin::Xcm(a.clone()).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,27 +1,25 @@
|
|||||||
// This file is part of Substrate.
|
// Copyright (C) 2023 Parity Technologies (UK) Ltd.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd.
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
// This program is free software: you can redistribute it and/or modify
|
//
|
||||||
// it under the terms of the GNU General Public License as published by
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
//
|
||||||
// (at your option) any later version.
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// This program is distributed in the hope that it will be useful,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// See the License for the specific language governing permissions and
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// limitations under the License.
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
//! Runtime API definition for assets.
|
//! Runtime API definition for assets.
|
||||||
|
|
||||||
use crate::runtime_api::FungiblesAccessError;
|
use crate::runtime_api::FungiblesAccessError;
|
||||||
|
use frame_support::traits::Contains;
|
||||||
use sp_std::{borrow::Borrow, vec::Vec};
|
use sp_std::{borrow::Borrow, vec::Vec};
|
||||||
use xcm::latest::{MultiAsset, MultiLocation};
|
use xcm::latest::{MultiAsset, MultiLocation};
|
||||||
use xcm_builder::ConvertedConcreteId;
|
use xcm_builder::{ConvertedConcreteId, MatchedConvertedConcreteId};
|
||||||
use xcm_executor::traits::{Convert, MatchesFungibles};
|
use xcm_executor::traits::{Convert, MatchesFungibles};
|
||||||
|
|
||||||
/// Converting any [`(AssetId, Balance)`] to [`MultiAsset`]
|
/// Converting any [`(AssetId, Balance)`] to [`MultiAsset`]
|
||||||
@@ -60,6 +58,29 @@ impl<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<
|
||||||
|
AssetId: Clone,
|
||||||
|
Balance: Clone,
|
||||||
|
MatchAssetId: Contains<MultiLocation>,
|
||||||
|
ConvertAssetId: Convert<MultiLocation, AssetId>,
|
||||||
|
ConvertBalance: Convert<u128, Balance>,
|
||||||
|
> MultiAssetConverter<AssetId, Balance, ConvertAssetId, ConvertBalance>
|
||||||
|
for MatchedConvertedConcreteId<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertBalance>
|
||||||
|
{
|
||||||
|
fn convert_ref(
|
||||||
|
value: impl Borrow<(AssetId, Balance)>,
|
||||||
|
) -> Result<MultiAsset, FungiblesAccessError> {
|
||||||
|
let (asset_id, balance) = value.borrow();
|
||||||
|
match ConvertAssetId::reverse_ref(asset_id) {
|
||||||
|
Ok(asset_id_as_multilocation) => match ConvertBalance::reverse_ref(balance) {
|
||||||
|
Ok(amount) => Ok((asset_id_as_multilocation, amount).into()),
|
||||||
|
Err(_) => Err(FungiblesAccessError::AmountToBalanceConversionFailed),
|
||||||
|
},
|
||||||
|
Err(_) => Err(FungiblesAccessError::AssetIdConversionFailed),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Helper function to convert collections with [`(AssetId, Balance)`] to [`MultiAsset`]
|
/// Helper function to convert collections with [`(AssetId, Balance)`] to [`MultiAsset`]
|
||||||
pub fn convert<'a, AssetId, Balance, ConvertAssetId, ConvertBalance, Converter>(
|
pub fn convert<'a, AssetId, Balance, ConvertAssetId, ConvertBalance, Converter>(
|
||||||
items: impl Iterator<Item = &'a (AssetId, Balance)>,
|
items: impl Iterator<Item = &'a (AssetId, Balance)>,
|
||||||
@@ -90,11 +111,12 @@ pub fn convert_balance<
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use frame_support::traits::Everything;
|
||||||
|
|
||||||
use xcm::latest::prelude::*;
|
use xcm::latest::prelude::*;
|
||||||
use xcm_executor::traits::{Identity, JustTry};
|
use xcm_executor::traits::{Identity, JustTry};
|
||||||
|
|
||||||
type Converter = ConvertedConcreteId<MultiLocation, u64, Identity, JustTry>;
|
type Converter = MatchedConvertedConcreteId<MultiLocation, u64, Everything, Identity, JustTry>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn converted_concrete_id_fungible_multi_asset_conversion_roundtrip_works() {
|
fn converted_concrete_id_fungible_multi_asset_conversion_roundtrip_works() {
|
||||||
|
|||||||
@@ -15,39 +15,79 @@
|
|||||||
|
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
|
pub mod foreign_creators;
|
||||||
pub mod fungible_conversion;
|
pub mod fungible_conversion;
|
||||||
|
pub mod matching;
|
||||||
pub mod runtime_api;
|
pub mod runtime_api;
|
||||||
|
|
||||||
|
use crate::matching::{Equals, LocalMultiLocationPattern, ParentLocation, StartsWith};
|
||||||
|
use frame_support::traits::EverythingBut;
|
||||||
use parachains_common::AssetIdForTrustBackedAssets;
|
use parachains_common::AssetIdForTrustBackedAssets;
|
||||||
use xcm_builder::{AsPrefixedGeneralIndex, ConvertedConcreteId};
|
use xcm::prelude::MultiLocation;
|
||||||
use xcm_executor::traits::JustTry;
|
use xcm_builder::{AsPrefixedGeneralIndex, MatchedConvertedConcreteId};
|
||||||
|
use xcm_executor::traits::{Identity, JustTry};
|
||||||
|
|
||||||
/// `MultiLocation` vs `AssetIdForTrustBackedAssets` converter for `TrustBackedAssets`
|
/// `MultiLocation` vs `AssetIdForTrustBackedAssets` converter for `TrustBackedAssets`
|
||||||
pub type AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation> =
|
pub type AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation> =
|
||||||
AsPrefixedGeneralIndex<TrustBackedAssetsPalletLocation, AssetIdForTrustBackedAssets, JustTry>;
|
AsPrefixedGeneralIndex<TrustBackedAssetsPalletLocation, AssetIdForTrustBackedAssets, JustTry>;
|
||||||
|
|
||||||
/// [`ConvertedConcreteId`] converter dedicated for `TrustBackedAssets`
|
/// [`MatchedConvertedConcreteId`] converter dedicated for `TrustBackedAssets`
|
||||||
pub type TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, Balance> =
|
pub type TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, Balance> =
|
||||||
ConvertedConcreteId<
|
MatchedConvertedConcreteId<
|
||||||
AssetIdForTrustBackedAssets,
|
AssetIdForTrustBackedAssets,
|
||||||
Balance,
|
Balance,
|
||||||
|
StartsWith<TrustBackedAssetsPalletLocation>,
|
||||||
AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation>,
|
AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation>,
|
||||||
JustTry,
|
JustTry,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
/// AssetId used for identifying assets by MultiLocation.
|
||||||
|
pub type MultiLocationForAssetId = MultiLocation;
|
||||||
|
|
||||||
|
/// [`MatchedConvertedConcreteId`] converter dedicated for storing `AssetId` as `MultiLocation`.
|
||||||
|
pub type MultiLocationConvertedConcreteId<MultiLocationFilter, Balance> =
|
||||||
|
MatchedConvertedConcreteId<
|
||||||
|
MultiLocationForAssetId,
|
||||||
|
Balance,
|
||||||
|
MultiLocationFilter,
|
||||||
|
Identity,
|
||||||
|
JustTry,
|
||||||
|
>;
|
||||||
|
|
||||||
|
/// [`MatchedConvertedConcreteId`] converter dedicated for storing `ForeignAssets` with `AssetId` as `MultiLocation`.
|
||||||
|
///
|
||||||
|
/// Excludes by default:
|
||||||
|
/// - parent as relay chain
|
||||||
|
/// - all local MultiLocations
|
||||||
|
///
|
||||||
|
/// `AdditionalMultiLocationExclusionFilter` can customize additional excluded MultiLocations
|
||||||
|
pub type ForeignAssetsConvertedConcreteId<AdditionalMultiLocationExclusionFilter, Balance> =
|
||||||
|
MultiLocationConvertedConcreteId<
|
||||||
|
EverythingBut<(
|
||||||
|
// Excludes relay/parent chain currency
|
||||||
|
Equals<ParentLocation>,
|
||||||
|
// Here we rely on fact that something like this works:
|
||||||
|
// assert!(MultiLocation::new(1, X1(Parachain(100))).starts_with(&MultiLocation::parent()));
|
||||||
|
// assert!(X1(Parachain(100)).starts_with(&Here));
|
||||||
|
StartsWith<LocalMultiLocationPattern>,
|
||||||
|
// Here we can exclude more stuff or leave it as `()`
|
||||||
|
AdditionalMultiLocationExclusionFilter,
|
||||||
|
)>,
|
||||||
|
Balance,
|
||||||
|
>;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::matching::StartsWithExplicitGlobalConsensus;
|
||||||
use xcm::latest::prelude::*;
|
use xcm::latest::prelude::*;
|
||||||
use xcm_executor::traits::Convert;
|
use xcm_executor::traits::{Convert, Error as MatchError, MatchesFungibles};
|
||||||
|
|
||||||
frame_support::parameter_types! {
|
|
||||||
pub TrustBackedAssetsPalletLocation: MultiLocation = MultiLocation::new(5, X1(PalletInstance(13)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn asset_id_for_trust_backed_assets_convert_works() {
|
fn asset_id_for_trust_backed_assets_convert_works() {
|
||||||
|
frame_support::parameter_types! {
|
||||||
|
pub TrustBackedAssetsPalletLocation: MultiLocation = MultiLocation::new(5, X1(PalletInstance(13)));
|
||||||
|
}
|
||||||
let local_asset_id = 123456789 as AssetIdForTrustBackedAssets;
|
let local_asset_id = 123456789 as AssetIdForTrustBackedAssets;
|
||||||
let expected_reverse_ref =
|
let expected_reverse_ref =
|
||||||
MultiLocation::new(5, X2(PalletInstance(13), GeneralIndex(local_asset_id.into())));
|
MultiLocation::new(5, X2(PalletInstance(13), GeneralIndex(local_asset_id.into())));
|
||||||
@@ -67,4 +107,201 @@ mod tests {
|
|||||||
local_asset_id
|
local_asset_id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn trust_backed_assets_match_fungibles_works() {
|
||||||
|
frame_support::parameter_types! {
|
||||||
|
pub TrustBackedAssetsPalletLocation: MultiLocation = MultiLocation::new(0, X1(PalletInstance(13)));
|
||||||
|
}
|
||||||
|
// setup convert
|
||||||
|
type TrustBackedAssetsConvert =
|
||||||
|
TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, u128>;
|
||||||
|
|
||||||
|
let test_data = vec![
|
||||||
|
// missing GeneralIndex
|
||||||
|
(ma_1000(0, X1(PalletInstance(13))), Err(MatchError::AssetIdConversionFailed)),
|
||||||
|
(
|
||||||
|
ma_1000(0, X2(PalletInstance(13), GeneralKey { data: [0; 32], length: 32 })),
|
||||||
|
Err(MatchError::AssetIdConversionFailed),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ma_1000(0, X2(PalletInstance(13), Parachain(1000))),
|
||||||
|
Err(MatchError::AssetIdConversionFailed),
|
||||||
|
),
|
||||||
|
// OK
|
||||||
|
(ma_1000(0, X2(PalletInstance(13), GeneralIndex(1234))), Ok((1234, 1000))),
|
||||||
|
(
|
||||||
|
ma_1000(0, X3(PalletInstance(13), GeneralIndex(1234), GeneralIndex(2222))),
|
||||||
|
Ok((1234, 1000)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ma_1000(
|
||||||
|
0,
|
||||||
|
X4(
|
||||||
|
PalletInstance(13),
|
||||||
|
GeneralIndex(1234),
|
||||||
|
GeneralIndex(2222),
|
||||||
|
GeneralKey { data: [0; 32], length: 32 },
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Ok((1234, 1000)),
|
||||||
|
),
|
||||||
|
// wrong pallet instance
|
||||||
|
(
|
||||||
|
ma_1000(0, X2(PalletInstance(77), GeneralIndex(1234))),
|
||||||
|
Err(MatchError::AssetNotHandled),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ma_1000(0, X3(PalletInstance(77), GeneralIndex(1234), GeneralIndex(2222))),
|
||||||
|
Err(MatchError::AssetNotHandled),
|
||||||
|
),
|
||||||
|
// wrong parent
|
||||||
|
(
|
||||||
|
ma_1000(1, X2(PalletInstance(13), GeneralIndex(1234))),
|
||||||
|
Err(MatchError::AssetNotHandled),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ma_1000(1, X3(PalletInstance(13), GeneralIndex(1234), GeneralIndex(2222))),
|
||||||
|
Err(MatchError::AssetNotHandled),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ma_1000(1, X2(PalletInstance(77), GeneralIndex(1234))),
|
||||||
|
Err(MatchError::AssetNotHandled),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ma_1000(1, X3(PalletInstance(77), GeneralIndex(1234), GeneralIndex(2222))),
|
||||||
|
Err(MatchError::AssetNotHandled),
|
||||||
|
),
|
||||||
|
// wrong parent
|
||||||
|
(
|
||||||
|
ma_1000(2, X2(PalletInstance(13), GeneralIndex(1234))),
|
||||||
|
Err(MatchError::AssetNotHandled),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ma_1000(2, X3(PalletInstance(13), GeneralIndex(1234), GeneralIndex(2222))),
|
||||||
|
Err(MatchError::AssetNotHandled),
|
||||||
|
),
|
||||||
|
// missing GeneralIndex
|
||||||
|
(ma_1000(0, X1(PalletInstance(77))), Err(MatchError::AssetNotHandled)),
|
||||||
|
(ma_1000(1, X1(PalletInstance(13))), Err(MatchError::AssetNotHandled)),
|
||||||
|
(ma_1000(2, X1(PalletInstance(13))), Err(MatchError::AssetNotHandled)),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (multi_asset, expected_result) in test_data {
|
||||||
|
assert_eq!(
|
||||||
|
<TrustBackedAssetsConvert as MatchesFungibles<AssetIdForTrustBackedAssets, u128>>::matches_fungibles(&multi_asset),
|
||||||
|
expected_result, "multi_asset: {:?}", multi_asset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn multi_location_converted_concrete_id_converter_works() {
|
||||||
|
frame_support::parameter_types! {
|
||||||
|
pub Parachain100Pattern: MultiLocation = MultiLocation::new(1, X1(Parachain(100)));
|
||||||
|
pub UniversalLocationNetworkId: NetworkId = NetworkId::ByGenesis([9; 32]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup convert
|
||||||
|
type Convert = ForeignAssetsConvertedConcreteId<
|
||||||
|
(
|
||||||
|
StartsWith<Parachain100Pattern>,
|
||||||
|
StartsWithExplicitGlobalConsensus<UniversalLocationNetworkId>,
|
||||||
|
),
|
||||||
|
u128,
|
||||||
|
>;
|
||||||
|
|
||||||
|
let test_data = vec![
|
||||||
|
// excluded as local
|
||||||
|
(ma_1000(0, Here), Err(MatchError::AssetNotHandled)),
|
||||||
|
(ma_1000(0, X1(Parachain(100))), Err(MatchError::AssetNotHandled)),
|
||||||
|
(
|
||||||
|
ma_1000(0, X2(PalletInstance(13), GeneralIndex(1234))),
|
||||||
|
Err(MatchError::AssetNotHandled),
|
||||||
|
),
|
||||||
|
// excluded as parent
|
||||||
|
(ma_1000(1, Here), Err(MatchError::AssetNotHandled)),
|
||||||
|
// excluded as additional filter - Parachain100Pattern
|
||||||
|
(ma_1000(1, X1(Parachain(100))), Err(MatchError::AssetNotHandled)),
|
||||||
|
(ma_1000(1, X2(Parachain(100), GeneralIndex(1234))), Err(MatchError::AssetNotHandled)),
|
||||||
|
(
|
||||||
|
ma_1000(1, X3(Parachain(100), PalletInstance(13), GeneralIndex(1234))),
|
||||||
|
Err(MatchError::AssetNotHandled),
|
||||||
|
),
|
||||||
|
// excluded as additional filter - StartsWithExplicitGlobalConsensus
|
||||||
|
(
|
||||||
|
ma_1000(1, X1(GlobalConsensus(NetworkId::ByGenesis([9; 32])))),
|
||||||
|
Err(MatchError::AssetNotHandled),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ma_1000(2, X1(GlobalConsensus(NetworkId::ByGenesis([9; 32])))),
|
||||||
|
Err(MatchError::AssetNotHandled),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ma_1000(
|
||||||
|
2,
|
||||||
|
X3(
|
||||||
|
GlobalConsensus(NetworkId::ByGenesis([9; 32])),
|
||||||
|
Parachain(200),
|
||||||
|
GeneralIndex(1234),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Err(MatchError::AssetNotHandled),
|
||||||
|
),
|
||||||
|
// ok
|
||||||
|
(ma_1000(1, X1(Parachain(200))), Ok((MultiLocation::new(1, X1(Parachain(200))), 1000))),
|
||||||
|
(ma_1000(2, X1(Parachain(200))), Ok((MultiLocation::new(2, X1(Parachain(200))), 1000))),
|
||||||
|
(
|
||||||
|
ma_1000(1, X2(Parachain(200), GeneralIndex(1234))),
|
||||||
|
Ok((MultiLocation::new(1, X2(Parachain(200), GeneralIndex(1234))), 1000)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ma_1000(2, X2(Parachain(200), GeneralIndex(1234))),
|
||||||
|
Ok((MultiLocation::new(2, X2(Parachain(200), GeneralIndex(1234))), 1000)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ma_1000(2, X1(GlobalConsensus(NetworkId::ByGenesis([7; 32])))),
|
||||||
|
Ok((
|
||||||
|
MultiLocation::new(2, X1(GlobalConsensus(NetworkId::ByGenesis([7; 32])))),
|
||||||
|
1000,
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ma_1000(
|
||||||
|
2,
|
||||||
|
X3(
|
||||||
|
GlobalConsensus(NetworkId::ByGenesis([7; 32])),
|
||||||
|
Parachain(200),
|
||||||
|
GeneralIndex(1234),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Ok((
|
||||||
|
MultiLocation::new(
|
||||||
|
2,
|
||||||
|
X3(
|
||||||
|
GlobalConsensus(NetworkId::ByGenesis([7; 32])),
|
||||||
|
Parachain(200),
|
||||||
|
GeneralIndex(1234),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
1000,
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (multi_asset, expected_result) in test_data {
|
||||||
|
assert_eq!(
|
||||||
|
<Convert as MatchesFungibles<MultiLocationForAssetId, u128>>::matches_fungibles(
|
||||||
|
&multi_asset
|
||||||
|
),
|
||||||
|
expected_result,
|
||||||
|
"multi_asset: {:?}",
|
||||||
|
multi_asset
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create MultiAsset
|
||||||
|
fn ma_1000(parents: u8, interior: Junctions) -> MultiAsset {
|
||||||
|
(MultiLocation::new(parents, interior), 1000).into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
// Copyright (C) 2023 Parity Technologies (UK) Ltd.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
use cumulus_primitives_core::ParaId;
|
||||||
|
use frame_support::{
|
||||||
|
pallet_prelude::Get,
|
||||||
|
traits::{Contains, ContainsPair},
|
||||||
|
};
|
||||||
|
use xcm::{
|
||||||
|
latest::prelude::{MultiAsset, MultiLocation},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct StartsWith<T>(sp_std::marker::PhantomData<T>);
|
||||||
|
impl<Location: Get<MultiLocation>> Contains<MultiLocation> for StartsWith<Location> {
|
||||||
|
fn contains(t: &MultiLocation) -> bool {
|
||||||
|
t.starts_with(&Location::get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Equals<T>(sp_std::marker::PhantomData<T>);
|
||||||
|
impl<Location: Get<MultiLocation>> Contains<MultiLocation> for Equals<Location> {
|
||||||
|
fn contains(t: &MultiLocation) -> bool {
|
||||||
|
t == &Location::get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StartsWithExplicitGlobalConsensus<T>(sp_std::marker::PhantomData<T>);
|
||||||
|
impl<Network: Get<NetworkId>> Contains<MultiLocation>
|
||||||
|
for StartsWithExplicitGlobalConsensus<Network>
|
||||||
|
{
|
||||||
|
fn contains(t: &MultiLocation) -> bool {
|
||||||
|
match t.interior.global_consensus() {
|
||||||
|
Ok(requested_network) if requested_network.eq(&Network::get()) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
frame_support::parameter_types! {
|
||||||
|
pub LocalMultiLocationPattern: MultiLocation = MultiLocation::new(0, Here);
|
||||||
|
pub ParentLocation: MultiLocation = MultiLocation::parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Accepts an asset if it is from the origin.
|
||||||
|
pub struct IsForeignConcreteAsset<IsForeign>(sp_std::marker::PhantomData<IsForeign>);
|
||||||
|
impl<IsForeign: ContainsPair<MultiLocation, MultiLocation>> ContainsPair<MultiAsset, MultiLocation>
|
||||||
|
for IsForeignConcreteAsset<IsForeign>
|
||||||
|
{
|
||||||
|
fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool {
|
||||||
|
log::trace!(target: "xcm::contains", "IsForeignConcreteAsset asset: {:?}, origin: {:?}", asset, origin);
|
||||||
|
matches!(asset.id, Concrete(ref id) if IsForeign::contains(id, &origin))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if `a` is from sibling location `b`. Checks that `MultiLocation-a` starts with
|
||||||
|
/// `MultiLocation-b`, and that the `ParaId` of `b` is not equal to `a`.
|
||||||
|
pub struct FromSiblingParachain<SelfParaId>(sp_std::marker::PhantomData<SelfParaId>);
|
||||||
|
impl<SelfParaId: Get<ParaId>> ContainsPair<MultiLocation, MultiLocation>
|
||||||
|
for FromSiblingParachain<SelfParaId>
|
||||||
|
{
|
||||||
|
fn contains(&a: &MultiLocation, b: &MultiLocation) -> bool {
|
||||||
|
// `a` needs to be from `b` at least
|
||||||
|
if !a.starts_with(&b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// here we check if sibling
|
||||||
|
match a {
|
||||||
|
MultiLocation { parents: 1, interior } => match interior.first() {
|
||||||
|
Some(Parachain(sibling_para_id))
|
||||||
|
if sibling_para_id.ne(&u32::from(SelfParaId::get())) =>
|
||||||
|
true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -112,6 +112,7 @@ runtime-benchmarks = [
|
|||||||
"cumulus-pallet-xcmp-queue/runtime-benchmarks",
|
"cumulus-pallet-xcmp-queue/runtime-benchmarks",
|
||||||
"pallet-xcm-benchmarks/runtime-benchmarks",
|
"pallet-xcm-benchmarks/runtime-benchmarks",
|
||||||
"pallet-state-trie-migration/runtime-benchmarks",
|
"pallet-state-trie-migration/runtime-benchmarks",
|
||||||
|
"assets-common/runtime-benchmarks",
|
||||||
]
|
]
|
||||||
try-runtime = [
|
try-runtime = [
|
||||||
"cumulus-pallet-aura-ext/try-runtime",
|
"cumulus-pallet-aura-ext/try-runtime",
|
||||||
|
|||||||
@@ -66,19 +66,23 @@ use parachains_common::{
|
|||||||
NORMAL_DISPATCH_RATIO, SLOT_DURATION,
|
NORMAL_DISPATCH_RATIO, SLOT_DURATION,
|
||||||
};
|
};
|
||||||
use xcm_config::{
|
use xcm_config::{
|
||||||
FellowshipLocation, GovernanceLocation, KsmLocation, TrustBackedAssetsConvertedConcreteId,
|
FellowshipLocation, ForeignAssetsConvertedConcreteId, GovernanceLocation, KsmLocation,
|
||||||
XcmConfig,
|
TrustBackedAssetsConvertedConcreteId, XcmConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(any(feature = "std", test))]
|
#[cfg(any(feature = "std", test))]
|
||||||
pub use sp_runtime::BuildStorage;
|
pub use sp_runtime::BuildStorage;
|
||||||
|
|
||||||
// Polkadot imports
|
// Polkadot imports
|
||||||
|
use assets_common::{
|
||||||
|
foreign_creators::ForeignCreators, matching::FromSiblingParachain, MultiLocationForAssetId,
|
||||||
|
};
|
||||||
use pallet_xcm::{EnsureXcm, IsVoiceOfBody};
|
use pallet_xcm::{EnsureXcm, IsVoiceOfBody};
|
||||||
use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate};
|
use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate};
|
||||||
use xcm::latest::BodyId;
|
use xcm::latest::BodyId;
|
||||||
use xcm_executor::XcmExecutor;
|
use xcm_executor::XcmExecutor;
|
||||||
|
|
||||||
|
use crate::xcm_config::ForeignCreatorsSovereignAccountOf;
|
||||||
use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight};
|
use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight};
|
||||||
|
|
||||||
impl_opaque_keys! {
|
impl_opaque_keys! {
|
||||||
@@ -264,6 +268,48 @@ impl pallet_assets::Config<TrustBackedAssetsInstance> for Runtime {
|
|||||||
type BenchmarkHelper = ();
|
type BenchmarkHelper = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parameter_types! {
|
||||||
|
// we just reuse the same deposits
|
||||||
|
pub const ForeignAssetsAssetDeposit: Balance = AssetDeposit::get();
|
||||||
|
pub const ForeignAssetsAssetAccountDeposit: Balance = AssetAccountDeposit::get();
|
||||||
|
pub const ForeignAssetsApprovalDeposit: Balance = ApprovalDeposit::get();
|
||||||
|
pub const ForeignAssetsAssetsStringLimit: u32 = AssetsStringLimit::get();
|
||||||
|
pub const ForeignAssetsMetadataDepositBase: Balance = MetadataDepositBase::get();
|
||||||
|
pub const ForeignAssetsMetadataDepositPerByte: Balance = MetadataDepositPerByte::get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assets managed by some foreign location. Note: we do not declare a `ForeignAssetsCall` type, as
|
||||||
|
/// this type is used in proxy definitions. We assume that a foreign location would not want to set
|
||||||
|
/// an individual, local account as a proxy for the issuance of their assets. This issuance should
|
||||||
|
/// be managed by the foreign location's governance.
|
||||||
|
pub type ForeignAssetsInstance = pallet_assets::Instance2;
|
||||||
|
impl pallet_assets::Config<ForeignAssetsInstance> for Runtime {
|
||||||
|
type RuntimeEvent = RuntimeEvent;
|
||||||
|
type Balance = Balance;
|
||||||
|
type AssetId = MultiLocationForAssetId;
|
||||||
|
type AssetIdParameter = MultiLocationForAssetId;
|
||||||
|
type Currency = Balances;
|
||||||
|
type CreateOrigin = ForeignCreators<
|
||||||
|
(FromSiblingParachain<parachain_info::Pallet<Runtime>>,),
|
||||||
|
ForeignCreatorsSovereignAccountOf,
|
||||||
|
AccountId,
|
||||||
|
>;
|
||||||
|
type ForceOrigin = AssetsForceOrigin;
|
||||||
|
type AssetDeposit = ForeignAssetsAssetDeposit;
|
||||||
|
type MetadataDepositBase = ForeignAssetsMetadataDepositBase;
|
||||||
|
type MetadataDepositPerByte = ForeignAssetsMetadataDepositPerByte;
|
||||||
|
type ApprovalDeposit = ForeignAssetsApprovalDeposit;
|
||||||
|
type StringLimit = ForeignAssetsAssetsStringLimit;
|
||||||
|
type Freezer = ();
|
||||||
|
type Extra = ();
|
||||||
|
type WeightInfo = weights::pallet_assets::WeightInfo<Runtime>;
|
||||||
|
type CallbackHandle = ();
|
||||||
|
type AssetAccountDeposit = ForeignAssetsAssetAccountDeposit;
|
||||||
|
type RemoveItemsLimit = frame_support::traits::ConstU32<1000>;
|
||||||
|
#[cfg(feature = "runtime-benchmarks")]
|
||||||
|
type BenchmarkHelper = xcm_config::XcmBenchmarkHelper;
|
||||||
|
}
|
||||||
|
|
||||||
parameter_types! {
|
parameter_types! {
|
||||||
// One storage item; key size is 32; value is size 4+4+16+32 bytes = 56 bytes.
|
// One storage item; key size is 32; value is size 4+4+16+32 bytes = 56 bytes.
|
||||||
pub const DepositBase: Balance = deposit(1, 88);
|
pub const DepositBase: Balance = deposit(1, 88);
|
||||||
@@ -336,6 +382,7 @@ impl Default for ProxyType {
|
|||||||
Self::Any
|
Self::Any
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InstanceFilter<RuntimeCall> for ProxyType {
|
impl InstanceFilter<RuntimeCall> for ProxyType {
|
||||||
fn filter(&self, c: &RuntimeCall) -> bool {
|
fn filter(&self, c: &RuntimeCall) -> bool {
|
||||||
match self {
|
match self {
|
||||||
@@ -689,6 +736,7 @@ construct_runtime!(
|
|||||||
Assets: pallet_assets::<Instance1>::{Pallet, Call, Storage, Event<T>} = 50,
|
Assets: pallet_assets::<Instance1>::{Pallet, Call, Storage, Event<T>} = 50,
|
||||||
Uniques: pallet_uniques::{Pallet, Call, Storage, Event<T>} = 51,
|
Uniques: pallet_uniques::{Pallet, Call, Storage, Event<T>} = 51,
|
||||||
Nfts: pallet_nfts::{Pallet, Call, Storage, Event<T>} = 52,
|
Nfts: pallet_nfts::{Pallet, Call, Storage, Event<T>} = 52,
|
||||||
|
ForeignAssets: pallet_assets::<Instance2>::{Pallet, Call, Storage, Event<T>} = 53,
|
||||||
|
|
||||||
#[cfg(feature = "state-trie-version-1")]
|
#[cfg(feature = "state-trie-version-1")]
|
||||||
StateTrieMigration: pallet_state_trie_migration = 70,
|
StateTrieMigration: pallet_state_trie_migration = 70,
|
||||||
@@ -741,6 +789,7 @@ mod benches {
|
|||||||
define_benchmarks!(
|
define_benchmarks!(
|
||||||
[frame_system, SystemBench::<Runtime>]
|
[frame_system, SystemBench::<Runtime>]
|
||||||
[pallet_assets, Assets]
|
[pallet_assets, Assets]
|
||||||
|
[pallet_assets, ForeignAssets]
|
||||||
[pallet_balances, Balances]
|
[pallet_balances, Balances]
|
||||||
[pallet_multisig, Multisig]
|
[pallet_multisig, Multisig]
|
||||||
[pallet_nfts, Nfts]
|
[pallet_nfts, Nfts]
|
||||||
@@ -916,11 +965,17 @@ impl_runtime_apis! {
|
|||||||
},
|
},
|
||||||
// collect pallet_assets (TrustBackedAssets)
|
// collect pallet_assets (TrustBackedAssets)
|
||||||
convert::<_, _, _, _, TrustBackedAssetsConvertedConcreteId>(
|
convert::<_, _, _, _, TrustBackedAssetsConvertedConcreteId>(
|
||||||
Assets::account_balances(account)
|
Assets::account_balances(account.clone())
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, balance)| balance > &0)
|
.filter(|(_, balance)| balance > &0)
|
||||||
)?,
|
)?,
|
||||||
// collect ... e.g. pallet_assets ForeignAssets
|
// collect pallet_assets (ForeignAssets)
|
||||||
|
convert::<_, _, _, _, ForeignAssetsConvertedConcreteId>(
|
||||||
|
ForeignAssets::account_balances(account)
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, balance)| balance > &0)
|
||||||
|
)?,
|
||||||
|
// collect ... e.g. other tokens
|
||||||
].concat())
|
].concat())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,13 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, ParachainInfo,
|
AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, ForeignAssets,
|
||||||
ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
|
ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
|
||||||
TrustBackedAssetsInstance, WeightToFee, XcmpQueue,
|
TrustBackedAssetsInstance, WeightToFee, XcmpQueue,
|
||||||
};
|
};
|
||||||
|
use assets_common::matching::{
|
||||||
|
FromSiblingParachain, IsForeignConcreteAsset, StartsWith, StartsWithExplicitGlobalConsensus,
|
||||||
|
};
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
match_types, parameter_types,
|
match_types, parameter_types,
|
||||||
traits::{ConstU32, Contains, Everything, Nothing, PalletInfoAccess},
|
traits::{ConstU32, Contains, Everything, Nothing, PalletInfoAccess},
|
||||||
@@ -36,8 +39,8 @@ use xcm::latest::prelude::*;
|
|||||||
use xcm_builder::{
|
use xcm_builder::{
|
||||||
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
|
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
|
||||||
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, EnsureXcmOrigin,
|
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, EnsureXcmOrigin,
|
||||||
FungiblesAdapter, IsConcrete, LocalMint, NativeAsset, ParentAsSuperuser, ParentIsPreset,
|
FungiblesAdapter, IsConcrete, LocalMint, NativeAsset, NoChecking, ParentAsSuperuser,
|
||||||
RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
|
ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
|
||||||
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
|
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
|
||||||
UsingComponents, WeightInfoBounds, WithComputedOrigin,
|
UsingComponents, WeightInfoBounds, WithComputedOrigin,
|
||||||
};
|
};
|
||||||
@@ -49,7 +52,7 @@ parameter_types! {
|
|||||||
pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
|
pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
|
||||||
pub UniversalLocation: InteriorMultiLocation =
|
pub UniversalLocation: InteriorMultiLocation =
|
||||||
X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into()));
|
X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into()));
|
||||||
pub const Local: MultiLocation = Here.into_location();
|
pub UniversalLocationNetworkId: NetworkId = UniversalLocation::get().global_consensus().unwrap();
|
||||||
pub TrustBackedAssetsPalletLocation: MultiLocation =
|
pub TrustBackedAssetsPalletLocation: MultiLocation =
|
||||||
PalletInstance(<Assets as PalletInfoAccess>::index() as u8).into();
|
PalletInstance(<Assets as PalletInfoAccess>::index() as u8).into();
|
||||||
pub CheckingAccount: AccountId = PolkadotXcm::check_account();
|
pub CheckingAccount: AccountId = PolkadotXcm::check_account();
|
||||||
@@ -83,7 +86,7 @@ pub type CurrencyTransactor = CurrencyAdapter<
|
|||||||
(),
|
(),
|
||||||
>;
|
>;
|
||||||
|
|
||||||
/// `AssetId/Balancer` converter for `TrustBackedAssets`
|
/// `AssetId/Balance` converter for `TrustBackedAssets`
|
||||||
pub type TrustBackedAssetsConvertedConcreteId =
|
pub type TrustBackedAssetsConvertedConcreteId =
|
||||||
assets_common::TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, Balance>;
|
assets_common::TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, Balance>;
|
||||||
|
|
||||||
@@ -103,8 +106,38 @@ pub type FungiblesTransactor = FungiblesAdapter<
|
|||||||
// The account to use for tracking teleports.
|
// The account to use for tracking teleports.
|
||||||
CheckingAccount,
|
CheckingAccount,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
/// `AssetId/Balance` converter for `TrustBackedAssets`
|
||||||
|
pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConvertedConcreteId<
|
||||||
|
(
|
||||||
|
// Ignore `TrustBackedAssets` explicitly
|
||||||
|
StartsWith<TrustBackedAssetsPalletLocation>,
|
||||||
|
// Ignore asset which starts explicitly with our `GlobalConsensus(NetworkId)`, means:
|
||||||
|
// - foreign assets from our consensus should be: `MultiLocation {parent: 1, X*(Parachain(xyz))}
|
||||||
|
// - foreign assets outside our consensus with the same `GlobalConsensus(NetworkId)` wont be accepted here
|
||||||
|
StartsWithExplicitGlobalConsensus<UniversalLocationNetworkId>,
|
||||||
|
),
|
||||||
|
Balance,
|
||||||
|
>;
|
||||||
|
|
||||||
|
/// Means for transacting foreign assets from different global consensus.
|
||||||
|
pub type ForeignFungiblesTransactor = FungiblesAdapter<
|
||||||
|
// Use this fungibles implementation:
|
||||||
|
ForeignAssets,
|
||||||
|
// Use this currency when it is a fungible asset matching the given location or name:
|
||||||
|
ForeignAssetsConvertedConcreteId,
|
||||||
|
// Convert an XCM MultiLocation into a local account id:
|
||||||
|
LocationToAccountId,
|
||||||
|
// Our chain's account ID type (we can't get away without mentioning it explicitly):
|
||||||
|
AccountId,
|
||||||
|
// We dont need to check teleports here.
|
||||||
|
NoChecking,
|
||||||
|
// The account to use for tracking teleports.
|
||||||
|
CheckingAccount,
|
||||||
|
>;
|
||||||
|
|
||||||
/// Means for transacting assets on this chain.
|
/// Means for transacting assets on this chain.
|
||||||
pub type AssetTransactors = (CurrencyTransactor, FungiblesTransactor);
|
pub type AssetTransactors = (CurrencyTransactor, FungiblesTransactor, ForeignFungiblesTransactor);
|
||||||
|
|
||||||
/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,
|
/// 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
|
/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can
|
||||||
@@ -213,6 +246,35 @@ impl Contains<RuntimeCall> for SafeCallFilter {
|
|||||||
pallet_assets::Call::touch { .. } |
|
pallet_assets::Call::touch { .. } |
|
||||||
pallet_assets::Call::refund { .. },
|
pallet_assets::Call::refund { .. },
|
||||||
) |
|
) |
|
||||||
|
RuntimeCall::ForeignAssets(
|
||||||
|
pallet_assets::Call::create { .. } |
|
||||||
|
pallet_assets::Call::force_create { .. } |
|
||||||
|
pallet_assets::Call::start_destroy { .. } |
|
||||||
|
pallet_assets::Call::destroy_accounts { .. } |
|
||||||
|
pallet_assets::Call::destroy_approvals { .. } |
|
||||||
|
pallet_assets::Call::finish_destroy { .. } |
|
||||||
|
pallet_assets::Call::mint { .. } |
|
||||||
|
pallet_assets::Call::burn { .. } |
|
||||||
|
pallet_assets::Call::transfer { .. } |
|
||||||
|
pallet_assets::Call::transfer_keep_alive { .. } |
|
||||||
|
pallet_assets::Call::force_transfer { .. } |
|
||||||
|
pallet_assets::Call::freeze { .. } |
|
||||||
|
pallet_assets::Call::thaw { .. } |
|
||||||
|
pallet_assets::Call::freeze_asset { .. } |
|
||||||
|
pallet_assets::Call::thaw_asset { .. } |
|
||||||
|
pallet_assets::Call::transfer_ownership { .. } |
|
||||||
|
pallet_assets::Call::set_team { .. } |
|
||||||
|
pallet_assets::Call::set_metadata { .. } |
|
||||||
|
pallet_assets::Call::clear_metadata { .. } |
|
||||||
|
pallet_assets::Call::force_clear_metadata { .. } |
|
||||||
|
pallet_assets::Call::force_asset_status { .. } |
|
||||||
|
pallet_assets::Call::approve_transfer { .. } |
|
||||||
|
pallet_assets::Call::cancel_approval { .. } |
|
||||||
|
pallet_assets::Call::force_cancel_approval { .. } |
|
||||||
|
pallet_assets::Call::transfer_approved { .. } |
|
||||||
|
pallet_assets::Call::touch { .. } |
|
||||||
|
pallet_assets::Call::refund { .. },
|
||||||
|
) |
|
||||||
RuntimeCall::Nfts(
|
RuntimeCall::Nfts(
|
||||||
pallet_nfts::Call::create { .. } |
|
pallet_nfts::Call::create { .. } |
|
||||||
pallet_nfts::Call::force_create { .. } |
|
pallet_nfts::Call::force_create { .. } |
|
||||||
@@ -322,7 +384,13 @@ impl xcm_executor::Config for XcmConfig {
|
|||||||
// Statemine acting _as_ a reserve location for KSM and assets created under `pallet-assets`.
|
// Statemine acting _as_ a reserve location for KSM and assets created under `pallet-assets`.
|
||||||
// For KSM, users must use teleport where allowed (e.g. with the Relay Chain).
|
// For KSM, users must use teleport where allowed (e.g. with the Relay Chain).
|
||||||
type IsReserve = ();
|
type IsReserve = ();
|
||||||
type IsTeleporter = NativeAsset; // <- should be enough to allow teleportation of KSM
|
// We allow:
|
||||||
|
// - teleportation of KSM
|
||||||
|
// - teleportation of sibling parachain's assets (as ForeignCreators)
|
||||||
|
type IsTeleporter = (
|
||||||
|
NativeAsset,
|
||||||
|
IsForeignConcreteAsset<FromSiblingParachain<parachain_info::Pallet<Runtime>>>,
|
||||||
|
);
|
||||||
type UniversalLocation = UniversalLocation;
|
type UniversalLocation = UniversalLocation;
|
||||||
type Barrier = Barrier;
|
type Barrier = Barrier;
|
||||||
type Weigher = WeightInfoBounds<
|
type Weigher = WeightInfoBounds<
|
||||||
@@ -415,3 +483,20 @@ impl cumulus_pallet_xcm::Config for Runtime {
|
|||||||
type RuntimeEvent = RuntimeEvent;
|
type RuntimeEvent = RuntimeEvent;
|
||||||
type XcmExecutor = XcmExecutor<XcmConfig>;
|
type XcmExecutor = XcmExecutor<XcmConfig>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type ForeignCreatorsSovereignAccountOf = (
|
||||||
|
SiblingParachainConvertsVia<Sibling, AccountId>,
|
||||||
|
AccountId32Aliases<RelayNetwork, AccountId>,
|
||||||
|
ParentIsPreset<AccountId>,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Simple conversion of `u32` into an `AssetId` for use in benchmarking.
|
||||||
|
pub struct XcmBenchmarkHelper;
|
||||||
|
#[cfg(feature = "runtime-benchmarks")]
|
||||||
|
use pallet_assets::BenchmarkHelper;
|
||||||
|
#[cfg(feature = "runtime-benchmarks")]
|
||||||
|
impl BenchmarkHelper<MultiLocation> for XcmBenchmarkHelper {
|
||||||
|
fn create_asset_id_parameter(id: u32) -> MultiLocation {
|
||||||
|
MultiLocation { parents: 1, interior: X1(Parachain(id)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,25 +1,27 @@
|
|||||||
use asset_test_utils::{ExtBuilder, RuntimeHelper};
|
use asset_test_utils::{ExtBuilder, RuntimeHelper};
|
||||||
use codec::Encode;
|
use codec::{Decode, Encode};
|
||||||
use cumulus_primitives_utility::ChargeWeightInFungibles;
|
use cumulus_primitives_utility::ChargeWeightInFungibles;
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
assert_noop, assert_ok, sp_io,
|
assert_noop, assert_ok,
|
||||||
|
traits::fungibles::InspectEnumerable,
|
||||||
weights::{Weight, WeightToFee as WeightToFeeT},
|
weights::{Weight, WeightToFee as WeightToFeeT},
|
||||||
};
|
};
|
||||||
use parachains_common::{AccountId, AuraId, Balance};
|
use parachains_common::{AccountId, AssetIdForTrustBackedAssets, AuraId, Balance};
|
||||||
use statemine_runtime::xcm_config::{
|
use statemine_runtime::xcm_config::{
|
||||||
AssetFeeAsExistentialDepositMultiplierFeeCharger, KsmLocation, TrustBackedAssetsPalletLocation,
|
AssetFeeAsExistentialDepositMultiplierFeeCharger, KsmLocation, TrustBackedAssetsPalletLocation,
|
||||||
};
|
};
|
||||||
pub use statemine_runtime::{
|
pub use statemine_runtime::{
|
||||||
constants::fee::WeightToFee, xcm_config::XcmConfig, Assets, Balances, ExistentialDeposit,
|
constants::fee::WeightToFee,
|
||||||
ReservedDmpWeight, Runtime, SessionKeys, System,
|
xcm_config::{CheckingAccount, ForeignCreatorsSovereignAccountOf, XcmConfig},
|
||||||
|
AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance,
|
||||||
|
MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, RuntimeCall,
|
||||||
|
RuntimeEvent, SessionKeys, System, TrustBackedAssetsInstance,
|
||||||
};
|
};
|
||||||
use xcm::latest::prelude::*;
|
use xcm::latest::prelude::*;
|
||||||
use xcm_executor::{
|
use xcm_executor::traits::{Convert, Identity, JustTry, WeightTrader};
|
||||||
traits::{Convert, WeightTrader},
|
|
||||||
XcmExecutor,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const ALICE: [u8; 32] = [1u8; 32];
|
const ALICE: [u8; 32] = [1u8; 32];
|
||||||
|
const SOME_ASSET_ADMIN: [u8; 32] = [5u8; 32];
|
||||||
|
|
||||||
type AssetIdForTrustBackedAssetsConvert =
|
type AssetIdForTrustBackedAssetsConvert =
|
||||||
assets_common::AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation>;
|
assets_common::AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation>;
|
||||||
@@ -371,9 +373,15 @@ fn test_assets_balances_api_works() {
|
|||||||
.build()
|
.build()
|
||||||
.execute_with(|| {
|
.execute_with(|| {
|
||||||
let local_asset_id = 1;
|
let local_asset_id = 1;
|
||||||
|
let foreign_asset_id_multilocation =
|
||||||
|
MultiLocation { parents: 1, interior: X2(Parachain(1234), GeneralIndex(12345)) };
|
||||||
|
|
||||||
// check before
|
// check before
|
||||||
assert_eq!(Assets::balance(local_asset_id, AccountId::from(ALICE)), 0);
|
assert_eq!(Assets::balance(local_asset_id, AccountId::from(ALICE)), 0);
|
||||||
|
assert_eq!(
|
||||||
|
ForeignAssets::balance(foreign_asset_id_multilocation, AccountId::from(ALICE)),
|
||||||
|
0
|
||||||
|
);
|
||||||
assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 0);
|
assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 0);
|
||||||
assert!(Runtime::query_account_balances(AccountId::from(ALICE)).unwrap().is_empty());
|
assert!(Runtime::query_account_balances(AccountId::from(ALICE)).unwrap().is_empty());
|
||||||
|
|
||||||
@@ -400,15 +408,37 @@ fn test_assets_balances_api_works() {
|
|||||||
minimum_asset_balance
|
minimum_asset_balance
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// create foreign asset
|
||||||
|
let foreign_asset_minimum_asset_balance = 3333333_u128;
|
||||||
|
assert_ok!(ForeignAssets::force_create(
|
||||||
|
RuntimeHelper::<Runtime>::root_origin(),
|
||||||
|
foreign_asset_id_multilocation.clone().into(),
|
||||||
|
AccountId::from(SOME_ASSET_ADMIN).into(),
|
||||||
|
false,
|
||||||
|
foreign_asset_minimum_asset_balance
|
||||||
|
));
|
||||||
|
|
||||||
|
// We first mint enough asset for the account to exist for assets
|
||||||
|
assert_ok!(ForeignAssets::mint(
|
||||||
|
RuntimeHelper::<Runtime>::origin_of(AccountId::from(SOME_ASSET_ADMIN)),
|
||||||
|
foreign_asset_id_multilocation.clone().into(),
|
||||||
|
AccountId::from(ALICE).into(),
|
||||||
|
6 * foreign_asset_minimum_asset_balance
|
||||||
|
));
|
||||||
|
|
||||||
// check after
|
// check after
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Assets::balance(local_asset_id, AccountId::from(ALICE)),
|
Assets::balance(local_asset_id, AccountId::from(ALICE)),
|
||||||
minimum_asset_balance
|
minimum_asset_balance
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ForeignAssets::balance(foreign_asset_id_multilocation, AccountId::from(ALICE)),
|
||||||
|
6 * minimum_asset_balance
|
||||||
|
);
|
||||||
assert_eq!(Balances::free_balance(AccountId::from(ALICE)), some_currency);
|
assert_eq!(Balances::free_balance(AccountId::from(ALICE)), some_currency);
|
||||||
|
|
||||||
let result = Runtime::query_account_balances(AccountId::from(ALICE)).unwrap();
|
let result = Runtime::query_account_balances(AccountId::from(ALICE)).unwrap();
|
||||||
assert_eq!(result.len(), 2);
|
assert_eq!(result.len(), 3);
|
||||||
|
|
||||||
// check currency
|
// check currency
|
||||||
assert!(result.iter().any(|asset| asset.eq(
|
assert!(result.iter().any(|asset| asset.eq(
|
||||||
@@ -423,53 +453,162 @@ fn test_assets_balances_api_works() {
|
|||||||
minimum_asset_balance
|
minimum_asset_balance
|
||||||
)
|
)
|
||||||
.into())));
|
.into())));
|
||||||
|
// check foreign asset
|
||||||
|
assert!(result.iter().any(|asset| asset.eq(&(
|
||||||
|
Identity::reverse_ref(foreign_asset_id_multilocation).unwrap(),
|
||||||
|
6 * foreign_asset_minimum_asset_balance
|
||||||
|
)
|
||||||
|
.into())));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
asset_test_utils::include_teleports_for_native_asset_works!(
|
||||||
fn receive_teleported_asset_works() {
|
Runtime,
|
||||||
ExtBuilder::<Runtime>::default()
|
XcmConfig,
|
||||||
.with_collators(vec![AccountId::from(ALICE)])
|
CheckingAccount,
|
||||||
.with_session_keys(vec![(
|
WeightToFee,
|
||||||
|
ParachainSystem,
|
||||||
|
asset_test_utils::CollatorSessionKeys::new(
|
||||||
AccountId::from(ALICE),
|
AccountId::from(ALICE),
|
||||||
AccountId::from(ALICE),
|
AccountId::from(ALICE),
|
||||||
SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) },
|
SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) }
|
||||||
)])
|
),
|
||||||
.build()
|
ExistentialDeposit::get(),
|
||||||
.execute_with(|| {
|
Box::new(|runtime_event_encoded: Vec<u8>| {
|
||||||
let xcm = Xcm(vec![
|
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
|
||||||
ReceiveTeleportedAsset(MultiAssets::from(vec![MultiAsset {
|
Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event),
|
||||||
id: Concrete(MultiLocation { parents: 1, interior: Here }),
|
_ => None,
|
||||||
fun: Fungible(10000000000000),
|
|
||||||
}])),
|
|
||||||
ClearOrigin,
|
|
||||||
BuyExecution {
|
|
||||||
fees: MultiAsset {
|
|
||||||
id: Concrete(MultiLocation { parents: 1, interior: Here }),
|
|
||||||
fun: Fungible(10000000000000),
|
|
||||||
},
|
|
||||||
weight_limit: Limited(Weight::from_parts(303531000, 65536)),
|
|
||||||
},
|
|
||||||
DepositAsset {
|
|
||||||
assets: Wild(AllCounted(1)),
|
|
||||||
beneficiary: MultiLocation {
|
|
||||||
parents: 0,
|
|
||||||
interior: X1(AccountId32 {
|
|
||||||
network: None,
|
|
||||||
id: [
|
|
||||||
18, 153, 85, 112, 1, 245, 88, 21, 211, 252, 181, 60, 116, 70, 58,
|
|
||||||
203, 12, 246, 209, 77, 70, 57, 179, 64, 152, 44, 96, 135, 127, 56,
|
|
||||||
70, 9,
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
let hash = xcm.using_encoded(sp_io::hashing::blake2_256);
|
|
||||||
|
|
||||||
let weight_limit = ReservedDmpWeight::get();
|
|
||||||
|
|
||||||
let outcome = XcmExecutor::<XcmConfig>::execute_xcm(Parent, xcm, hash, weight_limit);
|
|
||||||
assert_eq!(outcome.ensure_complete(), Ok(()));
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
}),
|
||||||
|
Box::new(|runtime_event_encoded: Vec<u8>| {
|
||||||
|
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
|
||||||
|
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
asset_test_utils::include_teleports_for_foreign_assets_works!(
|
||||||
|
Runtime,
|
||||||
|
XcmConfig,
|
||||||
|
CheckingAccount,
|
||||||
|
WeightToFee,
|
||||||
|
ParachainSystem,
|
||||||
|
ForeignCreatorsSovereignAccountOf,
|
||||||
|
ForeignAssetsInstance,
|
||||||
|
asset_test_utils::CollatorSessionKeys::new(
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) }
|
||||||
|
),
|
||||||
|
ExistentialDeposit::get(),
|
||||||
|
Box::new(|runtime_event_encoded: Vec<u8>| {
|
||||||
|
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
|
||||||
|
Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
Box::new(|runtime_event_encoded: Vec<u8>| {
|
||||||
|
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
|
||||||
|
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
asset_test_utils::include_asset_transactor_transfer_with_local_consensus_currency_works!(
|
||||||
|
Runtime,
|
||||||
|
XcmConfig,
|
||||||
|
asset_test_utils::CollatorSessionKeys::new(
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) }
|
||||||
|
),
|
||||||
|
ExistentialDeposit::get(),
|
||||||
|
Box::new(|| {
|
||||||
|
assert!(Assets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
assert!(ForeignAssets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
}),
|
||||||
|
Box::new(|| {
|
||||||
|
assert!(Assets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
assert!(ForeignAssets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
asset_test_utils::include_asset_transactor_transfer_with_pallet_assets_instance_works!(
|
||||||
|
asset_transactor_transfer_with_trust_backed_assets_works,
|
||||||
|
Runtime,
|
||||||
|
XcmConfig,
|
||||||
|
TrustBackedAssetsInstance,
|
||||||
|
AssetIdForTrustBackedAssets,
|
||||||
|
AssetIdForTrustBackedAssetsConvert,
|
||||||
|
asset_test_utils::CollatorSessionKeys::new(
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) }
|
||||||
|
),
|
||||||
|
ExistentialDeposit::get(),
|
||||||
|
12345,
|
||||||
|
Box::new(|| {
|
||||||
|
assert!(ForeignAssets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
}),
|
||||||
|
Box::new(|| {
|
||||||
|
assert!(ForeignAssets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
asset_test_utils::include_asset_transactor_transfer_with_pallet_assets_instance_works!(
|
||||||
|
asset_transactor_transfer_with_foreign_assets_works,
|
||||||
|
Runtime,
|
||||||
|
XcmConfig,
|
||||||
|
ForeignAssetsInstance,
|
||||||
|
MultiLocation,
|
||||||
|
JustTry,
|
||||||
|
asset_test_utils::CollatorSessionKeys::new(
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) }
|
||||||
|
),
|
||||||
|
ExistentialDeposit::get(),
|
||||||
|
MultiLocation { parents: 1, interior: X2(Parachain(1313), GeneralIndex(12345)) },
|
||||||
|
Box::new(|| {
|
||||||
|
assert!(Assets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
}),
|
||||||
|
Box::new(|| {
|
||||||
|
assert!(Assets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_parachain_assets_works!(
|
||||||
|
Runtime,
|
||||||
|
XcmConfig,
|
||||||
|
WeightToFee,
|
||||||
|
ForeignCreatorsSovereignAccountOf,
|
||||||
|
ForeignAssetsInstance,
|
||||||
|
MultiLocation,
|
||||||
|
JustTry,
|
||||||
|
asset_test_utils::CollatorSessionKeys::new(
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) }
|
||||||
|
),
|
||||||
|
ExistentialDeposit::get(),
|
||||||
|
AssetDeposit::get(),
|
||||||
|
MetadataDepositBase::get(),
|
||||||
|
MetadataDepositPerByte::get(),
|
||||||
|
Box::new(|pallet_asset_call| RuntimeCall::ForeignAssets(pallet_asset_call).encode()),
|
||||||
|
Box::new(|runtime_event_encoded: Vec<u8>| {
|
||||||
|
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
|
||||||
|
Ok(RuntimeEvent::ForeignAssets(pallet_asset_event)) => Some(pallet_asset_event),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
Box::new(|| {
|
||||||
|
assert!(Assets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
assert!(ForeignAssets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
}),
|
||||||
|
Box::new(|| {
|
||||||
|
assert!(Assets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
assert_eq!(ForeignAssets::asset_ids().collect::<Vec<_>>().len(), 1);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ runtime-benchmarks = [
|
|||||||
"pallet-collator-selection/runtime-benchmarks",
|
"pallet-collator-selection/runtime-benchmarks",
|
||||||
"cumulus-pallet-xcmp-queue/runtime-benchmarks",
|
"cumulus-pallet-xcmp-queue/runtime-benchmarks",
|
||||||
"pallet-xcm-benchmarks/runtime-benchmarks",
|
"pallet-xcm-benchmarks/runtime-benchmarks",
|
||||||
|
"assets-common/runtime-benchmarks",
|
||||||
]
|
]
|
||||||
try-runtime = [
|
try-runtime = [
|
||||||
"cumulus-pallet-aura-ext/try-runtime",
|
"cumulus-pallet-aura-ext/try-runtime",
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ parameter_types! {
|
|||||||
pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
|
pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
|
||||||
pub UniversalLocation: InteriorMultiLocation =
|
pub UniversalLocation: InteriorMultiLocation =
|
||||||
X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into()));
|
X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into()));
|
||||||
pub const Local: MultiLocation = MultiLocation::here();
|
|
||||||
pub TrustBackedAssetsPalletLocation: MultiLocation =
|
pub TrustBackedAssetsPalletLocation: MultiLocation =
|
||||||
PalletInstance(<Assets as PalletInfoAccess>::index() as u8).into();
|
PalletInstance(<Assets as PalletInfoAccess>::index() as u8).into();
|
||||||
pub CheckingAccount: AccountId = PolkadotXcm::check_account();
|
pub CheckingAccount: AccountId = PolkadotXcm::check_account();
|
||||||
@@ -83,7 +82,7 @@ pub type CurrencyTransactor = CurrencyAdapter<
|
|||||||
(),
|
(),
|
||||||
>;
|
>;
|
||||||
|
|
||||||
/// `AssetId/Balancer` converter for `TrustBackedAssets``
|
/// `AssetId/Balance` converter for `TrustBackedAssets``
|
||||||
pub type TrustBackedAssetsConvertedConcreteId =
|
pub type TrustBackedAssetsConvertedConcreteId =
|
||||||
assets_common::TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, Balance>;
|
assets_common::TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, Balance>;
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,27 @@
|
|||||||
use asset_test_utils::{ExtBuilder, RuntimeHelper};
|
use asset_test_utils::{ExtBuilder, RuntimeHelper};
|
||||||
use codec::Encode;
|
use codec::Decode;
|
||||||
use cumulus_primitives_utility::ChargeWeightInFungibles;
|
use cumulus_primitives_utility::ChargeWeightInFungibles;
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
assert_noop, assert_ok, sp_io,
|
assert_noop, assert_ok,
|
||||||
|
traits::fungibles::InspectEnumerable,
|
||||||
weights::{Weight, WeightToFee as WeightToFeeT},
|
weights::{Weight, WeightToFee as WeightToFeeT},
|
||||||
};
|
};
|
||||||
use parachains_common::{AccountId, Balance, StatemintAuraId as AuraId};
|
use parachains_common::{
|
||||||
|
AccountId, AssetIdForTrustBackedAssets, Balance, StatemintAuraId as AuraId,
|
||||||
|
};
|
||||||
use statemint_runtime::xcm_config::{
|
use statemint_runtime::xcm_config::{
|
||||||
AssetFeeAsExistentialDepositMultiplierFeeCharger, DotLocation, TrustBackedAssetsPalletLocation,
|
AssetFeeAsExistentialDepositMultiplierFeeCharger, CheckingAccount, DotLocation,
|
||||||
|
TrustBackedAssetsPalletLocation,
|
||||||
};
|
};
|
||||||
pub use statemint_runtime::{
|
pub use statemint_runtime::{
|
||||||
constants::fee::WeightToFee, xcm_config::XcmConfig, Assets, Balances, ExistentialDeposit,
|
constants::fee::WeightToFee, xcm_config::XcmConfig, AssetDeposit, Assets, Balances,
|
||||||
ReservedDmpWeight, Runtime, SessionKeys, System,
|
ExistentialDeposit, ParachainSystem, Runtime, RuntimeEvent, SessionKeys, System,
|
||||||
|
TrustBackedAssetsInstance,
|
||||||
};
|
};
|
||||||
use xcm::latest::prelude::*;
|
use xcm::latest::prelude::*;
|
||||||
use xcm_executor::{
|
use xcm_executor::traits::{Convert, WeightTrader};
|
||||||
traits::{Convert, WeightTrader},
|
|
||||||
XcmExecutor,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const ALICE: [u8; 32] = [1u8; 32];
|
const ALICE: [u8; 32] = [1u8; 32];
|
||||||
|
|
||||||
type AssetIdForTrustBackedAssetsConvert =
|
type AssetIdForTrustBackedAssetsConvert =
|
||||||
assets_common::AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation>;
|
assets_common::AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation>;
|
||||||
@@ -438,50 +440,63 @@ fn test_assets_balances_api_works() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
asset_test_utils::include_teleports_for_native_asset_works!(
|
||||||
fn receive_teleported_asset_works() {
|
Runtime,
|
||||||
ExtBuilder::<Runtime>::default()
|
XcmConfig,
|
||||||
.with_collators(vec![AccountId::from(ALICE)])
|
CheckingAccount,
|
||||||
.with_session_keys(vec![(
|
WeightToFee,
|
||||||
|
ParachainSystem,
|
||||||
|
asset_test_utils::CollatorSessionKeys::new(
|
||||||
AccountId::from(ALICE),
|
AccountId::from(ALICE),
|
||||||
AccountId::from(ALICE),
|
AccountId::from(ALICE),
|
||||||
SessionKeys { aura: AuraId::from(sp_core::ed25519::Public::from_raw(ALICE)) },
|
SessionKeys { aura: AuraId::from(sp_core::ed25519::Public::from_raw(ALICE)) }
|
||||||
)])
|
),
|
||||||
.build()
|
ExistentialDeposit::get(),
|
||||||
.execute_with(|| {
|
Box::new(|runtime_event_encoded: Vec<u8>| {
|
||||||
let xcm = Xcm(vec![
|
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
|
||||||
ReceiveTeleportedAsset(MultiAssets::from(vec![MultiAsset {
|
Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event),
|
||||||
id: Concrete(MultiLocation { parents: 1, interior: Here }),
|
_ => None,
|
||||||
fun: Fungible(10000000000000),
|
|
||||||
}])),
|
|
||||||
ClearOrigin,
|
|
||||||
BuyExecution {
|
|
||||||
fees: MultiAsset {
|
|
||||||
id: Concrete(MultiLocation { parents: 1, interior: Here }),
|
|
||||||
fun: Fungible(10000000000000),
|
|
||||||
},
|
|
||||||
weight_limit: Limited(Weight::from_parts(303531000, 65536)),
|
|
||||||
},
|
|
||||||
DepositAsset {
|
|
||||||
assets: Wild(AllCounted(1)),
|
|
||||||
beneficiary: MultiLocation {
|
|
||||||
parents: 0,
|
|
||||||
interior: X1(AccountId32 {
|
|
||||||
network: None,
|
|
||||||
id: [
|
|
||||||
18, 153, 85, 112, 1, 245, 88, 21, 211, 252, 181, 60, 116, 70, 58,
|
|
||||||
203, 12, 246, 209, 77, 70, 57, 179, 64, 152, 44, 96, 135, 127, 56,
|
|
||||||
70, 9,
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
let hash = xcm.using_encoded(sp_io::hashing::blake2_256);
|
|
||||||
|
|
||||||
let weight_limit = ReservedDmpWeight::get();
|
|
||||||
|
|
||||||
let outcome = XcmExecutor::<XcmConfig>::execute_xcm(Parent, xcm, hash, weight_limit);
|
|
||||||
assert_eq!(outcome.ensure_complete(), Ok(()));
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
}),
|
||||||
|
Box::new(|runtime_event_encoded: Vec<u8>| {
|
||||||
|
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
|
||||||
|
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
asset_test_utils::include_asset_transactor_transfer_with_local_consensus_currency_works!(
|
||||||
|
Runtime,
|
||||||
|
XcmConfig,
|
||||||
|
asset_test_utils::CollatorSessionKeys::new(
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
SessionKeys { aura: AuraId::from(sp_core::ed25519::Public::from_raw(ALICE)) }
|
||||||
|
),
|
||||||
|
ExistentialDeposit::get(),
|
||||||
|
Box::new(|| {
|
||||||
|
assert!(Assets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
}),
|
||||||
|
Box::new(|| {
|
||||||
|
assert!(Assets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
asset_test_utils::include_asset_transactor_transfer_with_pallet_assets_instance_works!(
|
||||||
|
asset_transactor_transfer_with_pallet_assets_instance_works,
|
||||||
|
Runtime,
|
||||||
|
XcmConfig,
|
||||||
|
TrustBackedAssetsInstance,
|
||||||
|
AssetIdForTrustBackedAssets,
|
||||||
|
AssetIdForTrustBackedAssetsConvert,
|
||||||
|
asset_test_utils::CollatorSessionKeys::new(
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
SessionKeys { aura: AuraId::from(sp_core::ed25519::Public::from_raw(ALICE)) }
|
||||||
|
),
|
||||||
|
ExistentialDeposit::get(),
|
||||||
|
12345,
|
||||||
|
Box::new(|| {}),
|
||||||
|
Box::new(|| {})
|
||||||
|
);
|
||||||
|
|||||||
@@ -6,11 +6,12 @@ edition = "2021"
|
|||||||
description = "Statemint parachain runtime"
|
description = "Statemint parachain runtime"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] }
|
||||||
|
|
||||||
# Substrate
|
# Substrate
|
||||||
|
|
||||||
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||||
frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||||
|
pallet-assets = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||||
pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||||
pallet-session = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
pallet-session = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||||
sp-consensus-aura = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
sp-consensus-aura = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||||
@@ -20,8 +21,21 @@ sp-std = { git = "https://github.com/paritytech/substrate", default-features = f
|
|||||||
sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||||
|
|
||||||
# Cumulus
|
# Cumulus
|
||||||
|
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false }
|
||||||
|
cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false }
|
||||||
pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false }
|
pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false }
|
||||||
parachains-common = { path = "../../../common", default-features = false }
|
parachains-common = { path = "../../../common", default-features = false }
|
||||||
|
assets-common = { path = "../common", default-features = false }
|
||||||
|
cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false }
|
||||||
|
cumulus-primitives-parachain-inherent = { path = "../../../../primitives/parachain-inherent", default-features = false }
|
||||||
|
cumulus-test-relay-sproof-builder = { path = "../../../../test/relay-sproof-builder", default-features = false }
|
||||||
|
parachain-info = { path = "../../../../parachains/pallets/parachain-info", default-features = false }
|
||||||
|
|
||||||
|
# Polkadot
|
||||||
|
xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
|
||||||
|
xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
|
||||||
|
pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
|
||||||
|
polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
hex-literal = "0.3.4"
|
hex-literal = "0.3.4"
|
||||||
@@ -32,14 +46,27 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran
|
|||||||
[features]
|
[features]
|
||||||
default = [ "std" ]
|
default = [ "std" ]
|
||||||
std = [
|
std = [
|
||||||
|
"cumulus-pallet-parachain-system/std",
|
||||||
|
"cumulus-primitives-core/std",
|
||||||
|
"cumulus-test-relay-sproof-builder/std",
|
||||||
|
"cumulus-primitives-parachain-inherent/std",
|
||||||
"frame-support/std",
|
"frame-support/std",
|
||||||
"frame-system/std",
|
"frame-system/std",
|
||||||
|
"pallet-assets/std",
|
||||||
"pallet-balances/std",
|
"pallet-balances/std",
|
||||||
|
"cumulus-pallet-parachain-system/std",
|
||||||
"pallet-collator-selection/std",
|
"pallet-collator-selection/std",
|
||||||
"pallet-session/std",
|
"pallet-session/std",
|
||||||
|
"assets-common/std",
|
||||||
"parachains-common/std",
|
"parachains-common/std",
|
||||||
|
"parachain-info/std",
|
||||||
|
"polkadot-parachain/std",
|
||||||
"sp-consensus-aura/std",
|
"sp-consensus-aura/std",
|
||||||
"sp-io/std",
|
"sp-io/std",
|
||||||
"sp-runtime/std",
|
"sp-runtime/std",
|
||||||
"sp-std/std",
|
"sp-std/std",
|
||||||
|
"xcm/std",
|
||||||
|
"xcm-executor/std",
|
||||||
|
"pallet-xcm/std",
|
||||||
|
"cumulus-pallet-xcmp-queue/std",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,11 +1,27 @@
|
|||||||
use frame_support::traits::GenesisBuild;
|
|
||||||
use sp_std::marker::PhantomData;
|
use sp_std::marker::PhantomData;
|
||||||
|
|
||||||
use frame_support::traits::OriginTrait;
|
use cumulus_primitives_core::{AbridgedHrmpChannel, ParaId, PersistedValidationData};
|
||||||
|
use cumulus_primitives_parachain_inherent::ParachainInherentData;
|
||||||
|
use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
|
||||||
|
use frame_support::{
|
||||||
|
dispatch::{DispatchResult, RawOrigin, UnfilteredDispatchable},
|
||||||
|
inherent::{InherentData, ProvideInherent},
|
||||||
|
traits::{GenesisBuild, OriginTrait},
|
||||||
|
weights::Weight,
|
||||||
|
};
|
||||||
use parachains_common::AccountId;
|
use parachains_common::AccountId;
|
||||||
|
use polkadot_parachain::primitives::{HrmpChannelId, RelayChainBlockNumber};
|
||||||
use sp_consensus_aura::AURA_ENGINE_ID;
|
use sp_consensus_aura::AURA_ENGINE_ID;
|
||||||
use sp_core::Encode;
|
use sp_core::Encode;
|
||||||
use sp_runtime::{Digest, DigestItem};
|
use sp_runtime::{Digest, DigestItem};
|
||||||
|
use xcm::{
|
||||||
|
latest::{MultiAsset, MultiLocation, XcmContext, XcmHash},
|
||||||
|
prelude::{Concrete, Fungible, Outcome, XcmError, XcmVersion},
|
||||||
|
};
|
||||||
|
use xcm_executor::{traits::TransactAsset, Assets};
|
||||||
|
|
||||||
|
pub mod test_cases;
|
||||||
|
pub use test_cases::CollatorSessionKeys;
|
||||||
|
|
||||||
pub type BalanceOf<Runtime> = <Runtime as pallet_balances::Config>::Balance;
|
pub type BalanceOf<Runtime> = <Runtime as pallet_balances::Config>::Balance;
|
||||||
pub type AccountIdOf<Runtime> = <Runtime as frame_system::Config>::AccountId;
|
pub type AccountIdOf<Runtime> = <Runtime as frame_system::Config>::AccountId;
|
||||||
@@ -14,7 +30,11 @@ pub type SessionKeysOf<Runtime> = <Runtime as pallet_session::Config>::Keys;
|
|||||||
|
|
||||||
// Basic builder based on balances, collators and pallet_sessopm
|
// Basic builder based on balances, collators and pallet_sessopm
|
||||||
pub struct ExtBuilder<
|
pub struct ExtBuilder<
|
||||||
Runtime: frame_system::Config + pallet_balances::Config + pallet_session::Config,
|
Runtime: frame_system::Config
|
||||||
|
+ pallet_balances::Config
|
||||||
|
+ pallet_session::Config
|
||||||
|
+ pallet_xcm::Config
|
||||||
|
+ parachain_info::Config,
|
||||||
> {
|
> {
|
||||||
// endowed accounts with balances
|
// endowed accounts with balances
|
||||||
balances: Vec<(AccountIdOf<Runtime>, BalanceOf<Runtime>)>,
|
balances: Vec<(AccountIdOf<Runtime>, BalanceOf<Runtime>)>,
|
||||||
@@ -22,19 +42,40 @@ pub struct ExtBuilder<
|
|||||||
collators: Vec<AccountIdOf<Runtime>>,
|
collators: Vec<AccountIdOf<Runtime>>,
|
||||||
// keys added to pallet session
|
// keys added to pallet session
|
||||||
keys: Vec<(AccountIdOf<Runtime>, ValidatorIdOf<Runtime>, SessionKeysOf<Runtime>)>,
|
keys: Vec<(AccountIdOf<Runtime>, ValidatorIdOf<Runtime>, SessionKeysOf<Runtime>)>,
|
||||||
|
// safe xcm version for pallet_xcm
|
||||||
|
safe_xcm_version: Option<XcmVersion>,
|
||||||
|
// para id
|
||||||
|
para_id: Option<ParaId>,
|
||||||
_runtime: PhantomData<Runtime>,
|
_runtime: PhantomData<Runtime>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Runtime: frame_system::Config + pallet_balances::Config + pallet_session::Config> Default
|
impl<
|
||||||
for ExtBuilder<Runtime>
|
Runtime: frame_system::Config
|
||||||
|
+ pallet_balances::Config
|
||||||
|
+ pallet_session::Config
|
||||||
|
+ pallet_xcm::Config
|
||||||
|
+ parachain_info::Config,
|
||||||
|
> Default for ExtBuilder<Runtime>
|
||||||
{
|
{
|
||||||
fn default() -> ExtBuilder<Runtime> {
|
fn default() -> ExtBuilder<Runtime> {
|
||||||
ExtBuilder { balances: vec![], collators: vec![], keys: vec![], _runtime: PhantomData }
|
ExtBuilder {
|
||||||
|
balances: vec![],
|
||||||
|
collators: vec![],
|
||||||
|
keys: vec![],
|
||||||
|
safe_xcm_version: None,
|
||||||
|
para_id: None,
|
||||||
|
_runtime: PhantomData,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Runtime: frame_system::Config + pallet_balances::Config + pallet_session::Config>
|
impl<
|
||||||
ExtBuilder<Runtime>
|
Runtime: frame_system::Config
|
||||||
|
+ pallet_balances::Config
|
||||||
|
+ pallet_session::Config
|
||||||
|
+ pallet_xcm::Config
|
||||||
|
+ parachain_info::Config,
|
||||||
|
> ExtBuilder<Runtime>
|
||||||
{
|
{
|
||||||
pub fn with_balances(
|
pub fn with_balances(
|
||||||
mut self,
|
mut self,
|
||||||
@@ -56,6 +97,21 @@ impl<Runtime: frame_system::Config + pallet_balances::Config + pallet_session::C
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_tracing(self) -> Self {
|
||||||
|
frame_support::sp_tracing::try_init_simple();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_safe_xcm_version(mut self, safe_xcm_version: XcmVersion) -> Self {
|
||||||
|
self.safe_xcm_version = Some(safe_xcm_version);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_para_id(mut self, para_id: ParaId) -> Self {
|
||||||
|
self.para_id = Some(para_id);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn build(self) -> sp_io::TestExternalities
|
pub fn build(self) -> sp_io::TestExternalities
|
||||||
where
|
where
|
||||||
Runtime:
|
Runtime:
|
||||||
@@ -64,6 +120,20 @@ impl<Runtime: frame_system::Config + pallet_balances::Config + pallet_session::C
|
|||||||
{
|
{
|
||||||
let mut t = frame_system::GenesisConfig::default().build_storage::<Runtime>().unwrap();
|
let mut t = frame_system::GenesisConfig::default().build_storage::<Runtime>().unwrap();
|
||||||
|
|
||||||
|
<pallet_xcm::GenesisConfig as GenesisBuild<Runtime>>::assimilate_storage(
|
||||||
|
&pallet_xcm::GenesisConfig { safe_xcm_version: self.safe_xcm_version },
|
||||||
|
&mut t,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if let Some(para_id) = self.para_id {
|
||||||
|
<parachain_info::GenesisConfig as frame_support::traits::GenesisBuild<Runtime>>::assimilate_storage(
|
||||||
|
¶chain_info::GenesisConfig { parachain_id: para_id },
|
||||||
|
&mut t,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
pallet_balances::GenesisConfig::<Runtime> { balances: self.balances.into() }
|
pallet_balances::GenesisConfig::<Runtime> { balances: self.balances.into() }
|
||||||
.assimilate_storage(&mut t)
|
.assimilate_storage(&mut t)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -132,3 +202,184 @@ where
|
|||||||
<Runtime as frame_system::Config>::RuntimeOrigin::signed(account_id.into())
|
<Runtime as frame_system::Config>::RuntimeOrigin::signed(account_id.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<XcmConfig: xcm_executor::Config> RuntimeHelper<XcmConfig> {
|
||||||
|
pub fn do_transfer(
|
||||||
|
from: MultiLocation,
|
||||||
|
to: MultiLocation,
|
||||||
|
(asset, amount): (MultiLocation, u128),
|
||||||
|
) -> Result<Assets, XcmError> {
|
||||||
|
<XcmConfig::AssetTransactor as TransactAsset>::transfer_asset(
|
||||||
|
&MultiAsset { id: Concrete(asset), fun: Fungible(amount) },
|
||||||
|
&from,
|
||||||
|
&to,
|
||||||
|
// We aren't able to track the XCM that initiated the fee deposit, so we create a
|
||||||
|
// fake message hash here
|
||||||
|
&XcmContext::with_message_hash([0; 32]),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Runtime: pallet_xcm::Config + cumulus_pallet_parachain_system::Config> RuntimeHelper<Runtime> {
|
||||||
|
pub fn do_teleport_assets<HrmpChannelOpener>(
|
||||||
|
origin: <Runtime as frame_system::Config>::RuntimeOrigin,
|
||||||
|
dest: MultiLocation,
|
||||||
|
beneficiary: MultiLocation,
|
||||||
|
(asset, amount): (MultiLocation, u128),
|
||||||
|
open_hrmp_channel: Option<(u32, u32)>,
|
||||||
|
) -> DispatchResult
|
||||||
|
where
|
||||||
|
HrmpChannelOpener: frame_support::inherent::ProvideInherent<
|
||||||
|
Call = cumulus_pallet_parachain_system::Call<Runtime>,
|
||||||
|
>,
|
||||||
|
{
|
||||||
|
// open hrmp (if needed)
|
||||||
|
if let Some((source_para_id, target_para_id)) = open_hrmp_channel {
|
||||||
|
mock_open_hrmp_channel::<Runtime, HrmpChannelOpener>(
|
||||||
|
source_para_id.into(),
|
||||||
|
target_para_id.into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// do teleport
|
||||||
|
<pallet_xcm::Pallet<Runtime>>::teleport_assets(
|
||||||
|
origin,
|
||||||
|
Box::new(dest.into()),
|
||||||
|
Box::new(beneficiary.into()),
|
||||||
|
Box::new((Concrete(asset), amount).into()),
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum XcmReceivedFrom {
|
||||||
|
Parent,
|
||||||
|
Sibling,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<ParachainSystem: cumulus_pallet_parachain_system::Config> RuntimeHelper<ParachainSystem> {
|
||||||
|
pub fn xcm_max_weight(from: XcmReceivedFrom) -> Weight {
|
||||||
|
use frame_support::traits::Get;
|
||||||
|
match from {
|
||||||
|
XcmReceivedFrom::Parent => ParachainSystem::ReservedDmpWeight::get(),
|
||||||
|
XcmReceivedFrom::Sibling => ParachainSystem::ReservedXcmpWeight::get(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Runtime: frame_system::Config + pallet_xcm::Config> RuntimeHelper<Runtime> {
|
||||||
|
pub fn assert_pallet_xcm_event_outcome(
|
||||||
|
unwrap_pallet_xcm_event: &Box<dyn Fn(Vec<u8>) -> Option<pallet_xcm::Event<Runtime>>>,
|
||||||
|
assert_outcome: fn(Outcome),
|
||||||
|
) {
|
||||||
|
let outcome = <frame_system::Pallet<Runtime>>::events()
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|e| unwrap_pallet_xcm_event(e.event.encode()))
|
||||||
|
.find_map(|e| match e {
|
||||||
|
pallet_xcm::Event::Attempted(outcome) => Some(outcome),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
match outcome {
|
||||||
|
Some(outcome) => assert_outcome(outcome),
|
||||||
|
None => assert!(false, "No `pallet_xcm::Event::Attempted(outcome)` event found!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Runtime: frame_system::Config + cumulus_pallet_xcmp_queue::Config> RuntimeHelper<Runtime> {
|
||||||
|
pub fn xcmp_queue_message_sent(
|
||||||
|
unwrap_xcmp_queue_event: Box<
|
||||||
|
dyn Fn(Vec<u8>) -> Option<cumulus_pallet_xcmp_queue::Event<Runtime>>,
|
||||||
|
>,
|
||||||
|
) -> Option<XcmHash> {
|
||||||
|
<frame_system::Pallet<Runtime>>::events()
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|e| unwrap_xcmp_queue_event(e.event.encode()))
|
||||||
|
.find_map(|e| match e {
|
||||||
|
cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { message_hash } => message_hash,
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn assert_metadata<Fungibles, AccountId>(
|
||||||
|
asset_id: impl Into<Fungibles::AssetId> + Copy,
|
||||||
|
expected_name: &str,
|
||||||
|
expected_symbol: &str,
|
||||||
|
expected_decimals: u8,
|
||||||
|
) where
|
||||||
|
Fungibles: frame_support::traits::tokens::fungibles::metadata::Inspect<AccountId>
|
||||||
|
+ frame_support::traits::tokens::fungibles::Inspect<AccountId>,
|
||||||
|
{
|
||||||
|
assert_eq!(Fungibles::name(asset_id.into()), Vec::from(expected_name),);
|
||||||
|
assert_eq!(Fungibles::symbol(asset_id.into()), Vec::from(expected_symbol),);
|
||||||
|
assert_eq!(Fungibles::decimals(asset_id.into()), expected_decimals);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn assert_total<Fungibles, AccountId>(
|
||||||
|
asset_id: impl Into<Fungibles::AssetId> + Copy,
|
||||||
|
expected_total_issuance: impl Into<Fungibles::Balance>,
|
||||||
|
expected_active_issuance: impl Into<Fungibles::Balance>,
|
||||||
|
) where
|
||||||
|
Fungibles: frame_support::traits::tokens::fungibles::metadata::Inspect<AccountId>
|
||||||
|
+ frame_support::traits::tokens::fungibles::Inspect<AccountId>,
|
||||||
|
{
|
||||||
|
assert_eq!(Fungibles::total_issuance(asset_id.into()), expected_total_issuance.into());
|
||||||
|
assert_eq!(Fungibles::active_issuance(asset_id.into()), expected_active_issuance.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper function which emulates opening HRMP channel which is needed for `XcmpQueue` to pass
|
||||||
|
pub fn mock_open_hrmp_channel<
|
||||||
|
C: cumulus_pallet_parachain_system::Config,
|
||||||
|
T: ProvideInherent<Call = cumulus_pallet_parachain_system::Call<C>>,
|
||||||
|
>(
|
||||||
|
sender: ParaId,
|
||||||
|
recipient: ParaId,
|
||||||
|
) {
|
||||||
|
let n = 1_u32;
|
||||||
|
let mut sproof_builder = RelayStateSproofBuilder::default();
|
||||||
|
sproof_builder.para_id = sender;
|
||||||
|
sproof_builder.hrmp_channels.insert(
|
||||||
|
HrmpChannelId { sender, recipient },
|
||||||
|
AbridgedHrmpChannel {
|
||||||
|
max_capacity: 10,
|
||||||
|
max_total_size: 10_000_000_u32,
|
||||||
|
max_message_size: 10_000_000_u32,
|
||||||
|
msg_count: 0,
|
||||||
|
total_size: 0_u32,
|
||||||
|
mqc_head: None,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
sproof_builder.hrmp_egress_channel_index = Some(vec![recipient]);
|
||||||
|
|
||||||
|
let (relay_parent_storage_root, relay_chain_state) = sproof_builder.into_state_root_and_proof();
|
||||||
|
let vfp = PersistedValidationData {
|
||||||
|
relay_parent_number: n as RelayChainBlockNumber,
|
||||||
|
relay_parent_storage_root,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
// It is insufficient to push the validation function params
|
||||||
|
// to storage; they must also be included in the inherent data.
|
||||||
|
let inherent_data = {
|
||||||
|
let mut inherent_data = InherentData::default();
|
||||||
|
let system_inherent_data = ParachainInherentData {
|
||||||
|
validation_data: vfp.clone(),
|
||||||
|
relay_chain_state,
|
||||||
|
downward_messages: Default::default(),
|
||||||
|
horizontal_messages: Default::default(),
|
||||||
|
};
|
||||||
|
inherent_data
|
||||||
|
.put_data(
|
||||||
|
cumulus_primitives_parachain_inherent::INHERENT_IDENTIFIER,
|
||||||
|
&system_inherent_data,
|
||||||
|
)
|
||||||
|
.expect("failed to put VFP inherent");
|
||||||
|
inherent_data
|
||||||
|
};
|
||||||
|
|
||||||
|
// execute the block
|
||||||
|
T::create_inherent(&inherent_data)
|
||||||
|
.expect("got an inherent")
|
||||||
|
.dispatch_bypass_filter(RawOrigin::None.into())
|
||||||
|
.expect("dispatch succeeded");
|
||||||
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -103,6 +103,7 @@ runtime-benchmarks = [
|
|||||||
"pallet-collator-selection/runtime-benchmarks",
|
"pallet-collator-selection/runtime-benchmarks",
|
||||||
"cumulus-pallet-xcmp-queue/runtime-benchmarks",
|
"cumulus-pallet-xcmp-queue/runtime-benchmarks",
|
||||||
"pallet-xcm-benchmarks/runtime-benchmarks",
|
"pallet-xcm-benchmarks/runtime-benchmarks",
|
||||||
|
"assets-common/runtime-benchmarks",
|
||||||
]
|
]
|
||||||
try-runtime = [
|
try-runtime = [
|
||||||
"cumulus-pallet-aura-ext/try-runtime",
|
"cumulus-pallet-aura-ext/try-runtime",
|
||||||
|
|||||||
@@ -69,17 +69,20 @@ use parachains_common::{
|
|||||||
NORMAL_DISPATCH_RATIO, SLOT_DURATION,
|
NORMAL_DISPATCH_RATIO, SLOT_DURATION,
|
||||||
};
|
};
|
||||||
use xcm_config::{
|
use xcm_config::{
|
||||||
TrustBackedAssetsConvertedConcreteId, WestendLocation, XcmConfig,
|
ForeignAssetsConvertedConcreteId, TrustBackedAssetsConvertedConcreteId, WestendLocation,
|
||||||
XcmOriginToTransactDispatchOrigin,
|
XcmConfig, XcmOriginToTransactDispatchOrigin,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(any(feature = "std", test))]
|
#[cfg(any(feature = "std", test))]
|
||||||
pub use sp_runtime::BuildStorage;
|
pub use sp_runtime::BuildStorage;
|
||||||
|
|
||||||
// Polkadot imports
|
use assets_common::{
|
||||||
|
foreign_creators::ForeignCreators, matching::FromSiblingParachain, MultiLocationForAssetId,
|
||||||
|
};
|
||||||
use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate};
|
use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate};
|
||||||
use xcm_executor::XcmExecutor;
|
use xcm_executor::XcmExecutor;
|
||||||
|
|
||||||
|
use crate::xcm_config::ForeignCreatorsSovereignAccountOf;
|
||||||
use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight};
|
use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight};
|
||||||
|
|
||||||
impl_opaque_keys! {
|
impl_opaque_keys! {
|
||||||
@@ -250,6 +253,48 @@ impl pallet_assets::Config<TrustBackedAssetsInstance> for Runtime {
|
|||||||
type BenchmarkHelper = ();
|
type BenchmarkHelper = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parameter_types! {
|
||||||
|
// we just reuse the same deposits
|
||||||
|
pub const ForeignAssetsAssetDeposit: Balance = AssetDeposit::get();
|
||||||
|
pub const ForeignAssetsAssetAccountDeposit: Balance = AssetAccountDeposit::get();
|
||||||
|
pub const ForeignAssetsApprovalDeposit: Balance = ApprovalDeposit::get();
|
||||||
|
pub const ForeignAssetsAssetsStringLimit: u32 = AssetsStringLimit::get();
|
||||||
|
pub const ForeignAssetsMetadataDepositBase: Balance = MetadataDepositBase::get();
|
||||||
|
pub const ForeignAssetsMetadataDepositPerByte: Balance = MetadataDepositPerByte::get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assets managed by some foreign location. Note: we do not declare a `ForeignAssetsCall` type, as
|
||||||
|
/// this type is used in proxy definitions. We assume that a foreign location would not want to set
|
||||||
|
/// an individual, local account as a proxy for the issuance of their assets. This issuance should
|
||||||
|
/// be managed by the foreign location's governance.
|
||||||
|
pub type ForeignAssetsInstance = pallet_assets::Instance2;
|
||||||
|
impl pallet_assets::Config<ForeignAssetsInstance> for Runtime {
|
||||||
|
type RuntimeEvent = RuntimeEvent;
|
||||||
|
type Balance = Balance;
|
||||||
|
type AssetId = MultiLocationForAssetId;
|
||||||
|
type AssetIdParameter = MultiLocationForAssetId;
|
||||||
|
type Currency = Balances;
|
||||||
|
type CreateOrigin = ForeignCreators<
|
||||||
|
(FromSiblingParachain<parachain_info::Pallet<Runtime>>,),
|
||||||
|
ForeignCreatorsSovereignAccountOf,
|
||||||
|
AccountId,
|
||||||
|
>;
|
||||||
|
type ForceOrigin = AssetsForceOrigin;
|
||||||
|
type AssetDeposit = ForeignAssetsAssetDeposit;
|
||||||
|
type MetadataDepositBase = ForeignAssetsMetadataDepositBase;
|
||||||
|
type MetadataDepositPerByte = ForeignAssetsMetadataDepositPerByte;
|
||||||
|
type ApprovalDeposit = ForeignAssetsApprovalDeposit;
|
||||||
|
type StringLimit = ForeignAssetsAssetsStringLimit;
|
||||||
|
type Freezer = ();
|
||||||
|
type Extra = ();
|
||||||
|
type WeightInfo = weights::pallet_assets::WeightInfo<Runtime>;
|
||||||
|
type CallbackHandle = ();
|
||||||
|
type AssetAccountDeposit = ForeignAssetsAssetAccountDeposit;
|
||||||
|
type RemoveItemsLimit = frame_support::traits::ConstU32<1000>;
|
||||||
|
#[cfg(feature = "runtime-benchmarks")]
|
||||||
|
type BenchmarkHelper = xcm_config::XcmBenchmarkHelper;
|
||||||
|
}
|
||||||
|
|
||||||
parameter_types! {
|
parameter_types! {
|
||||||
// One storage item; key size is 32; value is size 4+4+16+32 bytes = 56 bytes.
|
// One storage item; key size is 32; value is size 4+4+16+32 bytes = 56 bytes.
|
||||||
pub const DepositBase: Balance = deposit(1, 88);
|
pub const DepositBase: Balance = deposit(1, 88);
|
||||||
@@ -322,6 +367,7 @@ impl Default for ProxyType {
|
|||||||
Self::Any
|
Self::Any
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InstanceFilter<RuntimeCall> for ProxyType {
|
impl InstanceFilter<RuntimeCall> for ProxyType {
|
||||||
fn filter(&self, c: &RuntimeCall) -> bool {
|
fn filter(&self, c: &RuntimeCall) -> bool {
|
||||||
match self {
|
match self {
|
||||||
@@ -661,6 +707,7 @@ construct_runtime!(
|
|||||||
Assets: pallet_assets::<Instance1>::{Pallet, Call, Storage, Event<T>} = 50,
|
Assets: pallet_assets::<Instance1>::{Pallet, Call, Storage, Event<T>} = 50,
|
||||||
Uniques: pallet_uniques::{Pallet, Call, Storage, Event<T>} = 51,
|
Uniques: pallet_uniques::{Pallet, Call, Storage, Event<T>} = 51,
|
||||||
Nfts: pallet_nfts::{Pallet, Call, Storage, Event<T>} = 52,
|
Nfts: pallet_nfts::{Pallet, Call, Storage, Event<T>} = 52,
|
||||||
|
ForeignAssets: pallet_assets::<Instance2>::{Pallet, Call, Storage, Event<T>} = 53,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -710,6 +757,7 @@ mod benches {
|
|||||||
define_benchmarks!(
|
define_benchmarks!(
|
||||||
[frame_system, SystemBench::<Runtime>]
|
[frame_system, SystemBench::<Runtime>]
|
||||||
[pallet_assets, Assets]
|
[pallet_assets, Assets]
|
||||||
|
[pallet_assets, ForeignAssets]
|
||||||
[pallet_balances, Balances]
|
[pallet_balances, Balances]
|
||||||
[pallet_multisig, Multisig]
|
[pallet_multisig, Multisig]
|
||||||
[pallet_nfts, Nfts]
|
[pallet_nfts, Nfts]
|
||||||
@@ -929,11 +977,17 @@ impl_runtime_apis! {
|
|||||||
},
|
},
|
||||||
// collect pallet_assets (TrustBackedAssets)
|
// collect pallet_assets (TrustBackedAssets)
|
||||||
convert::<_, _, _, _, TrustBackedAssetsConvertedConcreteId>(
|
convert::<_, _, _, _, TrustBackedAssetsConvertedConcreteId>(
|
||||||
Assets::account_balances(account)
|
Assets::account_balances(account.clone())
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, balance)| balance > &0)
|
.filter(|(_, balance)| balance > &0)
|
||||||
)?,
|
)?,
|
||||||
// collect ... e.g. pallet_assets ForeignAssets
|
// collect pallet_assets (ForeignAssets)
|
||||||
|
convert::<_, _, _, _, ForeignAssetsConvertedConcreteId>(
|
||||||
|
ForeignAssets::account_balances(account)
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, balance)| balance > &0)
|
||||||
|
)?,
|
||||||
|
// collect ... e.g. other tokens
|
||||||
].concat())
|
].concat())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ use super::{
|
|||||||
ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
|
ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
|
||||||
TrustBackedAssetsInstance, WeightToFee, XcmpQueue,
|
TrustBackedAssetsInstance, WeightToFee, XcmpQueue,
|
||||||
};
|
};
|
||||||
|
use crate::ForeignAssets;
|
||||||
|
use assets_common::matching::{
|
||||||
|
FromSiblingParachain, IsForeignConcreteAsset, StartsWith, StartsWithExplicitGlobalConsensus,
|
||||||
|
};
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
match_types, parameter_types,
|
match_types, parameter_types,
|
||||||
traits::{ConstU32, Contains, Everything, Nothing, PalletInfoAccess},
|
traits::{ConstU32, Contains, Everything, Nothing, PalletInfoAccess},
|
||||||
@@ -36,8 +40,8 @@ use xcm::latest::prelude::*;
|
|||||||
use xcm_builder::{
|
use xcm_builder::{
|
||||||
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
|
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
|
||||||
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, EnsureXcmOrigin,
|
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, EnsureXcmOrigin,
|
||||||
FungiblesAdapter, IsConcrete, LocalMint, NativeAsset, ParentAsSuperuser, ParentIsPreset,
|
FungiblesAdapter, IsConcrete, LocalMint, NativeAsset, NoChecking, ParentAsSuperuser,
|
||||||
RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
|
ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
|
||||||
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
|
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
|
||||||
UsingComponents, WeightInfoBounds, WithComputedOrigin,
|
UsingComponents, WeightInfoBounds, WithComputedOrigin,
|
||||||
};
|
};
|
||||||
@@ -49,7 +53,7 @@ parameter_types! {
|
|||||||
pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
|
pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
|
||||||
pub UniversalLocation: InteriorMultiLocation =
|
pub UniversalLocation: InteriorMultiLocation =
|
||||||
X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into()));
|
X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into()));
|
||||||
pub const Local: MultiLocation = Here.into_location();
|
pub UniversalLocationNetworkId: NetworkId = UniversalLocation::get().global_consensus().unwrap();
|
||||||
pub TrustBackedAssetsPalletLocation: MultiLocation =
|
pub TrustBackedAssetsPalletLocation: MultiLocation =
|
||||||
PalletInstance(<Assets as PalletInfoAccess>::index() as u8).into();
|
PalletInstance(<Assets as PalletInfoAccess>::index() as u8).into();
|
||||||
pub CheckingAccount: AccountId = PolkadotXcm::check_account();
|
pub CheckingAccount: AccountId = PolkadotXcm::check_account();
|
||||||
@@ -81,7 +85,7 @@ pub type CurrencyTransactor = CurrencyAdapter<
|
|||||||
(),
|
(),
|
||||||
>;
|
>;
|
||||||
|
|
||||||
/// `AssetId/Balancer` converter for `TrustBackedAssets`
|
/// `AssetId/Balance` converter for `TrustBackedAssets`
|
||||||
pub type TrustBackedAssetsConvertedConcreteId =
|
pub type TrustBackedAssetsConvertedConcreteId =
|
||||||
assets_common::TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, Balance>;
|
assets_common::TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, Balance>;
|
||||||
|
|
||||||
@@ -101,8 +105,38 @@ pub type FungiblesTransactor = FungiblesAdapter<
|
|||||||
// The account to use for tracking teleports.
|
// The account to use for tracking teleports.
|
||||||
CheckingAccount,
|
CheckingAccount,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
/// `AssetId/Balance` converter for `TrustBackedAssets`
|
||||||
|
pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConvertedConcreteId<
|
||||||
|
(
|
||||||
|
// Ignore `TrustBackedAssets` explicitly
|
||||||
|
StartsWith<TrustBackedAssetsPalletLocation>,
|
||||||
|
// Ignore asset which starts explicitly with our `GlobalConsensus(NetworkId)`, means:
|
||||||
|
// - foreign assets from our consensus should be: `MultiLocation {parent: 1, X*(Parachain(xyz))}
|
||||||
|
// - foreign assets outside our consensus with the same `GlobalConsensus(NetworkId)` wont be accepted here
|
||||||
|
StartsWithExplicitGlobalConsensus<UniversalLocationNetworkId>,
|
||||||
|
),
|
||||||
|
Balance,
|
||||||
|
>;
|
||||||
|
|
||||||
|
/// Means for transacting foreign assets from different global consensus.
|
||||||
|
pub type ForeignFungiblesTransactor = FungiblesAdapter<
|
||||||
|
// Use this fungibles implementation:
|
||||||
|
ForeignAssets,
|
||||||
|
// Use this currency when it is a fungible asset matching the given location or name:
|
||||||
|
ForeignAssetsConvertedConcreteId,
|
||||||
|
// Convert an XCM MultiLocation into a local account id:
|
||||||
|
LocationToAccountId,
|
||||||
|
// Our chain's account ID type (we can't get away without mentioning it explicitly):
|
||||||
|
AccountId,
|
||||||
|
// We dont need to check teleports here.
|
||||||
|
NoChecking,
|
||||||
|
// The account to use for tracking teleports.
|
||||||
|
CheckingAccount,
|
||||||
|
>;
|
||||||
|
|
||||||
/// Means for transacting assets on this chain.
|
/// Means for transacting assets on this chain.
|
||||||
pub type AssetTransactors = (CurrencyTransactor, FungiblesTransactor);
|
pub type AssetTransactors = (CurrencyTransactor, FungiblesTransactor, ForeignFungiblesTransactor);
|
||||||
|
|
||||||
/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,
|
/// 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
|
/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can
|
||||||
@@ -177,7 +211,11 @@ impl Contains<RuntimeCall> for SafeCallFilter {
|
|||||||
RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) |
|
RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) |
|
||||||
RuntimeCall::XcmpQueue(..) |
|
RuntimeCall::XcmpQueue(..) |
|
||||||
RuntimeCall::DmpQueue(..) |
|
RuntimeCall::DmpQueue(..) |
|
||||||
RuntimeCall::Utility(pallet_utility::Call::as_derivative { .. }) |
|
RuntimeCall::Utility(
|
||||||
|
pallet_utility::Call::as_derivative { .. } |
|
||||||
|
pallet_utility::Call::batch { .. } |
|
||||||
|
pallet_utility::Call::batch_all { .. },
|
||||||
|
) |
|
||||||
RuntimeCall::Assets(
|
RuntimeCall::Assets(
|
||||||
pallet_assets::Call::create { .. } |
|
pallet_assets::Call::create { .. } |
|
||||||
pallet_assets::Call::force_create { .. } |
|
pallet_assets::Call::force_create { .. } |
|
||||||
@@ -206,6 +244,35 @@ impl Contains<RuntimeCall> for SafeCallFilter {
|
|||||||
pallet_assets::Call::touch { .. } |
|
pallet_assets::Call::touch { .. } |
|
||||||
pallet_assets::Call::refund { .. },
|
pallet_assets::Call::refund { .. },
|
||||||
) |
|
) |
|
||||||
|
RuntimeCall::ForeignAssets(
|
||||||
|
pallet_assets::Call::create { .. } |
|
||||||
|
pallet_assets::Call::force_create { .. } |
|
||||||
|
pallet_assets::Call::start_destroy { .. } |
|
||||||
|
pallet_assets::Call::destroy_accounts { .. } |
|
||||||
|
pallet_assets::Call::destroy_approvals { .. } |
|
||||||
|
pallet_assets::Call::finish_destroy { .. } |
|
||||||
|
pallet_assets::Call::mint { .. } |
|
||||||
|
pallet_assets::Call::burn { .. } |
|
||||||
|
pallet_assets::Call::transfer { .. } |
|
||||||
|
pallet_assets::Call::transfer_keep_alive { .. } |
|
||||||
|
pallet_assets::Call::force_transfer { .. } |
|
||||||
|
pallet_assets::Call::freeze { .. } |
|
||||||
|
pallet_assets::Call::thaw { .. } |
|
||||||
|
pallet_assets::Call::freeze_asset { .. } |
|
||||||
|
pallet_assets::Call::thaw_asset { .. } |
|
||||||
|
pallet_assets::Call::transfer_ownership { .. } |
|
||||||
|
pallet_assets::Call::set_team { .. } |
|
||||||
|
pallet_assets::Call::set_metadata { .. } |
|
||||||
|
pallet_assets::Call::clear_metadata { .. } |
|
||||||
|
pallet_assets::Call::force_clear_metadata { .. } |
|
||||||
|
pallet_assets::Call::force_asset_status { .. } |
|
||||||
|
pallet_assets::Call::approve_transfer { .. } |
|
||||||
|
pallet_assets::Call::cancel_approval { .. } |
|
||||||
|
pallet_assets::Call::force_cancel_approval { .. } |
|
||||||
|
pallet_assets::Call::transfer_approved { .. } |
|
||||||
|
pallet_assets::Call::touch { .. } |
|
||||||
|
pallet_assets::Call::refund { .. },
|
||||||
|
) |
|
||||||
RuntimeCall::Nfts(
|
RuntimeCall::Nfts(
|
||||||
pallet_nfts::Call::create { .. } |
|
pallet_nfts::Call::create { .. } |
|
||||||
pallet_nfts::Call::force_create { .. } |
|
pallet_nfts::Call::force_create { .. } |
|
||||||
@@ -315,7 +382,13 @@ impl xcm_executor::Config for XcmConfig {
|
|||||||
// Westmint acting _as_ a reserve location for WND and assets created under `pallet-assets`.
|
// Westmint acting _as_ a reserve location for WND and assets created under `pallet-assets`.
|
||||||
// For WND, users must use teleport where allowed (e.g. with the Relay Chain).
|
// For WND, users must use teleport where allowed (e.g. with the Relay Chain).
|
||||||
type IsReserve = ();
|
type IsReserve = ();
|
||||||
type IsTeleporter = NativeAsset; // <- should be enough to allow teleportation of WND
|
// We allow:
|
||||||
|
// - teleportation of WND
|
||||||
|
// - teleportation of sibling parachain's assets (as ForeignCreators)
|
||||||
|
type IsTeleporter = (
|
||||||
|
NativeAsset,
|
||||||
|
IsForeignConcreteAsset<FromSiblingParachain<parachain_info::Pallet<Runtime>>>,
|
||||||
|
);
|
||||||
type UniversalLocation = UniversalLocation;
|
type UniversalLocation = UniversalLocation;
|
||||||
type Barrier = Barrier;
|
type Barrier = Barrier;
|
||||||
type Weigher = WeightInfoBounds<
|
type Weigher = WeightInfoBounds<
|
||||||
@@ -403,3 +476,20 @@ impl cumulus_pallet_xcm::Config for Runtime {
|
|||||||
type RuntimeEvent = RuntimeEvent;
|
type RuntimeEvent = RuntimeEvent;
|
||||||
type XcmExecutor = XcmExecutor<XcmConfig>;
|
type XcmExecutor = XcmExecutor<XcmConfig>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type ForeignCreatorsSovereignAccountOf = (
|
||||||
|
SiblingParachainConvertsVia<Sibling, AccountId>,
|
||||||
|
AccountId32Aliases<RelayNetwork, AccountId>,
|
||||||
|
ParentIsPreset<AccountId>,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Simple conversion of `u32` into an `AssetId` for use in benchmarking.
|
||||||
|
pub struct XcmBenchmarkHelper;
|
||||||
|
#[cfg(feature = "runtime-benchmarks")]
|
||||||
|
use pallet_assets::BenchmarkHelper;
|
||||||
|
#[cfg(feature = "runtime-benchmarks")]
|
||||||
|
impl BenchmarkHelper<MultiLocation> for XcmBenchmarkHelper {
|
||||||
|
fn create_asset_id_parameter(id: u32) -> MultiLocation {
|
||||||
|
MultiLocation { parents: 1, interior: X1(Parachain(id)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,27 +1,34 @@
|
|||||||
use asset_test_utils::{ExtBuilder, RuntimeHelper};
|
use asset_test_utils::{ExtBuilder, RuntimeHelper, XcmReceivedFrom};
|
||||||
use codec::{DecodeLimit, Encode};
|
use codec::{Decode, DecodeLimit, Encode};
|
||||||
use cumulus_primitives_utility::ChargeWeightInFungibles;
|
use cumulus_primitives_utility::ChargeWeightInFungibles;
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
assert_noop, assert_ok, sp_io,
|
assert_noop, assert_ok, sp_io,
|
||||||
|
traits::fungibles::InspectEnumerable,
|
||||||
weights::{Weight, WeightToFee as WeightToFeeT},
|
weights::{Weight, WeightToFee as WeightToFeeT},
|
||||||
};
|
};
|
||||||
use parachains_common::{AccountId, AuraId, Balance};
|
use parachains_common::{AccountId, AssetIdForTrustBackedAssets, AuraId, Balance};
|
||||||
|
use std::convert::Into;
|
||||||
pub use westmint_runtime::{
|
pub use westmint_runtime::{
|
||||||
constants::fee::WeightToFee,
|
constants::fee::WeightToFee,
|
||||||
xcm_config::{TrustBackedAssetsPalletLocation, XcmConfig},
|
xcm_config::{CheckingAccount, TrustBackedAssetsPalletLocation, XcmConfig},
|
||||||
Assets, Balances, ExistentialDeposit, ReservedDmpWeight, Runtime, SessionKeys, System,
|
AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance,
|
||||||
|
ParachainSystem, Runtime, SessionKeys, System, TrustBackedAssetsInstance,
|
||||||
};
|
};
|
||||||
use westmint_runtime::{
|
use westmint_runtime::{
|
||||||
xcm_config::{AssetFeeAsExistentialDepositMultiplierFeeCharger, WestendLocation},
|
xcm_config::{
|
||||||
RuntimeCall,
|
AssetFeeAsExistentialDepositMultiplierFeeCharger, ForeignCreatorsSovereignAccountOf,
|
||||||
|
WestendLocation,
|
||||||
|
},
|
||||||
|
MetadataDepositBase, MetadataDepositPerByte, RuntimeCall, RuntimeEvent,
|
||||||
};
|
};
|
||||||
use xcm::{latest::prelude::*, VersionedXcm, MAX_XCM_DECODE_DEPTH};
|
use xcm::{latest::prelude::*, VersionedXcm, MAX_XCM_DECODE_DEPTH};
|
||||||
use xcm_executor::{
|
use xcm_executor::{
|
||||||
traits::{Convert, WeightTrader},
|
traits::{Convert, Identity, JustTry, WeightTrader},
|
||||||
XcmExecutor,
|
XcmExecutor,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ALICE: [u8; 32] = [1u8; 32];
|
const ALICE: [u8; 32] = [1u8; 32];
|
||||||
|
const SOME_ASSET_ADMIN: [u8; 32] = [5u8; 32];
|
||||||
|
|
||||||
type AssetIdForTrustBackedAssetsConvert =
|
type AssetIdForTrustBackedAssetsConvert =
|
||||||
assets_common::AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation>;
|
assets_common::AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation>;
|
||||||
@@ -371,9 +378,15 @@ fn test_assets_balances_api_works() {
|
|||||||
.build()
|
.build()
|
||||||
.execute_with(|| {
|
.execute_with(|| {
|
||||||
let local_asset_id = 1;
|
let local_asset_id = 1;
|
||||||
|
let foreign_asset_id_multilocation =
|
||||||
|
MultiLocation { parents: 1, interior: X2(Parachain(1234), GeneralIndex(12345)) };
|
||||||
|
|
||||||
// check before
|
// check before
|
||||||
assert_eq!(Assets::balance(local_asset_id, AccountId::from(ALICE)), 0);
|
assert_eq!(Assets::balance(local_asset_id, AccountId::from(ALICE)), 0);
|
||||||
|
assert_eq!(
|
||||||
|
ForeignAssets::balance(foreign_asset_id_multilocation, AccountId::from(ALICE)),
|
||||||
|
0
|
||||||
|
);
|
||||||
assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 0);
|
assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 0);
|
||||||
assert!(Runtime::query_account_balances(AccountId::from(ALICE)).unwrap().is_empty());
|
assert!(Runtime::query_account_balances(AccountId::from(ALICE)).unwrap().is_empty());
|
||||||
|
|
||||||
@@ -400,15 +413,37 @@ fn test_assets_balances_api_works() {
|
|||||||
minimum_asset_balance
|
minimum_asset_balance
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// create foreign asset
|
||||||
|
let foreign_asset_minimum_asset_balance = 3333333_u128;
|
||||||
|
assert_ok!(ForeignAssets::force_create(
|
||||||
|
RuntimeHelper::<Runtime>::root_origin(),
|
||||||
|
foreign_asset_id_multilocation.clone().into(),
|
||||||
|
AccountId::from(SOME_ASSET_ADMIN).into(),
|
||||||
|
false,
|
||||||
|
foreign_asset_minimum_asset_balance
|
||||||
|
));
|
||||||
|
|
||||||
|
// We first mint enough asset for the account to exist for assets
|
||||||
|
assert_ok!(ForeignAssets::mint(
|
||||||
|
RuntimeHelper::<Runtime>::origin_of(AccountId::from(SOME_ASSET_ADMIN)),
|
||||||
|
foreign_asset_id_multilocation.clone().into(),
|
||||||
|
AccountId::from(ALICE).into(),
|
||||||
|
6 * foreign_asset_minimum_asset_balance
|
||||||
|
));
|
||||||
|
|
||||||
// check after
|
// check after
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Assets::balance(local_asset_id, AccountId::from(ALICE)),
|
Assets::balance(local_asset_id, AccountId::from(ALICE)),
|
||||||
minimum_asset_balance
|
minimum_asset_balance
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ForeignAssets::balance(foreign_asset_id_multilocation, AccountId::from(ALICE)),
|
||||||
|
6 * minimum_asset_balance
|
||||||
|
);
|
||||||
assert_eq!(Balances::free_balance(AccountId::from(ALICE)), some_currency);
|
assert_eq!(Balances::free_balance(AccountId::from(ALICE)), some_currency);
|
||||||
|
|
||||||
let result = Runtime::query_account_balances(AccountId::from(ALICE)).unwrap();
|
let result = Runtime::query_account_balances(AccountId::from(ALICE)).unwrap();
|
||||||
assert_eq!(result.len(), 2);
|
assert_eq!(result.len(), 3);
|
||||||
|
|
||||||
// check currency
|
// check currency
|
||||||
assert!(result.iter().any(|asset| asset.eq(
|
assert!(result.iter().any(|asset| asset.eq(
|
||||||
@@ -423,56 +458,165 @@ fn test_assets_balances_api_works() {
|
|||||||
minimum_asset_balance
|
minimum_asset_balance
|
||||||
)
|
)
|
||||||
.into())));
|
.into())));
|
||||||
|
// check foreign asset
|
||||||
|
assert!(result.iter().any(|asset| asset.eq(&(
|
||||||
|
Identity::reverse_ref(foreign_asset_id_multilocation).unwrap(),
|
||||||
|
6 * foreign_asset_minimum_asset_balance
|
||||||
|
)
|
||||||
|
.into())));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
asset_test_utils::include_teleports_for_native_asset_works!(
|
||||||
fn receive_teleported_asset_works() {
|
Runtime,
|
||||||
ExtBuilder::<Runtime>::default()
|
XcmConfig,
|
||||||
.with_collators(vec![AccountId::from(ALICE)])
|
CheckingAccount,
|
||||||
.with_session_keys(vec![(
|
WeightToFee,
|
||||||
|
ParachainSystem,
|
||||||
|
asset_test_utils::CollatorSessionKeys::new(
|
||||||
AccountId::from(ALICE),
|
AccountId::from(ALICE),
|
||||||
AccountId::from(ALICE),
|
AccountId::from(ALICE),
|
||||||
SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) },
|
SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) }
|
||||||
)])
|
),
|
||||||
.build()
|
ExistentialDeposit::get(),
|
||||||
.execute_with(|| {
|
Box::new(|runtime_event_encoded: Vec<u8>| {
|
||||||
let xcm = Xcm(vec![
|
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
|
||||||
ReceiveTeleportedAsset(MultiAssets::from(vec![MultiAsset {
|
Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event),
|
||||||
id: Concrete(MultiLocation { parents: 1, interior: Here }),
|
_ => None,
|
||||||
fun: Fungible(10000000000000),
|
|
||||||
}])),
|
|
||||||
ClearOrigin,
|
|
||||||
BuyExecution {
|
|
||||||
fees: MultiAsset {
|
|
||||||
id: Concrete(MultiLocation { parents: 1, interior: Here }),
|
|
||||||
fun: Fungible(10000000000000),
|
|
||||||
},
|
|
||||||
weight_limit: Limited(Weight::from_parts(303531000, 65536)),
|
|
||||||
},
|
|
||||||
DepositAsset {
|
|
||||||
assets: Wild(AllCounted(1)),
|
|
||||||
beneficiary: MultiLocation {
|
|
||||||
parents: 0,
|
|
||||||
interior: X1(AccountId32 {
|
|
||||||
network: None,
|
|
||||||
id: [
|
|
||||||
18, 153, 85, 112, 1, 245, 88, 21, 211, 252, 181, 60, 116, 70, 58,
|
|
||||||
203, 12, 246, 209, 77, 70, 57, 179, 64, 152, 44, 96, 135, 127, 56,
|
|
||||||
70, 9,
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
let hash = xcm.using_encoded(sp_io::hashing::blake2_256);
|
|
||||||
|
|
||||||
let weight_limit = ReservedDmpWeight::get();
|
|
||||||
|
|
||||||
let outcome = XcmExecutor::<XcmConfig>::execute_xcm(Parent, xcm, hash, weight_limit);
|
|
||||||
assert_eq!(outcome.ensure_complete(), Ok(()));
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
}),
|
||||||
|
Box::new(|runtime_event_encoded: Vec<u8>| {
|
||||||
|
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
|
||||||
|
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
asset_test_utils::include_teleports_for_foreign_assets_works!(
|
||||||
|
Runtime,
|
||||||
|
XcmConfig,
|
||||||
|
CheckingAccount,
|
||||||
|
WeightToFee,
|
||||||
|
ParachainSystem,
|
||||||
|
ForeignCreatorsSovereignAccountOf,
|
||||||
|
ForeignAssetsInstance,
|
||||||
|
asset_test_utils::CollatorSessionKeys::new(
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) }
|
||||||
|
),
|
||||||
|
ExistentialDeposit::get(),
|
||||||
|
Box::new(|runtime_event_encoded: Vec<u8>| {
|
||||||
|
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
|
||||||
|
Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
Box::new(|runtime_event_encoded: Vec<u8>| {
|
||||||
|
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
|
||||||
|
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
asset_test_utils::include_asset_transactor_transfer_with_local_consensus_currency_works!(
|
||||||
|
Runtime,
|
||||||
|
XcmConfig,
|
||||||
|
asset_test_utils::CollatorSessionKeys::new(
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) }
|
||||||
|
),
|
||||||
|
ExistentialDeposit::get(),
|
||||||
|
Box::new(|| {
|
||||||
|
assert!(Assets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
assert!(ForeignAssets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
}),
|
||||||
|
Box::new(|| {
|
||||||
|
assert!(Assets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
assert!(ForeignAssets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
asset_test_utils::include_asset_transactor_transfer_with_pallet_assets_instance_works!(
|
||||||
|
asset_transactor_transfer_with_trust_backed_assets_works,
|
||||||
|
Runtime,
|
||||||
|
XcmConfig,
|
||||||
|
TrustBackedAssetsInstance,
|
||||||
|
AssetIdForTrustBackedAssets,
|
||||||
|
AssetIdForTrustBackedAssetsConvert,
|
||||||
|
asset_test_utils::CollatorSessionKeys::new(
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) }
|
||||||
|
),
|
||||||
|
ExistentialDeposit::get(),
|
||||||
|
12345,
|
||||||
|
Box::new(|| {
|
||||||
|
assert!(ForeignAssets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
}),
|
||||||
|
Box::new(|| {
|
||||||
|
assert!(ForeignAssets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
asset_test_utils::include_asset_transactor_transfer_with_pallet_assets_instance_works!(
|
||||||
|
asset_transactor_transfer_with_foreign_assets_works,
|
||||||
|
Runtime,
|
||||||
|
XcmConfig,
|
||||||
|
ForeignAssetsInstance,
|
||||||
|
MultiLocation,
|
||||||
|
JustTry,
|
||||||
|
asset_test_utils::CollatorSessionKeys::new(
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) }
|
||||||
|
),
|
||||||
|
ExistentialDeposit::get(),
|
||||||
|
MultiLocation { parents: 1, interior: X2(Parachain(1313), GeneralIndex(12345)) },
|
||||||
|
Box::new(|| {
|
||||||
|
assert!(Assets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
}),
|
||||||
|
Box::new(|| {
|
||||||
|
assert!(Assets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_parachain_assets_works!(
|
||||||
|
Runtime,
|
||||||
|
XcmConfig,
|
||||||
|
WeightToFee,
|
||||||
|
ForeignCreatorsSovereignAccountOf,
|
||||||
|
ForeignAssetsInstance,
|
||||||
|
MultiLocation,
|
||||||
|
JustTry,
|
||||||
|
asset_test_utils::CollatorSessionKeys::new(
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
AccountId::from(ALICE),
|
||||||
|
SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) }
|
||||||
|
),
|
||||||
|
ExistentialDeposit::get(),
|
||||||
|
AssetDeposit::get(),
|
||||||
|
MetadataDepositBase::get(),
|
||||||
|
MetadataDepositPerByte::get(),
|
||||||
|
Box::new(|pallet_asset_call| RuntimeCall::ForeignAssets(pallet_asset_call).encode()),
|
||||||
|
Box::new(|runtime_event_encoded: Vec<u8>| {
|
||||||
|
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
|
||||||
|
Ok(RuntimeEvent::ForeignAssets(pallet_asset_event)) => Some(pallet_asset_event),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
Box::new(|| {
|
||||||
|
assert!(Assets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
assert!(ForeignAssets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
}),
|
||||||
|
Box::new(|| {
|
||||||
|
assert!(Assets::asset_ids().collect::<Vec<_>>().is_empty());
|
||||||
|
assert_eq!(ForeignAssets::asset_ids().collect::<Vec<_>>().len(), 1);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn plain_receive_teleported_asset_works() {
|
fn plain_receive_teleported_asset_works() {
|
||||||
@@ -494,10 +638,8 @@ fn plain_receive_teleported_asset_works() {
|
|||||||
)
|
)
|
||||||
.map(xcm::v3::Xcm::<RuntimeCall>::try_from).expect("failed").expect("failed");
|
.map(xcm::v3::Xcm::<RuntimeCall>::try_from).expect("failed").expect("failed");
|
||||||
|
|
||||||
let weight_limit = ReservedDmpWeight::get();
|
|
||||||
|
|
||||||
let outcome =
|
let outcome =
|
||||||
XcmExecutor::<XcmConfig>::execute_xcm(Parent, maybe_msg, message_id, weight_limit);
|
XcmExecutor::<XcmConfig>::execute_xcm(Parent, maybe_msg, message_id, RuntimeHelper::<Runtime>::xcm_max_weight(XcmReceivedFrom::Parent));
|
||||||
assert_eq!(outcome.ensure_complete(), Ok(()));
|
assert_eq!(outcome.ensure_complete(), Ok(()));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ pub type CurrencyTransactor = CurrencyAdapter<
|
|||||||
LocationToAccountId,
|
LocationToAccountId,
|
||||||
// Our chain's account ID type (we can't get away without mentioning it explicitly):
|
// Our chain's account ID type (we can't get away without mentioning it explicitly):
|
||||||
AccountId,
|
AccountId,
|
||||||
// We don't track any teleports.
|
// We don't track any teleports of `Balances`.
|
||||||
(),
|
(),
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ pub type CurrencyTransactor = CurrencyAdapter<
|
|||||||
LocationToAccountId,
|
LocationToAccountId,
|
||||||
// Our chain's account ID type (we can't get away without mentioning it explicitly):
|
// Our chain's account ID type (we can't get away without mentioning it explicitly):
|
||||||
AccountId,
|
AccountId,
|
||||||
// We don't track any teleports.
|
// We don't track any teleports of `Balances`.
|
||||||
(),
|
(),
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ pub type CurrencyTransactor = CurrencyAdapter<
|
|||||||
LocationToAccountId,
|
LocationToAccountId,
|
||||||
// Our chain's account ID type (we can't get away without mentioning it explicitly):
|
// Our chain's account ID type (we can't get away without mentioning it explicitly):
|
||||||
AccountId,
|
AccountId,
|
||||||
// We don't track any teleports.
|
// We don't track any teleports of `Balances`.
|
||||||
(),
|
(),
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ parameter_types! {
|
|||||||
pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
|
pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
|
||||||
pub UniversalLocation: InteriorMultiLocation =
|
pub UniversalLocation: InteriorMultiLocation =
|
||||||
X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into()));
|
X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into()));
|
||||||
pub const Local: MultiLocation = Here.into_location();
|
|
||||||
pub CheckingAccount: AccountId = PolkadotXcm::check_account();
|
pub CheckingAccount: AccountId = PolkadotXcm::check_account();
|
||||||
pub const GovernanceLocation: MultiLocation = MultiLocation::parent();
|
pub const GovernanceLocation: MultiLocation = MultiLocation::parent();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user