diff --git a/Cargo.lock b/Cargo.lock index 81453f8e51..a34e028c5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2457,6 +2457,7 @@ dependencies = [ "sp-core 34.0.0", "sp-genesis-builder", "sp-inherents", + "sp-io 37.0.0", "sp-offchain", "sp-runtime 38.0.0", "sp-session", diff --git a/relay/kusama/src/impls.rs b/relay/kusama/src/impls.rs deleted file mode 100644 index 77e7ca941d..0000000000 --- a/relay/kusama/src/impls.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -use super::*; -use core::marker::PhantomData; -use frame_support::traits::tokens::ConversionFromAssetBalance; -use polkadot_primitives::Id as ParaId; -use xcm_builder::IsChildSystemParachain; - -// TODO: replace by types from polkadot-sdk https://github.com/paritytech/polkadot-sdk/pull/3659 -/// Determines if the given `asset_kind` is a native asset. If it is, returns the balance without -/// conversion; otherwise, delegates to the implementation specified by `I`. -/// -/// Example where the `asset_kind` represents the native asset: -/// - location: (1, Parachain(1000)), // location of a Sibling Parachain; -/// - asset_id: (1, Here), // the asset id in the context of `asset_kind.location`; -pub struct NativeOnSystemParachain(PhantomData); -impl ConversionFromAssetBalance - for NativeOnSystemParachain -where - I: ConversionFromAssetBalance, -{ - type Error = (); - fn from_asset_balance( - balance: Balance, - asset_kind: VersionedLocatableAsset, - ) -> Result { - use VersionedLocatableAsset::*; - let (location, asset_id) = match asset_kind.clone() { - V3 { location, asset_id } => (location.try_into()?, asset_id.try_into()?), - V4 { location, asset_id } => (location, asset_id), - }; - if asset_id.0.contains_parents_only(1) && - IsChildSystemParachain::::contains(&location) - { - Ok(balance) - } else { - I::from_asset_balance(balance, asset_kind).map_err(|_| ()) - } - } - #[cfg(feature = "runtime-benchmarks")] - fn ensure_successful(asset_kind: VersionedLocatableAsset) { - I::ensure_successful(asset_kind) - } -} diff --git a/relay/kusama/src/lib.rs b/relay/kusama/src/lib.rs index f36bbe75cc..5bd9c28a78 100644 --- a/relay/kusama/src/lib.rs +++ b/relay/kusama/src/lib.rs @@ -41,7 +41,8 @@ use polkadot_primitives::{ use polkadot_runtime_common::{ auctions, claims, crowdloan, impl_runtime_weights, impls::{ - DealWithFees, LocatableAssetConverter, VersionedLocatableAsset, VersionedLocationConverter, + ContainsParts as ContainsLocationParts, DealWithFees, LocatableAssetConverter, + VersionedLocatableAsset, VersionedLocationConverter, }, paras_registrar, prod_or_fast, slots, BalanceToU256, BlockHashCount, BlockLength, CurrencyToVote, SlowAdjustingFeeUpdate, U256ToBalance, @@ -86,9 +87,10 @@ use frame_support::{ genesis_builder_helper::{build_state, get_preset}, parameter_types, traits::{ - fungible::HoldConsideration, ConstU32, Contains, EitherOf, EitherOfDiverse, Everything, - InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, - ProcessMessageError, StorageMapShim, WithdrawReasons, + fungible::HoldConsideration, tokens::UnityOrOuterConversion, ConstU32, ConstU8, EitherOf, + EitherOfDiverse, Everything, FromContains, InstanceFilter, KeyOwnerProofSystem, + LinearStoragePrice, PrivilegeCmp, ProcessMessage, ProcessMessageError, StorageMapShim, + WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter, WeightToFee as _}, PalletId, @@ -154,9 +156,6 @@ use governance::{ Treasurer, TreasurySpender, }; -// Implemented types. -pub mod impls; - #[cfg(test)] mod tests; @@ -860,7 +859,7 @@ impl pallet_treasury::Config for Runtime { LocatableAssetConverter, VersionedLocationConverter, >; - type BalanceConverter = impls::NativeOnSystemParachain; + type BalanceConverter = AssetRateWithNative; type PayoutPeriod = PayoutSpendPeriod; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = polkadot_runtime_common::impls::benchmarks::TreasuryArguments; @@ -1614,6 +1613,19 @@ impl pallet_nomination_pools::Config for Runtime { type AdminOrigin = EitherOf, StakingAdmin>; } +/// The [frame_support::traits::tokens::ConversionFromAssetBalance] implementation provided by the +/// `AssetRate` pallet instance, with additional decoration to identify different IDs/locations of +/// native asset and provide a one-to-one balance conversion for them. +pub type AssetRateWithNative = UnityOrOuterConversion< + ContainsLocationParts< + FromContains< + xcm_builder::IsChildSystemParachain, + xcm_builder::IsParentsOnly>, + >, + >, + AssetRate, +>; + impl pallet_asset_rate::Config for Runtime { type WeightInfo = weights::pallet_asset_rate::WeightInfo; type RuntimeEvent = RuntimeEvent; diff --git a/relay/kusama/tests/asset_rate.rs b/relay/kusama/tests/asset_rate.rs new file mode 100644 index 0000000000..72ee7be0b0 --- /dev/null +++ b/relay/kusama/tests/asset_rate.rs @@ -0,0 +1,96 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! AssetRate pallet instance tests. + +use frame_support::traits::tokens::ConversionFromAssetBalance; +use polkadot_runtime_common::impls::VersionedLocatableAsset; +use staging_kusama_runtime::AssetRateWithNative; +use xcm::prelude::*; + +#[test] +fn native_asset_rate_works() { + sp_io::TestExternalities::default().execute_with(|| { + // success: native asset on Asset Hub as xcm v4 location + let native = VersionedLocatableAsset::V4 { + location: Location::new(0, [Parachain(1000)]), + asset_id: Location::parent().into(), + }; + let actual = AssetRateWithNative::from_asset_balance(100, native).unwrap(); + assert_eq!(actual, 100); + + // success: native asset on Asset Hub as xcm v3 location + let native = VersionedLocatableAsset::V3 { + location: xcm::v3::Location::new( + 0, + xcm::v3::Junctions::X1(xcm::v3::Junction::Parachain(1000)), + ), + asset_id: xcm::v3::Location::parent().into(), + }; + let actual = AssetRateWithNative::from_asset_balance(100, native).unwrap(); + assert_eq!(actual, 100); + + // success: native asset on People as xcm v4 location + let native = VersionedLocatableAsset::V4 { + location: Location::new(0, [Parachain(1004)]), + asset_id: Location::parent().into(), + }; + let actual = AssetRateWithNative::from_asset_balance(100, native).unwrap(); + assert_eq!(actual, 100); + + // success: native asset on People as xcm v3 location + let native = VersionedLocatableAsset::V3 { + location: xcm::v3::Location::new( + 0, + xcm::v3::Junctions::X1(xcm::v3::Junction::Parachain(1004)), + ), + asset_id: xcm::v3::Location::parent().into(), + }; + let actual = AssetRateWithNative::from_asset_balance(100, native).unwrap(); + assert_eq!(actual, 100); + + // failure: native asset on non system chain as xcm v4 location + let native_non_system = VersionedLocatableAsset::V4 { + location: Location::new(0, [Parachain(2000)]), + asset_id: Location::parent().into(), + }; + assert!(AssetRateWithNative::from_asset_balance(100, native_non_system).is_err()); + + // failure: native asset on non system chain as xcm v3 location + let native_non_system = VersionedLocatableAsset::V3 { + location: xcm::v3::Location::new( + 0, + xcm::v3::Junctions::X1(xcm::v3::Junction::Parachain(2000)), + ), + asset_id: xcm::v3::Location::parent().into(), + }; + assert!(AssetRateWithNative::from_asset_balance(100, native_non_system).is_err()); + + // failure: some asset on Asset Hub as xcm v4 location + let non_native = VersionedLocatableAsset::V4 { + location: Location::new(0, [Parachain(2000)]), + asset_id: Location::new(0, [PalletInstance(50), GeneralIndex(1984)]).into(), + }; + assert!(AssetRateWithNative::from_asset_balance(100, non_native).is_err()); + + // failure: native asset with invalid system chain location as xcm v4 location + let native_non_system = VersionedLocatableAsset::V4 { + location: Location::new(1, [Parachain(1000)]), + asset_id: Location::parent().into(), + }; + assert!(AssetRateWithNative::from_asset_balance(100, native_non_system).is_err()); + }); +} diff --git a/relay/polkadot/src/impls.rs b/relay/polkadot/src/impls.rs index 9d16785485..05188460ab 100644 --- a/relay/polkadot/src/impls.rs +++ b/relay/polkadot/src/impls.rs @@ -14,53 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use super::*; -use core::marker::PhantomData; -use frame_support::traits::{tokens::ConversionFromAssetBalance, Contains}; -use polkadot_primitives::Id as ParaId; -use xcm_builder::IsChildSystemParachain; - -// TODO: replace by types from polkadot-sdk https://github.com/paritytech/polkadot-sdk/pull/3659 -/// Determines if the given `asset_kind` is a native asset. If it is, returns the balance without -/// conversion; otherwise, delegates to the implementation specified by `I`. -/// -/// Example where the `asset_kind` represents the native asset: -/// - location: (1, Parachain(1000)), // location of a Sibling Parachain; -/// - asset_id: (1, Here), // the asset id in the context of `asset_kind.location`; -pub struct NativeOnSystemParachain(PhantomData); -impl ConversionFromAssetBalance - for NativeOnSystemParachain -where - I: ConversionFromAssetBalance, -{ - type Error = (); - fn from_asset_balance( - balance: Balance, - asset_kind: VersionedLocatableAsset, - ) -> Result { - use VersionedLocatableAsset::*; - let (location, asset_id) = match asset_kind.clone() { - V3 { location, asset_id } => (location.try_into()?, asset_id.try_into()?), - V4 { location, asset_id } => (location, asset_id), - }; - if asset_id.0.contains_parents_only(1) && - IsChildSystemParachain::::contains(&location) - { - Ok(balance) - } else { - I::from_asset_balance(balance, asset_kind).map_err(|_| ()) - } - } - #[cfg(feature = "runtime-benchmarks")] - fn ensure_successful(asset_kind: VersionedLocatableAsset) { - I::ensure_successful(asset_kind) - } -} - #[cfg(feature = "runtime-benchmarks")] pub mod benchmarks { - use super::{xcm_config::CheckAccount, ExistentialDeposit}; - use crate::Balances; + use crate::{xcm_config::CheckAccount, Balances, ExistentialDeposit}; use frame_support::{ dispatch::RawOrigin, traits::{Currency, EnsureOrigin}, diff --git a/relay/polkadot/src/lib.rs b/relay/polkadot/src/lib.rs index bb7ec1344f..08a782346f 100644 --- a/relay/polkadot/src/lib.rs +++ b/relay/polkadot/src/lib.rs @@ -24,7 +24,8 @@ use pallet_transaction_payment::FungibleAdapter; use polkadot_runtime_common::{ auctions, claims, crowdloan, impl_runtime_weights, impls::{ - DealWithFees, LocatableAssetConverter, VersionedLocatableAsset, VersionedLocationConverter, + ContainsParts as ContainsLocationParts, DealWithFees, LocatableAssetConverter, + VersionedLocatableAsset, VersionedLocationConverter, }, paras_registrar, prod_or_fast, slots, traits::OnSwap, @@ -62,9 +63,10 @@ use frame_support::{ genesis_builder_helper::{build_state, get_preset}, parameter_types, traits::{ - fungible::HoldConsideration, ConstU32, EitherOf, EitherOfDiverse, Everything, Get, - InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, OnRuntimeUpgrade, PrivilegeCmp, - ProcessMessage, ProcessMessageError, WithdrawReasons, + fungible::HoldConsideration, tokens::UnityOrOuterConversion, ConstU32, ConstU8, EitherOf, + EitherOfDiverse, Everything, FromContains, Get, InstanceFilter, KeyOwnerProofSystem, + LinearStoragePrice, OnRuntimeUpgrade, PrivilegeCmp, ProcessMessage, ProcessMessageError, + WithdrawReasons, }, weights::{ constants::{WEIGHT_PROOF_SIZE_PER_KB, WEIGHT_REF_TIME_PER_MICROS}, @@ -826,7 +828,7 @@ impl pallet_treasury::Config for Runtime { LocatableAssetConverter, VersionedLocationConverter, >; - type BalanceConverter = impls::NativeOnSystemParachain; + type BalanceConverter = AssetRateWithNative; type PayoutPeriod = PayoutSpendPeriod; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = polkadot_runtime_common::impls::benchmarks::TreasuryArguments; @@ -1554,6 +1556,19 @@ impl pallet_state_trie_migration::Config for Runtime { type MaxKeyLen = MigrationMaxKeyLen; } +/// The [frame_support::traits::tokens::ConversionFromAssetBalance] implementation provided by the +/// `AssetRate` pallet instance, with additional decoration to identify different IDs/locations of +/// native asset and provide a one-to-one balance conversion for them. +pub type AssetRateWithNative = UnityOrOuterConversion< + ContainsLocationParts< + FromContains< + xcm_builder::IsChildSystemParachain, + xcm_builder::IsParentsOnly>, + >, + >, + AssetRate, +>; + impl pallet_asset_rate::Config for Runtime { type WeightInfo = weights::pallet_asset_rate::WeightInfo; type RuntimeEvent = RuntimeEvent; diff --git a/relay/polkadot/tests/asset_rate.rs b/relay/polkadot/tests/asset_rate.rs new file mode 100644 index 0000000000..68fde7d7fa --- /dev/null +++ b/relay/polkadot/tests/asset_rate.rs @@ -0,0 +1,96 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! AssetRate pallet instance tests. + +use frame_support::traits::tokens::ConversionFromAssetBalance; +use polkadot_runtime::AssetRateWithNative; +use polkadot_runtime_common::impls::VersionedLocatableAsset; +use xcm::prelude::*; + +#[test] +fn native_asset_rate_works() { + sp_io::TestExternalities::default().execute_with(|| { + // success: native asset on Asset Hub as xcm v4 location + let native = VersionedLocatableAsset::V4 { + location: Location::new(0, [Parachain(1000)]), + asset_id: Location::parent().into(), + }; + let actual = AssetRateWithNative::from_asset_balance(100, native).unwrap(); + assert_eq!(actual, 100); + + // success: native asset on Asset Hub as xcm v3 location + let native = VersionedLocatableAsset::V3 { + location: xcm::v3::Location::new( + 0, + xcm::v3::Junctions::X1(xcm::v3::Junction::Parachain(1000)), + ), + asset_id: xcm::v3::Location::parent().into(), + }; + let actual = AssetRateWithNative::from_asset_balance(100, native).unwrap(); + assert_eq!(actual, 100); + + // success: native asset on People as xcm v4 location + let native = VersionedLocatableAsset::V4 { + location: Location::new(0, [Parachain(1004)]), + asset_id: Location::parent().into(), + }; + let actual = AssetRateWithNative::from_asset_balance(100, native).unwrap(); + assert_eq!(actual, 100); + + // success: native asset on People as xcm v3 location + let native = VersionedLocatableAsset::V3 { + location: xcm::v3::Location::new( + 0, + xcm::v3::Junctions::X1(xcm::v3::Junction::Parachain(1004)), + ), + asset_id: xcm::v3::Location::parent().into(), + }; + let actual = AssetRateWithNative::from_asset_balance(100, native).unwrap(); + assert_eq!(actual, 100); + + // failure: native asset on non system chain as xcm v4 location + let native_non_system = VersionedLocatableAsset::V4 { + location: Location::new(0, [Parachain(2000)]), + asset_id: Location::parent().into(), + }; + assert!(AssetRateWithNative::from_asset_balance(100, native_non_system).is_err()); + + // failure: native asset on non system chain as xcm v3 location + let native_non_system = VersionedLocatableAsset::V3 { + location: xcm::v3::Location::new( + 0, + xcm::v3::Junctions::X1(xcm::v3::Junction::Parachain(2000)), + ), + asset_id: xcm::v3::Location::parent().into(), + }; + assert!(AssetRateWithNative::from_asset_balance(100, native_non_system).is_err()); + + // failure: some asset on Asset Hub as xcm v4 location + let non_native = VersionedLocatableAsset::V4 { + location: Location::new(0, [Parachain(2000)]), + asset_id: Location::new(0, [PalletInstance(50), GeneralIndex(1984)]).into(), + }; + assert!(AssetRateWithNative::from_asset_balance(100, non_native).is_err()); + + // failure: native asset with invalid system chain location as xcm v4 location + let native_non_system = VersionedLocatableAsset::V4 { + location: Location::new(1, [Parachain(1000)]), + asset_id: Location::parent().into(), + }; + assert!(AssetRateWithNative::from_asset_balance(100, native_non_system).is_err()); + }); +} diff --git a/system-parachains/collectives/collectives-polkadot/Cargo.toml b/system-parachains/collectives/collectives-polkadot/Cargo.toml index 247a4f9554..6c7eec3d7d 100644 --- a/system-parachains/collectives/collectives-polkadot/Cargo.toml +++ b/system-parachains/collectives/collectives-polkadot/Cargo.toml @@ -87,6 +87,7 @@ system-parachains-constants = { workspace = true } [dev-dependencies] collectives-polkadot-runtime-constants = { workspace = true } +sp-io = { workspace = true } [build-dependencies] substrate-wasm-builder = { optional = true, workspace = true } @@ -221,6 +222,7 @@ std = [ "sp-core/std", "sp-genesis-builder/std", "sp-inherents/std", + "sp-io/std", "sp-offchain/std", "sp-runtime/std", "sp-session/std", diff --git a/system-parachains/collectives/collectives-polkadot/src/ambassador/mod.rs b/system-parachains/collectives/collectives-polkadot/src/ambassador/mod.rs index 94fa1ac705..034206c542 100644 --- a/system-parachains/collectives/collectives-polkadot/src/ambassador/mod.rs +++ b/system-parachains/collectives/collectives-polkadot/src/ambassador/mod.rs @@ -36,7 +36,7 @@ pub use origins::pallet_origins as pallet_ambassador_origins; use crate::{ xcm_config::{AssetHubUsdt, FellowshipAdminBodyId}, - *, + AssetRateWithNative, *, }; use frame_support::{ pallet_prelude::PalletInfoAccess, @@ -348,7 +348,7 @@ impl pallet_treasury::Config for Runtime { AmbassadorTreasuryPaymaster, crate::impls::benchmarks::OpenHrmpChannel>, >; - type BalanceConverter = crate::impls::NativeOnSiblingParachain; + type BalanceConverter = AssetRateWithNative; type PayoutPeriod = ConstU32<{ 30 * DAYS }>; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = polkadot_runtime_common::impls::benchmarks::TreasuryArguments< diff --git a/system-parachains/collectives/collectives-polkadot/src/fellowship/mod.rs b/system-parachains/collectives/collectives-polkadot/src/fellowship/mod.rs index 9f39e5ddfc..b1354bd647 100644 --- a/system-parachains/collectives/collectives-polkadot/src/fellowship/mod.rs +++ b/system-parachains/collectives/collectives-polkadot/src/fellowship/mod.rs @@ -23,9 +23,9 @@ use crate::{ impls::ToParentTreasury, weights, xcm_config::{AssetHubUsdt, LocationToAccountId, TreasurerBodyId}, - AccountId, AssetRate, Balance, Balances, FellowshipReferenda, GovernanceLocation, - ParachainInfo, PolkadotTreasuryAccount, Preimage, Runtime, RuntimeCall, RuntimeEvent, - RuntimeOrigin, Scheduler, DAYS, FELLOWSHIP_TREASURY_PALLET_ID, + AccountId, AssetRateWithNative, Balance, Balances, FellowshipReferenda, GovernanceLocation, + PolkadotTreasuryAccount, Preimage, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, + Scheduler, DAYS, FELLOWSHIP_TREASURY_PALLET_ID, }; use frame_support::{ parameter_types, @@ -324,7 +324,7 @@ impl pallet_treasury::Config for Runtime { type Paymaster = FellowshipTreasuryPaymaster; #[cfg(feature = "runtime-benchmarks")] type Paymaster = PayWithEnsure>>; - type BalanceConverter = crate::impls::NativeOnSiblingParachain; + type BalanceConverter = AssetRateWithNative; type PayoutPeriod = ConstU32<{ 30 * DAYS }>; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = polkadot_runtime_common::impls::benchmarks::TreasuryArguments< diff --git a/system-parachains/collectives/collectives-polkadot/src/impls.rs b/system-parachains/collectives/collectives-polkadot/src/impls.rs index c25c21766a..57df1ae2ff 100644 --- a/system-parachains/collectives/collectives-polkadot/src/impls.rs +++ b/system-parachains/collectives/collectives-polkadot/src/impls.rs @@ -16,14 +16,10 @@ use super::*; use frame_support::{ dispatch::DispatchResultWithPostInfo, - traits::{ - tokens::ConversionFromAssetBalance, Contains, Currency, Get, Imbalance, OnUnbalanced, - OriginTrait, PrivilegeCmp, - }, + traits::{Currency, Get, Imbalance, OnUnbalanced, OriginTrait, PrivilegeCmp}, }; use pallet_alliance::{ProposalIndex, ProposalProvider}; use parachains_common::impls::NegativeImbalance; -use polkadot_parachain_primitives::primitives::{Id as ParaId, IsSystem}; use sp_runtime::DispatchError; use sp_std::{cmp::Ordering, marker::PhantomData, prelude::*}; use xcm_executor::traits::ConvertLocation; @@ -160,55 +156,6 @@ impl PrivilegeCmp for EqualOrGreatestRootCmp { } } -// TODO: replace by types from polkadot-sdk https://github.com/paritytech/polkadot-sdk/pull/3659 -/// Contains a system-level sibling parachain. -pub struct IsSiblingSystemParachain(PhantomData<(ParaId, SelfParaId)>); -impl + Eq, SelfParaId: Get> Contains - for IsSiblingSystemParachain -{ - fn contains(l: &Location) -> bool { - matches!( - l.unpack(), - (1, [Parachain(id)]) if ParaId::from(*id).is_system() && SelfParaId::get() != ParaId::from(*id), - ) - } -} - -// TODO: replace by types from polkadot-sdk https://github.com/paritytech/polkadot-sdk/pull/3659 -/// Determines if the given `asset_kind` is a native asset. If it is, returns the balance without -/// conversion; otherwise, delegates to the implementation specified by `I`. -pub struct NativeOnSiblingParachain(PhantomData<(I, SelfParaId)>); -impl ConversionFromAssetBalance - for NativeOnSiblingParachain -where - I: ConversionFromAssetBalance, - SelfParaId: Get, -{ - type Error = (); - fn from_asset_balance( - balance: Balance, - asset_kind: VersionedLocatableAsset, - ) -> Result { - use VersionedLocatableAsset::*; - let (location, asset_id) = match asset_kind.clone() { - V3 { location, asset_id } => (location.try_into()?, asset_id.try_into()?), - V4 { location, asset_id } => (location, asset_id), - }; - - if asset_id.0.contains_parents_only(1) && - IsSiblingSystemParachain::::contains(&location) - { - Ok(balance) - } else { - I::from_asset_balance(balance, asset_kind).map_err(|_| ()) - } - } - #[cfg(feature = "runtime-benchmarks")] - fn ensure_successful(asset_kind: VersionedLocatableAsset) { - I::ensure_successful(asset_kind) - } -} - #[cfg(feature = "runtime-benchmarks")] pub mod benchmarks { use super::*; diff --git a/system-parachains/collectives/collectives-polkadot/src/lib.rs b/system-parachains/collectives/collectives-polkadot/src/lib.rs index 8dcd46e3ea..d798048d32 100644 --- a/system-parachains/collectives/collectives-polkadot/src/lib.rs +++ b/system-parachains/collectives/collectives-polkadot/src/lib.rs @@ -50,7 +50,9 @@ use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use fellowship::{pallet_fellowship_origins, Fellows}; use impls::{AllianceProposalProvider, EqualOrGreatestRootCmp, ToParentTreasury}; -use polkadot_runtime_common::impls::VersionedLocatableAsset; +use polkadot_runtime_common::impls::{ + ContainsParts as ContainsLocationParts, VersionedLocatableAsset, +}; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ @@ -72,8 +74,10 @@ use frame_support::{ genesis_builder_helper::{build_state, get_preset}, parameter_types, traits::{ - fungible::HoldConsideration, tokens::imbalance::ResolveTo, ConstBool, ConstU16, ConstU32, - ConstU64, ConstU8, EitherOfDiverse, InstanceFilter, LinearStoragePrice, TransformOrigin, + fungible::HoldConsideration, + tokens::{imbalance::ResolveTo, UnityOrOuterConversion}, + ConstBool, ConstU16, ConstU32, ConstU64, ConstU8, EitherOfDiverse, FromContains, + InstanceFilter, LinearStoragePrice, TransformOrigin, }, weights::{ConstantMultiplier, Weight, WeightToFee as _}, PalletId, @@ -92,7 +96,7 @@ use system_parachains_constants::{ SLOT_DURATION, }; use xcm_config::{ - GovernanceLocation, LocationToAccountId, StakingPot, TreasurerBodyId, + GovernanceLocation, LocationToAccountId, SelfParaId, StakingPot, TreasurerBodyId, XcmOriginToTransactDispatchOrigin, }; @@ -646,6 +650,19 @@ impl pallet_preimage::Config for Runtime { >; } +/// The [frame_support::traits::tokens::ConversionFromAssetBalance] implementation provided by the +/// `AssetRate` pallet instance, with additional decoration to identify different IDs/locations of +/// native asset and provide a one-to-one balance conversion for them. +pub type AssetRateWithNative = UnityOrOuterConversion< + ContainsLocationParts< + FromContains< + xcm_builder::IsSiblingSystemParachain, + xcm_builder::IsParentsOnly>, + >, + >, + AssetRate, +>; + impl pallet_asset_rate::Config for Runtime { type WeightInfo = weights::pallet_asset_rate::WeightInfo; type RuntimeEvent = RuntimeEvent; diff --git a/system-parachains/collectives/collectives-polkadot/src/xcm_config.rs b/system-parachains/collectives/collectives-polkadot/src/xcm_config.rs index 08e48844b2..dd20acca0b 100644 --- a/system-parachains/collectives/collectives-polkadot/src/xcm_config.rs +++ b/system-parachains/collectives/collectives-polkadot/src/xcm_config.rs @@ -18,6 +18,7 @@ use super::{ ParachainSystem, PolkadotXcm, PriceForParentDelivery, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, }; +use cumulus_primitives_core::ParaId; use frame_support::{ parameter_types, traits::{tokens::imbalance::ResolveTo, ConstU32, Contains, Equals, Everything, Nothing}, @@ -72,6 +73,7 @@ parameter_types! { asset_id: (PalletInstance(50), GeneralIndex(1984)).into(), }; pub StakingPot: AccountId = CollatorSelection::account_id(); + pub SelfParaId: ParaId = ParachainInfo::parachain_id(); } /// Type for specifying how a `Location` can be converted into an `AccountId`. This is used diff --git a/system-parachains/collectives/collectives-polkadot/tests/asset_rate.rs b/system-parachains/collectives/collectives-polkadot/tests/asset_rate.rs new file mode 100644 index 0000000000..05d0b7dae4 --- /dev/null +++ b/system-parachains/collectives/collectives-polkadot/tests/asset_rate.rs @@ -0,0 +1,96 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! AssetRate pallet instance tests. + +use collectives_polkadot_runtime::AssetRateWithNative; +use frame_support::traits::tokens::ConversionFromAssetBalance; +use polkadot_runtime_common::impls::VersionedLocatableAsset; +use xcm::prelude::*; + +#[test] +fn native_asset_rate_works() { + sp_io::TestExternalities::default().execute_with(|| { + // success: native asset on Asset Hub as xcm v4 location + let native = VersionedLocatableAsset::V4 { + location: Location::new(1, [Parachain(1000)]), + asset_id: Location::parent().into(), + }; + let actual = AssetRateWithNative::from_asset_balance(100, native).unwrap(); + assert_eq!(actual, 100); + + // success: native asset on Asset Hub as xcm v3 location + let native = VersionedLocatableAsset::V3 { + location: xcm::v3::Location::new( + 1, + xcm::v3::Junctions::X1(xcm::v3::Junction::Parachain(1000)), + ), + asset_id: xcm::v3::Location::parent().into(), + }; + let actual = AssetRateWithNative::from_asset_balance(100, native).unwrap(); + assert_eq!(actual, 100); + + // success: native asset on People as xcm v4 location + let native = VersionedLocatableAsset::V4 { + location: Location::new(1, [Parachain(1004)]), + asset_id: Location::parent().into(), + }; + let actual = AssetRateWithNative::from_asset_balance(100, native).unwrap(); + assert_eq!(actual, 100); + + // success: native asset on People as xcm v3 location + let native = VersionedLocatableAsset::V3 { + location: xcm::v3::Location::new( + 1, + xcm::v3::Junctions::X1(xcm::v3::Junction::Parachain(1004)), + ), + asset_id: xcm::v3::Location::parent().into(), + }; + let actual = AssetRateWithNative::from_asset_balance(100, native).unwrap(); + assert_eq!(actual, 100); + + // failure: native asset on non system chain as xcm v4 location + let native_non_system = VersionedLocatableAsset::V4 { + location: Location::new(1, [Parachain(2000)]), + asset_id: Location::parent().into(), + }; + assert!(AssetRateWithNative::from_asset_balance(100, native_non_system).is_err()); + + // failure: native asset on non system chain as xcm v3 location + let native_non_system = VersionedLocatableAsset::V3 { + location: xcm::v3::Location::new( + 1, + xcm::v3::Junctions::X1(xcm::v3::Junction::Parachain(2000)), + ), + asset_id: xcm::v3::Location::parent().into(), + }; + assert!(AssetRateWithNative::from_asset_balance(100, native_non_system).is_err()); + + // failure: some asset on Asset Hub as xcm v4 location + let non_native = VersionedLocatableAsset::V4 { + location: Location::new(1, [Parachain(2000)]), + asset_id: Location::new(0, [PalletInstance(50), GeneralIndex(1984)]).into(), + }; + assert!(AssetRateWithNative::from_asset_balance(100, non_native).is_err()); + + // failure: native asset with invalid system chain location as xcm v4 location + let native_non_system = VersionedLocatableAsset::V4 { + location: Location::new(0, [Parachain(1000)]), + asset_id: Location::parent().into(), + }; + assert!(AssetRateWithNative::from_asset_balance(100, native_non_system).is_err()); + }); +}