diff --git a/Cargo.lock b/Cargo.lock index 0d55487f8f19..163c507d8829 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -833,6 +833,7 @@ dependencies = [ "pallet-xcm", "parachains-common", "parity-scale-codec", + "penpal-runtime", "rococo-runtime", "rococo-system-emulated-network", "sp-runtime", @@ -1079,6 +1080,7 @@ dependencies = [ "impl-trait-for-tuples", "log", "pallet-asset-conversion", + "pallet-assets", "pallet-xcm", "parachains-common", "parity-scale-codec", @@ -11611,6 +11613,7 @@ dependencies = [ "penpal-runtime", "rococo-emulated-chain", "sp-core", + "staging-xcm", "westend-emulated-chain", ] diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs index 00f412564205..facab26996d8 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs @@ -55,5 +55,5 @@ decl_test_parachains! { impl_accounts_helpers_for_parachain!(AssetHubRococo); impl_assert_events_helpers_for_parachain!(AssetHubRococo); impl_assets_helpers_for_parachain!(AssetHubRococo, Rococo); -impl_foreign_assets_helpers_for_parachain!(AssetHubRococo, Rococo); +impl_foreign_assets_helpers_for_parachain!(AssetHubRococo); impl_xcm_helpers_for_parachain!(AssetHubRococo); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs index 25d7c1079b4d..11945c8cb4a6 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs @@ -55,5 +55,5 @@ decl_test_parachains! { impl_accounts_helpers_for_parachain!(AssetHubWestend); impl_assert_events_helpers_for_parachain!(AssetHubWestend); impl_assets_helpers_for_parachain!(AssetHubWestend, Westend); -impl_foreign_assets_helpers_for_parachain!(AssetHubWestend, Westend); +impl_foreign_assets_helpers_for_parachain!(AssetHubWestend); impl_xcm_helpers_for_parachain!(AssetHubWestend); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml index a853825d8ef6..dbbe510d3ec3 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml @@ -16,6 +16,9 @@ workspace = true sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } +# Polkadot +xcm = { package = "staging-xcm", path = "../../../../../../../../polkadot/xcm", default-features = false } + # Cumulus parachains-common = { path = "../../../../../../../parachains/common" } cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs index 9ab32a977d71..938516cec9e1 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs @@ -20,13 +20,17 @@ use sp_core::{sr25519, storage::Storage}; use emulated_integration_tests_common::{ accounts, build_genesis_storage, collators, get_account_id_from_seed, SAFE_XCM_VERSION, }; -use parachains_common::Balance; - +use parachains_common::{Balance, AccountId}; +use penpal_runtime::xcm_config::{RelayLocationV3, SystemAssetHubLocationV3}; // Penpal pub const PARA_ID_A: u32 = 2000; pub const PARA_ID_B: u32 = 2001; pub const ED: Balance = penpal_runtime::EXISTENTIAL_DEPOSIT; +pub fn asset_owner() -> AccountId { + get_account_id_from_seed::("Alice") +} + pub fn genesis(para_id: u32) -> Storage { let genesis_config = penpal_runtime::RuntimeGenesisConfig { system: penpal_runtime::SystemConfig::default(), @@ -61,6 +65,15 @@ pub fn genesis(para_id: u32) -> Storage { sudo: penpal_runtime::SudoConfig { key: Some(get_account_id_from_seed::("Alice")), }, + foreign_assets: penpal_runtime::ForeignAssetsConfig { + assets: vec![ + // AssetHub Native asset representation + (SystemAssetHubLocationV3::get(), get_account_id_from_seed::("Alice"), true, ED), + // Relay Native asset representation + (RelayLocationV3::get(), get_account_id_from_seed::("Alice"), true, ED) + ], + ..Default::default() + }, ..Default::default() }; diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs index 8f586a46a75c..eef2e1a6a4db 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs @@ -14,17 +14,14 @@ // limitations under the License. mod genesis; -pub use genesis::{genesis, ED, PARA_ID_A, PARA_ID_B}; -pub use penpal_runtime::xcm_config::{ - LocalTeleportableToAssetHub, LocalTeleportableToAssetHubV3, XcmConfig, -}; +pub use genesis::{genesis, asset_owner, ED, PARA_ID_A, PARA_ID_B}; // Substrate use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ - impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, + impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, impl_foreign_assets_helpers_for_parachain, impl_assets_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, }; use rococo_emulated_chain::Rococo; @@ -79,3 +76,5 @@ impl_assets_helpers_for_parachain!(PenpalA, Rococo); impl_assets_helpers_for_parachain!(PenpalB, Westend); impl_assert_events_helpers_for_parachain!(PenpalA); impl_assert_events_helpers_for_parachain!(PenpalB); +impl_foreign_assets_helpers_for_parachain!(PenpalA); +impl_foreign_assets_helpers_for_parachain!(PenpalB); diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index 4bbb4701e439..424572915646 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -728,7 +728,7 @@ macro_rules! impl_assets_helpers_for_parachain { #[macro_export] macro_rules! impl_foreign_assets_helpers_for_parachain { - ( $chain:ident, $relay_chain:ident ) => { + ( $chain:ident) => { $crate::impls::paste::paste! { impl $chain { /// Create foreign assets using sudo `ForeignAssets::force_create()` diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs index d3bb3238a3b4..0ab83cf3c924 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs @@ -19,14 +19,25 @@ pub use paste; pub use pallet_balances; pub use pallet_message_queue; pub use pallet_xcm; +pub use pallet_assets; +pub use frame_support::{pallet_prelude::Weight, weights::WeightToFee}; // Polkadot -pub use xcm::prelude::{AccountId32, WeightLimit}; +pub use xcm::{ + v3::Location as V3Location, + prelude::{ + OriginKind, AccountId32, WeightLimit, Asset, AssetId, Fungible, + Location, Here, VersionedXcm, Xcm, Unlimited, WithdrawAsset, BuyExecution, + Transact, ExpectTransactStatus, MaybeErrorCode, RefundSurplus, DepositAsset, + All + }, +}; // Cumulus pub use asset_test_utils; pub use cumulus_pallet_xcmp_queue; pub use xcm_emulator::Chain; +pub use parachains_common::AccountId; #[macro_export] macro_rules! test_parachain_is_trusted_teleporter { @@ -127,13 +138,19 @@ macro_rules! include_penpal_create_foreign_asset_on_asset_hub { $crate::impls::paste::paste! { pub fn penpal_create_foreign_asset_on_asset_hub( asset_id_on_penpal: u32, - foreign_asset_at_asset_hub: v3::Location, - ah_as_seen_by_penpal: Location, + foreign_asset_at_asset_hub: $crate::macros::V3Location, + ah_as_seen_by_penpal: $crate::macros::Location, is_sufficient: bool, - asset_owner: AccountId, + asset_owner: $crate::macros::AccountId, prefund_amount: u128, ) { - use frame_support::weights::WeightToFee; + use $crate::macros::{ + pallet_assets, pallet_xcm, Chain, Weight, OriginKind, Asset, AssetId, Fungible, + Location, Here, VersionedXcm, Xcm, Unlimited, WeightToFee, WithdrawAsset, BuyExecution, + Transact, ExpectTransactStatus, MaybeErrorCode, RefundSurplus, DepositAsset, + All + }; + let ah_check_account = $asset_hub::execute_with(|| { <$asset_hub as [<$asset_hub Pallet>]>::PolkadotXcm::check_account() }); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml index 0a397c2617b4..13eb7d8dfc49 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml @@ -34,5 +34,6 @@ parachains-common = { path = "../../../../../../parachains/common" } cumulus-pallet-parachain-system = { path = "../../../../../../pallets/parachain-system", default-features = false } testnet-parachains-constants = { path = "../../../../../runtimes/constants", features = ["rococo"] } asset-hub-rococo-runtime = { path = "../../../../../runtimes/assets/asset-hub-rococo" } +penpal-runtime = { path = "../../../../../runtimes/testing/penpal" } emulated-integration-tests-common = { path = "../../../common", default-features = false } rococo-system-emulated-network = { path = "../../../networks/rococo-system" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs index 1cc25cb54a14..7b44d5ee1051 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs @@ -13,59 +13,82 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub use codec::Encode; +#[cfg(test)] +mod imports { + pub use codec::Encode; + + // Substrate + pub use frame_support::{ + assert_err, assert_ok, + pallet_prelude::Weight, + sp_runtime::{DispatchError, DispatchResult, ModuleError}, + traits::fungibles::Inspect, + }; + + // Polkadot + pub use xcm::{ + prelude::{AccountId32 as AccountId32Junction, *}, + v3, + }; -// Substrate -pub use frame_support::{ - assert_err, assert_ok, - pallet_prelude::Weight, - sp_runtime::{AccountId32, DispatchError, DispatchResult}, - traits::fungibles::Inspect, -}; + // Cumulus + pub use asset_test_utils::xcm_helpers; + pub use emulated_integration_tests_common::{ + test_parachain_is_trusted_teleporter, + xcm_emulator::{ + assert_expected_events, bx, Chain, Parachain as Para, + RelayChain as Relay, Test, TestArgs, TestContext, TestExt, + }, + xcm_helpers::{xcm_transact_paid_execution, non_fee_asset}, + XCM_V3, + }; + pub use parachains_common::Balance; + pub use rococo_system_emulated_network::{ + asset_hub_rococo_emulated_chain::{ + genesis::{ED as ASSET_HUB_ROCOCO_ED, PARA_ID as ASSETHUB_PARA_ID}, AssetHubRococoParaPallet as AssetHubRococoPallet, + }, + penpal_emulated_chain::{PenpalAParaPallet as PenpalAPallet, PenpalBParaPallet as PenpalBPallet, asset_owner as penpal_asset_owner}, + rococo_emulated_chain::{genesis::ED as ROCOCO_ED, RococoRelayPallet as RococoPallet}, + AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver, + AssetHubRococoParaSender as AssetHubRococoSender, BridgeHubRococoPara as BridgeHubRococo, + BridgeHubRococoParaReceiver as BridgeHubRococoReceiver, PenpalAPara as PenpalA, + PenpalAParaReceiver as PenpalAReceiver, PenpalAParaSender as PenpalASender, + PenpalBPara as PenpalB, PenpalBParaReceiver as PenpalBReceiver, RococoRelay as Rococo, + RococoRelayReceiver as RococoReceiver, RococoRelaySender as RococoSender, + }; -// Polkadot -pub use xcm::{ - prelude::{AccountId32 as AccountId32Junction, *}, - v3::{self, Error, NetworkId::Rococo as RococoId}, -}; + // Runtimes + pub use rococo_runtime::xcm_config::{XcmConfig as RococoXcmConfig, UniversalLocation as RococoUniversalLocation}; + pub use asset_hub_rococo_runtime::xcm_config::{ + XcmConfig as AssetHubRococoXcmConfig, UniversalLocation as AssetHubRococoUniversalLocation, + TokenLocationV3 as RelayLocationV3, + }; + pub use penpal_runtime::xcm_config::{ + LocalTeleportableToAssetHubV3 as PenpalLocalTeleportableToAssetHubV3, + SystemAssetHubLocationV3, + UniversalLocation as PenpalUniversalLocation, XcmConfig as PenpalRococoXcmConfig + }; -// Cumulus -pub use asset_test_utils::xcm_helpers; -pub use emulated_integration_tests_common::{ - test_parachain_is_trusted_teleporter, - xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, - RelayChain as Relay, Test, TestArgs, TestContext, TestExt, - }, - xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, - PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, -}; -pub use parachains_common::{AccountId, Balance}; -pub use rococo_system_emulated_network::{ - asset_hub_rococo_emulated_chain::{ - genesis::ED as ASSET_HUB_ROCOCO_ED, AssetHubRococoParaPallet as AssetHubRococoPallet, - }, - penpal_emulated_chain::PenpalAParaPallet as PenpalAPallet, - rococo_emulated_chain::{genesis::ED as ROCOCO_ED, RococoRelayPallet as RococoPallet}, - AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver, - AssetHubRococoParaSender as AssetHubRococoSender, BridgeHubRococoPara as BridgeHubRococo, - BridgeHubRococoParaReceiver as BridgeHubRococoReceiver, PenpalAPara as PenpalA, - PenpalAParaReceiver as PenpalAReceiver, PenpalAParaSender as PenpalASender, - PenpalBPara as PenpalB, PenpalBParaReceiver as PenpalBReceiver, RococoRelay as Rococo, - RococoRelayReceiver as RococoReceiver, RococoRelaySender as RococoSender, -}; + pub const ASSET_ID: u32 = 1; + pub const ASSET_MIN_BALANCE: u128 = 1000; + // `Assets` pallet index + pub const ASSETS_PALLET_ID: u8 = 50; -pub const ASSET_ID: u32 = 1; -pub const ASSET_MIN_BALANCE: u128 = 1000; -// `Assets` pallet index -pub const ASSETS_PALLET_ID: u8 = 50; + pub type RelayToSystemParaTest = Test; + pub type RelayToParaTest = Test; + pub type SystemParaToRelayTest = Test; + pub type SystemParaToParaTest = Test; + pub type ParaToSystemParaTest = Test; + pub type ParaToParaThroughRelayTest = Test; + pub type ParaToParaThroughSystemParaTest = Test; -pub type RelayToSystemParaTest = Test; -pub type RelayToParaTest = Test; -pub type SystemParaToRelayTest = Test; -pub type SystemParaToParaTest = Test; -pub type ParaToSystemParaTest = Test; -pub type ParaToParaTest = Test; + emulated_integration_tests_common::include_penpal_create_foreign_asset_on_asset_hub!( + PenpalA, + AssetHubRococo, + ROCOCO_ED, + testnet_parachains_constants::rococo::fee::WeightToFee + ); +} #[cfg(test)] mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs index 21bed234304e..b3841af0e6c3 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs @@ -18,11 +18,3 @@ mod send; mod set_xcm_versions; mod swap; mod teleport; - -use crate::*; -emulated_integration_tests_common::include_penpal_create_foreign_asset_on_asset_hub!( - PenpalA, - AssetHubRococo, - ROCOCO_ED, - testnet_parachains_constants::rococo::fee::WeightToFee -); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index d2c3a323256c..fcf48632184c 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -13,14 +13,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; -use asset_hub_rococo_runtime::xcm_config::XcmConfig as AssetHubRococoXcmConfig; -use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig; -use rococo_system_emulated_network::penpal_emulated_chain::XcmConfig as PenpalRococoXcmConfig; +use crate::imports::*; fn relay_to_para_sender_assertions(t: RelayToParaTest) { type RuntimeEvent = ::RuntimeEvent; + Rococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799))); + assert_expected_events!( Rococo, vec![ @@ -40,10 +39,12 @@ fn relay_to_para_sender_assertions(t: RelayToParaTest) { fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; + AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( 864_610_000, 8_799, ))); + assert_expected_events!( AssetHubRococo, vec![ @@ -57,19 +58,28 @@ fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { ), amount: *amount == t.args.amount, }, + // Transport fees are paid + RuntimeEvent::PolkadotXcm( + pallet_xcm::Event::FeesPaid { .. } + ) => {}, ] ); + AssetHubRococo::assert_xcm_pallet_sent(); } -fn para_receiver_assertions(_: Test) { +fn system_para_to_para_receiver_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; + let system_para_native_asset_location = SystemAssetHubLocationV3::get(); + + PenpalA::assert_xcmp_queue_success(None); + assert_expected_events!( PenpalA, vec![ - RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == system_para_native_asset_location, + owner: *owner == t.receiver.account_id, + }, ] ); } @@ -81,11 +91,12 @@ fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { PenpalA, vec![ // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, balance, .. } ) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, + asset_id: *asset_id == SystemAssetHubLocationV3::get(), + owner: *owner == t.sender.account_id, + balance: *balance == t.args.amount, }, ] ); @@ -96,6 +107,9 @@ fn para_to_system_para_receiver_assertions(t: ParaToSystemParaTest) { let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of( AssetHubRococo::sibling_location_of(PenpalA::para_id()), ); + + AssetHubRococo::assert_xcmp_queue_success(None); + assert_expected_events!( AssetHubRococo, vec![ @@ -134,17 +148,56 @@ fn system_para_to_para_assets_sender_assertions(t: SystemParaToParaTest) { ), amount: *amount == t.args.amount, }, + // Native asset to pay for fees is transferred to Parachain's Sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { + who: *who == AssetHubRococo::sovereign_account_id_of( + t.args.dest.clone() + ), + }, + // Transport fees are paid + RuntimeEvent::PolkadotXcm( + pallet_xcm::Event::FeesPaid { .. } + ) => {}, ] ); } -fn system_para_to_para_assets_receiver_assertions(_: Test) { +fn system_para_to_para_assets_receiver_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; + let system_para_asset_location = xcm::v3::Location::new( + 1, [ + xcm::v3::Junction::Parachain(ASSETHUB_PARA_ID), + xcm::v3::Junction::PalletInstance(ASSETS_PALLET_ID), + xcm::v3::Junction::GeneralIndex(ASSET_ID.into()), + ] + ); + PenpalA::assert_xcmp_queue_success(None); assert_expected_events!( PenpalA, vec![ - RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, - RuntimeEvent::Assets(pallet_assets::Event::Issued { .. }) => {}, + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == SystemAssetHubLocationV3::get(), + owner: *owner == t.receiver.account_id, + }, + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { + asset_id: *asset_id == system_para_asset_location, + owner: *owner == t.receiver.account_id, + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn relay_to_para_assets_receiver_assertions(t: RelayToParaTest) { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == RelayLocationV3::get(), + owner: *owner == t.receiver.account_id, + }, RuntimeEvent::MessageQueue( pallet_message_queue::Event::Processed { success: true, .. } ) => {}, @@ -152,33 +205,57 @@ fn system_para_to_para_assets_receiver_assertions(_: Test) { ); } -fn para_to_para_sender_assertions(t: ParaToParaTest) { +fn para_to_para_through_relay_sender_assertions(t: ParaToParaThroughRelayTest) { type RuntimeEvent = ::RuntimeEvent; + + let relay_asset_location = RelayLocationV3::get(); + PenpalA::assert_xcm_pallet_attempted_complete(None); + // XCM sent to relay reserve + PenpalA::assert_parachain_system_ump_sent(); + assert_expected_events!( PenpalA, vec![ // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, balance }, ) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, + asset_id: *asset_id == relay_asset_location, + owner: *owner == t.sender.account_id, + balance: *balance == t.args.amount, + }, + ] + ); +} + +fn para_to_para_through_system_para_sender_assertions(t: ParaToParaThroughSystemParaTest) { + type RuntimeEvent = ::RuntimeEvent; + let system_para_native_asset_location = SystemAssetHubLocationV3::get(); + PenpalA::assert_xcm_pallet_attempted_complete(None); + + assert_expected_events!( + PenpalA, + vec![ + // Amount to reserve transfer is transferred to Parachain's Sovereign account + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, balance }, + ) => { + asset_id: *asset_id == system_para_native_asset_location, + owner: *owner == t.sender.account_id, + balance: *balance == t.args.amount, }, - // XCM sent to relay reserve - RuntimeEvent::ParachainSystem( - cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } - ) => {}, ] ); } -fn para_to_para_relay_hop_assertions(t: ParaToParaTest) { +fn para_to_para_relay_hop_assertions(t: ParaToParaThroughRelayTest) { type RuntimeEvent = ::RuntimeEvent; let sov_penpal_a_on_rococo = Rococo::sovereign_account_id_of(Rococo::child_location_of(PenpalA::para_id())); let sov_penpal_b_on_rococo = Rococo::sovereign_account_id_of(Rococo::child_location_of(PenpalB::para_id())); + assert_expected_events!( Rococo, vec![ @@ -202,15 +279,65 @@ fn para_to_para_relay_hop_assertions(t: ParaToParaTest) { ); } -fn para_to_para_receiver_assertions(_: ParaToParaTest) { +fn para_to_para_system_para_hop_assertions(t: ParaToParaThroughSystemParaTest) { + type RuntimeEvent = ::RuntimeEvent; + let sov_penpal_a_on_rococo = + Rococo::sovereign_account_id_of(Rococo::child_location_of(PenpalA::para_id())); + let sov_penpal_b_on_rococo = + Rococo::sovereign_account_id_of(Rococo::child_location_of(PenpalB::para_id())); + + AssetHubRococo::assert_xcmp_queue_success(None); + + assert_expected_events!( + AssetHubRococo, + vec![ + // Withdrawn from sender parachain SA + RuntimeEvent::Balances( + pallet_balances::Event::Burned { who, amount } + ) => { + who: *who == sov_penpal_a_on_rococo, + amount: *amount == t.args.amount, + }, + // Deposited to receiver parachain SA + RuntimeEvent::Balances( + pallet_balances::Event::Minted { who, .. } + ) => { + who: *who == sov_penpal_b_on_rococo, + }, + ] + ); +} + +fn para_to_para_through_relay_receiver_assertions(t: ParaToParaThroughRelayTest) { type RuntimeEvent = ::RuntimeEvent; + let relay_asset_location = RelayLocationV3::get(); + + PenpalB::assert_xcmp_queue_success(None); + assert_expected_events!( PenpalB, vec![ - RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == relay_asset_location, + owner: *owner == t.receiver.account_id, + }, + ] + ); +} + +fn para_to_para_through_system_para_receiver_assertions(t: ParaToParaThroughSystemParaTest) { + type RuntimeEvent = ::RuntimeEvent; + let system_para_native_asset_location = SystemAssetHubLocationV3::get(); + + PenpalB::assert_xcmp_queue_success(None); + + assert_expected_events!( + PenpalB, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == system_para_native_asset_location, + owner: *owner == t.receiver.account_id, + }, ] ); } @@ -248,7 +375,18 @@ fn para_to_system_para_reserve_transfer_assets(t: ParaToSystemParaTest) -> Dispa ) } -fn para_to_para_limited_reserve_transfer_assets(t: ParaToParaTest) -> DispatchResult { +fn para_to_para_through_relay_limited_reserve_transfer_assets(t: ParaToParaThroughRelayTest) -> DispatchResult { + ::PolkadotXcm::limited_reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + +fn para_to_para_through_system_para_limited_reserve_transfer_assets(t: ParaToParaThroughSystemParaTest) -> DispatchResult { ::PolkadotXcm::limited_reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), @@ -262,6 +400,7 @@ fn para_to_para_limited_reserve_transfer_assets(t: ParaToParaTest) -> DispatchRe /// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work #[test] fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { + // Init values for Relay Chain let signed_origin = ::RuntimeOrigin::signed(RococoSender::get().into()); let destination = Rococo::child_location_of(AssetHubRococo::para_id()); let beneficiary: Location = @@ -333,42 +472,58 @@ fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { fn reserve_transfer_native_asset_from_relay_to_para() { // Init values for Relay let destination = Rococo::child_location_of(PenpalA::para_id()); - let beneficiary_id = PenpalAReceiver::get(); + let sender = RococoSender::get(); let amount_to_send: Balance = ROCOCO_ED * 1000; + let assets: Assets = (Here, amount_to_send).into(); + // Init values fot Parachain + let relay_native_asset_location = RelayLocationV3::get(); + let receiver = PenpalAReceiver::get(); + + // Init Test let test_args = TestContext { - sender: RococoSender::get(), - receiver: PenpalAReceiver::get(), - args: TestArgs::new_relay(destination, beneficiary_id, amount_to_send), + sender, + receiver: receiver.clone(), + args: TestArgs::new_relay(destination.clone(), receiver.clone(), amount_to_send), }; - let mut test = RelayToParaTest::new(test_args); + // Query initial balances let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; + let receiver_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.into(), &receiver) + }); + // Set assertions and dispatchables test.set_assertion::(relay_to_para_sender_assertions); - test.set_assertion::(para_receiver_assertions); + test.set_assertion::(relay_to_para_assets_receiver_assertions); test.set_dispatchable::(relay_to_para_reserve_transfer_assets); test.assert(); + // Calculate delivery fees let delivery_fees = Rococo::execute_with(|| { + let reanchored_assets = assets.reanchored( &destination, &RococoUniversalLocation::get()).unwrap(); xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); + // Query final balances let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; + let receiver_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.into(), &receiver) + }); // Sender's balance is reduced assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); - // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; + // Receiver's asset balance is increased + assert!(receiver_assets_after > receiver_assets_before); + // Receiver's asset balance increased by `amount_to_send - delivery_fees - bought_execution`; // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but // should be non-zero - assert!(receiver_balance_after < receiver_balance_before + amount_to_send); + assert!(receiver_assets_after < receiver_assets_before + amount_to_send); } /// Reserve Transfers of native asset from System Parachain to Parachain should work @@ -376,87 +531,126 @@ fn reserve_transfer_native_asset_from_relay_to_para() { fn reserve_transfer_native_asset_from_system_para_to_para() { // Init values for System Parachain let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id()); - let beneficiary_id = PenpalAReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; - let assets = (Parent, amount_to_send).into(); + let sender = AssetHubRococoSender::get(); + let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 10000; + let assets: Assets = (Here, amount_to_send).into(); + + // Init values for Parachain + let system_para_native_asset_location = SystemAssetHubLocationV3::get(); + let receiver = PenpalAReceiver::get(); + // Init Test let test_args = TestContext { - sender: AssetHubRococoSender::get(), - receiver: PenpalAReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), + sender, + receiver: receiver.clone(), + args: TestArgs::new_para(destination.clone(), receiver.clone(), amount_to_send, assets.clone(), None, 0), }; - let mut test = SystemParaToParaTest::new(test_args); + // Query initial balances let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; + let receiver_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location.into(), &receiver) + }); + // Set assertions and dispatchables test.set_assertion::(system_para_to_para_sender_assertions); - test.set_assertion::(para_receiver_assertions); + // test.set_assertion::(system_para_to_para_native_assets_receiver_assertions); + test.set_assertion::(system_para_to_para_receiver_assertions); test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); test.assert(); - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - + // Calculate delivery fees let delivery_fees = AssetHubRococo::execute_with(|| { + let reanchored_assets = assets.reanchored( &destination, &AssetHubRococoUniversalLocation::get()).unwrap(); xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + + // Query final balances + let sender_balance_after = test.sender.balance; + let receiver_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &receiver) }); // Sender's balance is reduced assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); - // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; + // Receiver's assets is increased + assert!(receiver_assets_after > receiver_assets_before); + // Receiver's assets increased by `amount_to_send - delivery_fees - bought_execution`; // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but // should be non-zero - assert!(receiver_balance_after < receiver_balance_before + amount_to_send); + assert!(receiver_assets_after < receiver_assets_before + amount_to_send); } /// Reserve Transfers of native asset from Parachain to System Parachain should work #[test] fn reserve_transfer_native_asset_from_para_to_system_para() { - // Init values for Penpal Parachain + // Init values for Parachain let destination = PenpalA::sibling_location_of(AssetHubRococo::para_id()); - let beneficiary_id = AssetHubRococoReceiver::get(); + let sender = PenpalASender::get(); let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; - let assets = (Parent, amount_to_send).into(); + let assets: Assets = ((Parent, Parachain(ASSETHUB_PARA_ID)), amount_to_send).into(); + let system_para_native_asset_location = SystemAssetHubLocationV3::get(); + let asset_owner = penpal_asset_owner(); + + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner), + system_para_native_asset_location, + sender.clone(), + amount_to_send + ); + + // Init values for System Parachain + let receiver = AssetHubRococoReceiver::get(); + let penpal_location_as_seen_by_ahr = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location_as_seen_by_ahr); + + // fund Parachain's SA on System Parachain with the native tokens held in reserve + AssetHubRococo::fund_accounts(vec![(sov_penpal_on_ahr.into(), amount_to_send * 2)]); + // Init Test let test_args = TestContext { - sender: PenpalASender::get(), - receiver: AssetHubRococoReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para(destination.clone(), receiver.clone(), amount_to_send, assets.clone(), None, 0), }; - let mut test = ParaToSystemParaTest::new(test_args); - let sender_balance_before = test.sender.balance; + // Query initial balances + let sender_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &sender) + }); let receiver_balance_before = test.receiver.balance; - let penpal_location_as_seen_by_ahr = AssetHubRococo::sibling_location_of(PenpalA::para_id()); - let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location_as_seen_by_ahr); - - // fund the Penpal's SA on AHR with the native tokens held in reserve - AssetHubRococo::fund_accounts(vec![(sov_penpal_on_ahr.into(), amount_to_send * 2)]); - + // Set assertions and dispatchables test.set_assertion::(para_to_system_para_sender_assertions); test.set_assertion::(para_to_system_para_receiver_assertions); test.set_dispatchable::(para_to_system_para_reserve_transfer_assets); test.assert(); - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - + // Calculate delivery fees let delivery_fees = PenpalA::execute_with(|| { + let reanchored_assets = assets.reanchored( &destination, &PenpalUniversalLocation::get()).unwrap(); xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); + // Query final balances + let sender_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &sender) + }); + let receiver_balance_after = test.receiver.balance; + // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); + assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_after); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; @@ -469,149 +663,260 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { /// work #[test] fn reserve_transfer_assets_from_system_para_to_para() { - // Force create asset on AssetHubRococo and PenpalA from Relay Chain - AssetHubRococo::force_create_and_mint_asset( - ASSET_ID, - ASSET_MIN_BALANCE, - false, - AssetHubRococoSender::get(), - Some(Weight::from_parts(1_019_445_000, 200_000)), - ASSET_MIN_BALANCE * 1_000_000, - ); - PenpalA::force_create_and_mint_asset( - ASSET_ID, - ASSET_MIN_BALANCE, - false, - PenpalASender::get(), - None, - 0, - ); - // Init values for System Parachain let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id()); - let beneficiary_id = PenpalAReceiver::get(); - let fee_amount_to_send = ASSET_HUB_ROCOCO_ED * 1000; - let asset_amount_to_send = ASSET_MIN_BALANCE * 1000; + let sender = AssetHubRococoSender::get(); + let fee_amount_to_send = ASSET_HUB_ROCOCO_ED * 10000; + let asset_amount_to_send = ASSET_MIN_BALANCE * 10000; + let asset_owner = penpal_asset_owner(); let assets: Assets = vec![ - (Parent, fee_amount_to_send).into(), + (Here, fee_amount_to_send).into(), ([PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())], asset_amount_to_send) .into(), ] .into(); + let is_sufficient = false; + let min_balance = ASSET_MIN_BALANCE; let fee_asset_index = assets .inner() .iter() - .position(|r| r == &(Parent, fee_amount_to_send).into()) + .position(|r| r == &(Here, fee_amount_to_send).into()) .unwrap() as u32; + AssetHubRococo::force_create_and_mint_asset( + ASSET_ID, + min_balance, + is_sufficient, + asset_owner.clone(), + Some(Weight::from_parts(1_019_445_000, 200_000)), + min_balance * 1_000_000, + ); + + // Init values for Parachain + let receiver = PenpalAReceiver::get(); + let system_para_native_asset_location = SystemAssetHubLocationV3::get(); + let system_para_foreign_asset_location = xcm::v3::Location::new( + 1, [ + xcm::v3::Junction::Parachain(ASSETHUB_PARA_ID), + xcm::v3::Junction::PalletInstance(ASSETS_PALLET_ID), + xcm::v3::Junction::GeneralIndex(ASSET_ID.into()), + ] + ); + PenpalA::force_create_foreign_asset(system_para_foreign_asset_location.clone(), asset_owner.clone(), is_sufficient, min_balance, vec![]); + // Init Test let para_test_args = TestContext { - sender: AssetHubRococoSender::get(), - receiver: PenpalAReceiver::get(), + sender: sender.clone(), + receiver: receiver.clone(), args: TestArgs::new_para( destination, - beneficiary_id, + receiver.clone(), asset_amount_to_send, assets, None, fee_asset_index, ), }; - let mut test = SystemParaToParaTest::new(para_test_args); - // Create SA-of-Penpal-on-AHR with ED. - let penpal_location = AssetHubRococo::sibling_location_of(PenpalA::para_id()); - let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location); - AssetHubRococo::fund_accounts(vec![(sov_penpal_on_ahr.into(), ROCOCO_ED)]); - + // Query initial balances let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - let sender_assets_before = AssetHubRococo::execute_with(|| { type Assets = ::Assets; - >::balance(ASSET_ID, &AssetHubRococoSender::get()) + >::balance(ASSET_ID, &sender) }); - let receiver_assets_before = PenpalA::execute_with(|| { - type Assets = ::Assets; - >::balance(ASSET_ID, &PenpalAReceiver::get()) + let receiver_system_native_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location.clone(), &receiver) + }); + let receiver_foreign_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_foreign_asset_location.clone(), &receiver) }); + // Set assertions and dispatchables test.set_assertion::(system_para_to_para_assets_sender_assertions); test.set_assertion::(system_para_to_para_assets_receiver_assertions); test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); test.assert(); + // Query final balances let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced - assert!(sender_balance_after < sender_balance_before); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); - // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(receiver_balance_after < receiver_balance_before + fee_amount_to_send); - let sender_assets_after = AssetHubRococo::execute_with(|| { type Assets = ::Assets; - >::balance(ASSET_ID, &AssetHubRococoSender::get()) + >::balance(ASSET_ID, &sender) }); - let receiver_assets_after = PenpalA::execute_with(|| { - type Assets = ::Assets; - >::balance(ASSET_ID, &PenpalAReceiver::get()) + let receiver_system_native_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location.clone(), &receiver) }); + let receiver_foreign_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_foreign_asset_location.clone(), &receiver) + }); + // Sender's balance is reduced + assert!(sender_balance_after < sender_balance_before); + // Receiver's foreign asset balance is increased + assert!(receiver_foreign_assets_after > receiver_foreign_assets_before); + // Receiver's system asset balance increased by `amount_to_send - delivery_fees - bought_execution`; + // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but + // should be non-zero + assert!(receiver_system_native_assets_after < receiver_system_native_assets_before + fee_amount_to_send); - // Sender's balance is reduced by exact amount + // Sender's asset balance is reduced by exact amount assert_eq!(sender_assets_before - asset_amount_to_send, sender_assets_after); - // Receiver's balance is increased by exact amount - assert_eq!(receiver_assets_after, receiver_assets_before + asset_amount_to_send); + // Receiver's foreign asset balance is increased by exact amount + assert_eq!(receiver_foreign_assets_after, receiver_foreign_assets_before + asset_amount_to_send); } /// Reserve Transfers of native asset from Parachain to Parachain (through Relay reserve) should /// work #[test] -fn reserve_transfer_native_asset_from_para_to_para() { - // Init values for Penpal Parachain +fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { + // Init values for Parachain Origin let destination = PenpalA::sibling_location_of(PenpalB::para_id()); - let beneficiary_id = PenpalBReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 10000; + let sender = PenpalASender::get(); + let amount_to_send: Balance = ROCOCO_ED * 10000; + let asset_owner = penpal_asset_owner(); let assets = (Parent, amount_to_send).into(); + let relay_native_asset_location = RelayLocationV3::get(); + let sender_as_seen_by_relay = Rococo::child_location_of(PenpalA::para_id()); + let sov_of_sender_on_relay = Rococo::sovereign_account_id_of(sender_as_seen_by_relay); + + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner), + relay_native_asset_location, + sender.clone(), + amount_to_send + ); + // fund the Parachain Origin's SA on Relay Chain with the native tokens held in reserve + Rococo::fund_accounts(vec![(sov_of_sender_on_relay.into(), amount_to_send * 2)]); + + // Init values for Parachain Desitnation + let receiver = PenpalBReceiver::get(); + + // Init Test let test_args = TestContext { - sender: PenpalASender::get(), - receiver: PenpalBReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para(destination, receiver.clone(), amount_to_send, assets, None, 0), }; + let mut test = ParaToParaThroughRelayTest::new(test_args); - let mut test = ParaToParaTest::new(test_args); + // Query initial balances + let sender_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &sender) + }); + let receiver_assets_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &receiver) + }); - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; + // Set assertions and dispatchables + test.set_assertion::(para_to_para_through_relay_sender_assertions); + test.set_assertion::(para_to_para_relay_hop_assertions); + test.set_assertion::(para_to_para_through_relay_receiver_assertions); + test.set_dispatchable::(para_to_para_through_relay_limited_reserve_transfer_assets); + test.assert(); - let sender_as_seen_by_relay = Rococo::child_location_of(PenpalA::para_id()); - let sov_of_sender_on_relay = Rococo::sovereign_account_id_of(sender_as_seen_by_relay); + // Calculate delivery fees + let delivery_fees = PenpalA::execute_with(|| { + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + + // Query final balances + let sender_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &sender) + }); + let receiver_assets_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &receiver) + }); + + // Sender's balance is reduced + assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_after); + // Receiver's balance is increased + assert!(receiver_assets_after > receiver_assets_before); +} + +/// Reserve Transfers of native asset from Parachain to Parachain (through Relay reserve) should +/// work +#[test] +fn reserve_transfer_native_asset_from_para_to_para_through_system_para() { + // Init values for Parachain Origin + let destination = PenpalA::sibling_location_of(PenpalB::para_id()); + let sender = PenpalASender::get(); + let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 10000; + let asset_owner = penpal_asset_owner(); + let assets: Assets = ((Parent, Parachain(ASSETHUB_PARA_ID)), amount_to_send).into(); + let system_para_native_asset_location = SystemAssetHubLocationV3::get(); + let sender_as_seen_by_system_para = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let sov_of_sender_on_system_para = AssetHubRococo::sovereign_account_id_of(sender_as_seen_by_system_para); // fund the PenpalA's SA on Rococo with the native tokens held in reserve - Rococo::fund_accounts(vec![(sov_of_sender_on_relay.into(), amount_to_send * 2)]); + AssetHubRococo::fund_accounts(vec![(sov_of_sender_on_system_para.into(), amount_to_send * 2)]); + + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner), + system_para_native_asset_location, + sender.clone(), + amount_to_send + ); - test.set_assertion::(para_to_para_sender_assertions); - test.set_assertion::(para_to_para_relay_hop_assertions); - test.set_assertion::(para_to_para_receiver_assertions); - test.set_dispatchable::(para_to_para_limited_reserve_transfer_assets); - test.assert(); + // Init values for Parachain Desitnation + let receiver = PenpalBReceiver::get(); - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; + // Init Test + let test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para(destination.clone(), receiver.clone(), amount_to_send, assets.clone(), None, 0), + }; + let mut test = ParaToParaThroughSystemParaTest::new(test_args); + + // Query initial balances + let sender_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location.clone(), &sender) + }); + let receiver_assets_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location.clone(), &receiver) + }); + // Set assertions and dispatchables + test.set_assertion::(para_to_para_through_system_para_sender_assertions); + test.set_assertion::(para_to_para_system_para_hop_assertions); + test.set_assertion::(para_to_para_through_system_para_receiver_assertions); + test.set_dispatchable::(para_to_para_through_system_para_limited_reserve_transfer_assets); + test.assert(); + + // Calculate delivery fees let delivery_fees = PenpalA::execute_with(|| { + let reanchored_assets = assets.reanchored( &destination, &PenpalUniversalLocation::get()).unwrap(); xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + + // Query final balances + let sender_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location.clone(), &sender) + }); + let receiver_assets_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location.clone(), &receiver) }); // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); + assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_after); // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); + assert!(receiver_assets_after > receiver_assets_before); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs index 3c9e76a34e36..d1febbbe425c 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::imports::*; /// Relay Chain should be able to execute `Transact` instructions in System Parachain /// when `OriginKind::Superuser`. diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs index 7d630d368051..5662a78ab67f 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::imports::*; #[test] fn relay_sets_system_para_xcm_supported_version() { diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs index c6a10b252901..10a56f499cca 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs @@ -13,9 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; -use rococo_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHubV3 as PenpalLocalTeleportableToAssetHubV3; -use sp_runtime::ModuleError; +use crate::imports::*; #[test] fn swap_locally_on_chain_using_local_assets() { @@ -128,7 +126,7 @@ fn swap_locally_on_chain_using_foreign_assets() { .unwrap(); // 1. Create asset on penpal and, 2. Create foreign asset on asset_hub_rococo - super::penpal_create_foreign_asset_on_asset_hub( + penpal_create_foreign_asset_on_asset_hub( asset_id_on_penpal, foreign_asset_at_asset_hub_rococo, ah_as_seen_by_penpal, diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs index dfb5061b55f0..4af554eb9199 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs @@ -13,11 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; -use asset_hub_rococo_runtime::xcm_config::XcmConfig as AssetHubRococoXcmConfig; -use emulated_integration_tests_common::xcm_helpers::non_fee_asset; -use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig; -use rococo_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHubV3 as PenpalLocalTeleportableToAssetHubV3; +use crate::imports::*; fn relay_origin_assertions(t: RelayToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -114,18 +110,20 @@ fn para_dest_assertions(t: RelayToSystemParaTest) { fn penpal_to_ah_foreign_assets_sender_assertions(t: ParaToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; - PenpalA::assert_xcm_pallet_attempted_complete(None); + let system_para_native_asset_location = SystemAssetHubLocationV3::get(); let expected_asset_id = t.args.asset_id.unwrap(); let (_, expected_asset_amount) = non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); + + PenpalA::assert_xcm_pallet_attempted_complete(None); assert_expected_events!( PenpalA, vec![ - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, .. } ) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, + asset_id: *asset_id == system_para_native_asset_location, + owner: *owner == t.sender.account_id, }, RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { asset_id: *asset_id == expected_asset_id, @@ -144,6 +142,9 @@ fn penpal_to_ah_foreign_assets_receiver_assertions(t: ParaToSystemParaTest) { let (expected_foreign_asset_id, expected_foreign_asset_amount) = non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); let expected_foreign_asset_id_v3: v3::Location = expected_foreign_asset_id.try_into().unwrap(); + + AssetHubRococo::assert_xcmp_queue_success(None); + assert_expected_events!( AssetHubRococo, vec![ @@ -163,9 +164,9 @@ fn penpal_to_ah_foreign_assets_receiver_assertions(t: ParaToSystemParaTest) { amount: *amount == expected_foreign_asset_amount, }, RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, + // RuntimeEvent::MessageQueue( + // pallet_message_queue::Event::Processed { success: true, .. } + // ) => {}, ] ); } @@ -205,6 +206,10 @@ fn ah_to_penpal_foreign_assets_receiver_assertions(t: SystemParaToParaTest) { let (_, expected_asset_amount) = non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); let checking_account = ::PolkadotXcm::check_account(); + let system_para_native_asset_location = SystemAssetHubLocationV3::get(); + + PenpalA::assert_xcmp_queue_success(None); + assert_expected_events!( PenpalA, vec![ @@ -221,12 +226,11 @@ fn ah_to_penpal_foreign_assets_receiver_assertions(t: SystemParaToParaTest) { amount: *amount == expected_asset_amount, }, // native asset for fee is deposited to receiver - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == t.receiver.account_id, + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { + asset_id: *asset_id == system_para_native_asset_location, + owner: *owner == t.receiver.account_id, + amount: *amount == expected_asset_amount, }, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, ] ); } @@ -558,40 +562,57 @@ fn teleport_to_other_system_parachains_works() { /// (using native reserve-based transfer for fees) #[test] fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { + // Init values for Parachain + let fee_amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 10000; + let asset_owner = penpal_asset_owner(); + let system_para_native_asset_location = SystemAssetHubLocationV3::get(); + let sender = PenpalASender::get(); + + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner.clone()), + system_para_native_asset_location, + sender.clone(), + fee_amount_to_send + ); + let ah_as_seen_by_penpal = PenpalA::sibling_location_of(AssetHubRococo::para_id()); let asset_location_on_penpal = PenpalLocalTeleportableToAssetHubV3::get(); let asset_id_on_penpal = match asset_location_on_penpal.last() { Some(v3::Junction::GeneralIndex(id)) => *id as u32, _ => unreachable!(), }; - let asset_owner_on_penpal = PenpalASender::get(); + let foreign_asset_at_asset_hub_rococo = v3::Location::new(1, [v3::Junction::Parachain(PenpalA::para_id().into())]) .appended_with(asset_location_on_penpal) .unwrap(); - super::penpal_create_foreign_asset_on_asset_hub( + + penpal_create_foreign_asset_on_asset_hub( asset_id_on_penpal, foreign_asset_at_asset_hub_rococo, ah_as_seen_by_penpal.clone(), false, - asset_owner_on_penpal, + asset_owner, ASSET_MIN_BALANCE * 1_000_000, ); + + // Init values for System Parachain let penpal_to_ah_beneficiary_id = AssetHubRococoReceiver::get(); - let fee_amount_to_send = ASSET_HUB_ROCOCO_ED * 10_000; + // let fee_amount_to_send = ASSET_HUB_ROCOCO_ED * 10_000; let asset_amount_to_send = ASSET_MIN_BALANCE * 1000; let asset_location_on_penpal_latest: Location = asset_location_on_penpal.try_into().unwrap(); let penpal_assets: Assets = vec![ - (Parent, fee_amount_to_send).into(), + ((Parent, Parachain(ASSETHUB_PARA_ID)), fee_amount_to_send).into(), (asset_location_on_penpal_latest, asset_amount_to_send).into(), ] .into(); let fee_asset_index = penpal_assets .inner() .iter() - .position(|r| r == &(Parent, fee_amount_to_send).into()) + .position(|r| r == &((Parent, Parachain(ASSETHUB_PARA_ID)), fee_amount_to_send).into()) .unwrap() as u32; // Penpal to AH test args @@ -609,7 +630,12 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { }; let mut penpal_to_ah = ParaToSystemParaTest::new(penpal_to_ah_test_args); - let penpal_sender_balance_before = penpal_to_ah.sender.balance; + // let penpal_sender_balance_before = penpal_to_ah.sender.balance; + let penpal_sender_balance_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &PenpalASender::get()) + }); + let ah_receiver_balance_before = penpal_to_ah.receiver.balance; let penpal_sender_assets_before = PenpalA::execute_with(|| { @@ -629,7 +655,11 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { penpal_to_ah.set_dispatchable::(para_to_system_para_transfer_assets); penpal_to_ah.assert(); - let penpal_sender_balance_after = penpal_to_ah.sender.balance; + let penpal_sender_balance_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &PenpalASender::get()) + }); + let ah_receiver_balance_after = penpal_to_ah.receiver.balance; let penpal_sender_assets_after = PenpalA::execute_with(|| { @@ -678,14 +708,14 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { let ah_to_penpal_beneficiary_id = PenpalAReceiver::get(); let penpal_as_seen_by_ah = AssetHubRococo::sibling_location_of(PenpalA::para_id()); let ah_assets: Assets = vec![ - (Parent, fee_amount_to_send).into(), + (Here, fee_amount_to_send).into(), (foreign_asset_at_asset_hub_rococo_latest, asset_amount_to_send).into(), ] .into(); let fee_asset_index = ah_assets .inner() .iter() - .position(|r| r == &(Parent, fee_amount_to_send).into()) + .position(|r| r == &(Here, fee_amount_to_send).into()) .unwrap() as u32; // AH to Penpal test args @@ -704,7 +734,10 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { let mut ah_to_penpal = SystemParaToParaTest::new(ah_to_penpal_test_args); let ah_sender_balance_before = ah_to_penpal.sender.balance; - let penpal_receiver_balance_before = ah_to_penpal.receiver.balance; + let penpal_receiver_balance_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &PenpalAReceiver::get()) + }); let ah_sender_assets_before = AssetHubRococo::execute_with(|| { type ForeignAssets = ::ForeignAssets; @@ -724,7 +757,10 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { ah_to_penpal.assert(); let ah_sender_balance_after = ah_to_penpal.sender.balance; - let penpal_receiver_balance_after = ah_to_penpal.receiver.balance; + let penpal_receiver_balance_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &PenpalAReceiver::get()) + }); let ah_sender_assets_after = AssetHubRococo::execute_with(|| { type ForeignAssets = ::ForeignAssets; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index ed893091533a..c4335d2dcaae 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -671,7 +671,7 @@ impl cumulus_pallet_aura_ext::Config for Runtime {} parameter_types! { /// The asset ID for the asset that we use to pay for message delivery fees. - pub FeeAssetId: AssetId = AssetId(xcm_config::TokenLocation::get()); + pub FeeAssetId: AssetId = AssetId(xcm_config::TokenLocationAsNative::get()); /// The base fee for the message delivery fees. pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 2584dbdf3106..95c4fcbc618f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -23,6 +23,7 @@ use super::{ use assets_common::{ matching::{FromNetwork, FromSiblingParachain, IsForeignConcreteAsset}, TrustBackedAssetsAsLocation, + ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, }; use frame_support::{ parameter_types, @@ -66,7 +67,9 @@ use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; parameter_types! { pub const TokenLocation: Location = Location::parent(); + pub const TokenLocationAsNative: Location = Location::here(); pub const TokenLocationV3: xcm::v3::Location = xcm::v3::Location::parent(); + pub const TokenLocationAsNativeV3: xcm::v3::Location = xcm::v3::Location::here(); pub const RelayNetwork: NetworkId = NetworkId::Rococo; pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorLocation = @@ -117,7 +120,7 @@ pub type FungibleTransactor = FungibleAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: - IsConcrete, + (IsConcrete, IsConcrete), // Convert an XCM Location into a local account id: LocationToAccountId, // Our chain's account ID type (we can't get away without mentioning it explicitly): @@ -520,15 +523,6 @@ pub type AssetFeeAsExistentialDepositMultiplierFeeCharger = AssetFeeAsExistentia TrustBackedAssetsInstance, >; -/// Multiplier used for dedicated `TakeFirstAssetTrader` with `ForeignAssets` instance. -pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger = - AssetFeeAsExistentialDepositMultiplier< - Runtime, - WeightToFee, - pallet_assets::BalanceToAssetBalance, - ForeignAssetsInstance, - >; - /// Locations that will not be charged fees in the executor, /// either execution or delivery. /// We only waive fees for system functions, which these locations represent. @@ -569,6 +563,7 @@ impl xcm_executor::Config for XcmConfig { MaxInstructions, >; type Trader = ( + UsingComponents>, UsingComponents>, cumulus_primitives_utility::SwapFirstAssetTrader< TokenLocationV3, @@ -599,7 +594,7 @@ impl xcm_executor::Config for XcmConfig { // `pallet_assets` instance - `ForeignAssets`. cumulus_primitives_utility::TakeFirstAssetTrader< AccountId, - ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, + ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, ForeignAssetsConvertedConcreteId, ForeignAssets, cumulus_primitives_utility::XcmFeesTo32ByteAccount< diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs index cff2290222c3..ddb8a686f018 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -21,7 +21,7 @@ use asset_hub_rococo_runtime::{ xcm_config, xcm_config::{ bridging, AssetFeeAsExistentialDepositMultiplierFeeCharger, CheckingAccount, - ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, ForeignCreatorsSovereignAccountOf, + ForeignCreatorsSovereignAccountOf, LocationToAccountId, TokenLocation, TokenLocationV3, TrustBackedAssetsPalletLocation, TrustBackedAssetsPalletLocationV3, XcmConfig, }, @@ -30,6 +30,7 @@ use asset_hub_rococo_runtime::{ MetadataDepositPerByte, ParachainSystem, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, ToWestendXcmRouterInstance, TrustBackedAssetsInstance, XcmpQueue, }; +use assets_common::ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger; use asset_test_utils::{ test_cases_over_bridge::TestBridgingConfig, CollatorSessionKey, CollatorSessionKeys, ExtBuilder, SlotDurations, @@ -481,7 +482,7 @@ fn test_foreign_asset_xcm_take_first_trader() { // Lets calculate amount needed let asset_amount_needed = - ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger::charge_weight_in_fungibles( + ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger::::charge_weight_in_fungibles( foreign_location, bought, ) diff --git a/cumulus/parachains/runtimes/assets/common/Cargo.toml b/cumulus/parachains/runtimes/assets/common/Cargo.toml index c9252375cfbf..a558ff61f3ed 100644 --- a/cumulus/parachains/runtimes/assets/common/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/common/Cargo.toml @@ -21,6 +21,7 @@ sp-api = { path = "../../../../../substrate/primitives/api", default-features = sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } pallet-asset-conversion = { path = "../../../../../substrate/frame/asset-conversion", default-features = false } +pallet-assets = { path = "../../../../../substrate/frame/assets", default-features = false } # Polkadot pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false } diff --git a/cumulus/parachains/runtimes/assets/common/src/lib.rs b/cumulus/parachains/runtimes/assets/common/src/lib.rs index a0c912b6f0fe..30f1951e700e 100644 --- a/cumulus/parachains/runtimes/assets/common/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/common/src/lib.rs @@ -23,9 +23,10 @@ pub mod local_and_foreign_assets; pub mod matching; pub mod runtime_api; +use sp_runtime::traits::ConvertInto; use crate::matching::{LocalLocationPattern, ParentLocation}; use frame_support::traits::{Equals, EverythingBut}; -use parachains_common::{AssetIdForTrustBackedAssets, CollectionId, ItemId}; +use parachains_common::{xcm_config::AssetFeeAsExistentialDepositMultiplier, AssetIdForTrustBackedAssets, CollectionId, ItemId}; use xcm_builder::{ AsPrefixedGeneralIndex, MatchedConvertedConcreteId, StartsWith, V4V3LocationConverter, }; @@ -125,6 +126,15 @@ pub type PoolAssetsConvertedConcreteId = JustTry, >; +/// Multiplier used for dedicated `TakeFirstAssetTrader` with `ForeignAssets` instance. +pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger = + AssetFeeAsExistentialDepositMultiplier< + Runtime, + WeightToFee, + pallet_assets::BalanceToAssetBalance, + ForeignAssetsInstance, + >; + #[cfg(test)] mod tests { use super::*; diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index c0bcd7879626..87fdc27e64da 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -25,14 +25,14 @@ use super::{ AccountId, AllPalletsWithSystem, AssetId as AssetIdPalletAssets, Assets, Balance, Balances, ForeignAssets, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, - RuntimeOrigin, WeightToFee, XcmpQueue, + RuntimeOrigin, WeightToFee, XcmpQueue, ForeignAssetsInstance, Authorship, }; use core::marker::PhantomData; use frame_support::{ parameter_types, traits::{ fungibles::{self, Balanced, Credit}, - ConstU32, Contains, ContainsPair, Everything, Get, Nothing, + ConstU32, Contains, ContainsPair, Everything, Get, Nothing, EverythingBut }, weights::Weight, }; @@ -59,6 +59,7 @@ use xcm_executor::{traits::JustTry, XcmExecutor}; parameter_types! { pub const RelayLocation: Location = Location::parent(); + pub const NativeCurrency: Location = Location::here(); pub const RelayNetwork: Option = None; pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorLocation = [Parachain(ParachainInfo::parachain_id().into())].into(); @@ -81,7 +82,7 @@ pub type CurrencyTransactor = FungibleAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: - IsConcrete, + IsConcrete, // Do a simple punn to convert an AccountId32 Location into a native chain account ID: LocationToAccountId, // Our chain's account ID type (we can't get away without mentioning it explicitly): @@ -124,9 +125,17 @@ pub type FungiblesTransactor = FungiblesAdapter< CheckingAccount, >; -/// `AssetId/Balance` converter for `TrustBackedAssets` pub type ForeignAssetsConvertedConcreteId = - assets_common::ForeignAssetsConvertedConcreteId, Balance>; + assets_common::LocationConvertedConcreteId< + EverythingBut<( + // Here we rely on fact that something like this works: + // assert!(Location::new(1, + // [Parachain(100)]).starts_with(&Location::parent())); + // assert!([Parachain(100)].into().starts_with(&Here)); + StartsWith, + )>, + Balance, + >; /// Means for transacting foreign assets from different global consensus. pub type ForeignFungiblesTransactor = FungiblesAdapter< @@ -176,6 +185,7 @@ parameter_types! { pub UnitWeightCost: Weight = Weight::from_parts(1_000_000_000, 64 * 1024); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; + pub XcmAssetFeesReceiver: Option = Authorship::author(); } pub struct ParentOrParentsExecutivePlurality; @@ -280,6 +290,8 @@ pub const TELEPORTABLE_ASSET_ID: u32 = 2; parameter_types! { /// The location that this chain recognizes as the Relay network's Asset Hub. pub SystemAssetHubLocation: Location = Location::new(1, [Parachain(1000)]); + pub SystemAssetHubLocationV3: xcm::v3::Location = xcm::v3::Location::new(1, [xcm::v3::Junction::Parachain(1000)]); + pub RelayLocationV3: xcm::v3::Location = xcm::v3::Location::parent(); // ALWAYS ensure that the index in PalletInstance stays up-to-date with // the Relay Chain's Asset Hub's Assets pallet index pub SystemAssetHubAssetsPalletLocation: Location = @@ -332,8 +344,22 @@ impl xcm_executor::Config for XcmConfig { type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = FixedWeightBounds; - type Trader = - UsingComponents>; + type Trader = ( + UsingComponents>, + // This trader allows to pay with `is_sufficient=true` "Foreign" assets from dedicated + // `pallet_assets` instance - `ForeignAssets`. + cumulus_primitives_utility::TakeFirstAssetTrader< + AccountId, + assets_common::ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, + ForeignAssetsConvertedConcreteId, + ForeignAssets, + cumulus_primitives_utility::XcmFeesTo32ByteAccount< + ForeignFungiblesTransactor, + AccountId, + XcmAssetFeesReceiver, + >, + >, + ); type ResponseHandler = PolkadotXcm; type AssetTrap = PolkadotXcm; type AssetClaims = PolkadotXcm; diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index b26779f3ae9d..a305b19f2888 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -827,8 +827,10 @@ impl XcmExecutor { let to_weigh = self.holding.saturating_take(assets.clone()); self.holding.subsume_assets(to_weigh.clone()); + let to_weigh_reanchored = Self::reanchored(to_weigh, &dest, None); + let mut message_to_weigh = - vec![ReserveAssetDeposited(to_weigh.into()), ClearOrigin]; + vec![ReserveAssetDeposited(to_weigh_reanchored), ClearOrigin]; message_to_weigh.extend(xcm.0.clone().into_iter()); let (_, fee) = validate_send::(dest.clone(), Xcm(message_to_weigh))?;