diff --git a/asset-registry/src/mock/para.rs b/asset-registry/src/mock/para.rs index 6f7df77f2..eb846098a 100644 --- a/asset-registry/src/mock/para.rs +++ b/asset-registry/src/mock/para.rs @@ -10,10 +10,8 @@ use frame_support::{ PalletId, }; use frame_system::{EnsureRoot, EnsureSignedBy}; -use orml_traits::{ - location::{AbsoluteReserveProvider, RelativeReserveProvider}, - parameter_type_with_key, FixedConversionRateProvider, MultiCurrency, -}; +use orml_traits::{parameter_type_with_key, FixedConversionRateProvider, MultiCurrency}; +use orml_xtokens::{AbsoluteReserveProvider, RelativeReserveProvider}; use orml_xcm_support::{IsNativeConcrete, MultiCurrencyAdapter, MultiNativeAsset}; use pallet_xcm::XcmPassthrough; use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen}; diff --git a/traits/src/location.rs b/traits/src/location.rs index 63496d25d..ed3b9dc5f 100644 --- a/traits/src/location.rs +++ b/traits/src/location.rs @@ -1,75 +1,13 @@ use sp_core::{bounded::BoundedVec, ConstU32}; use xcm::v5::prelude::*; -pub trait Parse { - /// Returns the "chain" location part. It could be parent, sibling - /// parachain, or child parachain. - fn chain_part(&self) -> Option; - /// Returns "non-chain" location part. - fn non_chain_part(&self) -> Option; -} - -fn is_chain_junction(junction: Option<&Junction>) -> bool { - matches!(junction, Some(Parachain(_))) -} - -impl Parse for Location { - fn chain_part(&self) -> Option { - match (self.parents, self.first_interior()) { - // sibling parachain - (1, Some(Parachain(id))) => Some(Location::new(1, [Parachain(*id)])), - // parent - (1, _) => Some(Location::parent()), - // children parachain - (0, Some(Parachain(id))) => Some(Location::new(0, [Parachain(*id)])), - _ => None, - } - } - - fn non_chain_part(&self) -> Option { - let mut junctions = self.interior().clone(); - while is_chain_junction(junctions.first()) { - let _ = junctions.take_first(); - } - - if junctions != Here { - Some(Location::new(0, junctions)) - } else { - None - } - } -} +pub const ASSET_HUB_ID: u32 = 1000; pub trait Reserve { /// Returns assets reserve location. fn reserve(asset: &Asset) -> Option; } -// Provide reserve in absolute path view -pub struct AbsoluteReserveProvider; - -impl Reserve for AbsoluteReserveProvider { - fn reserve(asset: &Asset) -> Option { - let AssetId(location) = &asset.id; - location.chain_part() - } -} - -// Provide reserve in relative path view -// Self tokens are represeneted as Here -pub struct RelativeReserveProvider; - -impl Reserve for RelativeReserveProvider { - fn reserve(asset: &Asset) -> Option { - let AssetId(location) = &asset.id; - if location.parents == 0 && !is_chain_junction(location.first_interior()) { - Some(Location::here()) - } else { - location.chain_part() - } - } -} - pub trait RelativeLocations { fn sibling_parachain_general_key(para_id: u32, general_key: BoundedVec>) -> Location; } @@ -79,93 +17,3 @@ impl RelativeLocations for Location { Location::new(1, [Parachain(para_id), general_key.as_bounded_slice().into()]) } } - -#[cfg(test)] -mod tests { - use super::*; - - const PARACHAIN: Junction = Parachain(1); - const GENERAL_INDEX: Junction = GeneralIndex(1); - - fn concrete_fungible(id: Location) -> Asset { - (id, 1).into() - } - - #[test] - fn parent_as_reserve_chain() { - assert_eq!( - AbsoluteReserveProvider::reserve(&concrete_fungible(Location::new(1, [GENERAL_INDEX]))), - Some(Location::parent()) - ); - assert_eq!( - RelativeReserveProvider::reserve(&concrete_fungible(Location::new(1, [GENERAL_INDEX]))), - Some(Location::parent()) - ); - } - - #[test] - fn sibling_parachain_as_reserve_chain() { - assert_eq!( - AbsoluteReserveProvider::reserve(&concrete_fungible(Location::new(1, [PARACHAIN, GENERAL_INDEX]))), - Some(Location::new(1, [PARACHAIN])) - ); - assert_eq!( - RelativeReserveProvider::reserve(&concrete_fungible(Location::new(1, [PARACHAIN, GENERAL_INDEX]))), - Some(Location::new(1, [PARACHAIN])) - ); - } - - #[test] - fn child_parachain_as_reserve_chain() { - assert_eq!( - AbsoluteReserveProvider::reserve(&concrete_fungible(Location::new(0, [PARACHAIN, GENERAL_INDEX]))), - Some(PARACHAIN.into()) - ); - assert_eq!( - RelativeReserveProvider::reserve(&concrete_fungible(Location::new(0, [PARACHAIN, GENERAL_INDEX]))), - Some(PARACHAIN.into()) - ); - } - - #[test] - fn no_reserve_chain_for_absolute_self_for_relative() { - assert_eq!( - AbsoluteReserveProvider::reserve(&concrete_fungible(Location::new( - 0, - [Junction::from(BoundedVec::try_from(b"DOT".to_vec()).unwrap())] - ))), - None - ); - assert_eq!( - RelativeReserveProvider::reserve(&concrete_fungible(Location::new( - 0, - [Junction::from(BoundedVec::try_from(b"DOT".to_vec()).unwrap())] - ))), - Some(Location::here()) - ); - } - - #[test] - fn non_chain_part_works() { - assert_eq!(Location::parent().non_chain_part(), None); - assert_eq!(Location::new(1, [PARACHAIN]).non_chain_part(), None); - assert_eq!(Location::new(0, [PARACHAIN]).non_chain_part(), None); - - assert_eq!( - Location::new(1, [GENERAL_INDEX]).non_chain_part(), - Some(GENERAL_INDEX.into()) - ); - assert_eq!( - Location::new(1, [GENERAL_INDEX, GENERAL_INDEX]).non_chain_part(), - Some((GENERAL_INDEX, GENERAL_INDEX).into()) - ); - assert_eq!( - Location::new(1, [PARACHAIN, GENERAL_INDEX]).non_chain_part(), - Some(GENERAL_INDEX.into()) - ); - assert_eq!( - Location::new(0, [PARACHAIN, GENERAL_INDEX]).non_chain_part(), - Some(GENERAL_INDEX.into()) - ); - } -} diff --git a/xcm-support/src/tests.rs b/xcm-support/src/tests.rs index 9b38d0360..aae80c4b1 100644 --- a/xcm-support/src/tests.rs +++ b/xcm-support/src/tests.rs @@ -4,7 +4,7 @@ use super::*; -use orml_traits::{location::AbsoluteReserveProvider, location::RelativeLocations, ConcreteFungibleAsset}; +use orml_traits::{location::RelativeLocations, ConcreteFungibleAsset}; #[derive(Debug, PartialEq, Eq)] pub enum TestCurrencyId { @@ -88,22 +88,3 @@ fn is_native_concrete_does_not_matches_non_native_currencies() { }) .is_none()); } - -#[test] -fn multi_native_asset() { - assert!(MultiNativeAsset::::contains( - &Asset { - fun: Fungible(10), - id: AssetId(Location::parent()) - }, - &Parent.into() - )); - assert!(MultiNativeAsset::::contains( - &Asset::sibling_parachain_asset(1, b"TokenA".to_vec().try_into().unwrap(), 100), - &Location::new(1, [Parachain(1)]), - )); - assert!(!MultiNativeAsset::::contains( - &Asset::sibling_parachain_asset(1, b"TokenA".to_vec().try_into().unwrap(), 100), - &Location::parent(), - )); -} diff --git a/xtokens/src/lib.rs b/xtokens/src/lib.rs index 9aa22afe7..bb024d2ee 100644 --- a/xtokens/src/lib.rs +++ b/xtokens/src/lib.rs @@ -53,7 +53,7 @@ use xcm_executor::traits::WeightBounds; pub use module::*; use orml_traits::{ - location::{Parse, Reserve}, + location::{Reserve, ASSET_HUB_ID}, xcm_transfer::{Transferred, XtokensWeightInfo}, GetByKey, RateLimiter, XcmTransfer, }; @@ -565,7 +565,7 @@ pub mod module { if asset_len > 1 && fee_reserve != non_fee_reserve { // Current only support `ToReserve` with relay-chain asset as fee. other case // like `NonReserve` or `SelfReserve` with relay-chain fee is not support. - ensure!(non_fee_reserve == dest.chain_part(), Error::::InvalidAsset); + ensure!(non_fee_reserve == chain_part(&dest), Error::::InvalidAsset); let reserve_location = non_fee_reserve.clone().ok_or(Error::::AssetHasNoReserve)?; let min_xcm_fee = T::MinXcmFee::get(&reserve_location).ok_or(Error::::MinXcmFeeNotDefined)?; @@ -590,7 +590,7 @@ pub mod module { let mut override_recipient = T::SelfLocation::get(); if override_recipient == Location::here() { - let dest_chain_part = dest.chain_part().ok_or(Error::::InvalidDest)?; + let dest_chain_part = chain_part(&dest).ok_or(Error::::InvalidDest)?; let ancestry = T::UniversalLocation::get(); let _ = override_recipient .reanchor(&dest_chain_part, &ancestry) @@ -600,7 +600,7 @@ pub mod module { // First xcm sent to fee reserve chain and routed to dest chain. // We can use `MinXcmFee` configuration to decide which target parachain use // teleport. But as current there's only one case which is Parachain send back - // asset to Statemine/t, So we set `use_teleport` to always `true` in this case. + // asset to AssetHub, So we set `use_teleport` to always `true` in this case. Self::execute_and_send_reserve_kind_xcm( origin_location.clone(), assets_to_fee_reserve, @@ -684,10 +684,12 @@ pub mod module { let mut hash = msg.using_encoded(sp_io::hashing::blake2_256); let weight = T::Weigher::weight(&mut msg, Weight::MAX).map_err(|_| Error::::UnweighableMessage)?; - T::XcmExecutor::prepare_and_execute(origin_location, msg, &mut hash, weight, weight) + T::XcmExecutor::prepare_and_execute(origin_location.clone(), msg.clone(), &mut hash, weight, weight) .ensure_complete() .map_err(|error| { - log::error!("Failed execute transfer message with {error:?}"); + log::error!( + "Failed execute transfer message with {error:?}, origin: {origin_location:?}, msg: {msg:?}" + ); Error::::XcmExecutionFailed })?; @@ -817,7 +819,7 @@ pub mod module { /// Ensure has the `dest` has chain part and recipient part. fn ensure_valid_dest(dest: &Location) -> Result<(Location, Location), DispatchError> { - if let (Some(dest), Some(recipient)) = (dest.chain_part(), dest.non_chain_part()) { + if let (Some(dest), Some(recipient)) = (chain_part(dest), non_chain_part(dest)) { Ok((dest, recipient)) } else { Err(Error::::InvalidDest.into()) @@ -1066,3 +1068,60 @@ fn subtract_fee(asset: &Asset, amount: u128) -> Asset { id: asset.id.clone(), } } + +fn is_chain_junction(junction: Option<&Junction>) -> bool { + matches!(junction, Some(Parachain(_))) +} + +// Provide reserve in absolute path view +pub struct AbsoluteReserveProvider; + +impl Reserve for AbsoluteReserveProvider { + fn reserve(asset: &Asset) -> Option { + let AssetId(location) = &asset.id; + chain_part(location) + } +} + +// Provide reserve in relative path view +// Self tokens are represeneted as Here +pub struct RelativeReserveProvider; + +impl Reserve for RelativeReserveProvider { + fn reserve(asset: &Asset) -> Option { + let AssetId(location) = &asset.id; + if location.parents == 0 && !is_chain_junction(location.first_interior()) { + Some(Location::here()) + } else { + chain_part(location) + } + } +} + +/// Returns the "chain" location part. It could be parent, sibling +/// parachain, or child parachain. +pub fn chain_part(location: &Location) -> Option { + match (location.parents, location.first_interior()) { + // sibling parachain + (1, Some(Parachain(id))) => Some(Location::new(1, [Parachain(*id)])), + // parent -> assethub + (1, _) => Some(Location::new(1, [Parachain(ASSET_HUB_ID)])), + // children parachain + (0, Some(Parachain(id))) => Some(Location::new(0, [Parachain(*id)])), + _ => None, + } +} + +/// Returns "non-chain" location part. +pub fn non_chain_part(location: &Location) -> Option { + let mut junctions = location.interior().clone(); + while is_chain_junction(junctions.first()) { + let _ = junctions.take_first(); + } + + if junctions != Here { + Some(Location::new(0, junctions)) + } else { + None + } +} diff --git a/xtokens/src/mock/asset_hub.rs b/xtokens/src/mock/asset_hub.rs new file mode 100644 index 000000000..c15c97fea --- /dev/null +++ b/xtokens/src/mock/asset_hub.rs @@ -0,0 +1,188 @@ +use super::{AbsoluteReserveProvider, AllowTopLevelPaidExecution, Balance, ConcreteAssetFromSystem, ParachainXcmRouter}; + +use frame_support::{ + construct_runtime, derive_impl, parameter_types, + traits::{ConstU128, ConstU32, ContainsPair, Everything, Get, Nothing}, +}; +use frame_system::EnsureRoot; +use pallet_xcm::XcmPassthrough; +use polkadot_parachain_primitives::primitives::Sibling; +use sp_runtime::{traits::IdentityLookup, AccountId32}; +use sp_std::marker::PhantomData; +use xcm::v5::{prelude::*, Weight}; +use xcm_builder::{ + AccountId32Aliases, EnsureXcmOrigin, FixedWeightBounds, FungibleAdapter, IsConcrete, ParentIsPreset, + RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, +}; +use xcm_executor::{Config, XcmExecutor}; + +use crate::mock::{AllTokensAreCreatedEqualToWeight, KsmLocation}; +use orml_traits::location::Reserve; + +pub type AccountId = AccountId32; + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Block = Block; + type AccountData = pallet_balances::AccountData; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = ConstU32<50>; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ConstU128<1>; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = ConstU32<50>; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; + type FreezeIdentifier = [u8; 8]; + type MaxFreezes = (); + type DoneSlashHandler = (); +} + +parameter_types! { + pub const RelayNetwork: NetworkId = NetworkId::Kusama; + pub const RelayLocation: Location = Location::parent(); + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UniversalLocation: InteriorLocation = + [GlobalConsensus(RelayNetwork::get()), Parachain(MsgQueue::get().into())].into(); +} + +pub type LocationToAccountId = ( + ParentIsPreset, + SiblingParachainConvertsVia, + AccountId32Aliases, +); + +pub type XcmOriginToCallOrigin = ( + SovereignSignedViaLocation, + RelayChainAsNative, + SiblingParachainAsNative, + SignedAccountId32AsNative, + XcmPassthrough, +); + +pub type LocalAssetTransactor = + FungibleAdapter, LocationToAccountId, AccountId, ()>; + +pub type XcmRouter = ParachainXcmRouter; +pub type Barrier = (TakeWeightCredit, AllowTopLevelPaidExecution); + +parameter_types! { + pub const UnitWeightCost: Weight = Weight::from_parts(10, 10); + pub const BaseXcmWeight: Weight = Weight::from_parts(100_000_000, 100_000_000); + pub const MaxInstructions: u32 = 100; + pub const MaxAssetsIntoHolding: u32 = 64; +} + +pub struct MultiNativeAsset(PhantomData); +impl ContainsPair for MultiNativeAsset +where + ReserveProvider: Reserve, +{ + fn contains(asset: &Asset, origin: &Location) -> bool { + if let Some(ref reserve) = ReserveProvider::reserve(asset) { + if reserve == origin { + return true; + } + } + // allow parachain to be reserved of relay to bypass https://github.com/paritytech/polkadot-sdk/pull/5660 + if asset.id.0 == Location::parent() { + return true; + } + false + } +} + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = LocalAssetTransactor; + type OriginConverter = XcmOriginToCallOrigin; + type IsReserve = MultiNativeAsset; + type IsTeleporter = ConcreteAssetFromSystem; + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = FixedWeightBounds; + type Trader = AllTokensAreCreatedEqualToWeight; + type ResponseHandler = (); + type AssetTrap = PolkadotXcm; + type AssetClaims = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type AssetLocker = PolkadotXcm; + type AssetExchanger = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; + type Aliasers = (); + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); + type XcmRecorder = (); + type XcmEventEmitter = (); +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +pub type LocalOriginToLocation = SignedToAccountId32; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Everything; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Nothing; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + type AdminOrigin = EnsureRoot; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type AuthorizedAliasConsideration = (); +} + +impl orml_xcm_mock_message_queue::Config for Runtime { + type XcmExecutor = XcmExecutor; +} + +type Block = frame_system::mocking::MockBlock; + +construct_runtime!( + pub enum Runtime { + System: frame_system, + Balances: pallet_balances, + + MsgQueue: orml_xcm_mock_message_queue, + CumulusXcm: cumulus_pallet_xcm, + + PolkadotXcm: pallet_xcm, + } +); diff --git a/xtokens/src/mock/mod.rs b/xtokens/src/mock/mod.rs index 2bcdc5490..dfd0c7452 100644 --- a/xtokens/src/mock/mod.rs +++ b/xtokens/src/mock/mod.rs @@ -3,6 +3,9 @@ use super::*; use crate as orml_xtokens; +use frame_support::{parameter_types, traits::ContainsPair}; +use sp_core::Get; +use sp_std::marker::PhantomData; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; use sp_io::TestExternalities; @@ -13,6 +16,7 @@ use xcm_executor::AssetsInHolding; use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, ProcessMessageError, TestExt}; +pub mod asset_hub; pub mod para; pub mod para_relative_view; pub mod para_teleport; @@ -23,6 +27,23 @@ pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]); pub const BOB: AccountId32 = AccountId32::new([1u8; 32]); pub const CHARLIE: AccountId32 = AccountId32::new([2u8; 32]); +parameter_types! { + pub KsmLocation: Location = Parent.into(); +} + +/// Accepts an asset if it is a concrete asset from the system (Relay Chain or system parachain). +pub struct ConcreteAssetFromSystem(PhantomData); +impl> ContainsPair for ConcreteAssetFromSystem { + fn contains(asset: &Asset, origin: &Location) -> bool { + let is_system = match origin.unpack() { + (1, []) => true, + (1, [Parachain(id)]) => *id < 2000, + _ => false, + }; + asset.id.0 == AssetLocation::get() && is_system + } +} + #[derive( Encode, Decode, @@ -220,6 +241,15 @@ decl_test_parachain! { } } +decl_test_parachain! { + pub struct AssetHub { + Runtime = asset_hub::Runtime, + XcmpMessageHandler = asset_hub::MsgQueue, + DmpMessageHandler = asset_hub::MsgQueue, + new_ext = asset_hub_ext(ASSET_HUB_ID), + } +} + decl_test_relay_chain! { pub struct Relay { Runtime = relay::Runtime, @@ -236,6 +266,7 @@ decl_test_network! { pub struct TestNet { relay_chain = Relay, parachains = vec![ + (ASSET_HUB_ID, AssetHub), (1, ParaA), (2, ParaB), (3, ParaC), @@ -244,9 +275,9 @@ decl_test_network! { } } -pub type RelayBalances = pallet_balances::Pallet; pub type ParaTokens = orml_tokens::Pallet; pub type ParaXTokens = orml_xtokens::Pallet; +pub type AssetHubBalances = pallet_balances::Pallet; pub type ParaRelativeTokens = orml_tokens::Pallet; pub type ParaRelativeXTokens = orml_xtokens::Pallet; @@ -295,6 +326,28 @@ pub fn para_teleport_ext(para_id: u32) -> TestExternalities { ext } +pub fn asset_hub_ext(para_id: u32) -> sp_io::TestExternalities { + use asset_hub::{MsgQueue, Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(ALICE, 1_000)], + ..Default::default() + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + MsgQueue::set_para_id(para_id.into()); + }); + ext +} + pub fn relay_ext() -> sp_io::TestExternalities { use relay::{Runtime, System}; diff --git a/xtokens/src/mock/para.rs b/xtokens/src/mock/para.rs index 2482b0de5..72987180c 100644 --- a/xtokens/src/mock/para.rs +++ b/xtokens/src/mock/para.rs @@ -1,6 +1,6 @@ use super::{ - AllowTopLevelPaidExecution, Amount, Balance, CurrencyId, CurrencyIdConvert, ParachainXcmRouter, RateLimiter, - CHARLIE, + AbsoluteReserveProvider, AllowTopLevelPaidExecution, Amount, Balance, ConcreteAssetFromSystem, CurrencyId, + CurrencyIdConvert, ParachainXcmRouter, RateLimiter, CHARLIE, }; use crate as orml_xtokens; @@ -19,15 +19,15 @@ use sp_runtime::{ use sp_std::{cell::RefCell, marker::PhantomData}; use xcm::v5::{prelude::*, Weight}; use xcm_builder::{ - AccountId32Aliases, EnsureXcmOrigin, FixedWeightBounds, NativeAsset, ParentIsPreset, RelayChainAsNative, + AccountId32Aliases, EnsureXcmOrigin, FixedWeightBounds, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, }; use xcm_executor::{Config, XcmExecutor}; -use crate::mock::AllTokensAreCreatedEqualToWeight; +use crate::mock::{AllTokensAreCreatedEqualToWeight, KsmLocation}; use orml_traits::{ - location::{AbsoluteReserveProvider, Reserve}, + location::{Reserve, ASSET_HUB_ID}, parameter_type_with_key, RateLimiterError, }; use orml_xcm_support::{IsNativeConcrete, MultiCurrencyAdapter}; @@ -146,7 +146,7 @@ impl Config for XcmConfig { type AssetTransactor = LocalAssetTransactor; type OriginConverter = XcmOriginToCallOrigin; type IsReserve = MultiNativeAsset; - type IsTeleporter = NativeAsset; + type IsTeleporter = ConcreteAssetFromSystem; type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = FixedWeightBounds; @@ -235,6 +235,7 @@ impl Contains for ParentOrParachains { | (1, [Parachain(3), Junction::AccountId32 { .. }]) | (1, [Parachain(4), Junction::AccountId32 { .. }]) | (1, [Parachain(100), Junction::AccountId32 { .. }]) + | (1, [Parachain(ASSET_HUB_ID), Junction::AccountId32 { .. }]) ) } } @@ -244,6 +245,7 @@ parameter_type_with_key! { #[allow(clippy::match_ref_pats)] // false positive match (location.parents, location.first_interior()) { (1, Some(Parachain(3))) => Some(50), + (1, Some(Parachain(ASSET_HUB_ID))) => Some(50), _ => None, } }; diff --git a/xtokens/src/mock/para_relative_view.rs b/xtokens/src/mock/para_relative_view.rs index 70a679921..5afa19f82 100644 --- a/xtokens/src/mock/para_relative_view.rs +++ b/xtokens/src/mock/para_relative_view.rs @@ -1,4 +1,4 @@ -use super::{Amount, Balance, CurrencyId, CurrencyIdConvert, ParachainXcmRouter}; +use super::{AbsoluteReserveProvider, Amount, Balance, CurrencyId, CurrencyIdConvert, ParachainXcmRouter, RelativeReserveProvider}; use crate as orml_xtokens; use frame_support::{ @@ -23,7 +23,7 @@ use xcm_executor::{Config, XcmExecutor}; use crate::mock::AllTokensAreCreatedEqualToWeight; use orml_traits::{ - location::{AbsoluteReserveProvider, RelativeReserveProvider, Reserve}, + location::{Reserve, ASSET_HUB_ID}, parameter_type_with_key, }; use orml_xcm_support::{IsNativeConcrete, MultiCurrencyAdapter}; @@ -350,6 +350,7 @@ impl Contains for ParentOrParachains { | (1, [Parachain(3), Junction::AccountId32 { .. }]) | (1, [Parachain(4), Junction::AccountId32 { .. }]) | (1, [Parachain(100), Junction::AccountId32 { .. }]) + | (1, [Parachain(ASSET_HUB_ID), Junction::AccountId32 { .. }]) ) } } diff --git a/xtokens/src/mock/para_teleport.rs b/xtokens/src/mock/para_teleport.rs index fb7e4efb8..2b17acc92 100644 --- a/xtokens/src/mock/para_teleport.rs +++ b/xtokens/src/mock/para_teleport.rs @@ -1,4 +1,7 @@ -use super::{AllowTopLevelPaidExecution, Amount, Balance, CurrencyId, CurrencyIdConvert, ParachainXcmRouter}; +use super::{ + AbsoluteReserveProvider, AllowTopLevelPaidExecution, Amount, Balance, ConcreteAssetFromSystem, CurrencyId, + CurrencyIdConvert, ParachainXcmRouter, +}; use crate as orml_xtokens; use frame_support::{ @@ -14,15 +17,15 @@ use sp_runtime::{ }; use xcm::v5::{prelude::*, Weight}; use xcm_builder::{ - AccountId32Aliases, EnsureXcmOrigin, FixedWeightBounds, NativeAsset, ParentIsPreset, RelayChainAsNative, + AccountId32Aliases, EnsureXcmOrigin, FixedWeightBounds, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, }; use xcm_executor::{Config, XcmExecutor}; use crate::mock::teleport_currency_adapter::MultiTeleportCurrencyAdapter; -use crate::mock::AllTokensAreCreatedEqualToWeight; -use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key}; +use crate::mock::{AllTokensAreCreatedEqualToWeight, KsmLocation}; +use orml_traits::parameter_type_with_key; use orml_xcm_support::{DisabledParachainFee, IsNativeConcrete, MultiNativeAsset}; pub type AccountId = AccountId32; @@ -120,7 +123,7 @@ impl Config for XcmConfig { type AssetTransactor = LocalAssetTransactor; type OriginConverter = XcmOriginToCallOrigin; type IsReserve = MultiNativeAsset; - type IsTeleporter = NativeAsset; + type IsTeleporter = ConcreteAssetFromSystem; type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = FixedWeightBounds; diff --git a/xtokens/src/mock/relay.rs b/xtokens/src/mock/relay.rs index b033c0903..d476f058a 100644 --- a/xtokens/src/mock/relay.rs +++ b/xtokens/src/mock/relay.rs @@ -6,7 +6,8 @@ use frame_support::{ use frame_system::EnsureRoot; use sp_runtime::{traits::IdentityLookup, AccountId32}; -use crate::Weight; +use crate::mock::KsmLocation; +use crate::{Weight, ASSET_HUB_ID}; use cumulus_primitives_core::ParaId; use polkadot_runtime_parachains::{ configuration, @@ -58,7 +59,6 @@ impl configuration::Config for Runtime { } parameter_types! { - pub KsmLocation: Location = Here.into(); pub const KusamaNetwork: NetworkId = NetworkId::Kusama; pub UniversalLocation: InteriorLocation = [GlobalConsensus(KusamaNetwork::get())].into(); } @@ -81,11 +81,11 @@ pub type Barrier = (TakeWeightCredit, AllowTopLevelPaidExecutionFrom parameter_types! { pub Kusama: AssetFilter = Wild(AllOf { fun: WildFungible, id: AssetId(KsmLocation::get()) }); - pub Statemine: Location = Parachain(3).into(); - pub KusamaForStatemine: (AssetFilter, Location) = (Kusama::get(), Statemine::get()); + pub AssetHub: Location = Parachain(ASSET_HUB_ID).into(); + pub KusamaForAssetHub: (AssetFilter, Location) = (Kusama::get(), AssetHub::get()); } -pub type TrustedTeleporters = xcm_builder::Case; +pub type TrustedTeleporters = xcm_builder::Case; parameter_types! { pub const UnitWeightCost: Weight = Weight::from_parts(10, 10); diff --git a/xtokens/src/tests.rs b/xtokens/src/tests.rs index 5507b9687..3f3af0473 100644 --- a/xtokens/src/tests.rs +++ b/xtokens/src/tests.rs @@ -1,7 +1,6 @@ #![cfg(test)] use super::*; -use cumulus_primitives_core::ParaId; use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency}; use mock::*; use orml_traits::{ConcreteFungibleAsset, MultiCurrency}; @@ -11,18 +10,6 @@ use sp_runtime::{traits::AccountIdConversion, AccountId32}; use xcm::{v5::OriginKind::SovereignAccount, VersionedXcm}; use xcm_simulator::TestExt; -fn para_a_account() -> AccountId32 { - ParaId::from(1).into_account_truncating() -} - -fn para_b_account() -> AccountId32 { - ParaId::from(2).into_account_truncating() -} - -fn para_d_account() -> AccountId32 { - ParaId::from(4).into_account_truncating() -} - fn sibling_a_account() -> AccountId32 { Sibling::from(1).into_account_truncating() } @@ -50,11 +37,11 @@ fn print_events(name: &'static str) { } #[test] -fn send_relay_chain_asset_to_relay_chain() { +fn send_relay_chain_asset_to_asset_hub() { TestNet::reset(); - Relay::execute_with(|| { - let _ = RelayBalances::deposit_creating(¶_a_account(), 1_000); + AssetHub::execute_with(|| { + let _ = AssetHubBalances::deposit_creating(&sibling_a_account(), 1_000); }); ParaA::execute_with(|| { @@ -65,10 +52,13 @@ fn send_relay_chain_asset_to_relay_chain() { Box::new( Location::new( 1, - [Junction::AccountId32 { - network: None, - id: BOB.into(), - }] + [ + Parachain(ASSET_HUB_ID), + Junction::AccountId32 { + network: None, + id: BOB.into(), + } + ] ) .into() ), @@ -77,18 +67,18 @@ fn send_relay_chain_asset_to_relay_chain() { assert_eq!(ParaTokens::free_balance(CurrencyId::R, &ALICE), 500); }); - Relay::execute_with(|| { - assert_eq!(RelayBalances::free_balance(¶_a_account()), 500); - assert_eq!(RelayBalances::free_balance(&BOB), 450); + AssetHub::execute_with(|| { + assert_eq!(AssetHubBalances::free_balance(&sibling_a_account()), 500); + assert_eq!(AssetHubBalances::free_balance(&BOB), 450); }); } #[test] -fn send_relay_chain_asset_to_relay_chain_with_fee() { +fn send_relay_chain_asset_to_asset_hub_with_fee() { TestNet::reset(); - Relay::execute_with(|| { - let _ = RelayBalances::deposit_creating(¶_a_account(), 1_000); + AssetHub::execute_with(|| { + let _ = AssetHubBalances::deposit_creating(&sibling_a_account(), 1_000); }); ParaA::execute_with(|| { @@ -100,10 +90,13 @@ fn send_relay_chain_asset_to_relay_chain_with_fee() { Box::new( Location::new( 1, - [Junction::AccountId32 { - network: None, - id: BOB.into(), - }] + [ + Parachain(ASSET_HUB_ID), + Junction::AccountId32 { + network: None, + id: BOB.into(), + } + ] ) .into() ), @@ -113,9 +106,9 @@ fn send_relay_chain_asset_to_relay_chain_with_fee() { }); // It should use 50 for weight, so 450 should reach destination - Relay::execute_with(|| { - assert_eq!(RelayBalances::free_balance(¶_a_account()), 500); - assert_eq!(RelayBalances::free_balance(&BOB), 450); + AssetHub::execute_with(|| { + assert_eq!(AssetHubBalances::free_balance(&sibling_a_account()), 500); + assert_eq!(AssetHubBalances::free_balance(&BOB), 450); }); } @@ -154,8 +147,8 @@ fn cannot_lost_fund_on_send_failed() { fn send_relay_chain_asset_to_sibling() { TestNet::reset(); - Relay::execute_with(|| { - let _ = RelayBalances::deposit_creating(¶_a_account(), 1000); + AssetHub::execute_with(|| { + let _ = AssetHubBalances::deposit_creating(&sibling_a_account(), 1000); }); ParaA::execute_with(|| { @@ -181,9 +174,9 @@ fn send_relay_chain_asset_to_sibling() { assert_eq!(ParaTokens::free_balance(CurrencyId::R, &ALICE), 500); }); - Relay::execute_with(|| { - assert_eq!(RelayBalances::free_balance(¶_a_account()), 500); - assert_eq!(RelayBalances::free_balance(¶_b_account()), 450); + AssetHub::execute_with(|| { + assert_eq!(AssetHubBalances::free_balance(&sibling_a_account()), 500); + assert_eq!(AssetHubBalances::free_balance(&sibling_b_account()), 450); }); ParaB::execute_with(|| { @@ -195,8 +188,8 @@ fn send_relay_chain_asset_to_sibling() { fn send_relay_chain_asset_to_sibling_with_fee() { TestNet::reset(); - Relay::execute_with(|| { - let _ = RelayBalances::deposit_creating(¶_a_account(), 1000); + AssetHub::execute_with(|| { + let _ = AssetHubBalances::deposit_creating(&sibling_a_account(), 1000); }); ParaA::execute_with(|| { @@ -224,9 +217,9 @@ fn send_relay_chain_asset_to_sibling_with_fee() { }); // It should use 50 weight - Relay::execute_with(|| { - assert_eq!(RelayBalances::free_balance(¶_a_account()), 500); - assert_eq!(RelayBalances::free_balance(¶_b_account()), 450); + AssetHub::execute_with(|| { + assert_eq!(AssetHubBalances::free_balance(&sibling_a_account()), 500); + assert_eq!(AssetHubBalances::free_balance(&sibling_b_account()), 450); }); // It should use another 50 weight in paraB @@ -656,10 +649,13 @@ fn sending_sibling_asset_to_reserve_sibling_with_relay_fee_works() { ParaC::execute_with(|| { assert_ok!(ParaTeleportTokens::deposit(CurrencyId::C, &sibling_a_account(), 1_000)); + // ParaC might process the message before AssetHub teleports the asset to ParaC. + // This is why sibling_a_account needs to have R asset available. + assert_ok!(ParaTeleportTokens::deposit(CurrencyId::R, &sibling_a_account(), 1_000)); }); - Relay::execute_with(|| { - let _ = RelayBalances::deposit_creating(¶_a_account(), 1_000); + AssetHub::execute_with(|| { + let _ = AssetHubBalances::deposit_creating(&sibling_a_account(), 1_000); }); let fee_amount: u128 = 300; @@ -688,16 +684,16 @@ fn sending_sibling_asset_to_reserve_sibling_with_relay_fee_works() { assert_eq!(1000 - fee_amount, ParaTokens::free_balance(CurrencyId::R, &ALICE)); }); - Relay::execute_with(|| { + AssetHub::execute_with(|| { assert_eq!( 1000 - (fee_amount - dest_weight), - RelayBalances::free_balance(¶_a_account()) + AssetHubBalances::free_balance(&sibling_a_account()) ); }); ParaC::execute_with(|| { assert_eq!( - fee_amount - dest_weight * 4, + 1000 + fee_amount - dest_weight * 4, ParaTeleportTokens::free_balance(CurrencyId::R, &sibling_a_account()) ); @@ -716,10 +712,13 @@ fn sending_sibling_asset_to_reserve_sibling_with_relay_fee_works_with_relative_s ParaC::execute_with(|| { assert_ok!(ParaTeleportTokens::deposit(CurrencyId::C, &sibling_d_account(), 1_000)); + // ParaC might process the message before AssetHub teleports the asset to ParaC. + // This is why sibling_d_account needs to have R asset available. + assert_ok!(ParaTeleportTokens::deposit(CurrencyId::R, &sibling_d_account(), 1_000)); }); - Relay::execute_with(|| { - let _ = RelayBalances::deposit_creating(¶_d_account(), 1_000); + AssetHub::execute_with(|| { + let _ = AssetHubBalances::deposit_creating(&sibling_d_account(), 1_000); }); let fee_amount: u128 = 300; @@ -751,16 +750,16 @@ fn sending_sibling_asset_to_reserve_sibling_with_relay_fee_works_with_relative_s ); }); - Relay::execute_with(|| { + AssetHub::execute_with(|| { assert_eq!( 1000 - (fee_amount - dest_weight), - RelayBalances::free_balance(¶_d_account()) + AssetHubBalances::free_balance(&sibling_d_account()) ); }); ParaC::execute_with(|| { assert_eq!( - fee_amount - dest_weight * 4, + 1000 + fee_amount - dest_weight * 4, ParaTeleportTokens::free_balance(CurrencyId::R, &sibling_d_account()) ); @@ -781,8 +780,8 @@ fn sending_sibling_asset_to_reserve_sibling_with_relay_fee_not_enough() { assert_ok!(ParaTokens::deposit(CurrencyId::C, &sibling_a_account(), 1_000)); }); - Relay::execute_with(|| { - let _ = RelayBalances::deposit_creating(¶_a_account(), 1_000); + AssetHub::execute_with(|| { + let _ = AssetHubBalances::deposit_creating(&sibling_a_account(), 1_000); }); let fee_amount: u128 = 159; @@ -811,10 +810,10 @@ fn sending_sibling_asset_to_reserve_sibling_with_relay_fee_not_enough() { assert_eq!(1000 - fee_amount, ParaTokens::free_balance(CurrencyId::R, &ALICE)); }); - Relay::execute_with(|| { + AssetHub::execute_with(|| { assert_eq!( 1000 - (fee_amount - dest_weight), - RelayBalances::free_balance(¶_a_account()) + AssetHubBalances::free_balance(&sibling_a_account()) ); }); @@ -1018,18 +1017,18 @@ fn transfer_to_invalid_dest_fails() { fn send_as_sovereign() { TestNet::reset(); - Relay::execute_with(|| { - let _ = RelayBalances::deposit_creating(¶_a_account(), 1_000_000_000_000); + AssetHub::execute_with(|| { + let _ = AssetHubBalances::deposit_creating(&sibling_a_account(), 1_000_000_000_000); }); ParaA::execute_with(|| { let call = relay::RuntimeCall::System(frame_system::Call::::remark_with_event { remark: vec![1, 1, 1], }); - let assets: Asset = (Here, 1_000_000_000_000u128).into(); + let assets: Asset = (Parent, 1_000_000_000_000u128).into(); assert_ok!(para::OrmlXcm::send_as_sovereign( para::RuntimeOrigin::root(), - Box::new(Parent.into()), + Box::new(VersionedLocation::from(Location::new(1, [Parachain(ASSET_HUB_ID)]))), Box::new(VersionedXcm::from(Xcm(vec![ WithdrawAsset(assets.clone().into()), BuyExecution { @@ -1045,11 +1044,14 @@ fn send_as_sovereign() { )); }); - Relay::execute_with(|| { - assert!(relay::System::events().iter().any(|r| { + AssetHub::execute_with(|| { + assert!(asset_hub::System::events().iter().any(|r| { matches!( r.event, - relay::RuntimeEvent::System(frame_system::Event::::Remarked { sender: _, hash: _ }) + asset_hub::RuntimeEvent::System(frame_system::Event::::Remarked { + sender: _, + hash: _ + }) ) })); }) @@ -1059,8 +1061,8 @@ fn send_as_sovereign() { fn send_as_sovereign_fails_if_bad_origin() { TestNet::reset(); - Relay::execute_with(|| { - let _ = RelayBalances::deposit_creating(¶_a_account(), 1_000_000_000_000); + AssetHub::execute_with(|| { + let _ = AssetHubBalances::deposit_creating(&sibling_a_account(), 1_000_000_000_000); }); ParaA::execute_with(|| { @@ -1236,8 +1238,8 @@ fn specifying_more_than_assets_limit_should_error() { assert_ok!(ParaTokens::deposit(CurrencyId::B2, &sibling_a_account(), 1_000)); }); - Relay::execute_with(|| { - let _ = RelayBalances::deposit_creating(¶_a_account(), 1_000); + AssetHub::execute_with(|| { + let _ = AssetHubBalances::deposit_creating(&sibling_a_account(), 1_000); }); ParaA::execute_with(|| { @@ -1282,8 +1284,8 @@ fn sending_non_fee_assets_with_different_reserve_should_fail() { assert_ok!(ParaTokens::deposit(CurrencyId::B, &sibling_a_account(), 1_000)); }); - Relay::execute_with(|| { - let _ = RelayBalances::deposit_creating(¶_a_account(), 1_000); + AssetHub::execute_with(|| { + let _ = AssetHubBalances::deposit_creating(&sibling_a_account(), 1_000); }); ParaA::execute_with(|| { @@ -1561,8 +1563,8 @@ fn send_relative_view_sibling_asset_to_non_reserve_sibling() { fn send_relay_chain_asset_to_relative_view_sibling() { TestNet::reset(); - Relay::execute_with(|| { - let _ = RelayBalances::deposit_creating(¶_a_account(), 1000); + AssetHub::execute_with(|| { + let _ = AssetHubBalances::deposit_creating(&sibling_a_account(), 1000); }); ParaA::execute_with(|| { @@ -1588,9 +1590,9 @@ fn send_relay_chain_asset_to_relative_view_sibling() { assert_eq!(ParaTokens::free_balance(CurrencyId::R, &ALICE), 500); }); - Relay::execute_with(|| { - assert_eq!(RelayBalances::free_balance(¶_a_account()), 500); - assert_eq!(RelayBalances::free_balance(¶_d_account()), 450); + AssetHub::execute_with(|| { + assert_eq!(AssetHubBalances::free_balance(&sibling_a_account()), 500); + assert_eq!(AssetHubBalances::free_balance(&sibling_d_account()), 450); }); ParaD::execute_with(|| { @@ -1726,11 +1728,11 @@ fn send_with_insufficient_weight_limit() { fn send_relay_chain_asset_to_relay_chain_at_rate_limit() { TestNet::reset(); - Relay::execute_with(|| { - let _ = RelayBalances::deposit_creating(¶_a_account(), 4000); - assert_eq!(RelayBalances::free_balance(¶_a_account()), 4000); - assert_eq!(RelayBalances::free_balance(&ALICE), 1000); - assert_eq!(RelayBalances::free_balance(&BOB), 0); + AssetHub::execute_with(|| { + let _ = AssetHubBalances::deposit_creating(&sibling_a_account(), 4000); + assert_eq!(AssetHubBalances::free_balance(&sibling_a_account()), 4000); + assert_eq!(AssetHubBalances::free_balance(&ALICE), 1000); + assert_eq!(AssetHubBalances::free_balance(&BOB), 0); }); ParaA::execute_with(|| { @@ -1826,10 +1828,10 @@ fn send_relay_chain_asset_to_relay_chain_at_rate_limit() { assert_eq!(R_ACCUMULATION.with(|v| *v.borrow()), 2000); }); - Relay::execute_with(|| { - assert_eq!(RelayBalances::free_balance(¶_a_account()), 1799); - assert_eq!(RelayBalances::free_balance(&ALICE), 1151); - assert_eq!(RelayBalances::free_balance(&CHARLIE), 1900); + AssetHub::execute_with(|| { + assert_eq!(AssetHubBalances::free_balance(&sibling_a_account()), 1799); + assert_eq!(AssetHubBalances::free_balance(&ALICE), 1151); + assert_eq!(AssetHubBalances::free_balance(&CHARLIE), 1900); }); }