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:
joe petrowski
2023-03-23 15:14:27 +01:00
committed by GitHub
parent 44126eb857
commit af46f4b41e
25 changed files with 2865 additions and 237 deletions
@@ -15,39 +15,79 @@
#![cfg_attr(not(feature = "std"), no_std)]
pub mod foreign_creators;
pub mod fungible_conversion;
pub mod matching;
pub mod runtime_api;
use crate::matching::{Equals, LocalMultiLocationPattern, ParentLocation, StartsWith};
use frame_support::traits::EverythingBut;
use parachains_common::AssetIdForTrustBackedAssets;
use xcm_builder::{AsPrefixedGeneralIndex, ConvertedConcreteId};
use xcm_executor::traits::JustTry;
use xcm::prelude::MultiLocation;
use xcm_builder::{AsPrefixedGeneralIndex, MatchedConvertedConcreteId};
use xcm_executor::traits::{Identity, JustTry};
/// `MultiLocation` vs `AssetIdForTrustBackedAssets` converter for `TrustBackedAssets`
pub type AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation> =
AsPrefixedGeneralIndex<TrustBackedAssetsPalletLocation, AssetIdForTrustBackedAssets, JustTry>;
/// [`ConvertedConcreteId`] converter dedicated for `TrustBackedAssets`
/// [`MatchedConvertedConcreteId`] converter dedicated for `TrustBackedAssets`
pub type TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, Balance> =
ConvertedConcreteId<
MatchedConvertedConcreteId<
AssetIdForTrustBackedAssets,
Balance,
StartsWith<TrustBackedAssetsPalletLocation>,
AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation>,
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)]
mod tests {
use super::*;
use crate::matching::StartsWithExplicitGlobalConsensus;
use xcm::latest::prelude::*;
use xcm_executor::traits::Convert;
frame_support::parameter_types! {
pub TrustBackedAssetsPalletLocation: MultiLocation = MultiLocation::new(5, X1(PalletInstance(13)));
}
use xcm_executor::traits::{Convert, Error as MatchError, MatchesFungibles};
#[test]
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 expected_reverse_ref =
MultiLocation::new(5, X2(PalletInstance(13), GeneralIndex(local_asset_id.into())));
@@ -67,4 +107,201 @@ mod tests {
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()
}
}