diff --git a/Cargo.lock b/Cargo.lock index 5513c79c3bb3..fab399da0b17 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14470,6 +14470,7 @@ dependencies = [ "primitive-types", "scale-info", "sp-arithmetic", + "sp-core", "sp-io", "sp-runtime", "sp-std", diff --git a/runtime/kusama/src/xcm_config.rs b/runtime/kusama/src/xcm_config.rs index 0aa50a364a0c..8e2af5752b42 100644 --- a/runtime/kusama/src/xcm_config.rs +++ b/runtime/kusama/src/xcm_config.rs @@ -41,8 +41,9 @@ use xcm_builder::{ ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds, IsChildSystemParachain, IsConcrete, MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + SovereignSignedViaLocation, TakeWeightCredit, TinkernetMultisigAsAccountId, + TinkernetMultisigAsNative, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, + WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::traits::WithOriginFilter; @@ -70,6 +71,8 @@ pub type SovereignAccountOf = ( ChildParachainConvertsVia, // We can directly alias an `AccountId32` into a local account. AccountId32Aliases, + // We can derive a local account from a Tinkernet XCMultisig MultiLocation. + TinkernetMultisigAsAccountId, ); /// Our asset transactor. This is what allows us to interest with the runtime facilities from the point of @@ -99,6 +102,8 @@ type LocalOriginConverter = ( SignedAccountId32AsNative, // A system child parachain, expressed as a Superuser, converts to the `Root` origin. ChildSystemParachainAsSuperuser, + // Converts a Tinkernet XCMultisig MultiLocation into a `Signed` origin. + TinkernetMultisigAsNative, ); parameter_types! { diff --git a/runtime/rococo/src/xcm_config.rs b/runtime/rococo/src/xcm_config.rs index bc78ab7ab878..3d01b4f22833 100644 --- a/runtime/rococo/src/xcm_config.rs +++ b/runtime/rococo/src/xcm_config.rs @@ -40,8 +40,8 @@ use xcm_builder::{ ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds, IsChildSystemParachain, IsConcrete, MintLocation, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, - TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, - WithUniqueTopic, + TakeWeightCredit, TinkernetMultisigAsAccountId, TinkernetMultisigAsNative, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; @@ -53,8 +53,12 @@ parameter_types! { pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local); } -pub type LocationConverter = - (ChildParachainConvertsVia, AccountId32Aliases); +pub type LocationConverter = ( + ChildParachainConvertsVia, + AccountId32Aliases, + // We can derive a local account from a Tinkernet XCMultisig MultiLocation. + TinkernetMultisigAsAccountId, +); /// Our asset transactor. This is what allows us to interest with the runtime facilities from the point of /// view of XCM-only concepts like `MultiLocation` and `MultiAsset`. @@ -83,6 +87,8 @@ type LocalOriginConverter = ( SignedAccountId32AsNative, // A system child parachain, expressed as a Superuser, converts to the `Root` origin. ChildSystemParachainAsSuperuser, + // Converts a Tinkernet XCMultisig MultiLocation into a `Signed` origin. + TinkernetMultisigAsNative, ); parameter_types! { diff --git a/xcm/xcm-builder/Cargo.toml b/xcm/xcm-builder/Cargo.toml index 7dc7a7fc0aa2..82c77f59692b 100644 --- a/xcm/xcm-builder/Cargo.toml +++ b/xcm/xcm-builder/Cargo.toml @@ -15,6 +15,7 @@ sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", d sp-arithmetic = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-weights = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } @@ -49,6 +50,7 @@ std = [ "sp-arithmetic/std", "sp-io/std", "sp-runtime/std", + "sp-core/std", "sp-weights/std", "frame-support/std", "frame-system/std", diff --git a/xcm/xcm-builder/src/lib.rs b/xcm/xcm-builder/src/lib.rs index 984ace84dc69..08d0c32c1836 100644 --- a/xcm/xcm-builder/src/lib.rs +++ b/xcm/xcm-builder/src/lib.rs @@ -34,7 +34,7 @@ pub use location_conversion::{ ChildParachainConvertsVia, DescribeAccountId32Terminal, DescribeAccountIdTerminal, DescribeAccountKey20Terminal, DescribeAllTerminal, DescribeFamily, DescribeLocation, DescribePalletTerminal, DescribeTerminus, GlobalConsensusParachainConvertsFor, - HashedDescription, ParentIsPreset, SiblingParachainConvertsVia, + HashedDescription, ParentIsPreset, SiblingParachainConvertsVia, TinkernetMultisigAsAccountId, }; mod origin_conversion; @@ -42,7 +42,7 @@ pub use origin_conversion::{ BackingToPlurality, ChildParachainAsNative, ChildSystemParachainAsSuperuser, EnsureXcmOrigin, OriginToPluralityVoice, ParentAsSuperuser, RelayChainAsNative, SiblingParachainAsNative, SiblingSystemParachainAsSuperuser, SignedAccountId32AsNative, SignedAccountKey20AsNative, - SignedToAccountId32, SovereignSignedViaLocation, + SignedToAccountId32, SovereignSignedViaLocation, TinkernetMultisigAsNative, }; mod asset_conversion; diff --git a/xcm/xcm-builder/src/location_conversion.rs b/xcm/xcm-builder/src/location_conversion.rs index dc327c08d067..a62d44e1e6af 100644 --- a/xcm/xcm-builder/src/location_conversion.rs +++ b/xcm/xcm-builder/src/location_conversion.rs @@ -17,6 +17,7 @@ use crate::universal_exports::ensure_is_remote; use frame_support::traits::Get; use parity_scale_codec::{Compact, Decode, Encode}; +use sp_core::H256; use sp_io::hashing::blake2_256; use sp_runtime::traits::{AccountIdConversion, Convert, TrailingZeroInput}; use sp_std::{marker::PhantomData, prelude::*}; @@ -345,6 +346,52 @@ impl>, AccountId: From<[u8; 20]> + Into<[u8; 20]> } } +/// Tinkernet ParaId used when matching Multisig MultiLocations. +pub const KUSAMA_TINKERNET_PARA_ID: u32 = 2125; + +/// Tinkernet Multisig pallet instance used when matching Multisig MultiLocations. +pub const KUSAMA_TINKERNET_MULTISIG_PALLET: u8 = 71; + +/// Constant derivation function for Tinkernet Multisigs. +/// Uses the Tinkernet genesis hash as a salt. +pub fn derive_tinkernet_multisig(id: u128) -> Result { + AccountId::decode(&mut TrailingZeroInput::new( + &( + // The constant salt used to derive Tinkernet Multisigs, this is Tinkernet's genesis hash. + H256([ + 212, 46, 150, 6, 169, 149, 223, 228, 51, 220, 121, 85, 220, 42, 112, 244, 149, 243, + 80, 243, 115, 218, 162, 0, 9, 138, 232, 68, 55, 129, 106, 210, + ]), + // The actual multisig integer id. + u32::try_from(id).map_err(|_| ())?, + ) + .using_encoded(blake2_256), + )) + .map_err(|_| ()) +} + +/// Convert a Tinkernet Multisig `MultiLocation` value into a local `AccountId`. +pub struct TinkernetMultisigAsAccountId(PhantomData); +impl ConvertLocation + for TinkernetMultisigAsAccountId +{ + fn convert_location(location: &MultiLocation) -> Option { + match location { + MultiLocation { + parents: _, + interior: + X3( + Parachain(KUSAMA_TINKERNET_PARA_ID), + PalletInstance(KUSAMA_TINKERNET_MULTISIG_PALLET), + // Index from which the multisig account is derived. + GeneralIndex(id), + ), + } => derive_tinkernet_multisig(*id).ok(), + _ => None, + } + } +} + /// Converts a location which is a top-level parachain (i.e. a parachain held on a /// Relay-chain which provides its own consensus) into a 32-byte `AccountId`. /// @@ -789,4 +836,24 @@ mod tests { }; assert!(ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).is_none()); } + + #[test] + fn remote_tinkernet_multisig_convert_to_account() { + let mul = MultiLocation { + parents: 0, + interior: X3( + Parachain(KUSAMA_TINKERNET_PARA_ID), + PalletInstance(KUSAMA_TINKERNET_MULTISIG_PALLET), + GeneralIndex(0), + ), + }; + + assert_eq!( + [ + 97, 160, 244, 60, 133, 145, 170, 26, 202, 108, 203, 156, 114, 116, 175, 30, 156, + 195, 43, 101, 243, 51, 193, 162, 152, 188, 30, 165, 244, 81, 70, 90 + ], + TinkernetMultisigAsAccountId::<[u8; 32]>::convert_location(&mul).unwrap() + ); + } } diff --git a/xcm/xcm-builder/src/origin_conversion.rs b/xcm/xcm-builder/src/origin_conversion.rs index 0810b1ce2f8b..ecd7edd4f568 100644 --- a/xcm/xcm-builder/src/origin_conversion.rs +++ b/xcm/xcm-builder/src/origin_conversion.rs @@ -16,8 +16,12 @@ //! Various implementations for `ConvertOrigin`. +use crate::location_conversion::{ + derive_tinkernet_multisig, KUSAMA_TINKERNET_MULTISIG_PALLET, KUSAMA_TINKERNET_PARA_ID, +}; use frame_support::traits::{EnsureOrigin, Get, GetBacking, OriginTrait}; use frame_system::RawOrigin as SystemRawOrigin; +use parity_scale_codec::Decode; use polkadot_parachain::primitives::IsSystem; use sp_runtime::traits::TryConvert; use sp_std::marker::PhantomData; @@ -241,6 +245,37 @@ where } } +/// Convert a Tinkernet Multisig `MultiLocation` value into a `Signed` origin. +pub struct TinkernetMultisigAsNative(PhantomData); +impl ConvertOrigin + for TinkernetMultisigAsNative +where + RuntimeOrigin::AccountId: Decode, +{ + fn convert_origin( + origin: impl Into, + kind: OriginKind, + ) -> Result { + let origin = origin.into(); + match (kind, origin) { + ( + OriginKind::Native, + MultiLocation { + parents: _, + interior: + X3( + Junction::Parachain(KUSAMA_TINKERNET_PARA_ID), + Junction::PalletInstance(KUSAMA_TINKERNET_MULTISIG_PALLET), + // Index from which the multisig account is derived. + Junction::GeneralIndex(id), + ), + }, + ) => Ok(RuntimeOrigin::signed(derive_tinkernet_multisig(id).map_err(|_| origin)?)), + (_, origin) => Err(origin), + } + } +} + /// `EnsureOrigin` barrier to convert from dispatch origin to XCM origin, if one exists. pub struct EnsureXcmOrigin(PhantomData<(RuntimeOrigin, Conversion)>); impl>