diff --git a/parachain/runtime/kintsugi/src/xcm_config.rs b/parachain/runtime/kintsugi/src/xcm_config.rs index b625e7c8e6..df861934ca 100644 --- a/parachain/runtime/kintsugi/src/xcm_config.rs +++ b/parachain/runtime/kintsugi/src/xcm_config.rs @@ -3,7 +3,7 @@ use codec::{Decode, Encode}; use cumulus_primitives_core::ParaId; use frame_support::{ parameter_types, - traits::{Everything, Get, Nothing}, + traits::{Everything, Get, Nothing, OriginTrait}, }; use orml_asset_registry::{AssetRegistryTrader, FixedRateAssetRegistryTrader}; use orml_traits::{ @@ -13,14 +13,21 @@ use orml_xcm_support::{DepositToAlternative, IsNativeConcrete, MultiCurrencyAdap use pallet_xcm::XcmPassthrough; use polkadot_parachain::primitives::Sibling; use runtime_common::Transactless; +use sp_core::H256; +use sp_io::hashing::blake2_256; +use sp_runtime::traits::TrailingZeroInput; +use sp_std::{borrow::Borrow, marker::PhantomData}; use xcm::latest::{prelude::*, Weight}; use xcm_builder::{ AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeRevenue, TakeWeightCredit, + SovereignSignedViaLocation, TakeRevenue, TakeWeightCredit, WithComputedOrigin, +}; +use xcm_executor::{ + traits::{Convert as XcmConvert, ConvertOrigin, WithOriginFilter}, + XcmExecutor, }; -use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; use CurrencyId::ForeignAsset; parameter_types! { pub const ParentLocation: MultiLocation = MultiLocation::parent(); @@ -37,6 +44,8 @@ type LocationToAccountId = ( SiblingParachainConvertsVia, // Straight up local `AccountId32` origins just alias directly to `AccountId`. AccountId32Aliases, + // Mapping Tinkernet multisig to the correctly derived AccountId. + TinkernetMultisigAsAccountId, ); /// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, @@ -56,16 +65,22 @@ pub type XcmOriginToTransactDispatchOrigin = ( // Native signed account converter; this just converts an `AccountId32` origin into a normal // `Origin::Signed` origin of the same 32-byte value. SignedAccountId32AsNative, + // Derives signed AccountId origins for Tinkernet multisigs. + TinkernetMultisigAsNativeOrigin, // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. XcmPassthrough, ); -pub type Barrier = Transactless<( - TakeWeightCredit, - AllowTopLevelPaidExecutionFrom, - AllowKnownQueryResponses, - AllowSubscriptionsFrom, -)>; // required for others to keep track of our xcm version +pub type Barrier = ( + Transactless<( + TakeWeightCredit, + AllowTopLevelPaidExecutionFrom, + AllowKnownQueryResponses, + AllowSubscriptionsFrom, + )>, // required for others to keep track of our xcm version + // XCM barrier that allows Tinkernet Multisigs to transact if paying for execution. + WithComputedOrigin, UniversalLocation, ConstU32<8>>, +); parameter_types! { // One XCM operation is 200_000_000 weight, cross-chain transfer ~= 2x of transfer. @@ -430,6 +445,91 @@ impl orml_xtokens::Config for Runtime { type UniversalLocation = UniversalLocation; } +/// Tinkernet Multisig Multilocation for XCM barriers. +pub struct TinkernetMultisigMultiLocation; +impl Contains for TinkernetMultisigMultiLocation { + fn contains(t: &MultiLocation) -> bool { + matches!( + t, + MultiLocation { + parents: 1, + interior: Junctions::X3( + Junction::Parachain(2125), + Junction::PalletInstance(71), + Junction::GeneralIndex(_) + ) + } + ) + } +} + +/// 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 XcmConvert for TinkernetMultisigAsAccountId { + fn convert_ref(location: impl Borrow) -> Result { + match location.borrow() { + MultiLocation { + parents: 1, + interior: + X3( + Parachain(2125), + PalletInstance(71), + // Index from which the multisig account is derived. + GeneralIndex(id), + ), + } => derive_tinkernet_multisig(*id), + _ => Err(()), + } + } +} + +/// Convert a Tinkernet Multisig `MultiLocation` value into a `Signed` origin. +pub struct TinkernetMultisigAsNativeOrigin(PhantomData); +impl ConvertOrigin for TinkernetMultisigAsNativeOrigin +where + RuntimeOrigin::AccountId: Decode, +{ + fn convert_origin(origin: impl Into, kind: OriginKind) -> Result { + let origin = origin.into(); + match (kind, origin) { + ( + OriginKind::Native, + MultiLocation { + parents: 1, + interior: + X3( + Junction::Parachain(2125), + Junction::PalletInstance(71), + // Index from which the multisig account is derived. + Junction::GeneralIndex(id), + ), + }, + ) => Ok(RuntimeOrigin::signed( + derive_tinkernet_multisig(id).map_err(|_| origin)?, + )), + (_, origin) => Err(origin), + } + } +} + #[cfg(feature = "runtime-benchmarks")] use benchmark_impls::*;