diff --git a/Cargo.lock b/Cargo.lock index e41757fa16..cfee18fcb4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -552,6 +552,8 @@ dependencies = [ "frame-support", "kusama-emulated-chain", "parachains-common", + "penpal-emulated-chain", + "polkadot-parachain-primitives", "sp-core", "staging-xcm", ] @@ -681,7 +683,9 @@ dependencies = [ "emulated-integration-tests-common", "frame-support", "parachains-common", + "penpal-emulated-chain", "polkadot-emulated-chain", + "polkadot-parachain-primitives", "sp-core", "staging-xcm", ] diff --git a/integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/wksm-reaches-kusama.zndsl b/integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/wksm-reaches-kusama.zndsl index 7bb680f080..fd8b9bc5c3 100644 --- a/integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/wksm-reaches-kusama.zndsl +++ b/integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/wksm-reaches-kusama.zndsl @@ -5,6 +5,6 @@ Creds: config # send 3 wKSM back to Alice from Polkadot AH to Kusama AH asset-hub-kusama-collator-1: run {{ENV_PATH}}/helper.sh with "withdraw-reserve-assets-from-asset-hub-polkadot-local 3000000000000" within 120 seconds -# check that //Alice received at least 2.8 wKSM on Westend AH +# check that //Alice received at least 2.8 wKSM on Polkadot AH # (we wait until //Alice account increases here - there are no other transactions that may increase it) asset-hub-kusama-collator-1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-assets-balance-increased.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,2800000000000" within 300 seconds diff --git a/integration-tests/emulated/chains/parachains/assets/asset-hub-kusama/Cargo.toml b/integration-tests/emulated/chains/parachains/assets/asset-hub-kusama/Cargo.toml index c77fd8a674..a14a2362bd 100644 --- a/integration-tests/emulated/chains/parachains/assets/asset-hub-kusama/Cargo.toml +++ b/integration-tests/emulated/chains/parachains/assets/asset-hub-kusama/Cargo.toml @@ -18,7 +18,9 @@ parachains-common = { workspace = true, default-features = true } cumulus-primitives-core = { workspace = true, default-features = true } emulated-integration-tests-common = { workspace = true } xcm = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true } # Runtimes asset-hub-kusama-runtime = { workspace = true } kusama-emulated-chain = { workspace = true } +penpal-emulated-chain = { workspace = true } diff --git a/integration-tests/emulated/chains/parachains/assets/asset-hub-kusama/src/genesis.rs b/integration-tests/emulated/chains/parachains/assets/asset-hub-kusama/src/genesis.rs index b1677e8762..0da714d34a 100644 --- a/integration-tests/emulated/chains/parachains/assets/asset-hub-kusama/src/genesis.rs +++ b/integration-tests/emulated/chains/parachains/assets/asset-hub-kusama/src/genesis.rs @@ -14,17 +14,33 @@ // limitations under the License. // Substrate -use sp_core::storage::Storage; +use sp_core::{sr25519, storage::Storage}; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, + accounts, build_genesis_storage, collators, get_account_id_from_seed, RESERVABLE_ASSET_ID, + SAFE_XCM_VERSION, }; -use parachains_common::Balance; +use frame_support::sp_runtime::traits::AccountIdConversion; +use parachains_common::{AccountId, Balance}; +use polkadot_parachain_primitives::primitives::Sibling; +use xcm::prelude::*; pub const PARA_ID: u32 = 1000; pub const ED: Balance = asset_hub_kusama_runtime::ExistentialDeposit::get(); +frame_support::parameter_types! { + pub AssetHubKusamaAssetOwner: AccountId = get_account_id_from_seed::("Alice"); + pub PenpalATeleportableAssetLocation: Location + = Location::new(1, [ + Junction::Parachain(penpal_emulated_chain::PARA_ID_A), + Junction::PalletInstance(penpal_emulated_chain::ASSETS_PALLET_ID), + Junction::GeneralIndex(penpal_emulated_chain::TELEPORTABLE_ASSET_ID.into()), + ] + ); + pub PenpalASiblingSovereignAccount: AccountId = Sibling::from(penpal_emulated_chain::PARA_ID_A).into_account_truncating(); +} + pub fn genesis() -> Storage { let genesis_config = asset_hub_kusama_runtime::RuntimeGenesisConfig { system: asset_hub_kusama_runtime::SystemConfig::default(), @@ -60,6 +76,22 @@ pub fn genesis() -> Storage { safe_xcm_version: Some(SAFE_XCM_VERSION), ..Default::default() }, + assets: asset_hub_kusama_runtime::AssetsConfig { + assets: vec![(RESERVABLE_ASSET_ID, AssetHubKusamaAssetOwner::get(), true, ED)], + ..Default::default() + }, + foreign_assets: asset_hub_kusama_runtime::ForeignAssetsConfig { + assets: vec![ + // Penpal's teleportable asset representation + ( + PenpalATeleportableAssetLocation::get().try_into().unwrap(), + PenpalASiblingSovereignAccount::get(), + true, + ED, + ), + ], + ..Default::default() + }, ..Default::default() }; diff --git a/integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot/Cargo.toml b/integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot/Cargo.toml index b3fd011b36..169651781a 100644 --- a/integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot/Cargo.toml +++ b/integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot/Cargo.toml @@ -18,7 +18,9 @@ parachains-common = { workspace = true, default-features = true } cumulus-primitives-core = { workspace = true, default-features = true } emulated-integration-tests-common = { workspace = true } xcm = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true } # Runtimes asset-hub-polkadot-runtime = { workspace = true } polkadot-emulated-chain = { workspace = true } +penpal-emulated-chain = { workspace = true } \ No newline at end of file diff --git a/integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot/src/genesis.rs b/integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot/src/genesis.rs index 671eb79b67..649adefd6e 100644 --- a/integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot/src/genesis.rs +++ b/integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot/src/genesis.rs @@ -18,14 +18,38 @@ use sp_core::storage::Storage; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage, get_account_id_from_seed, get_from_seed, SAFE_XCM_VERSION, + accounts, build_genesis_storage, get_account_id_from_seed, get_from_seed, RESERVABLE_ASSET_ID, + SAFE_XCM_VERSION, }; +use frame_support::sp_runtime::traits::AccountIdConversion; use parachains_common::{AccountId, AssetHubPolkadotAuraId, Balance}; +use polkadot_parachain_primitives::primitives::Sibling; use sp_core::sr25519; +use xcm::prelude::*; pub const PARA_ID: u32 = 1000; pub const ED: Balance = asset_hub_polkadot_runtime::ExistentialDeposit::get(); +frame_support::parameter_types! { + pub AssetHubPolkadotAssetOwner: AccountId = get_account_id_from_seed::("Alice"); + pub PenpalATeleportableAssetLocation: Location + = Location::new(1, [ + Junction::Parachain(penpal_emulated_chain::PARA_ID_A), + Junction::PalletInstance(penpal_emulated_chain::ASSETS_PALLET_ID), + Junction::GeneralIndex(penpal_emulated_chain::TELEPORTABLE_ASSET_ID.into()), + ] + ); + pub PenpalBTeleportableAssetLocation: Location + = Location::new(1, [ + Junction::Parachain(penpal_emulated_chain::PARA_ID_B), + Junction::PalletInstance(penpal_emulated_chain::ASSETS_PALLET_ID), + Junction::GeneralIndex(penpal_emulated_chain::TELEPORTABLE_ASSET_ID.into()), + ] + ); + pub PenpalASiblingSovereignAccount: AccountId = Sibling::from(penpal_emulated_chain::PARA_ID_A).into_account_truncating(); + pub PenpalBSiblingSovereignAccount: AccountId = Sibling::from(penpal_emulated_chain::PARA_ID_B).into_account_truncating(); +} + fn invulnerables_asset_hub_polkadot() -> Vec<(AccountId, AssetHubPolkadotAuraId)> { vec![ ( @@ -43,7 +67,11 @@ pub fn genesis() -> Storage { let genesis_config = asset_hub_polkadot_runtime::RuntimeGenesisConfig { system: asset_hub_polkadot_runtime::SystemConfig::default(), balances: asset_hub_polkadot_runtime::BalancesConfig { - balances: accounts::init_balances().iter().cloned().map(|k| (k, ED * 4096)).collect(), + balances: accounts::init_balances() + .iter() + .cloned() + .map(|k| (k, ED * 4096 * 4096)) + .collect(), }, parachain_info: asset_hub_polkadot_runtime::ParachainInfoConfig { parachain_id: PARA_ID.into(), @@ -74,6 +102,28 @@ pub fn genesis() -> Storage { safe_xcm_version: Some(SAFE_XCM_VERSION), ..Default::default() }, + assets: asset_hub_polkadot_runtime::AssetsConfig { + assets: vec![(RESERVABLE_ASSET_ID, AssetHubPolkadotAssetOwner::get(), true, ED)], + ..Default::default() + }, + foreign_assets: asset_hub_polkadot_runtime::ForeignAssetsConfig { + assets: vec![ + // Penpal's teleportable asset representation + ( + PenpalATeleportableAssetLocation::get().try_into().unwrap(), + PenpalASiblingSovereignAccount::get().try_into().unwrap(), + true, + ED, + ), + ( + PenpalBTeleportableAssetLocation::get().try_into().unwrap(), + PenpalBSiblingSovereignAccount::get().try_into().unwrap(), + true, + ED, + ), + ], + ..Default::default() + }, ..Default::default() }; diff --git a/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs b/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs index 5ba5bfd3ea..a9ddf89522 100644 --- a/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs +++ b/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs @@ -14,19 +14,26 @@ // limitations under the License. // Substrate +use frame_support::parameter_types; use sp_core::{sr25519, storage::Storage}; // Cumulus 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::{AccountId, Balance}; +use penpal_runtime::xcm_config::{LocalReservableFromAssetHub, RelayLocation}; // Penpal pub const PARA_ID_A: u32 = 2000; pub const PARA_ID_B: u32 = 2001; pub const ED: Balance = penpal_runtime::ExistentialDeposit::get(); +parameter_types! { + pub PenpalSudoAccount: AccountId = get_account_id_from_seed::("Alice"); + pub PenpalAssetOwner: AccountId = PenpalSudoAccount::get(); +} + pub fn genesis(para_id: u32) -> Storage { let genesis_config = penpal_runtime::RuntimeGenesisConfig { system: penpal_runtime::SystemConfig::default(), @@ -58,8 +65,24 @@ pub fn genesis(para_id: u32) -> Storage { safe_xcm_version: Some(SAFE_XCM_VERSION), ..Default::default() }, - sudo: penpal_runtime::SudoConfig { - key: Some(get_account_id_from_seed::("Alice")), + sudo: penpal_runtime::SudoConfig { key: Some(PenpalSudoAccount::get()) }, + assets: penpal_runtime::AssetsConfig { + assets: vec![( + penpal_runtime::xcm_config::TELEPORTABLE_ASSET_ID, + PenpalAssetOwner::get(), + false, + ED, + )], + ..Default::default() + }, + foreign_assets: penpal_runtime::ForeignAssetsConfig { + assets: vec![ + // Relay Native asset representation + (RelayLocation::get(), PenpalAssetOwner::get(), true, ED), + // Sufficient AssetHub asset representation + (LocalReservableFromAssetHub::get(), PenpalAssetOwner::get(), true, ED), + ], + ..Default::default() }, ..Default::default() }; diff --git a/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs b/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs index f5491c9fe4..09fe2aa0e3 100644 --- a/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs +++ b/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs @@ -14,9 +14,10 @@ // limitations under the License. mod genesis; -pub use genesis::{genesis, ED, PARA_ID_A, PARA_ID_B}; +pub use genesis::{genesis, PenpalAssetOwner, ED, PARA_ID_A, PARA_ID_B}; pub use penpal_runtime::xcm_config::{ - CustomizableAssetFromSystemAssetHub, LocalTeleportableToAssetHub, XcmConfig, + CustomizableAssetFromSystemAssetHub, LocalReservableFromAssetHub, LocalTeleportableToAssetHub, + XcmConfig, ASSETS_PALLET_ID, RESERVABLE_ASSET_ID, TELEPORTABLE_ASSET_ID, }; // Substrate @@ -28,8 +29,6 @@ use emulated_integration_tests_common::{ impl_assets_helpers_for_parachain, impl_foreign_assets_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, }; -use kusama_emulated_chain::Kusama; -use polkadot_emulated_chain::Polkadot; // Penpal Parachain declaration decl_test_parachains! { diff --git a/integration-tests/emulated/helpers/src/lib.rs b/integration-tests/emulated/helpers/src/lib.rs index 2279be4b1e..7f29c0e16b 100644 --- a/integration-tests/emulated/helpers/src/lib.rs +++ b/integration-tests/emulated/helpers/src/lib.rs @@ -30,98 +30,7 @@ pub use xcm_emulator::Chain; /// TODO: when bumping to polkadot-sdk v1.8.0, /// remove this crate altogether and get the macros from `emulated-integration-tests-common`. -#[macro_export] -macro_rules! test_sibling_is_trusted_teleporter { - ( $sender_para:ty, $sender_xcm_config:ty, vec![$( $receiver_para:ty ),+], ($assets:expr, $amount:expr) ) => { - $crate::paste::paste! { - // init Origin variables - let sender = [<$sender_para Sender>]::get(); - let mut para_sender_balance_before = - <$sender_para as $crate::Chain>::account_data_of(sender.clone()).free; - let origin = <$sender_para as $crate::Chain>::RuntimeOrigin::signed(sender.clone()); - let fee_asset_item = 0; - let weight_limit = $crate::WeightLimit::Unlimited; - - $( - { - // init Destination variables - let receiver = [<$receiver_para Receiver>]::get(); - let para_receiver_balance_before = - <$receiver_para as $crate::Chain>::account_data_of(receiver.clone()).free; - let para_destination = - <$sender_para>::sibling_location_of(<$receiver_para>::para_id()); - let beneficiary: Location = - $crate::AccountId32 { network: None, id: receiver.clone().into() }.into(); - - // Send XCM message from Origin Parachain - // We are only testing the limited teleport version, which should be ok since success will - // depend only on a proper `XcmConfig` at destination. - <$sender_para>::execute_with(|| { - assert_ok!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::limited_teleport_assets( - origin.clone(), - bx!(para_destination.clone().into()), - bx!(beneficiary.clone().into()), - bx!($assets.clone().into()), - fee_asset_item, - weight_limit.clone(), - )); - - type RuntimeEvent = <$sender_para as $crate::Chain>::RuntimeEvent; - - assert_expected_events!( - $sender_para, - vec![ - RuntimeEvent::PolkadotXcm( - $crate::pallet_xcm::Event::Attempted { outcome: Outcome::Complete { .. } } - ) => {}, - RuntimeEvent::XcmpQueue( - $crate::cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } - ) => {}, - RuntimeEvent::Balances( - $crate::pallet_balances::Event::Burned { who: sender, amount } - ) => {}, - ] - ); - }); - - // Receive XCM message in Destination Parachain - <$receiver_para>::execute_with(|| { - type RuntimeEvent = <$receiver_para as $crate::Chain>::RuntimeEvent; - - assert_expected_events!( - $receiver_para, - vec![ - RuntimeEvent::Balances( - $crate::pallet_balances::Event::Minted { who: receiver, .. } - ) => {}, - RuntimeEvent::MessageQueue( - $crate::pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - }); - - // Check if balances are updated accordingly in Origin and Destination Parachains - let para_sender_balance_after = - <$sender_para as $crate::Chain>::account_data_of(sender.clone()).free; - let para_receiver_balance_after = - <$receiver_para as $crate::Chain>::account_data_of(receiver.clone()).free; - let delivery_fees = <$sender_para>::execute_with(|| { - $crate::asset_test_utils::xcm_helpers::teleport_assets_delivery_fees::< - <$sender_xcm_config as xcm_executor::Config>::XcmSender, - >($assets.clone(), fee_asset_item, weight_limit.clone(), beneficiary, para_destination) - }); - - assert_eq!(para_sender_balance_before - $amount - delivery_fees, para_sender_balance_after); - assert!(para_receiver_balance_after > para_receiver_balance_before); - - // Update sender balance - para_sender_balance_before = <$sender_para as $crate::Chain>::account_data_of(sender.clone()).free; - } - )+ - } - }; -} +/// TODO: backport this macros to polkadot-sdk #[macro_export] macro_rules! test_relay_is_trusted_teleporter { @@ -215,7 +124,7 @@ macro_rules! test_relay_is_trusted_teleporter { } #[macro_export] -macro_rules! test_parachain_is_trusted_teleporter { +macro_rules! test_parachain_is_trusted_teleporter_for_relay { ( $sender_para:ty, $sender_xcm_config:ty, $receiver_relay:ty, $amount:expr ) => { $crate::paste::paste! { // init Origin variables diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/lib.rs b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/lib.rs index d738a7ab8b..eb274ac988 100644 --- a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/lib.rs +++ b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/lib.rs @@ -28,24 +28,30 @@ pub use xcm::{ prelude::{AccountId32 as AccountId32Junction, *}, v3::{self, Error, NetworkId::Kusama as KusamaId}, }; +pub use xcm_executor::traits::TransferType; // 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, + PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, RESERVABLE_ASSET_ID, XCM_V3, }; -pub use integration_tests_helpers::test_sibling_is_trusted_teleporter; +pub use kusama_runtime::xcm_config::UniversalLocation as KusamaUniversalLocation; pub use kusama_system_emulated_network::{ asset_hub_kusama_emulated_chain::{ - genesis::ED as ASSET_HUB_KUSAMA_ED, AssetHubKusamaParaPallet as AssetHubKusamaPallet, + genesis::{AssetHubKusamaAssetOwner, ED as ASSET_HUB_KUSAMA_ED}, + AssetHubKusamaParaPallet as AssetHubKusamaPallet, }, kusama_emulated_chain::{genesis::ED as KUSAMA_ED, KusamaRelayPallet as KusamaPallet}, - penpal_emulated_chain::PenpalAParaPallet as PenpalAPallet, + penpal_emulated_chain::{ + CustomizableAssetFromSystemAssetHub, PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner, + PenpalBParaPallet as PenpalBPallet, ED as PENPAL_ED, + }, AssetHubKusamaPara as AssetHubKusama, AssetHubKusamaParaReceiver as AssetHubKusamaReceiver, AssetHubKusamaParaSender as AssetHubKusamaSender, BridgeHubKusamaPara as BridgeHubKusama, BridgeHubKusamaParaReceiver as BridgeHubKusamaReceiver, KusamaRelay as Kusama, @@ -56,7 +62,7 @@ pub use kusama_system_emulated_network::{ }; pub use parachains_common::{AccountId, Balance}; -pub const ASSET_ID: u32 = 1; +pub const ASSET_ID: u32 = 3; pub const ASSET_MIN_BALANCE: u128 = 1000; // `Assets` pallet index pub const ASSETS_PALLET_ID: u8 = 50; @@ -66,7 +72,9 @@ pub type RelayToParaTest = Test; pub type SystemParaToRelayTest = Test; pub type SystemParaToParaTest = Test; pub type ParaToSystemParaTest = Test; -pub type ParaToParaTest = Test; +pub type ParaToParaThroughRelayTest = Test; +pub type ParaToParaThroughAHTest = Test; +pub type RelayToParaThroughAHTest = Test; #[cfg(test)] mod tests; diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/hybrid_transfers.rs b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/hybrid_transfers.rs new file mode 100644 index 0000000000..30faf5568b --- /dev/null +++ b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/hybrid_transfers.rs @@ -0,0 +1,812 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::reserve_transfer::*; +use crate::{ + tests::teleport::do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt, + *, +}; +use asset_hub_kusama_runtime::xcm_config::KsmLocation; + +fn para_to_para_assethub_hop_assertions(t: ParaToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + let sov_penpal_a_on_ah = AssetHubKusama::sovereign_account_id_of( + AssetHubKusama::sibling_location_of(PenpalA::para_id()), + ); + let sov_penpal_b_on_ah = AssetHubKusama::sovereign_account_id_of( + AssetHubKusama::sibling_location_of(PenpalB::para_id()), + ); + + assert_expected_events!( + AssetHubKusama, + vec![ + // Withdrawn from sender parachain SA + RuntimeEvent::Balances( + pallet_balances::Event::Burned { who, amount } + ) => { + who: *who == sov_penpal_a_on_ah, + amount: *amount == t.args.amount, + }, + // Deposited to receiver parachain SA + RuntimeEvent::Balances( + pallet_balances::Event::Minted { who, .. } + ) => { + who: *who == sov_penpal_b_on_ah, + }, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); +} + +fn ah_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { + let fee_idx = t.args.fee_asset_item as usize; + let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.assets.into()), + bx!(TransferType::LocalReserve), + bx!(fee.id.into()), + bx!(TransferType::LocalReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), + t.args.weight_limit, + ) +} + +fn para_to_ah_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { + let fee_idx = t.args.fee_asset_item as usize; + let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.assets.into()), + bx!(TransferType::DestinationReserve), + bx!(fee.id.into()), + bx!(TransferType::DestinationReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), + t.args.weight_limit, + ) +} + +fn para_to_para_transfer_assets_through_ah(t: ParaToParaThroughAHTest) -> DispatchResult { + let fee_idx = t.args.fee_asset_item as usize; + let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); + let asset_hub_location: Location = PenpalA::sibling_location_of(AssetHubKusama::para_id()); + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.assets.into()), + bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), + bx!(fee.id.into()), + bx!(TransferType::RemoteReserve(asset_hub_location.into())), + bx!(VersionedXcm::from(custom_xcm_on_dest)), + t.args.weight_limit, + ) +} + +fn para_to_asset_hub_teleport_foreign_assets(t: ParaToSystemParaTest) -> DispatchResult { + let fee_idx = t.args.fee_asset_item as usize; + let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.assets.into()), + bx!(TransferType::Teleport), + bx!(fee.id.into()), + bx!(TransferType::DestinationReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), + t.args.weight_limit, + ) +} + +fn asset_hub_to_para_teleport_foreign_assets(t: SystemParaToParaTest) -> DispatchResult { + let fee_idx = t.args.fee_asset_item as usize; + let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.assets.into()), + bx!(TransferType::Teleport), + bx!(fee.id.into()), + bx!(TransferType::LocalReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), + t.args.weight_limit, + ) +} + +// =========================================================================== +// ======= Transfer - Native + Bridged Assets - AssetHub->Parachain ========== +// =========================================================================== +/// Transfers of native asset plus bridged asset from AssetHub to some Parachain +/// while paying fees using native asset. +#[test] +fn transfer_foreign_assets_from_asset_hub_to_para() { + let destination = AssetHubKusama::sibling_location_of(PenpalA::para_id()); + let sender = AssetHubKusamaSender::get(); + let native_amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 10000; + let native_asset_location = KsmLocation::get(); + let receiver = PenpalAReceiver::get(); + let assets_owner = PenpalAssetOwner::get(); + // Foreign asset used: bridged WND + let foreign_amount_to_send = ASSET_HUB_KUSAMA_ED * 10_000_000; + let wnd_at_rococo_parachains = + Location::new(2, [Junction::GlobalConsensus(NetworkId::Westend)]); + + // Configure destination chain to trust AH as reserve of WND + PenpalA::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + CustomizableAssetFromSystemAssetHub::key().to_vec(), + Location::new(2, [GlobalConsensus(Westend)]).encode(), + )], + )); + }); + PenpalA::force_create_foreign_asset( + wnd_at_rococo_parachains.clone(), + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + AssetHubKusama::force_create_foreign_asset( + wnd_at_rococo_parachains.clone().try_into().unwrap(), + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + AssetHubKusama::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner), + wnd_at_rococo_parachains.clone().try_into().unwrap(), + sender.clone(), + foreign_amount_to_send * 2, + ); + + // Assets to send + let assets: Vec = vec![ + (Parent, native_amount_to_send).into(), + (wnd_at_rococo_parachains.clone(), foreign_amount_to_send).into(), + ]; + let fee_asset_id = AssetId(Parent.into()); + let fee_asset_item = assets.iter().position(|a| a.id == fee_asset_id).unwrap() as u32; + + // Init Test + let test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para( + destination.clone(), + receiver.clone(), + native_amount_to_send, + assets.into(), + None, + fee_asset_item, + ), + }; + let mut test = SystemParaToParaTest::new(test_args); + + // Query initial balances + let sender_balance_before = test.sender.balance; + let sender_wnds_before = AssetHubKusama::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + wnd_at_rococo_parachains.clone().try_into().unwrap(), + &sender, + ) + }); + let receiver_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(native_asset_location.clone(), &receiver) + }); + let receiver_wnds_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains.clone(), &receiver) + }); + + // Set assertions and dispatchables + test.set_assertion::(system_para_to_para_sender_assertions); + test.set_assertion::(system_para_to_para_receiver_assertions); + test.set_dispatchable::(ah_to_para_transfer_assets); + test.assert(); + + // Query final balances + let sender_balance_after = test.sender.balance; + let sender_wnds_after = AssetHubKusama::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + wnd_at_rococo_parachains.clone().try_into().unwrap(), + &sender, + ) + }); + let receiver_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(native_asset_location, &receiver) + }); + let receiver_wnds_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &receiver) + }); + + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_balance_after < sender_balance_before - native_amount_to_send); + // Sender's balance is reduced by foreign amount sent + assert_eq!(sender_wnds_after, sender_wnds_before - foreign_amount_to_send); + // 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_assets_after < receiver_assets_before + native_amount_to_send); + // Receiver's balance is increased by foreign amount sent + assert_eq!(receiver_wnds_after, receiver_wnds_before + foreign_amount_to_send); +} + +/// Reserve Transfers of native asset from Parachain to System Parachain should work +// =========================================================================== +// ======= Transfer - Native + Bridged Assets - Parachain->AssetHub ========== +// =========================================================================== +/// Transfers of native asset plus bridged asset from some Parachain to AssetHub +/// while paying fees using native asset. +#[test] +fn transfer_foreign_assets_from_para_to_asset_hub() { + // Init values for Parachain + let destination = PenpalA::sibling_location_of(AssetHubKusama::para_id()); + let sender = PenpalASender::get(); + let native_amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 10000; + let native_asset_location = KsmLocation::get(); + let assets_owner = PenpalAssetOwner::get(); + + // Foreign asset used: bridged WND + let foreign_amount_to_send = ASSET_HUB_KUSAMA_ED * 10_000_000; + let wnd_at_rococo_parachains = + Location::new(2, [Junction::GlobalConsensus(NetworkId::Westend)]); + + // Configure destination chain to trust AH as reserve of WND + PenpalA::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + CustomizableAssetFromSystemAssetHub::key().to_vec(), + Location::new(2, [GlobalConsensus(Westend)]).encode(), + )], + )); + }); + PenpalA::force_create_foreign_asset( + wnd_at_rococo_parachains.clone(), + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + AssetHubKusama::force_create_foreign_asset( + wnd_at_rococo_parachains.clone().try_into().unwrap(), + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner.clone()), + native_asset_location.clone(), + sender.clone(), + native_amount_to_send * 2, + ); + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner.clone()), + wnd_at_rococo_parachains.clone(), + sender.clone(), + foreign_amount_to_send * 2, + ); + + // Init values for System Parachain + let receiver = AssetHubKusamaReceiver::get(); + let penpal_location_as_seen_by_ahr = AssetHubKusama::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ahr = AssetHubKusama::sovereign_account_id_of(penpal_location_as_seen_by_ahr); + + // fund Parachain's SA on AssetHub with the assets held in reserve + AssetHubKusama::fund_accounts(vec![( + sov_penpal_on_ahr.clone().into(), + native_amount_to_send * 2, + )]); + AssetHubKusama::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner), + wnd_at_rococo_parachains.clone().try_into().unwrap(), + sov_penpal_on_ahr, + foreign_amount_to_send * 2, + ); + + // Assets to send + let assets: Vec = vec![ + (Parent, native_amount_to_send).into(), + (wnd_at_rococo_parachains.clone(), foreign_amount_to_send).into(), + ]; + let fee_asset_id = AssetId(Parent.into()); + let fee_asset_item = assets.iter().position(|a| a.id == fee_asset_id).unwrap() as u32; + + // Init Test + let test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para( + destination.clone(), + receiver.clone(), + native_amount_to_send, + assets.into(), + None, + fee_asset_item, + ), + }; + let mut test = ParaToSystemParaTest::new(test_args); + + // Query initial balances + let sender_native_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(native_asset_location.clone(), &sender) + }); + let sender_wnds_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains.clone(), &sender) + }); + let receiver_native_before = test.receiver.balance; + let receiver_wnds_before = AssetHubKusama::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + wnd_at_rococo_parachains.clone().try_into().unwrap(), + &receiver, + ) + }); + + // 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_ah_transfer_assets); + test.assert(); + + // Query final balances + let sender_native_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(native_asset_location, &sender) + }); + let sender_wnds_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains.clone(), &sender) + }); + let receiver_native_after = test.receiver.balance; + let receiver_wnds_after = AssetHubKusama::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + wnd_at_rococo_parachains.try_into().unwrap(), + &receiver, + ) + }); + + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_native_after < sender_native_before - native_amount_to_send); + // Sender's balance is reduced by foreign amount sent + assert_eq!(sender_wnds_after, sender_wnds_before - foreign_amount_to_send); + // Receiver's balance is increased + assert!(receiver_native_after > receiver_native_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_native_after < receiver_native_before + native_amount_to_send); + // Receiver's balance is increased by foreign amount sent + assert_eq!(receiver_wnds_after, receiver_wnds_before + foreign_amount_to_send); +} + +// ============================================================================== +// ===== Transfer - Native + Bridged Assets - Parachain->AssetHub->Parachain ==== +// ============================================================================== +/// Transfers of native asset plus bridged asset from Parachain to Parachain +/// (through AssetHub reserve) with fees paid using native asset. +#[test] +fn transfer_foreign_assets_from_para_to_para_through_asset_hub() { + // Init values for Parachain Origin + let destination = PenpalA::sibling_location_of(PenpalB::para_id()); + let sender = PenpalASender::get(); + let roc_to_send: Balance = KUSAMA_ED * 10000; + let assets_owner = PenpalAssetOwner::get(); + let roc_location = KsmLocation::get(); + let sender_as_seen_by_ah = AssetHubKusama::sibling_location_of(PenpalA::para_id()); + let sov_of_sender_on_ah = AssetHubKusama::sovereign_account_id_of(sender_as_seen_by_ah); + let receiver_as_seen_by_ah = AssetHubKusama::sibling_location_of(PenpalB::para_id()); + let sov_of_receiver_on_ah = AssetHubKusama::sovereign_account_id_of(receiver_as_seen_by_ah); + let wnd_to_send = ASSET_HUB_KUSAMA_ED * 10_000_000; + + // Configure destination chain to trust AH as reserve of WND + PenpalB::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + CustomizableAssetFromSystemAssetHub::key().to_vec(), + Location::new(2, [GlobalConsensus(Westend)]).encode(), + )], + )); + }); + + // Register WND as foreign asset and transfer it around the Kusama ecosystem + let wnd_at_rococo_parachains = + Location::new(2, [Junction::GlobalConsensus(NetworkId::Westend)]); + AssetHubKusama::force_create_foreign_asset( + wnd_at_rococo_parachains.clone().try_into().unwrap(), + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + PenpalA::force_create_foreign_asset( + wnd_at_rococo_parachains.clone(), + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + PenpalB::force_create_foreign_asset( + wnd_at_rococo_parachains.clone(), + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner.clone()), + roc_location.clone(), + sender.clone(), + roc_to_send * 2, + ); + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner.clone()), + wnd_at_rococo_parachains.clone(), + sender.clone(), + wnd_to_send * 2, + ); + // fund the Parachain Origin's SA on Asset Hub with the assets held in reserve + AssetHubKusama::fund_accounts(vec![(sov_of_sender_on_ah.clone().into(), roc_to_send * 2)]); + AssetHubKusama::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner), + wnd_at_rococo_parachains.clone().try_into().unwrap(), + sov_of_sender_on_ah.clone(), + wnd_to_send * 2, + ); + + // Init values for Parachain Destination + let receiver = PenpalBReceiver::get(); + + // Assets to send + let assets: Vec = vec![ + (roc_location.clone(), roc_to_send).into(), + (wnd_at_rococo_parachains.clone(), wnd_to_send).into(), + ]; + let fee_asset_id: AssetId = roc_location.clone().into(); + let fee_asset_item = assets.iter().position(|a| a.id == fee_asset_id).unwrap() as u32; + + // Init Test + let test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para( + destination, + receiver.clone(), + roc_to_send, + assets.into(), + None, + fee_asset_item, + ), + }; + let mut test = ParaToParaThroughAHTest::new(test_args); + + // Query initial balances + let sender_rocs_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_location.clone(), &sender) + }); + let sender_wnds_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains.clone(), &sender) + }); + let rocs_in_sender_reserve_on_ahr_before = + ::account_data_of(sov_of_sender_on_ah.clone()).free; + let wnds_in_sender_reserve_on_ahr_before = AssetHubKusama::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance( + wnd_at_rococo_parachains.clone().try_into().unwrap(), + &sov_of_sender_on_ah, + ) + }); + let rocs_in_receiver_reserve_on_ahr_before = + ::account_data_of(sov_of_receiver_on_ah.clone()).free; + let wnds_in_receiver_reserve_on_ahr_before = AssetHubKusama::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance( + wnd_at_rococo_parachains.clone().try_into().unwrap(), + &sov_of_receiver_on_ah, + ) + }); + let receiver_rocs_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_location.clone(), &receiver) + }); + let receiver_wnds_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains.clone(), &receiver) + }); + + // Set assertions and dispatchables + test.set_assertion::(para_to_para_through_hop_sender_assertions); + test.set_assertion::(para_to_para_assethub_hop_assertions); + test.set_assertion::(para_to_para_through_hop_receiver_assertions); + test.set_dispatchable::(para_to_para_transfer_assets_through_ah); + test.assert(); + + // Query final balances + let sender_rocs_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_location.clone(), &sender) + }); + let sender_wnds_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains.clone(), &sender) + }); + let wnds_in_sender_reserve_on_ahr_after = AssetHubKusama::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance( + wnd_at_rococo_parachains.clone().try_into().unwrap(), + &sov_of_sender_on_ah, + ) + }); + let rocs_in_sender_reserve_on_ahr_after = + ::account_data_of(sov_of_sender_on_ah).free; + let wnds_in_receiver_reserve_on_ahr_after = AssetHubKusama::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance( + wnd_at_rococo_parachains.clone().try_into().unwrap(), + &sov_of_receiver_on_ah, + ) + }); + let rocs_in_receiver_reserve_on_ahr_after = + ::account_data_of(sov_of_receiver_on_ah).free; + let receiver_rocs_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_location, &receiver) + }); + let receiver_wnds_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &receiver) + }); + + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_rocs_after < sender_rocs_before - roc_to_send); + assert_eq!(sender_wnds_after, sender_wnds_before - wnd_to_send); + // Sovereign accounts on reserve are changed accordingly + assert_eq!( + rocs_in_sender_reserve_on_ahr_after, + rocs_in_sender_reserve_on_ahr_before - roc_to_send + ); + assert_eq!( + wnds_in_sender_reserve_on_ahr_after, + wnds_in_sender_reserve_on_ahr_before - wnd_to_send + ); + assert!(rocs_in_receiver_reserve_on_ahr_after > rocs_in_receiver_reserve_on_ahr_before); + assert_eq!( + wnds_in_receiver_reserve_on_ahr_after, + wnds_in_receiver_reserve_on_ahr_before + wnd_to_send + ); + // Receiver's balance is increased + assert!(receiver_rocs_after > receiver_rocs_before); + assert_eq!(receiver_wnds_after, receiver_wnds_before + wnd_to_send); +} + +// ============================================================================================== +// ==== Bidirectional Transfer - Native + Teleportable Foreign Assets - Parachain<->AssetHub ==== +// ============================================================================================== +/// Transfers of native asset plus teleportable foreign asset from Parachain to AssetHub and back +/// with fees paid using native asset. +#[test] +fn bidirectional_teleport_foreign_asset_between_para_and_asset_hub_using_explicit_transfer_types() { + do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt( + para_to_asset_hub_teleport_foreign_assets, + asset_hub_to_para_teleport_foreign_assets, + ); +} + +// =============================================================== +// ===== Transfer - Native Asset - Relay->AssetHub->Parachain ==== +// =============================================================== +/// Transfers of native asset Relay to Parachain (using AssetHub reserve). Parachains want to avoid +/// managing SAs on all system chains, thus want all their DOT-in-reserve to be held in their +/// Sovereign Account on Asset Hub. +#[test] +fn transfer_native_asset_from_relay_to_para_through_asset_hub() { + // Init values for Relay + let destination = Kusama::child_location_of(PenpalA::para_id()); + let sender = KusamaSender::get(); + let amount_to_send: Balance = KUSAMA_ED * 1000; + + // Init values for Parachain + let relay_native_asset_location = KsmLocation::get(); + let receiver = PenpalAReceiver::get(); + + // Init Test + let test_args = TestContext { + sender, + receiver: receiver.clone(), + args: TestArgs::new_relay(destination.clone(), receiver.clone(), amount_to_send), + }; + let mut test = RelayToParaThroughAHTest::new(test_args); + + let sov_penpal_on_ah = AssetHubKusama::sovereign_account_id_of( + AssetHubKusama::sibling_location_of(PenpalA::para_id()), + ); + // Query initial balances + let sender_balance_before = test.sender.balance; + let sov_penpal_on_ah_before = AssetHubKusama::execute_with(|| { + ::Balances::free_balance(sov_penpal_on_ah.clone()) + }); + let receiver_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &receiver) + }); + + fn relay_assertions(t: RelayToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + Kusama::assert_xcm_pallet_attempted_complete(None); + assert_expected_events!( + Kusama, + vec![ + // Amount to teleport is withdrawn from Sender + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { + who: *who == t.sender.account_id, + amount: *amount == t.args.amount, + }, + // Amount to teleport is deposited in Relay's `CheckAccount` + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) => { + who: *who == ::XcmPallet::check_account(), + amount: *amount == t.args.amount, + }, + ] + ); + } + fn asset_hub_assertions(_: RelayToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + let sov_penpal_on_ah = AssetHubKusama::sovereign_account_id_of( + AssetHubKusama::sibling_location_of(PenpalA::para_id()), + ); + assert_expected_events!( + AssetHubKusama, + vec![ + // Deposited to receiver parachain SA + RuntimeEvent::Balances( + pallet_balances::Event::Minted { who, .. } + ) => { + who: *who == sov_penpal_on_ah, + }, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + } + fn penpal_assertions(t: RelayToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + let expected_id = + t.args.assets.into_inner().first().unwrap().id.0.clone().try_into().unwrap(); + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == expected_id, + owner: *owner == t.receiver.account_id, + }, + ] + ); + } + fn transfer_assets_dispatchable(t: RelayToParaThroughAHTest) -> DispatchResult { + let fee_idx = t.args.fee_asset_item as usize; + let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); + let asset_hub_location = Kusama::child_location_of(AssetHubKusama::para_id()); + let context = KusamaUniversalLocation::get(); + + // reanchor fees to the view of destination (Penpal) + let mut remote_fees = fee.clone().reanchored(&t.args.dest, &context).unwrap(); + if let Fungible(ref mut amount) = remote_fees.fun { + // we already spent some fees along the way, just use half of what we started with + *amount = *amount / 2; + } + let xcm_on_final_dest = Xcm::<()>(vec![ + BuyExecution { fees: remote_fees, weight_limit: t.args.weight_limit.clone() }, + DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }, + ]); + + // reanchor final dest (Penpal) to the view of hop (Asset Hub) + let mut dest = t.args.dest.clone(); + dest.reanchor(&asset_hub_location, &context).unwrap(); + // on Asset Hub, forward assets to Penpal + let xcm_on_hop = Xcm::<()>(vec![DepositReserveAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + dest, + xcm: xcm_on_final_dest, + }]); + + // First leg is a teleport, from there a local-reserve-transfer to final dest + ::XcmPallet::transfer_assets_using_type_and_then( + t.signed_origin, + bx!(asset_hub_location.into()), + bx!(t.args.assets.into()), + bx!(TransferType::Teleport), + bx!(fee.id.into()), + bx!(TransferType::Teleport), + bx!(VersionedXcm::from(xcm_on_hop)), + t.args.weight_limit, + ) + } + + // Set assertions and dispatchables + test.set_assertion::(relay_assertions); + test.set_assertion::(asset_hub_assertions); + test.set_assertion::(penpal_assertions); + test.set_dispatchable::(transfer_assets_dispatchable); + test.assert(); + + // Query final balances + let sender_balance_after = test.sender.balance; + let sov_penpal_on_ah_after = AssetHubKusama::execute_with(|| { + ::Balances::free_balance(sov_penpal_on_ah) + }); + let receiver_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location, &receiver) + }); + + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_balance_after < sender_balance_before - amount_to_send); + // SA on AH balance is increased + assert!(sov_penpal_on_ah_after > sov_penpal_on_ah_before); + // 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_assets_after < receiver_assets_before + amount_to_send); +} diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/mod.rs b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/mod.rs index ee5f15aa92..8fffec23d7 100644 --- a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/mod.rs +++ b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/mod.rs @@ -14,19 +14,10 @@ // limitations under the License. mod claim_assets; +mod hybrid_transfers; mod reserve_transfer; mod send; mod set_xcm_versions; mod swap; mod teleport; mod treasury; - -use crate::*; -// FAIL-CI @bkontur -/*emulated_integration_tests_common::include_penpal_create_foreign_asset_on_asset_hub!( - PenpalA, - AssetHubKusama, - KUSAMA_ED, - system_parachains_constants::kusama::fee::WeightToFee -); -*/ diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/reserve_transfer.rs b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/reserve_transfer.rs index 09523d8649..c89465fa95 100644 --- a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/reserve_transfer.rs +++ b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/reserve_transfer.rs @@ -14,9 +14,8 @@ // limitations under the License. use crate::*; -use asset_hub_kusama_runtime::xcm_config::XcmConfig as AssetHubKusamaXcmConfig; -use kusama_runtime::xcm_config::XcmConfig as KusamaXcmConfig; -use kusama_system_emulated_network::penpal_emulated_chain::XcmConfig as PenpalKusamaXcmConfig; +use asset_hub_kusama_runtime::xcm_config::KsmLocation; +use kusama_system_emulated_network::penpal_emulated_chain::LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub; fn relay_to_para_sender_assertions(t: RelayToParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -39,7 +38,7 @@ fn relay_to_para_sender_assertions(t: RelayToParaTest) { ); } -fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { +pub fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; AssetHubKusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( 864_610_000, @@ -63,12 +62,34 @@ fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { ); } -fn para_receiver_assertions(_: Test) { +pub fn system_para_to_para_receiver_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; + + PenpalB::assert_xcmp_queue_success(None); + for asset in t.args.assets.into_inner().into_iter() { + let expected_id = asset.id.0.try_into().unwrap(); + assert_expected_events!( + PenpalB, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == expected_id, + owner: *owner == t.receiver.account_id, + }, + ] + ); + } +} + +fn relay_to_para_assets_receiver_assertions(t: RelayToParaTest) { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( PenpalA, vec![ - RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == KsmLocation::get(), + owner: *owner == t.receiver.account_id, + }, RuntimeEvent::MessageQueue( pallet_message_queue::Event::Processed { success: true, .. } ) => {}, @@ -76,25 +97,29 @@ fn para_receiver_assertions(_: Test) { ); } -fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { +pub fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; - PenpalA::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799))); - assert_expected_events!( - PenpalA, - vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { who, amount } - ) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, - }, - ] - ); + PenpalA::assert_xcm_pallet_attempted_complete(None); + for asset in t.args.assets.into_inner().into_iter() { + let expected_id = asset.id.0; + let asset_amount = if let Fungible(a) = asset.fun { Some(a) } else { None }.unwrap(); + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, balance } + ) => { + asset_id: *asset_id == expected_id, + owner: *owner == t.sender.account_id, + balance: *balance == asset_amount, + }, + ] + ); + } } -fn para_to_system_para_receiver_assertions(t: ParaToSystemParaTest) { +pub fn para_to_system_para_receiver_assertions(t: ParaToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; let sov_penpal_on_ahk = AssetHubKusama::sovereign_account_id_of( AssetHubKusama::sibling_location_of(PenpalA::para_id()), @@ -124,7 +149,6 @@ fn system_para_to_para_assets_sender_assertions(t: SystemParaToParaTest) { 864_610_000, 8799, ))); - assert_expected_events!( AssetHubKusama, vec![ @@ -132,53 +156,72 @@ fn system_para_to_para_assets_sender_assertions(t: SystemParaToParaTest) { RuntimeEvent::Assets( pallet_assets::Event::Transferred { asset_id, from, to, amount } ) => { - asset_id: *asset_id == ASSET_ID, + asset_id: *asset_id == RESERVABLE_ASSET_ID, from: *from == t.sender.account_id, to: *to == AssetHubKusama::sovereign_account_id_of( t.args.dest.clone() ), 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 == AssetHubKusama::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 = PenpalLocalReservableFromAssetHub::get(); + PenpalA::assert_xcmp_queue_success(None); assert_expected_events!( PenpalA, vec![ - RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, - RuntimeEvent::Assets(pallet_assets::Event::Issued { .. }) => {}, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == KsmLocation::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 para_to_para_sender_assertions(t: ParaToParaTest) { +pub fn para_to_para_through_hop_sender_assertions(t: Test) { type RuntimeEvent = ::RuntimeEvent; + PenpalA::assert_xcm_pallet_attempted_complete(None); - assert_expected_events!( - PenpalA, - vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { who, amount } - ) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, - }, - // XCM sent to relay reserve - RuntimeEvent::ParachainSystem( - cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } - ) => {}, - ] - ); + for asset in t.args.assets.into_inner() { + let expected_id = asset.id.0.clone().try_into().unwrap(); + let amount = if let Fungible(a) = asset.fun { Some(a) } else { None }.unwrap(); + 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 == expected_id, + owner: *owner == t.sender.account_id, + balance: *balance == amount, + }, + ] + ); + } } -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_kusama = Kusama::sovereign_account_id_of(Kusama::child_location_of(PenpalA::para_id())); @@ -207,17 +250,22 @@ fn para_to_para_relay_hop_assertions(t: ParaToParaTest) { ); } -fn para_to_para_receiver_assertions(_: ParaToParaTest) { +pub fn para_to_para_through_hop_receiver_assertions(t: Test) { type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - PenpalB, - vec![ - RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); + + PenpalB::assert_xcmp_queue_success(None); + for asset in t.args.assets.into_inner().into_iter() { + let expected_id = asset.id.0.try_into().unwrap(); + assert_expected_events!( + PenpalB, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == expected_id, + owner: *owner == t.receiver.account_id, + }, + ] + ); + } } fn relay_to_para_reserve_transfer_assets(t: RelayToParaTest) -> DispatchResult { @@ -253,7 +301,9 @@ 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()), @@ -338,42 +388,49 @@ 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 = Kusama::child_location_of(PenpalA::para_id()); - let beneficiary_id = PenpalAReceiver::get(); + let sender = KusamaSender::get(); let amount_to_send: Balance = KUSAMA_ED * 1000; + // Init values for Parachain + let relay_native_asset_location = KsmLocation::get(); + let receiver = PenpalAReceiver::get(); + + // Init Test let test_args = TestContext { - sender: KusamaSender::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.clone(), &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(); - let delivery_fees = Kusama::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 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, &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`; + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_balance_after < sender_balance_before - amount_to_send); + // 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 @@ -381,87 +438,123 @@ 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 = AssetHubKusama::sibling_location_of(PenpalA::para_id()); - let beneficiary_id = PenpalAReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; - let assets = (Parent, amount_to_send).into(); + let sender = AssetHubKusamaSender::get(); + let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 10000; + let assets: Assets = (Parent, amount_to_send).into(); + + // Init values for Parachain + let system_para_native_asset_location = KsmLocation::get(); + let receiver = PenpalAReceiver::get(); + // Init Test let test_args = TestContext { - sender: AssetHubKusamaSender::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.clone(), &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_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; - - let delivery_fees = AssetHubKusama::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + 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`; + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_balance_after < sender_balance_before - amount_to_send); + // 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(AssetHubKusama::para_id()); - let beneficiary_id = AssetHubKusamaReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; - let assets = (Parent, amount_to_send).into(); + let sender = PenpalASender::get(); + let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 10000; + let assets: Assets = (Parent, amount_to_send).into(); + let system_para_native_asset_location = KsmLocation::get(); + let asset_owner = PenpalAssetOwner::get(); + + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner), + system_para_native_asset_location.clone(), + sender.clone(), + amount_to_send * 2, + ); + + // Init values for System Parachain + let receiver = AssetHubKusamaReceiver::get(); + let penpal_location_as_seen_by_ahr = AssetHubKusama::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ahr = AssetHubKusama::sovereign_account_id_of(penpal_location_as_seen_by_ahr); + + // fund Parachain's SA on System Parachain with the native tokens held in reserve + AssetHubKusama::fund_accounts(vec![(sov_penpal_on_ahr.into(), amount_to_send * 2)]); + // Init Test let test_args = TestContext { - sender: PenpalASender::get(), - receiver: AssetHubKusamaReceiver::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.clone(), &sender) + }); let receiver_balance_before = test.receiver.balance; - let penpal_location_as_seen_by_ahk = AssetHubKusama::sibling_location_of(PenpalA::para_id()); - let sov_penpal_on_ahk = AssetHubKusama::sovereign_account_id_of(penpal_location_as_seen_by_ahk); - - // fund the Penpal's SA on AHK with the native tokens held in reserve - AssetHubKusama::fund_accounts(vec![(sov_penpal_on_ahk, 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; - - let delivery_fees = PenpalA::execute_with(|| { - xcm_helpers::teleport_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(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); + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_assets_after < sender_assets_before - amount_to_send); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; @@ -474,53 +567,182 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { /// work #[test] fn reserve_transfer_assets_from_system_para_to_para() { - // FAIL-CI @bkontur pls fix + // Init values for System Parachain + let destination = AssetHubKusama::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ahr = AssetHubKusama::sovereign_account_id_of(destination.clone()); + let sender = AssetHubKusamaSender::get(); + let fee_amount_to_send = ASSET_HUB_KUSAMA_ED * 10000; + let asset_amount_to_send = PENPAL_ED * 10000; + let asset_owner = AssetHubKusamaAssetOwner::get(); + let asset_owner_signer = ::RuntimeOrigin::signed(asset_owner.clone()); + let assets: Assets = vec![ + (Parent, fee_amount_to_send).into(), + ( + [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(RESERVABLE_ASSET_ID.into())], + asset_amount_to_send, + ) + .into(), + ] + .into(); + let fee_asset_index = assets + .inner() + .iter() + .position(|r| r == &(Parent, fee_amount_to_send).into()) + .unwrap() as u32; + AssetHubKusama::mint_asset( + asset_owner_signer, + RESERVABLE_ASSET_ID, + asset_owner, + asset_amount_to_send * 2, + ); + + // Create SA-of-Penpal-on-AHR with ED. + AssetHubKusama::fund_accounts(vec![(sov_penpal_on_ahr.into(), ASSET_HUB_KUSAMA_ED)]); + + // Init values for Parachain + let receiver = PenpalAReceiver::get(); + let system_para_native_asset_location = KsmLocation::get(); + let system_para_foreign_asset_location = PenpalLocalReservableFromAssetHub::get(); + + // Init Test + let para_test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para( + destination, + receiver.clone(), + asset_amount_to_send, + assets, + None, + fee_asset_index, + ), + }; + let mut test = SystemParaToParaTest::new(para_test_args); + + // Query initial balances + let sender_balance_before = test.sender.balance; + let sender_assets_before = AssetHubKusama::execute_with(|| { + type Assets = ::Assets; + >::balance(RESERVABLE_ASSET_ID, &sender) + }); + 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 sender_assets_after = AssetHubKusama::execute_with(|| { + type Assets = ::Assets; + >::balance(RESERVABLE_ASSET_ID, &sender) + }); + 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, &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 asset balance is reduced by exact amount + assert_eq!(sender_assets_before - asset_amount_to_send, sender_assets_after); + // 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_through_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_KUSAMA_ED * 10000; + let sender = PenpalASender::get(); + let amount_to_send: Balance = KUSAMA_ED * 10000; + let asset_owner = PenpalAssetOwner::get(); let assets = (Parent, amount_to_send).into(); + let relay_native_asset_location = KsmLocation::get(); + let sender_as_seen_by_relay = Kusama::child_location_of(PenpalA::para_id()); + let sov_of_sender_on_relay = Kusama::sovereign_account_id_of(sender_as_seen_by_relay); - let test_args = TestContext { - sender: PenpalASender::get(), - receiver: PenpalBReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner), + relay_native_asset_location.clone(), + sender.clone(), + amount_to_send * 2, + ); - let mut test = ParaToParaTest::new(test_args); + // fund the Parachain Origin's SA on Relay Chain with the native tokens held in reserve + Kusama::fund_accounts(vec![(sov_of_sender_on_relay.into(), amount_to_send * 2)]); - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; + // Init values for Parachain Destination + let receiver = PenpalBReceiver::get(); - let sender_as_seen_by_relay = Kusama::child_location_of(PenpalA::para_id()); - let sov_of_sender_on_relay = Kusama::sovereign_account_id_of(sender_as_seen_by_relay); + // Init Test + let test_args = TestContext { + 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); - // fund the PenpalA's SA on Kusama with the native tokens held in reserve - Kusama::fund_accounts(vec![(sov_of_sender_on_relay, amount_to_send * 2)]); + // 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) + }); - test.set_assertion::(para_to_para_sender_assertions); + // Set assertions and dispatchables + test.set_assertion::(para_to_para_through_hop_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.set_assertion::(para_to_para_through_hop_receiver_assertions); + test.set_dispatchable::(para_to_para_through_relay_limited_reserve_transfer_assets); test.assert(); - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - let delivery_fees = PenpalA::execute_with(|| { - xcm_helpers::teleport_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, &receiver) }); - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_assets_after < sender_assets_before - amount_to_send); // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); + assert!(receiver_assets_after > receiver_assets_before); } diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/swap.rs b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/swap.rs index 6565c31b53..881ece1e7e 100644 --- a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/swap.rs +++ b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/swap.rs @@ -123,42 +123,26 @@ fn swap_locally_on_chain_using_foreign_assets() { v3::Location::try_from(asset_hub_kusama_runtime::xcm_config::KsmLocation::get()) .expect("conversion works"), ); - - let ah_as_seen_by_penpal = PenpalA::sibling_location_of(AssetHubKusama::para_id()); let asset_location_on_penpal = v3::Location::try_from(PenpalLocalTeleportableToAssetHub::get()).expect("conversion works"); - 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_kusama = v3::Location::new(1, [v3::Junction::Parachain(PenpalA::para_id().into())]) .appended_with(asset_location_on_penpal) .unwrap(); - // 1. Create asset on penpal and, 2. Create foreign asset on asset_hub_kusama - /* - // FAIL-CI @bkontur - super::penpal_create_foreign_asset_on_asset_hub( - asset_id_on_penpal, - foreign_asset_at_asset_hub_kusama, - ah_as_seen_by_penpal, - true, - asset_owner_on_penpal, - ASSET_MIN_BALANCE * 1_000_000, - );*/ - let penpal_as_seen_by_ah = AssetHubKusama::sibling_location_of(PenpalA::para_id()); let sov_penpal_on_ahk = AssetHubKusama::sovereign_account_id_of(penpal_as_seen_by_ah); AssetHubKusama::fund_accounts(vec![ - (AssetHubKusamaSender::get(), 5_000_000 * ASSET_HUB_KUSAMA_ED), /* An account to swap - * ksm - * for something else. */ + // An account to swap ksmfor something else. + (AssetHubKusamaSender::get(), 5_000_000 * ASSET_HUB_KUSAMA_ED), + // Penpal's sovereign account in AH should have some balance + (sov_penpal_on_ahk.clone().into(), 100_000_000 * ASSET_HUB_KUSAMA_ED), ]); AssetHubKusama::execute_with(|| { - // 3: Mint foreign asset on asset_hub_kusama: + // 0: No need to create foreign asset as it exists in genesis. + // + // 1:: Mint foreign asset on asset_hub_kusama: // // (While it might be nice to use batch, // currently that's disabled due to safe call filters.) @@ -169,7 +153,7 @@ fn swap_locally_on_chain_using_foreign_assets() { ::RuntimeOrigin::signed(sov_penpal_on_ahk.clone()), foreign_asset_at_asset_hub_kusama, sov_penpal_on_ahk.clone().into(), - 3_000_000_000_000, + ASSET_HUB_KUSAMA_ED * 3_000_000_000_000, )); assert_expected_events!( @@ -221,8 +205,8 @@ fn swap_locally_on_chain_using_foreign_assets() { ::AssetConversion::swap_exact_tokens_for_tokens( ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), path, - 100000, - 1000, + 100000 * ASSET_HUB_KUSAMA_ED, + 1000 * ASSET_HUB_KUSAMA_ED, AssetHubKusamaSender::get(), true ) @@ -232,8 +216,8 @@ fn swap_locally_on_chain_using_foreign_assets() { AssetHubKusama, vec![ RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::SwapExecuted { amount_in, amount_out, .. },) => { - amount_in: *amount_in == 100000, - amount_out: *amount_out == 199399, + amount_in: *amount_in == 333333300000, + amount_out: *amount_out == 498874118173, }, ] ); @@ -243,7 +227,7 @@ fn swap_locally_on_chain_using_foreign_assets() { ::RuntimeOrigin::signed(sov_penpal_on_ahk.clone()), asset_native.clone(), Box::new(foreign_asset_at_asset_hub_kusama), - 1414213562273 - 2_000_000_000, // all but the 2 EDs can't be retrieved. + 1414213562273 / 2, // remove only half 0, 0, sov_penpal_on_ahk.clone(), diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/teleport.rs b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/teleport.rs index 18460d6a8b..d637893f4b 100644 --- a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/teleport.rs +++ b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/teleport.rs @@ -14,7 +14,7 @@ // limitations under the License. use crate::*; -use asset_hub_kusama_runtime::xcm_config::XcmConfig as AssetHubKusamaXcmConfig; +use asset_hub_kusama_runtime::xcm_config::{KsmLocation, XcmConfig as AssetHubKusamaXcmConfig}; use emulated_integration_tests_common::xcm_helpers::non_fee_asset; use kusama_runtime::xcm_config::XcmConfig as KusamaXcmConfig; use kusama_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub; @@ -114,18 +114,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 = KsmLocation::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::Withdraw { 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 +146,8 @@ 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(); + + AssetHubKusama::assert_xcmp_queue_success(None); assert_expected_events!( AssetHubKusama, vec![ @@ -163,9 +167,6 @@ 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, .. } - ) => {}, ] ); } @@ -205,6 +206,9 @@ 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 = KsmLocation::get(); + + PenpalA::assert_xcmp_queue_success(None); assert_expected_events!( PenpalA, vec![ @@ -221,12 +225,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::Deposit { 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, .. } - ) => {}, ] ); } @@ -242,16 +245,6 @@ fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { ) } -fn relay_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { ::PolkadotXcm::limited_teleport_assets( t.signed_origin, @@ -263,16 +256,6 @@ fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResu ) } -fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - fn para_to_system_para_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { ::PolkadotXcm::transfer_assets( t.signed_origin, @@ -418,178 +401,41 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { assert_eq!(receiver_balance_after, receiver_balance_before); } -/// Teleport of native asset from Relay Chain to the System Parachain should work -#[test] -fn teleport_native_assets_from_relay_to_system_para_works() { - // Init values for Relay Chain - let amount_to_send: Balance = KUSAMA_ED * 1000; - let dest = Kusama::child_location_of(AssetHubKusama::para_id()); - let beneficiary_id = AssetHubKusamaReceiver::get(); - let test_args = TestContext { - sender: KusamaSender::get(), - receiver: AssetHubKusamaReceiver::get(), - args: TestArgs::new_relay(dest, beneficiary_id, amount_to_send), - }; - - let mut test = RelayToSystemParaTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(relay_origin_assertions); - test.set_assertion::(para_dest_assertions); - test.set_dispatchable::(relay_teleport_assets); - test.assert(); - - let delivery_fees = Kusama::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - let sender_balance_after = test.sender.balance; - 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); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - -/// Teleport of native asset from System Parachains to the Relay Chain -/// should work when there is enough balance in Relay Chain's `CheckAccount` -#[test] -fn teleport_native_assets_back_from_system_para_to_relay_works() { - // Dependency - Relay Chain's `CheckAccount` should have enough balance - teleport_native_assets_from_relay_to_system_para_works(); - - // Init values for Relay Chain - let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; - let destination = AssetHubKusama::parent_location(); - let beneficiary_id = KusamaReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubKusamaSender::get(), - receiver: KusamaReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions); - test.set_dispatchable::(system_para_teleport_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - let delivery_fees = AssetHubKusama::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - // 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); -} - -/// Teleport of native asset from System Parachain to Relay Chain -/// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` -#[test] -fn teleport_native_assets_from_system_para_to_relay_fails() { - // Init values for Relay Chain - let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; - let destination = AssetHubKusama::parent_location(); - let beneficiary_id = KusamaReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubKusamaSender::get(), - receiver: KusamaReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions_fail); - test.set_dispatchable::(system_para_teleport_assets); - test.assert(); - - let delivery_fees = AssetHubKusama::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - let sender_balance_after = test.sender.balance; - 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); - // Receiver's balance does not change - assert_eq!(receiver_balance_after, receiver_balance_before); -} - #[test] fn teleport_to_other_system_parachains_works() { let amount = ASSET_HUB_KUSAMA_ED * 100; let native_asset: Assets = (Parent, amount).into(); - /*test_sibling_is_trusted_teleporter!( + test_parachain_is_trusted_teleporter!( AssetHubKusama, // Origin AssetHubKusamaXcmConfig, // XCM Configuration vec![BridgeHubKusama], // Destinations (native_asset, amount) - );*/ - todo!() // FAIL-CI @bkontur + ); } -/// Bidirectional teleports of local Penpal assets to Asset Hub as foreign assets should work -/// (using native reserve-based transfer for fees) -#[test] -fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { - let ah_as_seen_by_penpal = PenpalA::sibling_location_of(AssetHubKusama::para_id()); - let asset_location_on_penpal = - v3::Location::try_from(PenpalLocalTeleportableToAssetHub::get()).expect("conversion works"); +/// Bidirectional teleports of local Penpal assets to Asset Hub as foreign assets while paying +/// fees using (reserve transferred) native asset. +pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt( + para_to_ah_dispatchable: fn(ParaToSystemParaTest) -> DispatchResult, + ah_to_para_dispatchable: fn(SystemParaToParaTest) -> DispatchResult, +) { + // Init values for Parachain + let fee_amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 10000; + let asset_location_on_penpal = PenpalLocalTeleportableToAssetHub::get(); let asset_id_on_penpal = match asset_location_on_penpal.last() { - Some(v3::Junction::GeneralIndex(id)) => *id as u32, + Some(Junction::GeneralIndex(id)) => *id as u32, _ => unreachable!(), }; - let asset_owner_on_penpal = PenpalASender::get(); - let foreign_asset_at_asset_hub_kusama = - v3::Location::new(1, [v3::Junction::Parachain(PenpalA::para_id().into())]) - .appended_with(asset_location_on_penpal) - .unwrap(); - /* - // FAIL-CI @bkontur - super::penpal_create_foreign_asset_on_asset_hub( - asset_id_on_penpal, - foreign_asset_at_asset_hub_kusama, - ah_as_seen_by_penpal.clone(), - false, - asset_owner_on_penpal, - ASSET_MIN_BALANCE * 1_000_000, - );*/ - let penpal_to_ah_beneficiary_id = AssetHubKusamaReceiver::get(); - - let fee_amount_to_send = ASSET_HUB_KUSAMA_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 asset_amount_to_send = ASSET_HUB_KUSAMA_ED * 1000; + let asset_owner = PenpalAssetOwner::get(); + let system_para_native_asset_location = KsmLocation::get(); + let sender = PenpalASender::get(); + let penpal_check_account = ::PolkadotXcm::check_account(); + let ah_as_seen_by_penpal = PenpalA::sibling_location_of(AssetHubKusama::para_id()); let penpal_assets: Assets = vec![ (Parent, fee_amount_to_send).into(), - (asset_location_on_penpal_latest, asset_amount_to_send).into(), + (asset_location_on_penpal.clone(), asset_amount_to_send).into(), ] .into(); let fee_asset_index = penpal_assets @@ -598,6 +444,38 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { .position(|r| r == &(Parent, fee_amount_to_send).into()) .unwrap() as u32; + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner.clone()), + system_para_native_asset_location.clone(), + sender.clone(), + fee_amount_to_send * 2, + ); + // No need to create the asset (only mint) as it exists in genesis. + PenpalA::mint_asset( + ::RuntimeOrigin::signed(asset_owner.clone()), + asset_id_on_penpal, + sender.clone(), + asset_amount_to_send, + ); + // fund Parachain's check account to be able to teleport + PenpalA::fund_accounts(vec![(penpal_check_account.clone().into(), ASSET_HUB_KUSAMA_ED * 1000)]); + + // prefund SA of Penpal on AssetHub with enough native tokens to pay for fees + let penpal_as_seen_by_ah = AssetHubKusama::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ah = AssetHubKusama::sovereign_account_id_of(penpal_as_seen_by_ah); + AssetHubKusama::fund_accounts(vec![( + sov_penpal_on_ah.clone().into(), + ASSET_HUB_KUSAMA_ED * 100_000_000_000, + )]); + + // Init values for System Parachain + let foreign_asset_at_asset_hub_kusama = + Location::new(1, [Junction::Parachain(PenpalA::para_id().into())]) + .appended_with(asset_location_on_penpal) + .unwrap(); + let penpal_to_ah_beneficiary_id = AssetHubKusamaReceiver::get(); + // Penpal to AH test args let penpal_to_ah_test_args = TestContext { sender: PenpalASender::get(), @@ -612,8 +490,14 @@ 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 = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + system_para_native_asset_location.clone(), + &PenpalASender::get(), + ) + }); - let penpal_sender_balance_before = penpal_to_ah.sender.balance; let ah_receiver_balance_before = penpal_to_ah.receiver.balance; let penpal_sender_assets_before = PenpalA::execute_with(|| { @@ -623,17 +507,24 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { let ah_receiver_assets_before = AssetHubKusama::execute_with(|| { type Assets = ::ForeignAssets; >::balance( - foreign_asset_at_asset_hub_kusama, + foreign_asset_at_asset_hub_kusama.clone().try_into().unwrap(), &AssetHubKusamaReceiver::get(), ) }); penpal_to_ah.set_assertion::(penpal_to_ah_foreign_assets_sender_assertions); penpal_to_ah.set_assertion::(penpal_to_ah_foreign_assets_receiver_assertions); - penpal_to_ah.set_dispatchable::(para_to_system_para_transfer_assets); + penpal_to_ah.set_dispatchable::(para_to_ah_dispatchable); 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.clone(), + &PenpalASender::get(), + ) + }); + let ah_receiver_balance_after = penpal_to_ah.receiver.balance; let penpal_sender_assets_after = PenpalA::execute_with(|| { @@ -643,7 +534,7 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { let ah_receiver_assets_after = AssetHubKusama::execute_with(|| { type Assets = ::ForeignAssets; >::balance( - foreign_asset_at_asset_hub_kusama, + foreign_asset_at_asset_hub_kusama.clone().try_into().unwrap(), &AssetHubKusamaReceiver::get(), ) }); @@ -671,19 +562,17 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { type ForeignAssets = ::ForeignAssets; assert_ok!(ForeignAssets::transfer( ::RuntimeOrigin::signed(AssetHubKusamaReceiver::get()), - foreign_asset_at_asset_hub_kusama, + foreign_asset_at_asset_hub_kusama.clone().try_into().unwrap(), AssetHubKusamaSender::get().into(), asset_amount_to_send, )); }); - let foreign_asset_at_asset_hub_kusama_latest: Location = - foreign_asset_at_asset_hub_kusama.try_into().unwrap(); let ah_to_penpal_beneficiary_id = PenpalAReceiver::get(); let penpal_as_seen_by_ah = AssetHubKusama::sibling_location_of(PenpalA::para_id()); let ah_assets: Assets = vec![ (Parent, fee_amount_to_send).into(), - (foreign_asset_at_asset_hub_kusama_latest, asset_amount_to_send).into(), + (foreign_asset_at_asset_hub_kusama.clone(), asset_amount_to_send).into(), ] .into(); let fee_asset_index = ah_assets @@ -708,12 +597,18 @@ 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.clone(), + &PenpalAReceiver::get(), + ) + }); let ah_sender_assets_before = AssetHubKusama::execute_with(|| { type ForeignAssets = ::ForeignAssets; >::balance( - foreign_asset_at_asset_hub_kusama, + foreign_asset_at_asset_hub_kusama.clone().try_into().unwrap(), &AssetHubKusamaSender::get(), ) }); @@ -724,16 +619,22 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { ah_to_penpal.set_assertion::(ah_to_penpal_foreign_assets_sender_assertions); ah_to_penpal.set_assertion::(ah_to_penpal_foreign_assets_receiver_assertions); - ah_to_penpal.set_dispatchable::(system_para_to_para_transfer_assets); + ah_to_penpal.set_dispatchable::(ah_to_para_dispatchable); 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 = AssetHubKusama::execute_with(|| { type ForeignAssets = ::ForeignAssets; >::balance( - foreign_asset_at_asset_hub_kusama, + foreign_asset_at_asset_hub_kusama.try_into().unwrap(), &AssetHubKusamaSender::get(), ) }); @@ -756,3 +657,13 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { // Receiver's balance is increased by exact amount assert_eq!(penpal_receiver_assets_after, penpal_receiver_assets_before + asset_amount_to_send); } + +/// Bidirectional teleports of local Penpal assets to Asset Hub as foreign assets should work +/// (using native reserve-based transfer for fees) +#[test] +fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { + do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt( + para_to_system_para_transfer_assets, + system_para_to_para_transfer_assets, + ); +} diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/lib.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/lib.rs index 786d0b15f4..be401c5145 100644 --- a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/lib.rs +++ b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/lib.rs @@ -30,10 +30,12 @@ pub use xcm::{ prelude::{AccountId32 as AccountId32Junction, *}, v3::{self, Error, NetworkId::Polkadot as PolkadotId}, }; +pub use xcm_executor::traits::TransferType; // 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, @@ -41,17 +43,21 @@ pub use emulated_integration_tests_common::{ xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, }; -pub use integration_tests_helpers::test_sibling_is_trusted_teleporter; pub use parachains_common::{AccountId, Balance}; +pub use polkadot_runtime::xcm_config::UniversalLocation as PolkadotUniversalLocation; pub use polkadot_system_emulated_network::{ asset_hub_polkadot_emulated_chain::{ - genesis::ED as ASSET_HUB_POLKADOT_ED, AssetHubPolkadotParaPallet as AssetHubPolkadotPallet, + genesis::{AssetHubPolkadotAssetOwner, ED as ASSET_HUB_POLKADOT_ED}, + AssetHubPolkadotParaPallet as AssetHubPolkadotPallet, }, collectives_polkadot_emulated_chain::{ genesis::ED as COLLECTIVES_POLKADOT_ED, CollectivesPolkadotParaPallet as CollectivesPolkadotPallet, }, - penpal_emulated_chain::PenpalBParaPallet as PenpalBPallet, + penpal_emulated_chain::{ + CustomizableAssetFromSystemAssetHub, PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner, + PenpalBParaPallet as PenpalBPallet, ED as PENPAL_ED, + }, polkadot_emulated_chain::{genesis::ED as POLKADOT_ED, PolkadotRelayPallet as PolkadotPallet}, AssetHubPolkadotPara as AssetHubPolkadot, AssetHubPolkadotParaReceiver as AssetHubPolkadotReceiver, @@ -65,7 +71,7 @@ pub use polkadot_system_emulated_network::{ PolkadotRelayReceiver as PolkadotReceiver, PolkadotRelaySender as PolkadotSender, }; -pub const ASSET_ID: u32 = 1; +pub const ASSET_ID: u32 = 3; pub const ASSET_MIN_BALANCE: u128 = 1000; // `Assets` pallet index pub const ASSETS_PALLET_ID: u8 = 50; @@ -75,7 +81,9 @@ pub type RelayToParaTest = Test; pub type SystemParaToRelayTest = Test; pub type SystemParaToParaTest = Test; pub type ParaToSystemParaTest = Test; -pub type ParaToParaTest = Test; +pub type ParaToParaThroughRelayTest = Test; +pub type ParaToParaThroughAHTest = Test; +pub type RelayToParaThroughAHTest = Test; #[cfg(test)] mod tests; diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/hybrid_transfers.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/hybrid_transfers.rs new file mode 100644 index 0000000000..e17cb07583 --- /dev/null +++ b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/hybrid_transfers.rs @@ -0,0 +1,815 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::reserve_transfer::*; +use crate::{ + tests::teleport::do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt, + *, +}; +use asset_hub_polkadot_runtime::xcm_config::DotLocation; + +fn para_to_para_assethub_hop_assertions(t: ParaToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + let sov_penpal_a_on_ah = AssetHubPolkadot::sovereign_account_id_of( + AssetHubPolkadot::sibling_location_of(PenpalB::para_id()), + ); + let sov_penpal_b_on_ah = AssetHubPolkadot::sovereign_account_id_of( + AssetHubPolkadot::sibling_location_of(PenpalA::para_id()), + ); + + assert_expected_events!( + AssetHubPolkadot, + vec![ + // Withdrawn from sender parachain SA + RuntimeEvent::Balances( + pallet_balances::Event::Burned { who, amount } + ) => { + who: *who == sov_penpal_a_on_ah, + amount: *amount == t.args.amount, + }, + // Deposited to receiver parachain SA + RuntimeEvent::Balances( + pallet_balances::Event::Minted { who, .. } + ) => { + who: *who == sov_penpal_b_on_ah, + }, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); +} + +fn ah_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { + let fee_idx = t.args.fee_asset_item as usize; + let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.assets.into()), + bx!(TransferType::LocalReserve), + bx!(fee.id.into()), + bx!(TransferType::LocalReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), + t.args.weight_limit, + ) +} + +fn para_to_ah_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { + let fee_idx = t.args.fee_asset_item as usize; + let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.assets.into()), + bx!(TransferType::DestinationReserve), + bx!(fee.id.into()), + bx!(TransferType::DestinationReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), + t.args.weight_limit, + ) +} + +fn para_to_para_transfer_assets_through_ah(t: ParaToParaThroughAHTest) -> DispatchResult { + let fee_idx = t.args.fee_asset_item as usize; + let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); + let asset_hub_location: Location = PenpalB::sibling_location_of(AssetHubPolkadot::para_id()); + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.assets.into()), + bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), + bx!(fee.id.into()), + bx!(TransferType::RemoteReserve(asset_hub_location.into())), + bx!(VersionedXcm::from(custom_xcm_on_dest)), + t.args.weight_limit, + ) +} + +fn para_to_asset_hub_teleport_foreign_assets(t: ParaToSystemParaTest) -> DispatchResult { + let fee_idx = t.args.fee_asset_item as usize; + let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.assets.into()), + bx!(TransferType::Teleport), + bx!(fee.id.into()), + bx!(TransferType::DestinationReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), + t.args.weight_limit, + ) +} + +fn asset_hub_to_para_teleport_foreign_assets(t: SystemParaToParaTest) -> DispatchResult { + let fee_idx = t.args.fee_asset_item as usize; + let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.assets.into()), + bx!(TransferType::Teleport), + bx!(fee.id.into()), + bx!(TransferType::LocalReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), + t.args.weight_limit, + ) +} + +// =========================================================================== +// ======= Transfer - Native + Bridged Assets - AssetHub->Parachain ========== +// =========================================================================== +/// Transfers of native asset plus bridged asset from AssetHub to some Parachain +/// while paying fees using native asset. +#[test] +fn transfer_foreign_assets_from_asset_hub_to_para() { + let destination = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); + let sender = AssetHubPolkadotSender::get(); + let native_amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 10000; + let native_asset_location = DotLocation::get(); + let receiver = PenpalBReceiver::get(); + let assets_owner = PenpalAssetOwner::get(); + // Foreign asset used: bridged WND + let foreign_amount_to_send = ASSET_HUB_POLKADOT_ED * 10_000_000; + let wnd_at_rococo_parachains = + Location::new(2, [Junction::GlobalConsensus(NetworkId::Westend)]); + + // Configure destination chain to trust AH as reserve of WND + PenpalB::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + CustomizableAssetFromSystemAssetHub::key().to_vec(), + Location::new(2, [GlobalConsensus(Westend)]).encode(), + )], + )); + }); + PenpalB::force_create_foreign_asset( + wnd_at_rococo_parachains.clone(), + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + AssetHubPolkadot::force_create_foreign_asset( + wnd_at_rococo_parachains.clone().try_into().unwrap(), + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + AssetHubPolkadot::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner), + wnd_at_rococo_parachains.clone().try_into().unwrap(), + sender.clone(), + foreign_amount_to_send * 2, + ); + + // Assets to send + let assets: Vec = vec![ + (Parent, native_amount_to_send).into(), + (wnd_at_rococo_parachains.clone(), foreign_amount_to_send).into(), + ]; + let fee_asset_id = AssetId(Parent.into()); + let fee_asset_item = assets.iter().position(|a| a.id == fee_asset_id).unwrap() as u32; + + // Init Test + let test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para( + destination.clone(), + receiver.clone(), + native_amount_to_send, + assets.into(), + None, + fee_asset_item, + ), + }; + let mut test = SystemParaToParaTest::new(test_args); + + // Query initial balances + let sender_balance_before = test.sender.balance; + let sender_wnds_before = AssetHubPolkadot::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + wnd_at_rococo_parachains.clone().try_into().unwrap(), + &sender, + ) + }); + let receiver_assets_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(native_asset_location.clone(), &receiver) + }); + let receiver_wnds_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains.clone(), &receiver) + }); + + // Set assertions and dispatchables + test.set_assertion::(system_para_to_para_sender_assertions); + test.set_assertion::(system_para_to_para_receiver_assertions); + test.set_dispatchable::(ah_to_para_transfer_assets); + test.assert(); + + // Query final balances + let sender_balance_after = test.sender.balance; + let sender_wnds_after = AssetHubPolkadot::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + wnd_at_rococo_parachains.clone().try_into().unwrap(), + &sender, + ) + }); + let receiver_assets_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(native_asset_location, &receiver) + }); + let receiver_wnds_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &receiver) + }); + + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_balance_after < sender_balance_before - native_amount_to_send); + // Sender's balance is reduced by foreign amount sent + assert_eq!(sender_wnds_after, sender_wnds_before - foreign_amount_to_send); + // 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_assets_after < receiver_assets_before + native_amount_to_send); + // Receiver's balance is increased by foreign amount sent + assert_eq!(receiver_wnds_after, receiver_wnds_before + foreign_amount_to_send); +} + +/// Reserve Transfers of native asset from Parachain to System Parachain should work +// =========================================================================== +// ======= Transfer - Native + Bridged Assets - Parachain->AssetHub ========== +// =========================================================================== +/// Transfers of native asset plus bridged asset from some Parachain to AssetHub +/// while paying fees using native asset. +#[test] +fn transfer_foreign_assets_from_para_to_asset_hub() { + // Init values for Parachain + let destination = PenpalB::sibling_location_of(AssetHubPolkadot::para_id()); + let sender = PenpalBSender::get(); + let native_amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 10000; + let native_asset_location = DotLocation::get(); + let assets_owner = PenpalAssetOwner::get(); + + // Foreign asset used: bridged WND + let foreign_amount_to_send = ASSET_HUB_POLKADOT_ED * 10_000_000; + let wnd_at_rococo_parachains = + Location::new(2, [Junction::GlobalConsensus(NetworkId::Westend)]); + + // Configure destination chain to trust AH as reserve of WND + PenpalB::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + CustomizableAssetFromSystemAssetHub::key().to_vec(), + Location::new(2, [GlobalConsensus(Westend)]).encode(), + )], + )); + }); + PenpalB::force_create_foreign_asset( + wnd_at_rococo_parachains.clone(), + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + AssetHubPolkadot::force_create_foreign_asset( + wnd_at_rococo_parachains.clone().try_into().unwrap(), + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + + // fund Parachain's sender account + PenpalB::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner.clone()), + native_asset_location.clone(), + sender.clone(), + native_amount_to_send * 2, + ); + PenpalB::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner.clone()), + wnd_at_rococo_parachains.clone(), + sender.clone(), + foreign_amount_to_send * 2, + ); + + // Init values for System Parachain + let receiver = AssetHubPolkadotReceiver::get(); + let penpal_location_as_seen_by_ahr = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); + let sov_penpal_on_ahr = + AssetHubPolkadot::sovereign_account_id_of(penpal_location_as_seen_by_ahr); + + // fund Parachain's SA on AssetHub with the assets held in reserve + AssetHubPolkadot::fund_accounts(vec![( + sov_penpal_on_ahr.clone().into(), + native_amount_to_send * 2, + )]); + AssetHubPolkadot::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner), + wnd_at_rococo_parachains.clone().try_into().unwrap(), + sov_penpal_on_ahr, + foreign_amount_to_send * 2, + ); + + // Assets to send + let assets: Vec = vec![ + (Parent, native_amount_to_send).into(), + (wnd_at_rococo_parachains.clone(), foreign_amount_to_send).into(), + ]; + let fee_asset_id = AssetId(Parent.into()); + let fee_asset_item = assets.iter().position(|a| a.id == fee_asset_id).unwrap() as u32; + + // Init Test + let test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para( + destination.clone(), + receiver.clone(), + native_amount_to_send, + assets.into(), + None, + fee_asset_item, + ), + }; + let mut test = ParaToSystemParaTest::new(test_args); + + // Query initial balances + let sender_native_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(native_asset_location.clone(), &sender) + }); + let sender_wnds_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains.clone(), &sender) + }); + let receiver_native_before = test.receiver.balance; + let receiver_wnds_before = AssetHubPolkadot::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + wnd_at_rococo_parachains.clone().try_into().unwrap(), + &receiver, + ) + }); + + // 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_ah_transfer_assets); + test.assert(); + + // Query final balances + let sender_native_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(native_asset_location, &sender) + }); + let sender_wnds_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains.clone(), &sender) + }); + let receiver_native_after = test.receiver.balance; + let receiver_wnds_after = AssetHubPolkadot::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + wnd_at_rococo_parachains.try_into().unwrap(), + &receiver, + ) + }); + + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_native_after < sender_native_before - native_amount_to_send); + // Sender's balance is reduced by foreign amount sent + assert_eq!(sender_wnds_after, sender_wnds_before - foreign_amount_to_send); + // Receiver's balance is increased + assert!(receiver_native_after > receiver_native_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_native_after < receiver_native_before + native_amount_to_send); + // Receiver's balance is increased by foreign amount sent + assert_eq!(receiver_wnds_after, receiver_wnds_before + foreign_amount_to_send); +} + +// ============================================================================== +// ===== Transfer - Native + Bridged Assets - Parachain->AssetHub->Parachain ==== +// ============================================================================== +/// Transfers of native asset plus bridged asset from Parachain to Parachain +/// (through AssetHub reserve) with fees paid using native asset. +#[test] +fn transfer_foreign_assets_from_para_to_para_through_asset_hub() { + // Init values for Parachain Origin + let destination = PenpalB::sibling_location_of(PenpalA::para_id()); + let sender = PenpalBSender::get(); + let roc_to_send: Balance = POLKADOT_ED * 10000; + let assets_owner = PenpalAssetOwner::get(); + let roc_location = DotLocation::get(); + let sender_as_seen_by_ah = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); + let sov_of_sender_on_ah = AssetHubPolkadot::sovereign_account_id_of(sender_as_seen_by_ah); + let receiver_as_seen_by_ah = AssetHubPolkadot::sibling_location_of(PenpalA::para_id()); + let sov_of_receiver_on_ah = AssetHubPolkadot::sovereign_account_id_of(receiver_as_seen_by_ah); + let wnd_to_send = ASSET_HUB_POLKADOT_ED * 10_000_000; + + // Configure destination chain to trust AH as reserve of WND + PenpalA::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + CustomizableAssetFromSystemAssetHub::key().to_vec(), + Location::new(2, [GlobalConsensus(Westend)]).encode(), + )], + )); + }); + + // Register WND as foreign asset and transfer it around the Polkadot ecosystem + let wnd_at_rococo_parachains = + Location::new(2, [Junction::GlobalConsensus(NetworkId::Westend)]); + AssetHubPolkadot::force_create_foreign_asset( + wnd_at_rococo_parachains.clone().try_into().unwrap(), + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + PenpalB::force_create_foreign_asset( + wnd_at_rococo_parachains.clone(), + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + PenpalA::force_create_foreign_asset( + wnd_at_rococo_parachains.clone(), + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + + // fund Parachain's sender account + PenpalB::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner.clone()), + roc_location.clone(), + sender.clone(), + roc_to_send * 2, + ); + PenpalB::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner.clone()), + wnd_at_rococo_parachains.clone(), + sender.clone(), + wnd_to_send * 2, + ); + // fund the Parachain Origin's SA on Asset Hub with the assets held in reserve + AssetHubPolkadot::fund_accounts(vec![(sov_of_sender_on_ah.clone().into(), roc_to_send * 2)]); + AssetHubPolkadot::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner), + wnd_at_rococo_parachains.clone().try_into().unwrap(), + sov_of_sender_on_ah.clone(), + wnd_to_send * 2, + ); + + // Init values for Parachain Destination + let receiver = PenpalAReceiver::get(); + + // Assets to send + let assets: Vec = vec![ + (roc_location.clone(), roc_to_send).into(), + (wnd_at_rococo_parachains.clone(), wnd_to_send).into(), + ]; + let fee_asset_id: AssetId = roc_location.clone().into(); + let fee_asset_item = assets.iter().position(|a| a.id == fee_asset_id).unwrap() as u32; + + // Init Test + let test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para( + destination, + receiver.clone(), + roc_to_send, + assets.into(), + None, + fee_asset_item, + ), + }; + let mut test = ParaToParaThroughAHTest::new(test_args); + + // Query initial balances + let sender_rocs_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_location.clone(), &sender) + }); + let sender_wnds_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains.clone(), &sender) + }); + let rocs_in_sender_reserve_on_ahr_before = + ::account_data_of(sov_of_sender_on_ah.clone()).free; + let wnds_in_sender_reserve_on_ahr_before = AssetHubPolkadot::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance( + wnd_at_rococo_parachains.clone().try_into().unwrap(), + &sov_of_sender_on_ah, + ) + }); + let rocs_in_receiver_reserve_on_ahr_before = + ::account_data_of(sov_of_receiver_on_ah.clone()).free; + let wnds_in_receiver_reserve_on_ahr_before = AssetHubPolkadot::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance( + wnd_at_rococo_parachains.clone().try_into().unwrap(), + &sov_of_receiver_on_ah, + ) + }); + let receiver_rocs_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_location.clone(), &receiver) + }); + let receiver_wnds_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains.clone(), &receiver) + }); + + // Set assertions and dispatchables + test.set_assertion::(para_to_para_through_hop_sender_assertions); + test.set_assertion::(para_to_para_assethub_hop_assertions); + test.set_assertion::(para_to_para_through_hop_receiver_assertions); + test.set_dispatchable::(para_to_para_transfer_assets_through_ah); + test.assert(); + + // Query final balances + let sender_rocs_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_location.clone(), &sender) + }); + let sender_wnds_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains.clone(), &sender) + }); + let wnds_in_sender_reserve_on_ahr_after = AssetHubPolkadot::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance( + wnd_at_rococo_parachains.clone().try_into().unwrap(), + &sov_of_sender_on_ah, + ) + }); + let rocs_in_sender_reserve_on_ahr_after = + ::account_data_of(sov_of_sender_on_ah).free; + let wnds_in_receiver_reserve_on_ahr_after = AssetHubPolkadot::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance( + wnd_at_rococo_parachains.clone().try_into().unwrap(), + &sov_of_receiver_on_ah, + ) + }); + let rocs_in_receiver_reserve_on_ahr_after = + ::account_data_of(sov_of_receiver_on_ah).free; + let receiver_rocs_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_location, &receiver) + }); + let receiver_wnds_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &receiver) + }); + + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_rocs_after < sender_rocs_before - roc_to_send); + assert_eq!(sender_wnds_after, sender_wnds_before - wnd_to_send); + // Sovereign accounts on reserve are changed accordingly + assert_eq!( + rocs_in_sender_reserve_on_ahr_after, + rocs_in_sender_reserve_on_ahr_before - roc_to_send + ); + assert_eq!( + wnds_in_sender_reserve_on_ahr_after, + wnds_in_sender_reserve_on_ahr_before - wnd_to_send + ); + assert!(rocs_in_receiver_reserve_on_ahr_after > rocs_in_receiver_reserve_on_ahr_before); + assert_eq!( + wnds_in_receiver_reserve_on_ahr_after, + wnds_in_receiver_reserve_on_ahr_before + wnd_to_send + ); + // Receiver's balance is increased + assert!(receiver_rocs_after > receiver_rocs_before); + assert_eq!(receiver_wnds_after, receiver_wnds_before + wnd_to_send); +} + +// ============================================================================================== +// ==== Bidirectional Transfer - Native + Teleportable Foreign Assets - Parachain<->AssetHub ==== +// ============================================================================================== +/// Transfers of native asset plus teleportable foreign asset from Parachain to AssetHub and back +/// with fees paid using native asset. +#[test] +fn bidirectional_teleport_foreign_asset_between_para_and_asset_hub_using_explicit_transfer_types() { + do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt( + para_to_asset_hub_teleport_foreign_assets, + asset_hub_to_para_teleport_foreign_assets, + ); +} + +// =============================================================== +// ===== Transfer - Native Asset - Relay->AssetHub->Parachain ==== +// =============================================================== +/// Transfers of native asset Relay to Parachain (using AssetHub reserve). Parachains want to avoid +/// managing SAs on all system chains, thus want all their DOT-in-reserve to be held in their +/// Sovereign Account on Asset Hub. +#[test] +fn transfer_native_asset_from_relay_to_para_through_asset_hub() { + // Init values for Relay + let destination = Polkadot::child_location_of(PenpalB::para_id()); + let sender = PolkadotSender::get(); + let amount_to_send: Balance = POLKADOT_ED * 1000; + + // Init values for Parachain + let relay_native_asset_location = DotLocation::get(); + let receiver = PenpalBReceiver::get(); + + // Init Test + let test_args = TestContext { + sender, + receiver: receiver.clone(), + args: TestArgs::new_relay(destination.clone(), receiver.clone(), amount_to_send), + }; + let mut test = RelayToParaThroughAHTest::new(test_args); + + let sov_penpal_on_ah = AssetHubPolkadot::sovereign_account_id_of( + AssetHubPolkadot::sibling_location_of(PenpalB::para_id()), + ); + // Query initial balances + let sender_balance_before = test.sender.balance; + let sov_penpal_on_ah_before = AssetHubPolkadot::execute_with(|| { + ::Balances::free_balance( + sov_penpal_on_ah.clone(), + ) + }); + let receiver_assets_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &receiver) + }); + + fn relay_assertions(t: RelayToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + Polkadot::assert_xcm_pallet_attempted_complete(None); + assert_expected_events!( + Polkadot, + vec![ + // Amount to teleport is withdrawn from Sender + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { + who: *who == t.sender.account_id, + amount: *amount == t.args.amount, + }, + // Amount to teleport is deposited in Relay's `CheckAccount` + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) => { + who: *who == ::XcmPallet::check_account(), + amount: *amount == t.args.amount, + }, + ] + ); + } + fn asset_hub_assertions(_: RelayToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + let sov_penpal_on_ah = AssetHubPolkadot::sovereign_account_id_of( + AssetHubPolkadot::sibling_location_of(PenpalB::para_id()), + ); + assert_expected_events!( + AssetHubPolkadot, + vec![ + // Deposited to receiver parachain SA + RuntimeEvent::Balances( + pallet_balances::Event::Minted { who, .. } + ) => { + who: *who == sov_penpal_on_ah, + }, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + } + fn penpal_assertions(t: RelayToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + let expected_id = + t.args.assets.into_inner().first().unwrap().id.0.clone().try_into().unwrap(); + assert_expected_events!( + PenpalB, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == expected_id, + owner: *owner == t.receiver.account_id, + }, + ] + ); + } + fn transfer_assets_dispatchable(t: RelayToParaThroughAHTest) -> DispatchResult { + let fee_idx = t.args.fee_asset_item as usize; + let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); + let asset_hub_location = Polkadot::child_location_of(AssetHubPolkadot::para_id()); + let context = PolkadotUniversalLocation::get(); + + // reanchor fees to the view of destination (Penpal) + let mut remote_fees = fee.clone().reanchored(&t.args.dest, &context).unwrap(); + if let Fungible(ref mut amount) = remote_fees.fun { + // we already spent some fees along the way, just use half of what we started with + *amount = *amount / 2; + } + let xcm_on_final_dest = Xcm::<()>(vec![ + BuyExecution { fees: remote_fees, weight_limit: t.args.weight_limit.clone() }, + DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }, + ]); + + // reanchor final dest (Penpal) to the view of hop (Asset Hub) + let mut dest = t.args.dest.clone(); + dest.reanchor(&asset_hub_location, &context).unwrap(); + // on Asset Hub, forward assets to Penpal + let xcm_on_hop = Xcm::<()>(vec![DepositReserveAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + dest, + xcm: xcm_on_final_dest, + }]); + + // First leg is a teleport, from there a local-reserve-transfer to final dest + ::XcmPallet::transfer_assets_using_type_and_then( + t.signed_origin, + bx!(asset_hub_location.into()), + bx!(t.args.assets.into()), + bx!(TransferType::Teleport), + bx!(fee.id.into()), + bx!(TransferType::Teleport), + bx!(VersionedXcm::from(xcm_on_hop)), + t.args.weight_limit, + ) + } + + // Set assertions and dispatchables + test.set_assertion::(relay_assertions); + test.set_assertion::(asset_hub_assertions); + test.set_assertion::(penpal_assertions); + test.set_dispatchable::(transfer_assets_dispatchable); + test.assert(); + + // Query final balances + let sender_balance_after = test.sender.balance; + let sov_penpal_on_ah_after = AssetHubPolkadot::execute_with(|| { + ::Balances::free_balance(sov_penpal_on_ah) + }); + let receiver_assets_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location, &receiver) + }); + + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_balance_after < sender_balance_before - amount_to_send); + // SA on AH balance is increased + assert!(sov_penpal_on_ah_after > sov_penpal_on_ah_before); + // 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_assets_after < receiver_assets_before + amount_to_send); +} diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/mod.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/mod.rs index 42c5414a2b..564257ab0d 100644 --- a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/mod.rs +++ b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/mod.rs @@ -15,19 +15,10 @@ mod claim_assets; mod fellowship_treasury; +mod hybrid_transfers; mod reserve_transfer; mod send; mod set_xcm_versions; mod swap; mod teleport; mod treasury; - -use crate::*; -// FAIL-CI @branislav -/*emulated_integration_tests_common::include_penpal_create_foreign_asset_on_asset_hub!( - PenpalB, - AssetHubPolkadot, - POLKADOT_ED, - system_parachains_constants::polkadot::fee::WeightToFee -); -*/ diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/reserve_transfer.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/reserve_transfer.rs index 741c661bf0..79cb11bd7c 100644 --- a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/reserve_transfer.rs +++ b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/reserve_transfer.rs @@ -14,9 +14,9 @@ // limitations under the License. use crate::*; -use asset_hub_polkadot_runtime::xcm_config::XcmConfig as AssetHubPolkadotXcmConfig; -use polkadot_runtime::xcm_config::XcmConfig as PolkadotXcmConfig; -use polkadot_system_emulated_network::penpal_emulated_chain::XcmConfig as PenpalPolkadotXcmConfig; +use asset_hub_polkadot_runtime::xcm_config::DotLocation; +use emulated_integration_tests_common::RESERVABLE_ASSET_ID; +use polkadot_system_emulated_network::penpal_emulated_chain::LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub; fn relay_to_para_sender_assertions(t: RelayToParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -39,7 +39,7 @@ fn relay_to_para_sender_assertions(t: RelayToParaTest) { ); } -fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { +pub fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; AssetHubPolkadot::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( 676_119_000, @@ -63,12 +63,34 @@ fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { ); } -fn para_receiver_assertions(_: Test) { +pub fn system_para_to_para_receiver_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; + + PenpalB::assert_xcmp_queue_success(None); + for asset in t.args.assets.into_inner().into_iter() { + let expected_id = asset.id.0.try_into().unwrap(); + assert_expected_events!( + PenpalB, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == expected_id, + owner: *owner == t.receiver.account_id, + }, + ] + ); + } +} + +fn relay_to_para_assets_receiver_assertions(t: RelayToParaTest) { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( PenpalB, vec![ - RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == DotLocation::get(), + owner: *owner == t.receiver.account_id, + }, RuntimeEvent::MessageQueue( pallet_message_queue::Event::Processed { success: true, .. } ) => {}, @@ -76,25 +98,29 @@ fn para_receiver_assertions(_: Test) { ); } -fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { +pub fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; - PenpalB::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799))); - assert_expected_events!( - PenpalB, - vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { who, amount } - ) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, - }, - ] - ); + PenpalB::assert_xcm_pallet_attempted_complete(None); + for asset in t.args.assets.into_inner().into_iter() { + let expected_id = asset.id.0; + let asset_amount = if let Fungible(a) = asset.fun { Some(a) } else { None }.unwrap(); + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, balance } + ) => { + asset_id: *asset_id == expected_id, + owner: *owner == t.sender.account_id, + balance: *balance == asset_amount, + }, + ] + ); + } } -fn para_to_system_para_receiver_assertions(t: ParaToSystemParaTest) { +pub fn para_to_system_para_receiver_assertions(t: ParaToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; let sov_penpal_on_ahp = AssetHubPolkadot::sovereign_account_id_of( AssetHubPolkadot::sibling_location_of(PenpalB::para_id()), @@ -143,42 +169,51 @@ fn system_para_to_para_assets_sender_assertions(t: SystemParaToParaTest) { ); } -fn system_para_to_para_assets_receiver_assertions(_: Test) { +fn system_para_to_para_assets_receiver_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - PenpalB, - vec![ - RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, - RuntimeEvent::Assets(pallet_assets::Event::Issued { .. }) => {}, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); -} -fn para_to_para_sender_assertions(t: ParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - PenpalA::assert_xcm_pallet_attempted_complete(None); + let system_para_asset_location = PenpalLocalReservableFromAssetHub::get(); + PenpalB::assert_xcmp_queue_success(None); assert_expected_events!( PenpalB, vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { who, amount } - ) => { - who: *who == t.sender.account_id, + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == DotLocation::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, }, - // XCM sent to relay reserve - RuntimeEvent::ParachainSystem( - cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } - ) => {}, ] ); } -fn para_to_para_relay_hop_assertions(t: ParaToParaTest) { +pub fn para_to_para_through_hop_sender_assertions(t: Test) { + type RuntimeEvent = ::RuntimeEvent; + + PenpalB::assert_xcm_pallet_attempted_complete(None); + for asset in t.args.assets.into_inner() { + let expected_id = asset.id.0.clone().try_into().unwrap(); + let amount = if let Fungible(a) = asset.fun { Some(a) } else { None }.unwrap(); + assert_expected_events!( + PenpalB, + 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 == expected_id, + owner: *owner == t.sender.account_id, + balance: *balance == amount, + }, + ] + ); + } +} + +fn para_to_para_relay_hop_assertions(t: ParaToParaThroughRelayTest) { type RuntimeEvent = ::RuntimeEvent; let sov_penpal_a_on_polkadot = Polkadot::sovereign_account_id_of(Polkadot::child_location_of(PenpalA::para_id())); @@ -207,17 +242,22 @@ fn para_to_para_relay_hop_assertions(t: ParaToParaTest) { ); } -fn para_to_para_receiver_assertions(_: ParaToParaTest) { +pub fn para_to_para_through_hop_receiver_assertions(t: Test) { type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - PenpalA, - vec![ - RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); + + PenpalA::assert_xcmp_queue_success(None); + for asset in t.args.assets.into_inner().into_iter() { + let expected_id = asset.id.0.try_into().unwrap(); + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == expected_id, + owner: *owner == t.receiver.account_id, + }, + ] + ); + } } fn relay_to_para_reserve_transfer_assets(t: RelayToParaTest) -> DispatchResult { @@ -253,7 +293,9 @@ 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()), @@ -338,42 +380,49 @@ 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 = Polkadot::child_location_of(PenpalB::para_id()); - let beneficiary_id = PenpalBReceiver::get(); + let sender = PolkadotSender::get(); let amount_to_send: Balance = POLKADOT_ED * 1000; + // Init values for Parachain + let relay_native_asset_location = DotLocation::get(); + let receiver = PenpalBReceiver::get(); + + // Init Test let test_args = TestContext { - sender: PolkadotSender::get(), - receiver: PenpalBReceiver::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 = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &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(); - let delivery_fees = Polkadot::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 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 = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_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`; + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_balance_after < sender_balance_before - amount_to_send); + // 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 @@ -381,88 +430,125 @@ 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 = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); - let beneficiary_id = PenpalBReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; - let assets = (Parent, amount_to_send).into(); + let sender = AssetHubPolkadotSender::get(); + let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 10000; + let assets: Assets = (Parent, amount_to_send).into(); + // Init values for Parachain + let system_para_native_asset_location = DotLocation::get(); + let receiver = PenpalBReceiver::get(); + + // Init Test let test_args = TestContext { - sender: AssetHubPolkadotSender::get(), - receiver: PenpalBReceiver::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 = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location.clone(), &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_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; - - let delivery_fees = AssetHubPolkadot::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + let receiver_assets_after = PenpalB::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`; + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_balance_after < sender_balance_before - amount_to_send); + // 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 = PenpalB::sibling_location_of(AssetHubPolkadot::para_id()); - let beneficiary_id = AssetHubPolkadotReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; - let assets = (Parent, amount_to_send).into(); + let sender = PenpalBSender::get(); + let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 10000; + let assets: Assets = (Parent, amount_to_send).into(); + let system_para_native_asset_location = DotLocation::get(); + let asset_owner = PenpalAssetOwner::get(); + + // fund Parachain's sender account + PenpalB::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner), + system_para_native_asset_location.clone(), + sender.clone(), + amount_to_send * 2, + ); + // Init values for System Parachain + let receiver = AssetHubPolkadotReceiver::get(); + let penpal_location_as_seen_by_ahr = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); + let sov_penpal_on_ahr = + AssetHubPolkadot::sovereign_account_id_of(penpal_location_as_seen_by_ahr); + + // fund Parachain's SA on System Parachain with the native tokens held in reserve + AssetHubPolkadot::fund_accounts(vec![(sov_penpal_on_ahr.into(), amount_to_send * 2)]); + + // Init Test let test_args = TestContext { - sender: PenpalBSender::get(), - receiver: AssetHubPolkadotReceiver::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 = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location.clone(), &sender) + }); let receiver_balance_before = test.receiver.balance; - let penpal_location_as_seen_by_ahp = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); - let sov_penpal_on_ahp = - AssetHubPolkadot::sovereign_account_id_of(penpal_location_as_seen_by_ahp); - - // fund the Penpal's SA on AHP with the native tokens held in reserve - AssetHubPolkadot::fund_accounts(vec![(sov_penpal_on_ahp, 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; - - let delivery_fees = PenpalB::execute_with(|| { - xcm_helpers::teleport_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 = PenpalB::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); + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_assets_after < sender_assets_before - amount_to_send); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; @@ -475,53 +561,183 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { /// work #[test] fn reserve_transfer_assets_from_system_para_to_para() { - // FAIL-CI @clara pls fix + // Init values for System Parachain + let destination = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); + let sov_penpal_on_ahr = AssetHubPolkadot::sovereign_account_id_of(destination.clone()); + let sender = AssetHubPolkadotSender::get(); + let fee_amount_to_send = ASSET_HUB_POLKADOT_ED * 10000; + let asset_amount_to_send = PENPAL_ED * 10000; + let asset_owner = AssetHubPolkadotAssetOwner::get(); + let asset_owner_signer = + ::RuntimeOrigin::signed(asset_owner.clone()); + let assets: Assets = vec![ + (Parent, fee_amount_to_send).into(), + ( + [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(RESERVABLE_ASSET_ID.into())], + asset_amount_to_send, + ) + .into(), + ] + .into(); + let fee_asset_index = assets + .inner() + .iter() + .position(|r| r == &(Parent, fee_amount_to_send).into()) + .unwrap() as u32; + AssetHubPolkadot::mint_asset( + asset_owner_signer, + RESERVABLE_ASSET_ID, + asset_owner, + asset_amount_to_send * 2, + ); + + // Create SA-of-Penpal-on-AHR with ED. + AssetHubPolkadot::fund_accounts(vec![(sov_penpal_on_ahr.into(), ASSET_HUB_POLKADOT_ED)]); + + // Init values for Parachain + let receiver = PenpalBReceiver::get(); + let system_para_native_asset_location = DotLocation::get(); + let system_para_foreign_asset_location = PenpalLocalReservableFromAssetHub::get(); + + // Init Test + let para_test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para( + destination, + receiver.clone(), + asset_amount_to_send, + assets, + None, + fee_asset_index, + ), + }; + let mut test = SystemParaToParaTest::new(para_test_args); + + // Query initial balances + let sender_balance_before = test.sender.balance; + let sender_assets_before = AssetHubPolkadot::execute_with(|| { + type Assets = ::Assets; + >::balance(RESERVABLE_ASSET_ID, &sender) + }); + let receiver_system_native_assets_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location.clone(), &receiver) + }); + let receiver_foreign_assets_before = PenpalB::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 sender_assets_after = AssetHubPolkadot::execute_with(|| { + type Assets = ::Assets; + >::balance(RESERVABLE_ASSET_ID, &sender) + }); + let receiver_system_native_assets_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location.clone(), &receiver) + }); + let receiver_foreign_assets_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_foreign_asset_location, &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 asset balance is reduced by exact amount + assert_eq!(sender_assets_before - asset_amount_to_send, sender_assets_after); + // 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_through_relay() { + // Init values for Parachain Origin let destination = PenpalB::sibling_location_of(PenpalA::para_id()); - let beneficiary_id = PenpalAReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 10000; + let sender = PenpalBSender::get(); + let amount_to_send: Balance = POLKADOT_ED * 10000; + let asset_owner = PenpalAssetOwner::get(); let assets = (Parent, amount_to_send).into(); + let relay_native_asset_location = DotLocation::get(); + let sender_as_seen_by_relay = Polkadot::child_location_of(PenpalB::para_id()); + let sov_of_sender_on_relay = Polkadot::sovereign_account_id_of(sender_as_seen_by_relay); - let test_args = TestContext { - sender: PenpalBSender::get(), - receiver: PenpalAReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; + // fund Parachain's sender account + PenpalB::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner), + relay_native_asset_location.clone(), + sender.clone(), + amount_to_send * 2, + ); - let mut test = ParaToParaTest::new(test_args); + // fund the Parachain Origin's SA on Relay Chain with the native tokens held in reserve + Polkadot::fund_accounts(vec![(sov_of_sender_on_relay.into(), amount_to_send * 2)]); - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; + // Init values for Parachain Destination + let receiver = PenpalAReceiver::get(); - let sender_as_seen_by_relay = Polkadot::child_location_of(PenpalB::para_id()); - let sov_of_sender_on_relay = Polkadot::sovereign_account_id_of(sender_as_seen_by_relay); + // Init Test + let test_args = TestContext { + 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); - // fund the PenpalB's SA on Polkadot with the native tokens held in reserve - Polkadot::fund_accounts(vec![(sov_of_sender_on_relay, amount_to_send * 2)]); + // Query initial balances + let sender_assets_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &sender) + }); + let receiver_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &receiver) + }); - test.set_assertion::(para_to_para_sender_assertions); + // Set assertions and dispatchables + test.set_assertion::(para_to_para_through_hop_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.set_assertion::(para_to_para_through_hop_receiver_assertions); + test.set_dispatchable::(para_to_para_through_relay_limited_reserve_transfer_assets); test.assert(); - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - let delivery_fees = PenpalB::execute_with(|| { - xcm_helpers::teleport_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 = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &sender) + }); + let receiver_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location, &receiver) }); - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_assets_after < sender_assets_before - amount_to_send); // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); + assert!(receiver_assets_after > receiver_assets_before); } diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/swap.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/swap.rs index a040f79f5f..cb46e55b2d 100644 --- a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/swap.rs +++ b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/swap.rs @@ -132,42 +132,26 @@ fn swap_locally_on_chain_using_foreign_assets() { v3::Location::try_from(asset_hub_polkadot_runtime::xcm_config::DotLocation::get()) .expect("conversion works"), ); - - let ah_as_seen_by_penpal = PenpalB::sibling_location_of(AssetHubPolkadot::para_id()); let asset_location_on_penpal = v3::Location::try_from(PenpalLocalTeleportableToAssetHub::get()).expect("conversion works"); - 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 = PenpalBSender::get(); let foreign_asset_at_asset_hub_polkadot = - v3::Location::new(1, [v3::Junction::Parachain(PenpalB::para_id().into())]) + v3::Location::new(1, [v3::Junction::Parachain(PenpalA::para_id().into())]) .appended_with(asset_location_on_penpal) .unwrap(); - // 1. Create asset on penpal and, 2. Create foreign asset on asset_hub_polkadot - /* - // FAIL-CI @bkontur - super::penpal_create_foreign_asset_on_asset_hub( - asset_id_on_penpal, - foreign_asset_at_asset_hub_polkadot, - ah_as_seen_by_penpal, - true, - asset_owner_on_penpal, - ASSET_MIN_BALANCE * 1_000_000, - );*/ - - let penpal_as_seen_by_ah = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); - let sov_penpal_on_ahk = AssetHubPolkadot::sovereign_account_id_of(penpal_as_seen_by_ah); + let penpal_as_seen_by_ah = AssetHubPolkadot::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ahp = AssetHubPolkadot::sovereign_account_id_of(penpal_as_seen_by_ah); AssetHubPolkadot::fund_accounts(vec![ - (AssetHubPolkadotSender::get(), 5_000_000 * POLKADOT_ED), /* An account to swap - * dot - * for something else. */ + // An account to swap dot for something else. + (AssetHubPolkadotSender::get(), 5_000_000 * ASSET_HUB_POLKADOT_ED), + // Penpal's sovereign account in AH should have some balance + (sov_penpal_on_ahp.clone().into(), 100_000_000 * ASSET_HUB_POLKADOT_ED), ]); AssetHubPolkadot::execute_with(|| { - // 3: Mint foreign asset on asset_hub_polkadot: + // 0: No need to create foreign asset as it exists in genesis. + // + // 1:: Mint foreign asset on asset_hub_polkadot: // // (While it might be nice to use batch, // currently that's disabled due to safe call filters.) @@ -175,10 +159,10 @@ fn swap_locally_on_chain_using_foreign_assets() { type RuntimeEvent = ::RuntimeEvent; // 3. Mint foreign asset (in reality this should be a teleport or some such) assert_ok!(::ForeignAssets::mint( - ::RuntimeOrigin::signed(sov_penpal_on_ahk.clone()), + ::RuntimeOrigin::signed(sov_penpal_on_ahp.clone()), foreign_asset_at_asset_hub_polkadot, - sov_penpal_on_ahk.clone().into(), - 3_000_000_000_000, + sov_penpal_on_ahp.clone().into(), + ASSET_HUB_POLKADOT_ED * 3_000_000_000_000, )); assert_expected_events!( @@ -204,14 +188,14 @@ fn swap_locally_on_chain_using_foreign_assets() { // 5. Add liquidity: assert_ok!(::AssetConversion::add_liquidity( - ::RuntimeOrigin::signed(sov_penpal_on_ahk.clone()), + ::RuntimeOrigin::signed(sov_penpal_on_ahp.clone()), asset_native.clone(), Box::new(foreign_asset_at_asset_hub_polkadot), 1_000_000_000_000, 2_000_000_000_000, 0, 0, - sov_penpal_on_ahk.clone() + sov_penpal_on_ahp.clone() )); assert_expected_events!( @@ -230,8 +214,8 @@ fn swap_locally_on_chain_using_foreign_assets() { ::AssetConversion::swap_exact_tokens_for_tokens( ::RuntimeOrigin::signed(AssetHubPolkadotSender::get()), path, - 100000, - 1000, + 100000 * ASSET_HUB_POLKADOT_ED, + 1000 * ASSET_HUB_POLKADOT_ED, AssetHubPolkadotSender::get(), true ) @@ -241,8 +225,8 @@ fn swap_locally_on_chain_using_foreign_assets() { AssetHubPolkadot, vec![ RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::SwapExecuted { amount_in, amount_out, .. },) => { - amount_in: *amount_in == 100000, - amount_out: *amount_out == 199399, + amount_in: *amount_in == 10000000000000, + amount_out: *amount_out == 1817684594348, }, ] ); @@ -250,13 +234,13 @@ fn swap_locally_on_chain_using_foreign_assets() { // 7. Remove liquidity assert_ok!( ::AssetConversion::remove_liquidity( - ::RuntimeOrigin::signed(sov_penpal_on_ahk.clone()), + ::RuntimeOrigin::signed(sov_penpal_on_ahp.clone()), asset_native.clone(), Box::new(foreign_asset_at_asset_hub_polkadot), - 1414213562273 - 2_000_000_000, // all but the 2 EDs can't be retrieved. + 1414213562273 / 2, // remove only half 0, 0, - sov_penpal_on_ahk.clone(), + sov_penpal_on_ahp.clone(), ) ); }); diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/teleport.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/teleport.rs index e8e60aa53c..4307bc7bb2 100644 --- a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/teleport.rs +++ b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/teleport.rs @@ -14,7 +14,7 @@ // limitations under the License. use crate::*; -use asset_hub_polkadot_runtime::xcm_config::XcmConfig as AssetHubPolkadotXcmConfig; +use asset_hub_polkadot_runtime::xcm_config::{DotLocation, XcmConfig as AssetHubPolkadotXcmConfig}; use emulated_integration_tests_common::xcm_helpers::non_fee_asset; use polkadot_runtime::xcm_config::XcmConfig as PolkadotXcmConfig; use polkadot_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub; @@ -114,18 +114,20 @@ fn para_dest_assertions(t: RelayToSystemParaTest) { fn penpal_to_ah_foreign_assets_sender_assertions(t: ParaToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; - PenpalB::assert_xcm_pallet_attempted_complete(None); + let system_para_native_asset_location = DotLocation::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(); + + PenpalB::assert_xcm_pallet_attempted_complete(None); assert_expected_events!( PenpalB, vec![ - RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { 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 +146,7 @@ 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(); + AssetHubPolkadot::assert_xcmp_queue_success(None); assert_expected_events!( AssetHubPolkadot, vec![ @@ -163,9 +166,6 @@ 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, .. } - ) => {}, ] ); } @@ -205,6 +205,9 @@ 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 = DotLocation::get(); + + PenpalB::assert_xcmp_queue_success(None); assert_expected_events!( PenpalB, vec![ @@ -221,12 +224,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::Deposit { 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, .. } - ) => {}, ] ); } @@ -242,16 +244,6 @@ fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { ) } -fn relay_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { ::PolkadotXcm::limited_teleport_assets( t.signed_origin, @@ -263,16 +255,6 @@ fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResu ) } -fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - fn system_para_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { ::PolkadotXcm::transfer_assets( t.signed_origin, @@ -418,135 +400,12 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { assert_eq!(receiver_balance_after, receiver_balance_before); } -/// Teleport of native asset from Relay Chain to the System Parachain should work -#[test] -fn teleport_native_assets_from_relay_to_system_para_works() { - // Init values for Relay Chain - let amount_to_send: Balance = POLKADOT_ED * 1000; - let dest = Polkadot::child_location_of(AssetHubPolkadot::para_id()); - let beneficiary = AssetHubPolkadotReceiver::get(); - let test_args = TestContext { - sender: PolkadotSender::get(), - receiver: beneficiary.clone(), - args: TestArgs::new_relay(dest, beneficiary, amount_to_send), - }; - - let mut test = RelayToSystemParaTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(relay_origin_assertions); - test.set_assertion::(para_dest_assertions); - test.set_dispatchable::(relay_teleport_assets); - test.assert(); - - let delivery_fees = Polkadot::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - let sender_balance_after = test.sender.balance; - 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); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - -/// Teleport of native asset from System Parachains to the Relay Chain -/// should work when there is enough balance in Relay Chain's `CheckAccount` -#[test] -fn teleport_native_assets_back_from_system_para_to_relay_works() { - // Dependency - Relay Chain's `CheckAccount` should have enough balance - teleport_native_assets_from_relay_to_system_para_works(); - - // Init values for Relay Chain - let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; - let destination = AssetHubPolkadot::parent_location(); - let beneficiary_id = PolkadotReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubPolkadotSender::get(), - receiver: PolkadotReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions); - test.set_dispatchable::(system_para_teleport_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - let delivery_fees = AssetHubPolkadot::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - // 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); -} - -/// Teleport of native asset from System Parachain to Relay Chain -/// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` -#[test] -fn teleport_native_assets_from_system_para_to_relay_fails() { - // Init values for Relay Chain - let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; - let destination = AssetHubPolkadot::parent_location(); - let beneficiary_id = PolkadotReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubPolkadotSender::get(), - receiver: PolkadotReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions_fail); - test.set_dispatchable::(system_para_teleport_assets); - test.assert(); - - let delivery_fees = AssetHubPolkadot::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - let sender_balance_after = test.sender.balance; - 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); - // Receiver's balance does not change - assert_eq!(receiver_balance_after, receiver_balance_before); -} - #[test] fn teleport_to_other_system_parachains_works() { let amount = ASSET_HUB_POLKADOT_ED * 100; let native_asset: Assets = (Parent, amount).into(); - test_sibling_is_trusted_teleporter!( + test_parachain_is_trusted_teleporter!( AssetHubPolkadot, // Origin AssetHubPolkadotXcmConfig, // XCM Configuration vec![BridgeHubPolkadot], // Destinations @@ -554,41 +413,28 @@ fn teleport_to_other_system_parachains_works() { ); } -/// Bidirectional teleports of local Penpal assets to Asset Hub as foreign assets should work -/// (using native reserve-based transfer for fees) -#[test] -fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { - let ah_as_seen_by_penpal = PenpalB::sibling_location_of(AssetHubPolkadot::para_id()); - let asset_location_on_penpal = - v3::Location::try_from(PenpalLocalTeleportableToAssetHub::get()).expect("conversion works"); +/// Bidirectional teleports of local Penpal assets to Asset Hub as foreign assets while paying +/// fees using (reserve transferred) native asset. +pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt( + para_to_ah_dispatchable: fn(ParaToSystemParaTest) -> DispatchResult, + ah_to_para_dispatchable: fn(SystemParaToParaTest) -> DispatchResult, +) { + // Init values for Parachain + let fee_amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 10000; + let asset_location_on_penpal = PenpalLocalTeleportableToAssetHub::get(); let asset_id_on_penpal = match asset_location_on_penpal.last() { - Some(v3::Junction::GeneralIndex(id)) => *id as u32, + Some(Junction::GeneralIndex(id)) => *id as u32, _ => unreachable!(), }; - let asset_owner_on_penpal = PenpalBSender::get(); - let foreign_asset_at_asset_hub_polkadot = - v3::Location::new(1, [v3::Junction::Parachain(PenpalB::para_id().into())]) - .appended_with(asset_location_on_penpal) - .unwrap(); - /* - // FAIL-CI @bkontur - super::penpal_create_foreign_asset_on_asset_hub( - asset_id_on_penpal, - foreign_asset_at_asset_hub_polkadot, - ah_as_seen_by_penpal.clone(), - false, - asset_owner_on_penpal, - ASSET_MIN_BALANCE * 1_000_000, - );*/ - let penpal_to_ah_beneficiary_id = AssetHubPolkadotReceiver::get(); - - let fee_amount_to_send = ASSET_HUB_POLKADOT_ED * 1000; - let asset_amount_to_send = ASSET_MIN_BALANCE * 1000; - - let asset_location_on_penpal_latest: Location = asset_location_on_penpal.try_into().unwrap(); + let asset_amount_to_send = ASSET_HUB_POLKADOT_ED * 1000; + let asset_owner = PenpalAssetOwner::get(); + let system_para_native_asset_location = DotLocation::get(); + let sender = PenpalBSender::get(); + let penpal_check_account = ::PolkadotXcm::check_account(); + let ah_as_seen_by_penpal = PenpalB::sibling_location_of(AssetHubPolkadot::para_id()); let penpal_assets: Assets = vec![ (Parent, fee_amount_to_send).into(), - (asset_location_on_penpal_latest, asset_amount_to_send).into(), + (asset_location_on_penpal.clone(), asset_amount_to_send).into(), ] .into(); let fee_asset_index = penpal_assets @@ -597,6 +443,41 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { .position(|r| r == &(Parent, fee_amount_to_send).into()) .unwrap() as u32; + // fund Parachain's sender account + PenpalB::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner.clone()), + system_para_native_asset_location.clone(), + sender.clone(), + fee_amount_to_send * 2, + ); + // No need to create the asset (only mint) as it exists in genesis. + PenpalB::mint_asset( + ::RuntimeOrigin::signed(asset_owner.clone()), + asset_id_on_penpal, + sender.clone(), + asset_amount_to_send, + ); + // fund Parachain's check account to be able to teleport + PenpalB::fund_accounts(vec![( + penpal_check_account.clone().into(), + ASSET_HUB_POLKADOT_ED * 1000, + )]); + + // prefund SA of Penpal on AssetHub with enough native tokens to pay for fees + let penpal_as_seen_by_ah = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); + let sov_penpal_on_ah = AssetHubPolkadot::sovereign_account_id_of(penpal_as_seen_by_ah); + AssetHubPolkadot::fund_accounts(vec![( + sov_penpal_on_ah.clone().into(), + ASSET_HUB_POLKADOT_ED * 100_000_000_000, + )]); + + // Init values for System Parachain + let foreign_asset_at_asset_hub_polkadot = + Location::new(1, [Junction::Parachain(PenpalB::para_id().into())]) + .appended_with(asset_location_on_penpal) + .unwrap(); + let penpal_to_ah_beneficiary_id = AssetHubPolkadotReceiver::get(); + // Penpal to AH test args let penpal_to_ah_test_args = TestContext { sender: PenpalBSender::get(), @@ -611,8 +492,14 @@ 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 = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + system_para_native_asset_location.clone(), + &PenpalBSender::get(), + ) + }); - let penpal_sender_balance_before = penpal_to_ah.sender.balance; let ah_receiver_balance_before = penpal_to_ah.receiver.balance; let penpal_sender_assets_before = PenpalB::execute_with(|| { @@ -622,17 +509,24 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { let ah_receiver_assets_before = AssetHubPolkadot::execute_with(|| { type Assets = ::ForeignAssets; >::balance( - foreign_asset_at_asset_hub_polkadot, + foreign_asset_at_asset_hub_polkadot.clone().try_into().unwrap(), &AssetHubPolkadotReceiver::get(), ) }); penpal_to_ah.set_assertion::(penpal_to_ah_foreign_assets_sender_assertions); penpal_to_ah.set_assertion::(penpal_to_ah_foreign_assets_receiver_assertions); - penpal_to_ah.set_dispatchable::(para_to_system_para_transfer_assets); + penpal_to_ah.set_dispatchable::(para_to_ah_dispatchable); penpal_to_ah.assert(); - let penpal_sender_balance_after = penpal_to_ah.sender.balance; + let penpal_sender_balance_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + system_para_native_asset_location.clone(), + &PenpalBSender::get(), + ) + }); + let ah_receiver_balance_after = penpal_to_ah.receiver.balance; let penpal_sender_assets_after = PenpalB::execute_with(|| { @@ -642,7 +536,7 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { let ah_receiver_assets_after = AssetHubPolkadot::execute_with(|| { type Assets = ::ForeignAssets; >::balance( - foreign_asset_at_asset_hub_polkadot, + foreign_asset_at_asset_hub_polkadot.clone().try_into().unwrap(), &AssetHubPolkadotReceiver::get(), ) }); @@ -670,19 +564,17 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { type ForeignAssets = ::ForeignAssets; assert_ok!(ForeignAssets::transfer( ::RuntimeOrigin::signed(AssetHubPolkadotReceiver::get()), - foreign_asset_at_asset_hub_polkadot, + foreign_asset_at_asset_hub_polkadot.clone().try_into().unwrap(), AssetHubPolkadotSender::get().into(), asset_amount_to_send, )); }); - let foreign_asset_at_asset_hub_polkadot_latest: Location = - foreign_asset_at_asset_hub_polkadot.try_into().unwrap(); let ah_to_penpal_beneficiary_id = PenpalBReceiver::get(); let penpal_as_seen_by_ah = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); let ah_assets: Assets = vec![ (Parent, fee_amount_to_send).into(), - (foreign_asset_at_asset_hub_polkadot_latest, asset_amount_to_send).into(), + (foreign_asset_at_asset_hub_polkadot.clone(), asset_amount_to_send).into(), ] .into(); let fee_asset_index = ah_assets @@ -707,12 +599,18 @@ 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 = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + system_para_native_asset_location.clone(), + &PenpalBReceiver::get(), + ) + }); let ah_sender_assets_before = AssetHubPolkadot::execute_with(|| { type ForeignAssets = ::ForeignAssets; >::balance( - foreign_asset_at_asset_hub_polkadot, + foreign_asset_at_asset_hub_polkadot.clone().try_into().unwrap(), &AssetHubPolkadotSender::get(), ) }); @@ -723,16 +621,22 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { ah_to_penpal.set_assertion::(ah_to_penpal_foreign_assets_sender_assertions); ah_to_penpal.set_assertion::(ah_to_penpal_foreign_assets_receiver_assertions); - ah_to_penpal.set_dispatchable::(system_para_to_para_transfer_assets); + ah_to_penpal.set_dispatchable::(ah_to_para_dispatchable); 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 = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + system_para_native_asset_location, + &PenpalBReceiver::get(), + ) + }); let ah_sender_assets_after = AssetHubPolkadot::execute_with(|| { type ForeignAssets = ::ForeignAssets; >::balance( - foreign_asset_at_asset_hub_polkadot, + foreign_asset_at_asset_hub_polkadot.try_into().unwrap(), &AssetHubPolkadotSender::get(), ) }); @@ -755,3 +659,13 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { // Receiver's balance is increased by exact amount assert_eq!(penpal_receiver_assets_after, penpal_receiver_assets_before + asset_amount_to_send); } + +/// Bidirectional teleports of local Penpal assets to Asset Hub as foreign assets should work +/// (using native reserve-based transfer for fees) +#[test] +fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { + do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt( + para_to_system_para_transfer_assets, + system_para_to_para_transfer_assets, + ); +} diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/lib.rs b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/lib.rs index 80351d89ff..c930e54f2c 100644 --- a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/lib.rs +++ b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/lib.rs @@ -34,6 +34,7 @@ pub use bp_messages::LaneId; pub use emulated_integration_tests_common::{ accounts::{ALICE, BOB}, impls::Inspect, + 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, @@ -41,7 +42,6 @@ pub use emulated_integration_tests_common::{ xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, }; -pub use integration_tests_helpers::test_sibling_is_trusted_teleporter; pub use kusama_polkadot_system_emulated_network::{ asset_hub_kusama_emulated_chain::{ genesis::ED as ASSET_HUB_KUSAMA_ED, AssetHubKusamaParaPallet as AssetHubKusamaPallet, diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/teleport.rs b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/teleport.rs index a5f8abdfb4..c1aebaabfc 100644 --- a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/teleport.rs +++ b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/teleport.rs @@ -21,13 +21,10 @@ fn teleport_to_other_system_parachains_works() { let amount = BRIDGE_HUB_KUSAMA_ED * 100; let native_asset: Assets = (Parent, amount).into(); - /* - FAIL-CI @bkontur - test_sibling_is_trusted_teleporter!( + test_parachain_is_trusted_teleporter!( BridgeHubKusama, // Origin XcmConfig, // XCM configuration vec![AssetHubKusama], // Destinations (native_asset, amount) - );*/ - todo!() + ); } diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/lib.rs b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/lib.rs index febcff3c6c..9aefaed933 100644 --- a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/lib.rs +++ b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/lib.rs @@ -34,6 +34,7 @@ pub use bp_messages::LaneId; pub use emulated_integration_tests_common::{ accounts::{ALICE, BOB}, impls::Inspect, + 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, @@ -41,7 +42,6 @@ pub use emulated_integration_tests_common::{ xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, }; -pub use integration_tests_helpers::test_sibling_is_trusted_teleporter; pub use kusama_polkadot_system_emulated_network::{ asset_hub_kusama_emulated_chain::{ genesis::ED as ASSET_HUB_KUSAMA_ED, AssetHubKusamaParaPallet as AssetHubKusamaPallet, diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/teleport.rs b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/teleport.rs index c5efd1b974..76eec63125 100644 --- a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/teleport.rs +++ b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/teleport.rs @@ -15,18 +15,16 @@ use crate::*; use bridge_hub_polkadot_runtime::xcm_config::XcmConfig; -use integration_tests_helpers::test_parachain_is_trusted_teleporter; #[test] fn teleport_to_other_system_parachains_works() { let amount = BRIDGE_HUB_POLKADOT_ED * 100; let native_asset: Assets = (Parent, amount).into(); - /*test_parachain_is_trusted_teleporter!( - BridgeHubPolkadot, // Origin - XcmConfig, // XCM Configuration - BridgeHubPolkadot, // Destination + test_parachain_is_trusted_teleporter!( + BridgeHubPolkadot, // Origin + XcmConfig, // XCM Configuration + vec![AssetHubPolkadot], // Destination (native_asset, amount) - );*/ - todo!() // FAIL-CI @bkontur + ); } diff --git a/integration-tests/emulated/tests/collectives/collectives-polkadot/src/lib.rs b/integration-tests/emulated/tests/collectives/collectives-polkadot/src/lib.rs index a2d6d55926..0cf2df8c40 100644 --- a/integration-tests/emulated/tests/collectives/collectives-polkadot/src/lib.rs +++ b/integration-tests/emulated/tests/collectives/collectives-polkadot/src/lib.rs @@ -19,6 +19,7 @@ pub use xcm::{prelude::*, v3}; // Cumulus pub use emulated_integration_tests_common::{ accounts::ALICE, + test_parachain_is_trusted_teleporter, xcm_emulator::{assert_expected_events, bx, Chain, Parachain, RelayChain as Relay, TestExt}, }; pub use polkadot_system_emulated_network::{ diff --git a/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/teleport.rs b/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/teleport.rs index 7d2b7a627e..27ccd27b55 100644 --- a/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/teleport.rs +++ b/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/teleport.rs @@ -18,8 +18,7 @@ use asset_hub_polkadot_runtime::xcm_config::XcmConfig as AssetHubPolkadotXcmConf use collectives_polkadot_runtime::xcm_config::XcmConfig as CollectivesPolkadotXcmConfig; use frame_support::assert_ok; use integration_tests_helpers::{ - test_parachain_is_trusted_teleporter, test_relay_is_trusted_teleporter, - test_sibling_is_trusted_teleporter, + test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, }; use polkadot_runtime::xcm_config::XcmConfig as PolkadotXcmConfig; @@ -35,7 +34,7 @@ fn teleport_from_and_to_relay() { (native_asset, amount) ); - test_parachain_is_trusted_teleporter!( + test_parachain_is_trusted_teleporter_for_relay!( CollectivesPolkadot, // Origin CollectivesPolkadotXcmConfig, // XCM Configuration Polkadot, // Destination @@ -48,7 +47,7 @@ fn teleport_from_collectives_to_asset_hub() { let amount = ASSET_HUB_POLKADOT_ED * 100; let native_asset: Assets = (Parent, amount).into(); - test_sibling_is_trusted_teleporter!( + test_parachain_is_trusted_teleporter!( CollectivesPolkadot, // Origin CollectivesPolkadotXcmConfig, // XCM Configuration vec![AssetHubPolkadot], // Destinations @@ -61,7 +60,7 @@ fn teleport_from_asset_hub_to_collectives() { let amount = COLLECTIVES_POLKADOT_ED * 100; let native_asset: Assets = (Parent, amount).into(); - test_sibling_is_trusted_teleporter!( + test_parachain_is_trusted_teleporter!( AssetHubPolkadot, // Origin AssetHubPolkadotXcmConfig, // XCM Configuration vec![CollectivesPolkadot], // Destinations diff --git a/relay/kusama/src/lib.rs b/relay/kusama/src/lib.rs index f04b7f19f4..16c1e7d270 100644 --- a/relay/kusama/src/lib.rs +++ b/relay/kusama/src/lib.rs @@ -86,7 +86,7 @@ use frame_system::{EnsureRoot, EnsureSigned}; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; use pallet_identity::legacy::IdentityInfo; use pallet_session::historical as session_historical; -use pallet_transaction_payment::{CurrencyAdapter, FeeDetails, RuntimeDispatchInfo}; +use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo}; use sp_core::{ConstU128, OpaqueMetadata, H256}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, diff --git a/relay/polkadot/src/lib.rs b/relay/polkadot/src/lib.rs index 3504b2b41c..a1802a94c3 100644 --- a/relay/polkadot/src/lib.rs +++ b/relay/polkadot/src/lib.rs @@ -20,7 +20,7 @@ // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. #![recursion_limit = "512"] -use pallet_transaction_payment::{CurrencyAdapter, FungibleAdapter}; +use pallet_transaction_payment::FungibleAdapter; use polkadot_runtime_common::{ auctions, claims, crowdloan, impl_runtime_weights, impls::{ diff --git a/system-parachains/asset-hubs/asset-hub-kusama/src/lib.rs b/system-parachains/asset-hubs/asset-hub-kusama/src/lib.rs index 12ca6bca2a..6c4c0dbcf0 100644 --- a/system-parachains/asset-hubs/asset-hub-kusama/src/lib.rs +++ b/system-parachains/asset-hubs/asset-hub-kusama/src/lib.rs @@ -59,10 +59,9 @@ use frame_support::{ genesis_builder_helper::{build_state, get_preset}, ord_parameter_types, parameter_types, traits::{ - fungible, fungibles, - tokens::imbalance::{ResolveAssetTo, ResolveTo}, - AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, - Equals, InstanceFilter, TransformOrigin, WithdrawReasons, + fungible, fungibles, tokens::imbalance::ResolveAssetTo, AsEnsureOriginWithArg, ConstBool, + ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Equals, InstanceFilter, + TransformOrigin, WithdrawReasons, }, weights::{ConstantMultiplier, Weight}, BoundedVec, PalletId, @@ -71,7 +70,6 @@ use frame_system::{ limits::{BlockLength, BlockWeights}, EnsureRoot, EnsureSigned, EnsureSignedBy, }; -use pallet_collator_selection::StakingPotAccountId; use pallet_nfts::PalletFeatures; use parachains_common::{ message_queue::*, AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, BlockNumber, Hash, @@ -1375,7 +1373,7 @@ impl_runtime_apis! { use sp_storage::TrackedStorageKey; use xcm::latest::prelude::{ Asset, Fungible, Here, InteriorLocation, Junction, Junction::*, Location, NetworkId, - NonFungible, Parent, ParentThen, Response, XCM_VERSION, + NonFungible, Parent, ParentThen, Response, XCM_VERSION, Assets as XcmAssets, }; use frame_system_benchmarking::Pallet as SystemBench; @@ -1448,7 +1446,7 @@ impl_runtime_apis! { } fn set_up_complex_asset_transfer( - ) -> Option<(xcm::v4::Assets, u32, Location, Box)> { + ) -> Option<(XcmAssets, u32, Location, Box)> { // Transfer to Relay some local AH asset (local-reserve-transfer) while paying // fees using teleported native token. // (We don't care that Relay doesn't accept incoming unknown AH local asset) @@ -1479,7 +1477,7 @@ impl_runtime_apis! { ); let transfer_asset: Asset = (asset_location, asset_amount).into(); - let assets: xcm::v4::Assets = vec![fee_asset.clone(), transfer_asset].into(); + let assets: XcmAssets = vec![fee_asset.clone(), transfer_asset].into(); let fee_index = if assets.get(0).unwrap().eq(&fee_asset) { 0 } else { 1 }; // verify transferred successfully @@ -1515,30 +1513,26 @@ impl_runtime_apis! { fn valid_destination() -> Result { Ok(KsmLocation::get()) } - fn worst_case_holding(depositable_count: u32) -> xcm::v4::Assets { + fn worst_case_holding(depositable_count: u32) -> XcmAssets { // A mix of fungible, non-fungible, and concrete assets. let holding_non_fungibles = MaxAssetsIntoHolding::get() / 2 - depositable_count; - let holding_fungibles = holding_non_fungibles.saturating_sub(1); + let holding_fungibles = holding_non_fungibles.saturating_sub(2); // -2 for two `iter::once` bellow let fungibles_amount: u128 = 100; - let mut assets = (0..holding_fungibles) + (0..holding_fungibles) .map(|i| { Asset { id: AssetId(GeneralIndex(i as u128).into()), - fun: Fungible(fungibles_amount * i as u128), + fun: Fungible(fungibles_amount * (i + 1) as u128), // non-zero amount } }) .chain(core::iter::once(Asset { id: AssetId(Here.into()), fun: Fungible(u128::MAX) })) + .chain(core::iter::once(Asset { id: AssetId(KsmLocation::get()), fun: Fungible(1_000_000 * UNITS) })) .chain((0..holding_non_fungibles).map(|i| Asset { id: AssetId(GeneralIndex(i as u128).into()), fun: NonFungible(asset_instance_from(i)), })) - .collect::>(); - - assets.push(Asset { - id: AssetId(KsmLocation::get()), - fun: Fungible(1_000_000 * UNITS), - }); - assets.into() + .collect::>() + .into() } } @@ -1580,7 +1574,7 @@ impl_runtime_apis! { (0u64, Response::Version(Default::default())) } - fn worst_case_asset_exchange() -> Result<(xcm::v4::Assets, xcm::v4::Assets), BenchmarkError> { + fn worst_case_asset_exchange() -> Result<(XcmAssets, XcmAssets), BenchmarkError> { Err(BenchmarkError::Skip) } @@ -1597,9 +1591,9 @@ impl_runtime_apis! { Ok(KsmLocation::get()) } - fn claimable_asset() -> Result<(Location, Location, xcm::v4::Assets), BenchmarkError> { + fn claimable_asset() -> Result<(Location, Location, XcmAssets), BenchmarkError> { let origin = KsmLocation::get(); - let assets: xcm::v4::Assets = (AssetId(KsmLocation::get()), 1_000 * UNITS).into(); + let assets: XcmAssets = (AssetId(KsmLocation::get()), 1_000 * UNITS).into(); let ticket = Location { parents: 0, interior: Here }; Ok((origin, ticket, assets)) } diff --git a/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs b/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs index 2643c76d61..8cf01924b7 100644 --- a/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs +++ b/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs @@ -93,10 +93,9 @@ use frame_support::{ genesis_builder_helper::{build_state, get_preset}, parameter_types, traits::{ - fungible, fungibles, - tokens::imbalance::{ResolveAssetTo, ResolveTo}, - AsEnsureOriginWithArg, ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Equals, - InstanceFilter, NeverEnsureOrigin, TransformOrigin, WithdrawReasons, + fungible, fungibles, tokens::imbalance::ResolveAssetTo, AsEnsureOriginWithArg, ConstBool, + ConstU32, ConstU64, ConstU8, EitherOfDiverse, Equals, InstanceFilter, NeverEnsureOrigin, + TransformOrigin, WithdrawReasons, }, weights::{ConstantMultiplier, Weight}, PalletId, @@ -105,7 +104,6 @@ use frame_system::{ limits::{BlockLength, BlockWeights}, EnsureRoot, EnsureSigned, }; -use pallet_collator_selection::StakingPotAccountId; use pallet_nfts::PalletFeatures; use parachains_common::{ message_queue::*, AccountId, AssetHubPolkadotAuraId as AuraId, AssetIdForTrustBackedAssets, @@ -1367,7 +1365,7 @@ impl_runtime_apis! { use sp_storage::TrackedStorageKey; use xcm::latest::prelude::{ Asset, Fungible, Here, InteriorLocation, Junction, Junction::*, Location, NetworkId, - NonFungible, Parent, ParentThen, Response, XCM_VERSION, + NonFungible, Parent, ParentThen, Response, XCM_VERSION, Assets as XcmAssets, }; use frame_system_benchmarking::Pallet as SystemBench; @@ -1440,7 +1438,7 @@ impl_runtime_apis! { } fn set_up_complex_asset_transfer( - ) -> Option<(xcm::v4::Assets, u32, Location, Box)> { + ) -> Option<(XcmAssets, u32, Location, Box)> { // Transfer to Relay some local AH asset (local-reserve-transfer) while paying // fees using teleported native token. // (We don't care that Relay doesn't accept incoming unknown AH local asset) @@ -1471,7 +1469,7 @@ impl_runtime_apis! { ); let transfer_asset: Asset = (asset_location, asset_amount).into(); - let assets: xcm::v4::Assets = vec![fee_asset.clone(), transfer_asset].into(); + let assets: XcmAssets = vec![fee_asset.clone(), transfer_asset].into(); let fee_index = if assets.get(0).unwrap().eq(&fee_asset) { 0 } else { 1 }; // verify transferred successfully @@ -1507,30 +1505,26 @@ impl_runtime_apis! { fn valid_destination() -> Result { Ok(DotLocation::get()) } - fn worst_case_holding(depositable_count: u32) -> xcm::v4::Assets { + fn worst_case_holding(depositable_count: u32) -> XcmAssets { // A mix of fungible, non-fungible, and concrete assets. let holding_non_fungibles = MaxAssetsIntoHolding::get() / 2 - depositable_count; - let holding_fungibles = holding_non_fungibles - 1; + let holding_fungibles = holding_non_fungibles.saturating_sub(2); // -2 for two `iter::once` bellow let fungibles_amount: u128 = 100; - let mut assets = (0..holding_fungibles) + (0..holding_fungibles) .map(|i| { Asset { id: AssetId(GeneralIndex(i as u128).into()), - fun: Fungible(fungibles_amount * i as u128), + fun: Fungible(fungibles_amount * (i + 1) as u128), // non-zero amount } }) .chain(core::iter::once(Asset { id: AssetId(Here.into()), fun: Fungible(u128::MAX) })) + .chain(core::iter::once(Asset { id: AssetId(DotLocation::get()), fun: Fungible(1_000_000 * UNITS) })) .chain((0..holding_non_fungibles).map(|i| Asset { id: AssetId(GeneralIndex(i as u128).into()), fun: NonFungible(asset_instance_from(i)), })) - .collect::>(); - - assets.push(Asset { - id: AssetId(DotLocation::get()), - fun: Fungible(1_000_000 * UNITS), - }); - assets.into() + .collect::>() + .into() } } @@ -1572,7 +1566,7 @@ impl_runtime_apis! { (0u64, Response::Version(Default::default())) } - fn worst_case_asset_exchange() -> Result<(xcm::v4::Assets, xcm::v4::Assets), BenchmarkError> { + fn worst_case_asset_exchange() -> Result<(XcmAssets, XcmAssets), BenchmarkError> { Err(BenchmarkError::Skip) } @@ -1589,9 +1583,9 @@ impl_runtime_apis! { Ok(DotLocation::get()) } - fn claimable_asset() -> Result<(Location, Location, xcm::v4::Assets), BenchmarkError> { + fn claimable_asset() -> Result<(Location, Location, XcmAssets), BenchmarkError> { let origin = DotLocation::get(); - let assets: xcm::v4::Assets = (AssetId(DotLocation::get()), 1_000 * UNITS).into(); + let assets: XcmAssets = (AssetId(DotLocation::get()), 1_000 * UNITS).into(); let ticket = Location { parents: 0, interior: Here }; Ok((origin, ticket, assets)) } diff --git a/system-parachains/asset-hubs/asset-hub-polkadot/src/xcm_config.rs b/system-parachains/asset-hubs/asset-hub-polkadot/src/xcm_config.rs index 870fb750f4..5f5858908a 100644 --- a/system-parachains/asset-hubs/asset-hub-polkadot/src/xcm_config.rs +++ b/system-parachains/asset-hubs/asset-hub-polkadot/src/xcm_config.rs @@ -34,12 +34,9 @@ use frame_support::{ use frame_system::EnsureRoot; use pallet_collator_selection::StakingPotAccountId; use pallet_xcm::XcmPassthrough; -use parachains_common::{ - impls::ToStakingPot, - xcm_config::{ - AllSiblingSystemParachains, AssetFeeAsExistentialDepositMultiplier, - ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, RelayOrOtherSystemParachains, - }, +use parachains_common::xcm_config::{ + AllSiblingSystemParachains, AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem, + ParentRelayOrSiblingParachains, RelayOrOtherSystemParachains, }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_constants::system_parachain; @@ -157,7 +154,7 @@ pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConverte StartsWithExplicitGlobalConsensus, ), Balance, - xcm::v3::Location, // FAIL-CI @bkontur good? + xcm::v3::Location, >; /// Means for transacting foreign assets from different global consensus. diff --git a/system-parachains/bridge-hubs/bridge-hub-kusama/primitives/src/lib.rs b/system-parachains/bridge-hubs/bridge-hub-kusama/primitives/src/lib.rs index 36ae75ff32..a289cb8a35 100644 --- a/system-parachains/bridge-hubs/bridge-hub-kusama/primitives/src/lib.rs +++ b/system-parachains/bridge-hubs/bridge-hub-kusama/primitives/src/lib.rs @@ -102,11 +102,11 @@ frame_support::parameter_types! { /// Transaction fee that is paid at the Kusama BridgeHub for delivering single inbound message. /// (initially was calculated by test `BridgeHubKusama::can_calculate_fee_for_complex_message_delivery_transaction` + `33%`) - pub const BridgeHubKusamaBaseDeliveryFeeInKsms: u128 = 56_374_989_788; + pub const BridgeHubKusamaBaseDeliveryFeeInKsms: u128 = 56_375_711_123; /// Transaction fee that is paid at the Kusama BridgeHub for delivering single outbound message confirmation. /// (initially was calculated by test `BridgeHubKusama::can_calculate_fee_for_complex_message_confirmation_transaction` + `33%`) - pub const BridgeHubKusamaBaseConfirmationFeeInKsms: u128 = 53_808_755_240; + pub const BridgeHubKusamaBaseConfirmationFeeInKsms: u128 = 53_809_476_575; } /// Compute the total estimated fee that needs to be paid in KSMs by the sender when sending diff --git a/system-parachains/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs b/system-parachains/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs index 7a30ee4b4d..9d06ce666a 100644 --- a/system-parachains/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs +++ b/system-parachains/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs @@ -28,12 +28,9 @@ use frame_support::{ use frame_system::EnsureRoot; use pallet_collator_selection::StakingPotAccountId; use pallet_xcm::XcmPassthrough; -use parachains_common::{ - impls::ToStakingPot, - xcm_config::{ - AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, - RelayOrOtherSystemParachains, - }, +use parachains_common::xcm_config::{ + AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, + RelayOrOtherSystemParachains, }; use polkadot_parachain_primitives::primitives::Sibling; use snowbridge_runtime_common::XcmExportFeeToSibling; diff --git a/system-parachains/bridge-hubs/bridge-hub-kusama/tests/snowbridge.rs b/system-parachains/bridge-hubs/bridge-hub-kusama/tests/snowbridge.rs index 0796ffc8e6..11b2298d40 100644 --- a/system-parachains/bridge-hubs/bridge-hub-kusama/tests/snowbridge.rs +++ b/system-parachains/bridge-hubs/bridge-hub-kusama/tests/snowbridge.rs @@ -35,16 +35,12 @@ use sp_core::H160; use sp_keyring::AccountKeyring::Alice; use sp_runtime::{ generic::{Era, SignedPayload}, - traits::Header, AccountId32, }; use xcm::latest::prelude::*; use xcm_builder::HandleFee; use xcm_executor::traits::{FeeManager, FeeReason}; -type RuntimeHelper = - parachains_runtimes_test_utils::RuntimeHelper; - parameter_types! { pub const DefaultBridgeHubEthereumBaseFee: Balance = 2_750_872_500_000; } diff --git a/system-parachains/bridge-hubs/bridge-hub-kusama/tests/tests.rs b/system-parachains/bridge-hubs/bridge-hub-kusama/tests/tests.rs index 74e0f4c4a2..607c350757 100644 --- a/system-parachains/bridge-hubs/bridge-hub-kusama/tests/tests.rs +++ b/system-parachains/bridge-hubs/bridge-hub-kusama/tests/tests.rs @@ -39,7 +39,7 @@ use sp_consensus_aura::SlotDuration; use sp_keyring::AccountKeyring::Alice; use sp_runtime::{ generic::{Era, SignedPayload}, - AccountId32, + AccountId32, Perbill, }; use system_parachains_constants::kusama::{ consensus::RELAY_CHAIN_SLOT_DURATION_MILLIS, fee::WeightToFee, @@ -307,7 +307,7 @@ pub fn complex_relay_extrinsic_works() { #[test] pub fn can_calculate_weight_for_paid_export_message_with_reserve_transfer() { - check_sane_fees_values( + bridge_hub_test_utils::check_sane_fees_values( "bp_bridge_hub_kusama::BridgeHubKusamaBaseXcmFeeInKsms", bp_bridge_hub_kusama::BridgeHubKusamaBaseXcmFeeInKsms::get(), || { @@ -328,7 +328,7 @@ pub fn can_calculate_weight_for_paid_export_message_with_reserve_transfer() { #[test] pub fn can_calculate_fee_for_complex_message_delivery_transaction() { - check_sane_fees_values( + bridge_hub_test_utils::check_sane_fees_values( "bp_bridge_hub_kusama::BridgeHubKusamaBaseDeliveryFeeInKsms", bp_bridge_hub_kusama::BridgeHubKusamaBaseDeliveryFeeInKsms::get(), || { @@ -347,7 +347,7 @@ pub fn can_calculate_fee_for_complex_message_delivery_transaction() { #[test] pub fn can_calculate_fee_for_complex_message_confirmation_transaction() { - check_sane_fees_values( + bridge_hub_test_utils::check_sane_fees_values( "bp_bridge_hub_kusama::BridgeHubKusamaBaseConfirmationFeeInKsms", bp_bridge_hub_kusama::BridgeHubKusamaBaseConfirmationFeeInKsms::get(), || { @@ -371,55 +371,3 @@ fn treasury_pallet_account_not_none() { LocationToAccountId::convert_location(&RelayTreasuryLocation::get()).unwrap() ) } - -use sp_runtime::Perbill; - -// TODO:(PR#159): remove when `polkadot-sdk@1.8.0` bump (https://github.com/polkadot-fellows/runtimes/issues/186) -/// A helper function for comparing the actual value of a fee constant with its estimated value. The -/// estimated value can be overestimated (`overestimate_in_percent`), and if the difference to the -/// actual value is below `margin_overestimate_diff_in_percent_for_lowering`, we should lower the -/// actual value. -pub fn check_sane_fees_values( - const_name: &str, - actual: u128, - calculate_estimated_fee: fn() -> u128, - overestimate_in_percent: Perbill, - margin_overestimate_diff_in_percent_for_lowering: Option, - label: &str, -) { - let estimated = calculate_estimated_fee(); - let estimated_plus_overestimate = estimated + (overestimate_in_percent * estimated); - let diff_to_estimated = diff_as_percent(actual, estimated); - let diff_to_estimated_plus_overestimate = diff_as_percent(actual, estimated_plus_overestimate); - - log::error!( - target: "bridges::estimate", - "{label}:\nconstant: {const_name}\n[+] actual: {actual}\n[+] estimated: {estimated} ({diff_to_estimated:.2?})\n[+] estimated(+33%): {estimated_plus_overestimate} ({diff_to_estimated_plus_overestimate:.2?})", - ); - - // check if estimated value is sane - assert!( - estimated <= actual, - "estimated: {estimated}, actual: {actual}, please adjust `{const_name}` to the value: {estimated_plus_overestimate}", - ); - assert!( - estimated_plus_overestimate <= actual, - "estimated_plus_overestimate: {estimated_plus_overestimate}, actual: {actual}, please adjust `{const_name}` to the value: {estimated_plus_overestimate}", - ); - - if let Some(margin_overestimate_diff_in_percent_for_lowering) = - margin_overestimate_diff_in_percent_for_lowering - { - assert!( - diff_to_estimated_plus_overestimate > margin_overestimate_diff_in_percent_for_lowering as f64, - "diff_to_estimated_plus_overestimate: {diff_to_estimated_plus_overestimate:.2}, overestimate_diff_in_percent_for_lowering: {margin_overestimate_diff_in_percent_for_lowering}, please adjust `{const_name}` to the value: {estimated_plus_overestimate}", - ); - } -} - -// TODO:(PR#159): remove when `polkadot-sdk@1.8.0` bump (https://github.com/polkadot-fellows/runtimes/issues/186) -pub fn diff_as_percent(left: u128, right: u128) -> f64 { - let left = left as f64; - let right = right as f64; - ((left - right).abs() / left) * 100f64 * (if left >= right { -1 } else { 1 }) as f64 -} diff --git a/system-parachains/bridge-hubs/bridge-hub-polkadot/primitives/src/lib.rs b/system-parachains/bridge-hubs/bridge-hub-polkadot/primitives/src/lib.rs index 8cfe7b494c..3677b3e547 100644 --- a/system-parachains/bridge-hubs/bridge-hub-polkadot/primitives/src/lib.rs +++ b/system-parachains/bridge-hubs/bridge-hub-polkadot/primitives/src/lib.rs @@ -93,11 +93,11 @@ frame_support::parameter_types! { /// Transaction fee that is paid at the Polkadot BridgeHub for delivering single inbound message. /// (initially was calculated by test `BridgeHubPolkadot::can_calculate_fee_for_complex_message_delivery_transaction` + `33%`) - pub const BridgeHubPolkadotBaseDeliveryFeeInDots: Balance = 16_912_512_364; + pub const BridgeHubPolkadotBaseDeliveryFeeInDots: Balance = 16_912_728_765; /// Transaction fee that is paid at the Polkadot BridgeHub for delivering single outbound message confirmation. /// (initially was calculated by test `BridgeHubPolkadot::can_calculate_fee_for_complex_message_confirmation_transaction` + `33%`) - pub const BridgeHubPolkadotBaseConfirmationFeeInDots: Balance = 16_142_641_864; + pub const BridgeHubPolkadotBaseConfirmationFeeInDots: Balance = 16_142_858_265; } /// Compute the total estimated fee that needs to be paid in DOTs by the sender when sending diff --git a/system-parachains/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs b/system-parachains/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs index 5c4eb1a438..4bf847fb38 100644 --- a/system-parachains/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs +++ b/system-parachains/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs @@ -27,12 +27,9 @@ use frame_support::{ use frame_system::EnsureRoot; use pallet_collator_selection::StakingPotAccountId; use pallet_xcm::XcmPassthrough; -use parachains_common::{ - impls::ToStakingPot, - xcm_config::{ - AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, - RelayOrOtherSystemParachains, - }, +use parachains_common::xcm_config::{ + AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, + RelayOrOtherSystemParachains, }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_constants::system_parachain; diff --git a/system-parachains/bridge-hubs/bridge-hub-polkadot/tests/snowbridge.rs b/system-parachains/bridge-hubs/bridge-hub-polkadot/tests/snowbridge.rs index 4bf2af4d03..ebf8b73e2b 100644 --- a/system-parachains/bridge-hubs/bridge-hub-polkadot/tests/snowbridge.rs +++ b/system-parachains/bridge-hubs/bridge-hub-polkadot/tests/snowbridge.rs @@ -35,16 +35,12 @@ use sp_core::H160; use sp_keyring::AccountKeyring::Alice; use sp_runtime::{ generic::{Era, SignedPayload}, - traits::Header, AccountId32, }; use xcm::latest::prelude::*; use xcm_builder::HandleFee; use xcm_executor::traits::{FeeManager, FeeReason}; -type RuntimeHelper = - parachains_runtimes_test_utils::RuntimeHelper; - parameter_types! { pub const DefaultBridgeHubEthereumBaseFee: Balance = 2_750_872_500_000; } diff --git a/system-parachains/bridge-hubs/bridge-hub-polkadot/tests/tests.rs b/system-parachains/bridge-hubs/bridge-hub-polkadot/tests/tests.rs index 0f03bd3415..360b583274 100644 --- a/system-parachains/bridge-hubs/bridge-hub-polkadot/tests/tests.rs +++ b/system-parachains/bridge-hubs/bridge-hub-polkadot/tests/tests.rs @@ -308,7 +308,7 @@ pub fn complex_relay_extrinsic_works() { #[test] pub fn can_calculate_weight_for_paid_export_message_with_reserve_transfer() { - check_sane_fees_values( + bridge_hub_test_utils::check_sane_fees_values( "bp_bridge_hub_polkadot::BridgeHubPolkadotBaseXcmFeeInDots", bp_bridge_hub_polkadot::BridgeHubPolkadotBaseXcmFeeInDots::get(), || { @@ -329,7 +329,7 @@ pub fn can_calculate_weight_for_paid_export_message_with_reserve_transfer() { #[test] pub fn can_calculate_fee_for_complex_message_delivery_transaction() { - check_sane_fees_values( + bridge_hub_test_utils::check_sane_fees_values( "bp_bridge_hub_polkadot::BridgeHubPolkadotBaseDeliveryFeeInDots", bp_bridge_hub_polkadot::BridgeHubPolkadotBaseDeliveryFeeInDots::get(), || { @@ -348,7 +348,7 @@ pub fn can_calculate_fee_for_complex_message_delivery_transaction() { #[test] pub fn can_calculate_fee_for_complex_message_confirmation_transaction() { - check_sane_fees_values( + bridge_hub_test_utils::check_sane_fees_values( "bp_bridge_hub_polkadot::BridgeHubPolkadotBaseConfirmationFeeInDots", bp_bridge_hub_polkadot::BridgeHubPolkadotBaseConfirmationFeeInDots::get(), || { @@ -372,53 +372,3 @@ fn treasury_pallet_account_not_none() { LocationToAccountId::convert_location(&RelayTreasuryLocation::get()).unwrap() ) } - -// TODO:(PR#159): remove when `polkadot-sdk@1.8.0` bump (https://github.com/polkadot-fellows/runtimes/issues/186) -/// A helper function for comparing the actual value of a fee constant with its estimated value. The -/// estimated value can be overestimated (`overestimate_in_percent`), and if the difference to the -/// actual value is below `margin_overestimate_diff_in_percent_for_lowering`, we should lower the -/// actual value. -pub fn check_sane_fees_values( - const_name: &str, - actual: u128, - calculate_estimated_fee: fn() -> u128, - overestimate_in_percent: Perbill, - margin_overestimate_diff_in_percent_for_lowering: Option, - label: &str, -) { - let estimated = calculate_estimated_fee(); - let estimated_plus_overestimate = estimated + (overestimate_in_percent * estimated); - let diff_to_estimated = diff_as_percent(actual, estimated); - let diff_to_estimated_plus_overestimate = diff_as_percent(actual, estimated_plus_overestimate); - - log::error!( - target: "bridges::estimate", - "{label}:\nconstant: {const_name}\n[+] actual: {actual}\n[+] estimated: {estimated} ({diff_to_estimated:.2?})\n[+] estimated(+33%): {estimated_plus_overestimate} ({diff_to_estimated_plus_overestimate:.2?})", - ); - - // check if estimated value is sane - assert!( - estimated <= actual, - "estimated: {estimated}, actual: {actual}, please adjust `{const_name}` to the value: {estimated_plus_overestimate}", - ); - assert!( - estimated_plus_overestimate <= actual, - "estimated_plus_overestimate: {estimated_plus_overestimate}, actual: {actual}, please adjust `{const_name}` to the value: {estimated_plus_overestimate}", - ); - - if let Some(margin_overestimate_diff_in_percent_for_lowering) = - margin_overestimate_diff_in_percent_for_lowering - { - assert!( - diff_to_estimated_plus_overestimate > margin_overestimate_diff_in_percent_for_lowering as f64, - "diff_to_estimated_plus_overestimate: {diff_to_estimated_plus_overestimate:.2}, overestimate_diff_in_percent_for_lowering: {margin_overestimate_diff_in_percent_for_lowering}, please adjust `{const_name}` to the value: {estimated_plus_overestimate}", - ); - } -} - -// TODO:(PR#159): remove when `polkadot-sdk@1.8.0` bump (https://github.com/polkadot-fellows/runtimes/issues/186) -pub fn diff_as_percent(left: u128, right: u128) -> f64 { - let left = left as f64; - let right = right as f64; - ((left - right).abs() / left) * 100f64 * (if left >= right { -1 } else { 1 }) as f64 -} diff --git a/system-parachains/collectives/collectives-polkadot/src/xcm_config.rs b/system-parachains/collectives/collectives-polkadot/src/xcm_config.rs index 9eeab4b6ee..bf69613d39 100644 --- a/system-parachains/collectives/collectives-polkadot/src/xcm_config.rs +++ b/system-parachains/collectives/collectives-polkadot/src/xcm_config.rs @@ -25,12 +25,9 @@ use frame_support::{ use frame_system::EnsureRoot; use pallet_collator_selection::StakingPotAccountId; use pallet_xcm::XcmPassthrough; -use parachains_common::{ - impls::ToStakingPot, - xcm_config::{ - AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, - RelayOrOtherSystemParachains, - }, +use parachains_common::xcm_config::{ + AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, + RelayOrOtherSystemParachains, }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_constants::{ diff --git a/system-parachains/coretime/coretime-kusama/src/xcm_config.rs b/system-parachains/coretime/coretime-kusama/src/xcm_config.rs index a2b868528a..24e98f5125 100644 --- a/system-parachains/coretime/coretime-kusama/src/xcm_config.rs +++ b/system-parachains/coretime/coretime-kusama/src/xcm_config.rs @@ -27,12 +27,9 @@ use frame_support::{ use frame_system::EnsureRoot; use pallet_collator_selection::StakingPotAccountId; use pallet_xcm::XcmPassthrough; -use parachains_common::{ - impls::ToStakingPot, - xcm_config::{ - AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, - RelayOrOtherSystemParachains, - }, +use parachains_common::xcm_config::{ + AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, + RelayOrOtherSystemParachains, }; use polkadot_parachain_primitives::primitives::Sibling; use sp_runtime::traits::AccountIdConversion; diff --git a/system-parachains/people/people-kusama/src/xcm_config.rs b/system-parachains/people/people-kusama/src/xcm_config.rs index 4aa53abd3d..4fd753ea6a 100644 --- a/system-parachains/people/people-kusama/src/xcm_config.rs +++ b/system-parachains/people/people-kusama/src/xcm_config.rs @@ -26,7 +26,6 @@ use frame_system::EnsureRoot; use pallet_collator_selection::StakingPotAccountId; use pallet_xcm::XcmPassthrough; use parachains_common::{ - impls::ToStakingPot, xcm_config::{ AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, RelayOrOtherSystemParachains,