diff --git a/pallets/asset-manager/src/lib.rs b/pallets/asset-manager/src/lib.rs index 51af3f703..39b411d79 100644 --- a/pallets/asset-manager/src/lib.rs +++ b/pallets/asset-manager/src/lib.rs @@ -261,6 +261,9 @@ pub mod pallet { /// Location Already Exists LocationAlreadyExists, + /// MultiLocation Type Not Supported + LocationNotSupported, + /// An error occured while creating a new asset at the [`AssetRegistry`]. ErrorCreatingAsset, @@ -348,6 +351,12 @@ pub mod pallet { !LocationAssetId::::contains_key(&location), Error::::LocationAlreadyExists ); + if let Some(multi) = location.clone().into() { + ensure!( + Self::is_allowed_asset_location(&multi), + Error::::LocationNotSupported + ); + } let asset_id = Self::next_asset_id_and_increment()?; >::AssetRegistry::create_asset( asset_id, @@ -399,6 +408,12 @@ pub mod pallet { !LocationAssetId::::contains_key(&location), Error::::LocationAlreadyExists ); + if let Some(multi) = location.clone().into() { + ensure!( + Self::is_allowed_asset_location(&multi), + Error::::LocationNotSupported + ); + } // change the ledger state. let old_location = AssetIdLocation::::get(asset_id).ok_or(Error::::UpdateNonExistentAsset)?; @@ -603,24 +618,47 @@ pub mod pallet { Ok(()) } } + + /// defines what types of locations can be registered as assets + fn is_allowed_asset_location(location: &MultiLocation) -> bool { + let p = location.parents; + if p > 1 { + return false; + } + match location.interior { + // Local or relay asset + Junctions::Here => p == 0 || p == 1, + // A parachain native asset + Junctions::X1(Junction::Parachain { .. }) => p == 1, + // Send tokens to sibling chain. + Junctions::X2(Junction::Parachain { .. }, Junction::PalletInstance { .. }) + | Junctions::X2(Junction::Parachain { .. }, Junction::GeneralKey { .. }) => p == 1, + Junctions::X3( + Junction::Parachain { .. }, + Junction::PalletInstance { .. }, + Junction::GeneralIndex { .. }, + ) => p == 1, + _ => false, + } + } } - /// Check the multilocation destination is supported by calamari/manta. + /// impl used by xtokens as `MultiLocationsFilter`. Defines where we're allowed to **send** to impl Contains for Pallet where T: Config, { #[inline] fn contains(location: &MultiLocation) -> bool { - // check parents + // xtokens / XCM must not be used to send transfers local to our parachain + // and we don't support nested chains if location.parents != 1 { return false; } - match location.interior { - // Send tokens back to relaychain. + // Send tokens to an account on the relaychain. Junctions::X1(Junction::AccountId32 { .. }) => true, - // Send tokens to sibling chain. + // Send tokens to an account on a sibling chain. Junctions::X2(Junction::Parachain(para_id), Junction::AccountId32 { .. }) | Junctions::X2(Junction::Parachain(para_id), Junction::AccountKey20 { .. }) => { AllowedDestParaIds::::contains_key(para_id) diff --git a/runtime/calamari/src/xcm_config.rs b/runtime/calamari/src/xcm_config.rs index 28dfe1558..f32e548be 100644 --- a/runtime/calamari/src/xcm_config.rs +++ b/runtime/calamari/src/xcm_config.rs @@ -350,6 +350,7 @@ impl orml_xtokens::Config for Runtime { type LocationInverter = LocationInverter; type MaxAssetsForTransfer = MaxAssetsForTransfer; type MinXcmFee = AssetManager; + /// filter multilocations our chain is allowed to send XCM to type MultiLocationsFilter = AssetManager; type ReserveProvider = AbsoluteReserveProvider; }