From dda93087c930afc6e15d2719916cd68803c75dbc Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 13 Mar 2024 12:56:27 +0200 Subject: [PATCH 01/30] pallet-xcm: deprecate unlimited_* weight extrinsics --- .../asset-hub-rococo/src/tests/teleport.rs | 143 ------------------ .../asset-hub-westend/src/tests/teleport.rs | 143 ------------------ .../bridge-hub-rococo/src/tests/snowbridge.rs | 3 +- polkadot/runtime/westend/src/tests.rs | 3 +- polkadot/xcm/pallet-xcm/src/lib.rs | 14 +- .../pallet-xcm/src/tests/assets_transfer.rs | 81 +++------- polkadot/xcm/xcm-simulator/example/src/lib.rs | 3 +- 7 files changed, 38 insertions(+), 352 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs index 0cc5ddb9f64d..01e9054e60dd 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs @@ -245,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, @@ -266,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, @@ -421,129 +401,6 @@ 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 = ROCOCO_ED * 1000; - let dest = Rococo::child_location_of(AssetHubRococo::para_id()); - let beneficiary_id = AssetHubRococoReceiver::get(); - let test_args = TestContext { - sender: RococoSender::get(), - receiver: AssetHubRococoReceiver::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 = Rococo::execute_with(|| { - xcm_helpers::transfer_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_ROCOCO_ED * 1000; - let destination = AssetHubRococo::parent_location(); - let beneficiary_id = RococoReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubRococoSender::get(), - receiver: RococoReceiver::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 = AssetHubRococo::execute_with(|| { - xcm_helpers::transfer_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_ROCOCO_ED * 1000; - let destination = AssetHubRococo::parent_location(); - let beneficiary_id = RococoReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubRococoSender::get(), - receiver: RococoReceiver::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 = AssetHubRococo::execute_with(|| { - xcm_helpers::transfer_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_ROCOCO_ED * 100; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs index 61f547fe7c5e..1680d871e080 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs @@ -245,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, @@ -266,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, @@ -421,129 +401,6 @@ 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 = WESTEND_ED * 1000; - let dest = Westend::child_location_of(AssetHubWestend::para_id()); - let beneficiary_id = AssetHubWestendReceiver::get(); - let test_args = TestContext { - sender: WestendSender::get(), - receiver: AssetHubWestendReceiver::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 = Westend::execute_with(|| { - xcm_helpers::transfer_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_WESTEND_ED * 1000; - let destination = AssetHubWestend::parent_location(); - let beneficiary_id = WestendReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubWestendSender::get(), - receiver: WestendReceiver::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 = AssetHubWestend::execute_with(|| { - xcm_helpers::transfer_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_WESTEND_ED * 1000; - let destination = AssetHubWestend::parent_location(); - let beneficiary_id = WestendReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubWestendSender::get(), - receiver: WestendReceiver::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 = AssetHubWestend::execute_with(|| { - xcm_helpers::transfer_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_WESTEND_ED * 100; diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs index 1e74d63e1d52..7eff656ad229 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs @@ -458,12 +458,13 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { AssetHubRococoReceiver::get(), ); // Send the Weth back to Ethereum - ::PolkadotXcm::reserve_transfer_assets( + ::PolkadotXcm::limited_reserve_transfer_assets( RuntimeOrigin::signed(AssetHubRococoReceiver::get()), Box::new(destination), Box::new(beneficiary), Box::new(multi_assets), 0, + Unlimited, ) .unwrap(); let free_balance_after = ::Balances::free_balance( diff --git a/polkadot/runtime/westend/src/tests.rs b/polkadot/runtime/westend/src/tests.rs index 9f9963160590..f9c5a07a2eee 100644 --- a/polkadot/runtime/westend/src/tests.rs +++ b/polkadot/runtime/westend/src/tests.rs @@ -55,11 +55,12 @@ fn sanity_check_teleport_assets_weight() { // Usually when XCM runs into an issue, it will return a weight of `Weight::MAX`, // so this test will certainly ensure that this problem does not occur. use frame_support::dispatch::GetDispatchInfo; - let weight = pallet_xcm::Call::::teleport_assets { + let weight = pallet_xcm::Call::::limited_teleport_assets { dest: Box::new(Here.into()), beneficiary: Box::new(Here.into()), assets: Box::new((Here, 200_000).into()), fee_asset_item: 0, + weight_limit: Unlimited, } .get_dispatch_info() .weight; diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 1a1f8b402a39..c1c4f4f88754 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -947,6 +947,10 @@ pub mod pallet { _ => Weight::MAX, } })] + #[allow(deprecated)] + #[deprecated( + note = "This extrinsic uses `WeightLimit::Unlimited`, please migrate to `limited_teleport_assets` or `transfer_assets`" + )] pub fn teleport_assets( origin: OriginFor, dest: Box, @@ -1005,6 +1009,10 @@ pub mod pallet { _ => Weight::MAX, } })] + #[allow(deprecated)] + #[deprecated( + note = "This extrinsic uses `WeightLimit::Unlimited`, please migrate to `limited_reserve_transfer_assets` or `transfer_assets`" + )] pub fn reserve_transfer_assets( origin: OriginFor, dest: Box, @@ -1140,7 +1148,7 @@ pub mod pallet { /// /// Fee payment on the destination side is made from the asset in the `assets` vector of /// index `fee_asset_item`, up to enough to pay for `weight_limit` of weight. If more weight - /// is needed than `weight_limit`, then the operation will fail and the assets send may be + /// is needed than `weight_limit`, then the operation will fail and the sent assets may be /// at risk. /// /// - `origin`: Must be capable of withdrawing the `assets` and executing XCM. @@ -1194,7 +1202,7 @@ pub mod pallet { /// /// Fee payment on the destination side is made from the asset in the `assets` vector of /// index `fee_asset_item`, up to enough to pay for `weight_limit` of weight. If more weight - /// is needed than `weight_limit`, then the operation will fail and the assets send may be + /// is needed than `weight_limit`, then the operation will fail and the sent assets may be /// at risk. /// /// - `origin`: Must be capable of withdrawing the `assets` and executing XCM. @@ -1262,7 +1270,7 @@ pub mod pallet { /// Fee payment on the destination side is made from the asset in the `assets` vector of /// index `fee_asset_item` (hence referred to as `fees`), up to enough to pay for /// `weight_limit` of weight. If more weight is needed than `weight_limit`, then the - /// operation will fail and the assets sent may be at risk. + /// operation will fail and the sent assets may be at risk. /// /// `assets` (excluding `fees`) must have same reserve location or otherwise be teleportable /// to `dest`, no limitations imposed on `fees`. diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index 27be5cce1458..d8a37f152915 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -31,13 +31,17 @@ use sp_runtime::{traits::AccountIdConversion, DispatchError, ModuleError}; use xcm::prelude::*; use xcm_executor::traits::ConvertLocation; -// Helper function to deduplicate testing different teleport types. -fn do_test_and_verify_teleport_assets( - origin_location: Location, - expected_beneficiary: Location, - call: Call, - expected_weight_limit: WeightLimit, -) { +/// Test `limited_teleport_assets` +/// +/// Asserts that the sender's balance is decreased as a result of execution of +/// local effects. +#[test] +fn limited_teleport_assets_works() { + let origin_location: Location = AccountId32 { network: None, id: ALICE.into() }.into(); + let expected_beneficiary: Location = AccountId32 { network: None, id: BOB.into() }.into(); + let weight_limit = WeightLimit::Limited(Weight::from_parts(5000, 5000)); + let expected_weight_limit = weight_limit.clone(); + let balances = vec![ (ALICE, INITIAL_BALANCE), (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), @@ -47,7 +51,14 @@ fn do_test_and_verify_teleport_assets( let weight = BaseXcmWeight::get() * 2; assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); // call extrinsic - call(); + assert_ok!(XcmPallet::limited_teleport_assets( + RuntimeOrigin::signed(ALICE), + Box::new(RelayLocation::get().into()), + Box::new(expected_beneficiary.clone().into()), + Box::new((Here, SEND_AMOUNT).into()), + 0, + weight_limit, + )); assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); assert_eq!( sent_xcm(), @@ -88,57 +99,6 @@ fn do_test_and_verify_teleport_assets( }); } -/// Test `teleport_assets` -/// -/// Asserts that the sender's balance is decreased as a result of execution of -/// local effects. -#[test] -fn teleport_assets_works() { - let origin_location: Location = AccountId32 { network: None, id: ALICE.into() }.into(); - let beneficiary: Location = AccountId32 { network: None, id: BOB.into() }.into(); - do_test_and_verify_teleport_assets( - origin_location.clone(), - beneficiary.clone(), - || { - assert_ok!(XcmPallet::teleport_assets( - RuntimeOrigin::signed(ALICE), - Box::new(RelayLocation::get().into()), - Box::new(beneficiary.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - )); - }, - Unlimited, - ); -} - -/// Test `limited_teleport_assets` -/// -/// Asserts that the sender's balance is decreased as a result of execution of -/// local effects. -#[test] -fn limited_teleport_assets_works() { - let origin_location: Location = AccountId32 { network: None, id: ALICE.into() }.into(); - let beneficiary: Location = AccountId32 { network: None, id: BOB.into() }.into(); - let weight_limit = WeightLimit::Limited(Weight::from_parts(5000, 5000)); - let expected_weight_limit = weight_limit.clone(); - do_test_and_verify_teleport_assets( - origin_location.clone(), - beneficiary.clone(), - || { - assert_ok!(XcmPallet::limited_teleport_assets( - RuntimeOrigin::signed(ALICE), - Box::new(RelayLocation::get().into()), - Box::new(beneficiary.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - weight_limit, - )); - }, - expected_weight_limit, - ); -} - /// `limited_teleport_assets` should fail for filtered assets #[test] fn limited_teleport_filtered_assets_disallowed() { @@ -184,12 +144,13 @@ fn reserve_transfer_assets_with_paid_router_works() { let dest: Location = Junction::AccountId32 { network: None, id: user_account.clone().into() }.into(); assert_eq!(Balances::total_balance(&user_account), INITIAL_BALANCE); - assert_ok!(XcmPallet::reserve_transfer_assets( + assert_ok!(XcmPallet::limited_reserve_transfer_assets( RuntimeOrigin::signed(user_account.clone()), Box::new(Parachain(paid_para_id).into()), Box::new(dest.clone().into()), Box::new((Here, SEND_AMOUNT).into()), 0, + Unlimited, )); // XCM_FEES_NOT_WAIVED_USER_ACCOUNT spent amount diff --git a/polkadot/xcm/xcm-simulator/example/src/lib.rs b/polkadot/xcm/xcm-simulator/example/src/lib.rs index d134957fbc1c..cf330064a26b 100644 --- a/polkadot/xcm/xcm-simulator/example/src/lib.rs +++ b/polkadot/xcm/xcm-simulator/example/src/lib.rs @@ -250,12 +250,13 @@ mod tests { let withdraw_amount = 123; Relay::execute_with(|| { - assert_ok!(RelayChainPalletXcm::reserve_transfer_assets( + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( relay_chain::RuntimeOrigin::signed(ALICE), Box::new(Parachain(1).into()), Box::new(AccountId32 { network: None, id: ALICE.into() }.into()), Box::new((Here, withdraw_amount).into()), 0, + Unlimited, )); assert_eq!( relay_chain::Balances::free_balance(&child_account_id(1)), From 1db1cae089338ee97936d4689649b11308befab3 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 13 Mar 2024 12:57:37 +0200 Subject: [PATCH 02/30] pallet-xcm: remove extrinsics guessed weight and rely on runtime benchmarks instead --- polkadot/xcm/pallet-xcm/src/lib.rs | 114 +---------------------------- 1 file changed, 3 insertions(+), 111 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index c1c4f4f88754..094fafcc389a 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -898,10 +898,9 @@ pub mod pallet { } } - #[pallet::call] + #[pallet::call(weight(::WeightInfo))] impl Pallet { #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::send())] pub fn send( origin: OriginFor, dest: Box, @@ -930,23 +929,6 @@ pub mod pallet { /// - `fee_asset_item`: The index into `assets` of the item which should be used to pay /// fees. #[pallet::call_index(1)] - #[pallet::weight({ - let maybe_assets: Result = (*assets.clone()).try_into(); - let maybe_dest: Result = (*dest.clone()).try_into(); - match (maybe_assets, maybe_dest) { - (Ok(assets), Ok(dest)) => { - use sp_std::vec; - let count = assets.len() as u32; - let mut message = Xcm(vec![ - WithdrawAsset(assets), - SetFeesMode { jit_withdraw: true }, - InitiateTeleport { assets: Wild(AllCounted(count)), dest, xcm: Xcm(vec![]) }, - ]); - T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::teleport_assets().saturating_add(w)) - } - _ => Weight::MAX, - } - })] #[allow(deprecated)] #[deprecated( note = "This extrinsic uses `WeightLimit::Unlimited`, please migrate to `limited_teleport_assets` or `transfer_assets`" @@ -992,23 +974,6 @@ pub mod pallet { /// - `fee_asset_item`: The index into `assets` of the item which should be used to pay /// fees. #[pallet::call_index(2)] - #[pallet::weight({ - let maybe_assets: Result = (*assets.clone()).try_into(); - let maybe_dest: Result = (*dest.clone()).try_into(); - match (maybe_assets, maybe_dest) { - (Ok(assets), Ok(dest)) => { - use sp_std::vec; - // heaviest version of locally executed XCM program: equivalent in weight to - // transfer assets to SA, reanchor them, extend XCM program, and send onward XCM - let mut message = Xcm(vec![ - SetFeesMode { jit_withdraw: true }, - TransferReserveAsset { assets, dest, xcm: Xcm(vec![]) } - ]); - T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::reserve_transfer_assets().saturating_add(w)) - } - _ => Weight::MAX, - } - })] #[allow(deprecated)] #[deprecated( note = "This extrinsic uses `WeightLimit::Unlimited`, please migrate to `limited_reserve_transfer_assets` or `transfer_assets`" @@ -1057,7 +1022,6 @@ pub mod pallet { /// - `location`: The destination that is being described. /// - `xcm_version`: The latest version of XCM that `location` supports. #[pallet::call_index(4)] - #[pallet::weight(T::WeightInfo::force_xcm_version())] pub fn force_xcm_version( origin: OriginFor, location: Box, @@ -1076,7 +1040,6 @@ pub mod pallet { /// - `origin`: Must be an origin specified by AdminOrigin. /// - `maybe_xcm_version`: The default XCM encoding version, or `None` to disable. #[pallet::call_index(5)] - #[pallet::weight(T::WeightInfo::force_default_xcm_version())] pub fn force_default_xcm_version( origin: OriginFor, maybe_xcm_version: Option, @@ -1091,7 +1054,6 @@ pub mod pallet { /// - `origin`: Must be an origin specified by AdminOrigin. /// - `location`: The location to which we should subscribe for XCM version notifications. #[pallet::call_index(6)] - #[pallet::weight(T::WeightInfo::force_subscribe_version_notify())] pub fn force_subscribe_version_notify( origin: OriginFor, location: Box, @@ -1115,7 +1077,6 @@ pub mod pallet { /// - `location`: The location to which we are currently subscribed for XCM version /// notifications which we no longer desire. #[pallet::call_index(7)] - #[pallet::weight(T::WeightInfo::force_unsubscribe_version_notify())] pub fn force_unsubscribe_version_notify( origin: OriginFor, location: Box, @@ -1163,23 +1124,7 @@ pub mod pallet { /// fees. /// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase. #[pallet::call_index(8)] - #[pallet::weight({ - let maybe_assets: Result = (*assets.clone()).try_into(); - let maybe_dest: Result = (*dest.clone()).try_into(); - match (maybe_assets, maybe_dest) { - (Ok(assets), Ok(dest)) => { - use sp_std::vec; - // heaviest version of locally executed XCM program: equivalent in weight to - // transfer assets to SA, reanchor them, extend XCM program, and send onward XCM - let mut message = Xcm(vec![ - SetFeesMode { jit_withdraw: true }, - TransferReserveAsset { assets, dest, xcm: Xcm(vec![]) } - ]); - T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::reserve_transfer_assets().saturating_add(w)) - } - _ => Weight::MAX, - } - })] + #[pallet::weight(T::WeightInfo::reserve_transfer_assets())] pub fn limited_reserve_transfer_assets( origin: OriginFor, dest: Box, @@ -1217,23 +1162,7 @@ pub mod pallet { /// fees. /// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase. #[pallet::call_index(9)] - #[pallet::weight({ - let maybe_assets: Result = (*assets.clone()).try_into(); - let maybe_dest: Result = (*dest.clone()).try_into(); - match (maybe_assets, maybe_dest) { - (Ok(assets), Ok(dest)) => { - use sp_std::vec; - let count = assets.len() as u32; - let mut message = Xcm(vec![ - WithdrawAsset(assets), - SetFeesMode { jit_withdraw: true }, - InitiateTeleport { assets: Wild(AllCounted(count)), dest, xcm: Xcm(vec![]) }, - ]); - T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::teleport_assets().saturating_add(w)) - } - _ => Weight::MAX, - } - })] + #[pallet::weight(T::WeightInfo::teleport_assets())] pub fn limited_teleport_assets( origin: OriginFor, dest: Box, @@ -1257,7 +1186,6 @@ pub mod pallet { /// - `origin`: Must be an origin specified by AdminOrigin. /// - `suspended`: `true` to suspend, `false` to resume. #[pallet::call_index(10)] - #[pallet::weight(T::WeightInfo::force_suspension())] pub fn force_suspension(origin: OriginFor, suspended: bool) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; XcmExecutionSuspended::::set(suspended); @@ -1298,26 +1226,6 @@ pub mod pallet { /// fees. /// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase. #[pallet::call_index(11)] - #[pallet::weight({ - let maybe_assets: Result = (*assets.clone()).try_into(); - let maybe_dest: Result = (*dest.clone()).try_into(); - match (maybe_assets, maybe_dest) { - (Ok(assets), Ok(dest)) => { - use sp_std::vec; - // heaviest version of locally executed XCM program: equivalent in weight to withdrawing fees, - // burning them, transferring rest of assets to SA, reanchoring them, extending XCM program, - // and sending onward XCM - let mut message = Xcm(vec![ - SetFeesMode { jit_withdraw: true }, - WithdrawAsset(assets.clone()), - BurnAsset(assets.clone()), - TransferReserveAsset { assets, dest, xcm: Xcm(vec![]) } - ]); - T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::transfer_assets().saturating_add(w)) - } - _ => Weight::MAX, - } - })] pub fn transfer_assets( origin: OriginFor, dest: Box, @@ -1407,22 +1315,6 @@ pub mod pallet { /// was the latest when they were trapped. /// - `beneficiary`: The location/account where the claimed assets will be deposited. #[pallet::call_index(12)] - #[pallet::weight({ - let assets_version = assets.identify_version(); - let maybe_assets: Result = (*assets.clone()).try_into(); - let maybe_beneficiary: Result = (*beneficiary.clone()).try_into(); - match (maybe_assets, maybe_beneficiary) { - (Ok(assets), Ok(beneficiary)) => { - let ticket: Location = GeneralIndex(assets_version as u128).into(); - let mut message = Xcm(vec![ - ClaimAsset { assets: assets.clone(), ticket }, - DepositAsset { assets: AllCounted(assets.len() as u32).into(), beneficiary }, - ]); - T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::claim_assets().saturating_add(w)) - } - _ => Weight::MAX - } - })] pub fn claim_assets( origin: OriginFor, assets: Box, From f5e1dfb9f298fd294d7d9a63627de7e553dfc7f1 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 13 Mar 2024 12:57:58 +0200 Subject: [PATCH 03/30] pallet-xcm: add new extrinsic for asset transfers using explicit reserve Add `transfer_assets_using_reserve()` for transferring assets from local chain to destination chain using an explicit reserve location (typically local Asset Hub). By default, an asset's reserve is its origin chain. But sometimes we may want to explicitly use another chain as reserve (as long as allowed by runtime `IsReserve` filter). This is very helpful for transferring assets with multiple configured reserves (such as Asset Hub ForeignAssets), when the transfer strictly depends on the used reserve. E.g. For transferring Foreign Assets over a bridge, Asset Hub must be used as the reserve location. --- .../src/weights/pallet_xcm.rs | 4 + .../src/weights/pallet_xcm.rs | 4 + .../src/weights/pallet_xcm.rs | 4 + .../src/weights/pallet_xcm.rs | 4 + .../src/weights/pallet_xcm.rs | 4 + .../coretime-rococo/src/weights/pallet_xcm.rs | 4 + .../src/weights/pallet_xcm.rs | 4 + .../people-rococo/src/weights/pallet_xcm.rs | 4 + .../people-westend/src/weights/pallet_xcm.rs | 4 + .../parachains/runtimes/test-utils/src/lib.rs | 3 +- .../runtime/rococo/src/weights/pallet_xcm.rs | 4 + .../runtime/westend/src/weights/pallet_xcm.rs | 4 + polkadot/xcm/pallet-xcm/src/lib.rs | 167 ++++++++++++++++-- 13 files changed, 194 insertions(+), 20 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs index 51b6543bae82..ef9bd8d3dc64 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs @@ -48,6 +48,10 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + fn transfer_assets_using_reserve() -> Weight { + // TODO: benchmark + Weight::from_parts(0, 0) + } /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs index 71facff87d35..ea81bf0b4f7b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs @@ -48,6 +48,10 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + fn transfer_assets_using_reserve() -> Weight { + // TODO: benchmark + Weight::from_parts(0, 0) + } /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs index a732e1a57343..074e34c1c261 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs @@ -48,6 +48,10 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + fn transfer_assets_using_reserve() -> Weight { + // TODO: benchmark + Weight::from_parts(0, 0) + } /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs index a78ff2355efa..1073a0c8658e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs @@ -48,6 +48,10 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + fn transfer_assets_using_reserve() -> Weight { + // TODO: benchmark + Weight::from_parts(0, 0) + } /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs index 5d427d850046..e2ba905455cd 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs @@ -48,6 +48,10 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + fn transfer_assets_using_reserve() -> Weight { + // TODO: benchmark + Weight::from_parts(0, 0) + } /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs index c5d315467c1e..e0fe3c7320d6 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs @@ -48,6 +48,10 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + fn transfer_assets_using_reserve() -> Weight { + // TODO: benchmark + Weight::from_parts(0, 0) + } /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs index 0082db3099d0..b286caed9c01 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs @@ -48,6 +48,10 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + fn transfer_assets_using_reserve() -> Weight { + // TODO: benchmark + Weight::from_parts(0, 0) + } /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs index fabce29b5fd9..304777128bc0 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs @@ -48,6 +48,10 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + fn transfer_assets_using_reserve() -> Weight { + // TODO: benchmark + Weight::from_parts(0, 0) + } /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs index c337289243b7..22f27c407266 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs @@ -48,6 +48,10 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + fn transfer_assets_using_reserve() -> Weight { + // TODO: benchmark + Weight::from_parts(0, 0) + } /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) diff --git a/cumulus/parachains/runtimes/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs index e62daa16a125..3c84243306fb 100644 --- a/cumulus/parachains/runtimes/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs @@ -425,12 +425,13 @@ impl< } // do teleport - >::teleport_assets( + >::limited_teleport_assets( origin, Box::new(dest.into()), Box::new(beneficiary.into()), Box::new((AssetId(asset), amount).into()), 0, + Unlimited, ) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs index 5544ca44658c..50d472d2e242 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs @@ -346,4 +346,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + fn transfer_assets_using_reserve() -> Weight { + // TODO: benchmark + Weight::from_parts(0, 0) + } } diff --git a/polkadot/runtime/westend/src/weights/pallet_xcm.rs b/polkadot/runtime/westend/src/weights/pallet_xcm.rs index 10725cecf249..ab487aaca94d 100644 --- a/polkadot/runtime/westend/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/westend/src/weights/pallet_xcm.rs @@ -48,6 +48,10 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + fn transfer_assets_using_reserve() -> Weight { + // TODO: benchmark + Weight::from_parts(0, 0) + } /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 094fafcc389a..8214015f4283 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -86,6 +86,7 @@ pub trait WeightInfo { fn new_query() -> Weight; fn take_response() -> Weight; fn claim_assets() -> Weight; + fn transfer_assets_using_reserve() -> Weight; } /// fallback implementation @@ -170,6 +171,10 @@ impl WeightInfo for TestWeightInfo { fn claim_assets() -> Weight { Weight::from_parts(100_000_000, 0) } + + fn transfer_assets_using_reserve() -> Weight { + Weight::from_parts(100_000_000, 0) + } } #[frame_support::pallet] @@ -1297,15 +1302,16 @@ pub mod pallet { FeesHandling::Separate { local_xcm, remote_xcm } }; - Self::build_and_execute_xcm_transfer_type( - origin, - dest, + let (local_xcm, remote_xcm) = Self::build_xcm_transfer_type( + origin.clone(), + dest.clone(), beneficiary, assets, assets_transfer_type, fees, weight_limit, - ) + )?; + Self::execute_xcm_transfer(origin, dest, local_xcm, remote_xcm) } /// Claims assets trapped on this pallet because of leftover assets during XCM execution. @@ -1349,6 +1355,111 @@ pub mod pallet { })?; Ok(()) } + + /// Transfer some assets from the local chain to the destination chain through using an + /// explicit reserve location (typically local Asset Hub). + /// + /// `assets` must have same reserve location and may not be teleportable to `dest`, + /// but may be teleportable to their `force_reserve` location. + /// - `assets` have local reserve: transfer assets to sovereign account of destination + /// chain and forward a notification XCM to `dest` to mint and deposit reserve-based + /// assets to `beneficiary`. + /// - `assets` have destination reserve: burn local assets and forward a notification to + /// `dest` chain to withdraw the reserve assets from this chain's sovereign account and + /// deposit them to `beneficiary`. + /// - `assets` have remote reserve: burn local assets, forward XCM to reserve chain to move + /// reserves from this chain's SA to `dest` chain's SA, and forward another XCM to `dest` + /// to mint and deposit reserve-based assets to `beneficiary`. + /// + /// Fee payment on the source, destination and all intermediary hops, is specified through + /// `fees`, but make sure enough of the specified `fees` asset is included in the given list + /// of `assets`. `fees` should be enough to pay for `weight_limit`. If more weight is needed + /// than `weight_limit`, then the operation will fail and the sent assets may be at risk. + /// + /// - `origin`: Must be capable of withdrawing the `assets` and executing XCM. + /// - `dest`: Destination context for the assets. Will typically be `[Parent, + /// Parachain(..)]` to send from parachain to parachain, or `[Parachain(..)]` to send from + /// relay to parachain, or `(parents: 2, (GlobalConsensus(..), ..))` to send from + /// parachain across a bridge to another ecosystem destination. + /// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will + /// generally be an `AccountId32` value. + /// - `assets`: The assets to be withdrawn. This should include the assets used to pay the + /// fee on the `dest` (and possibly reserve) chains. + /// - `fees`: One of the included `assets` to be be used to pay fees. + /// - `using_reserve`: Forces this transfer to use `using_reserve` location as the reserve + /// location for `assets`. Will typically be `None`, or `Some(LocalAssetHubLocation)` for + /// transferring ForeignAssets going through Asset Hub. + /// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase. + #[pallet::call_index(13)] + pub fn transfer_assets_using_reserve( + origin: OriginFor, + dest: Box, + beneficiary: Box, + assets: Box, + fees: Box, + using_reserve: Box, + weight_limit: WeightLimit, + ) -> DispatchResult { + let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; + let dest: Location = (*dest).try_into().map_err(|()| Error::::BadVersion)?; + let beneficiary: Location = + (*beneficiary).try_into().map_err(|()| Error::::BadVersion)?; + let assets: Assets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; + let fees: Asset = (*fees).try_into().map_err(|()| Error::::BadVersion)?; + let reserve: Location = + (*using_reserve).try_into().map_err(|()| Error::::BadVersion)?; + log::debug!( + target: "xcm::pallet_xcm::transfer_assets_using_reserve", + "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, fees {:?}, using reserve {:?}", + origin_location, dest, beneficiary, assets, fees, reserve, + ); + + ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::::TooManyAssets); + let value = (origin_location, assets.into_inner()); + ensure!(T::XcmReserveTransferFilter::contains(&value), Error::::Filtered); + let (origin, assets) = value; + + let fee_asset_index = + assets.iter().position(|a| a.id == fees.id).ok_or(Error::::FeesNotMet)?; + let fee_asset = assets.get(fee_asset_index).ok_or(Error::::Empty)?; + ensure!( + matches!((&fee_asset.fun, &fees.fun), (Fungible(a), Fungible(f)) if a >= f), + Error::::FeesNotMet + ); + + // Find transfer types for fee and non-fee assets, to get to the explicit reserve. + let (fees_transfer_type, mut assets_transfer_type) = + Self::find_fee_and_assets_transfer_types(&assets, fee_asset_index, &reserve)?; + // Ensure `reserve` is configured reserve for `assets`. + // Future enhancement: also support teleports to local reserve chain. + ensure!( + matches!(assets_transfer_type, TransferType::DestinationReserve), + Error::::InvalidAssetUnsupportedReserve + ); + + // local and remote XCM programs to potentially handle fees separately + let fees = if fees_transfer_type == assets_transfer_type { + // no need for custom fees instructions, fees are batched with assets, and we are + // doing classic remote reserve transfer + assets_transfer_type = TransferType::RemoteReserve(reserve); + FeesHandling::Batched { fees } + } else { + // Future enhancement: also support combinations of reserve and teleport for assets + // and fees. + return Err(Error::::Filtered.into()) + }; + + let (local_xcm, remote_xcm) = Self::build_xcm_transfer_type( + origin.clone(), + dest.clone(), + beneficiary, + assets, + assets_transfer_type, + fees, + weight_limit, + )?; + Self::execute_xcm_transfer(origin, dest, local_xcm, remote_xcm) + } } } @@ -1514,15 +1625,16 @@ impl Pallet { // Ensure all assets (including fees) have same reserve location. ensure!(assets_transfer_type == fees_transfer_type, Error::::TooManyReserves); - Self::build_and_execute_xcm_transfer_type( - origin, - dest, + let (local_xcm, remote_xcm) = Self::build_xcm_transfer_type( + origin.clone(), + dest.clone(), beneficiary, assets, assets_transfer_type, FeesHandling::Batched { fees }, weight_limit, - ) + )?; + Self::execute_xcm_transfer(origin, dest, local_xcm, remote_xcm) } fn do_teleport_assets( @@ -1555,18 +1667,19 @@ impl Pallet { } let fees = assets.get(fee_asset_item as usize).ok_or(Error::::Empty)?.clone(); - Self::build_and_execute_xcm_transfer_type( - origin_location, - dest, + let (local_xcm, remote_xcm) = Self::build_xcm_transfer_type( + origin_location.clone(), + dest.clone(), beneficiary, assets, TransferType::Teleport, FeesHandling::Batched { fees }, weight_limit, - ) + )?; + Self::execute_xcm_transfer(origin_location, dest, local_xcm, remote_xcm) } - fn build_and_execute_xcm_transfer_type( + fn build_xcm_transfer_type( origin: Location, dest: Location, beneficiary: Location, @@ -1574,14 +1687,14 @@ impl Pallet { transfer_type: TransferType, fees: FeesHandling, weight_limit: WeightLimit, - ) -> DispatchResult { + ) -> Result<(Xcm<::RuntimeCall>, Option>), Error> { log::debug!( - target: "xcm::pallet_xcm::build_and_execute_xcm_transfer_type", + target: "xcm::pallet_xcm::build_xcm_transfer_type", "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, transfer_type {:?}, \ fees_handling {:?}, weight_limit: {:?}", origin, dest, beneficiary, assets, transfer_type, fees, weight_limit, ); - let (mut local_xcm, remote_xcm) = match transfer_type { + Ok(match transfer_type { TransferType::LocalReserve => { let (local, remote) = Self::local_reserve_transfer_programs( origin.clone(), @@ -1631,7 +1744,21 @@ impl Pallet { )?; (local, Some(remote)) }, - }; + }) + } + + fn execute_xcm_transfer( + origin: Location, + dest: Location, + mut local_xcm: Xcm<::RuntimeCall>, + remote_xcm: Option>, + ) -> DispatchResult { + log::debug!( + target: "xcm::pallet_xcm::execute_xcm_transfer", + "origin {:?}, dest {:?}, local_xcm {:?}, remote_xcm {:?}", + origin, dest, local_xcm, remote_xcm, + ); + let weight = T::Weigher::weight(&mut local_xcm).map_err(|()| Error::::UnweighableMessage)?; let mut hash = local_xcm.using_encoded(sp_io::hashing::blake2_256); @@ -1645,7 +1772,7 @@ impl Pallet { Self::deposit_event(Event::Attempted { outcome: outcome.clone() }); outcome.ensure_complete().map_err(|error| { log::error!( - target: "xcm::pallet_xcm::build_and_execute_xcm_transfer_type", + target: "xcm::pallet_xcm::execute_xcm_transfer", "XCM execution failed with error {:?}", error ); Error::::LocalExecutionIncomplete @@ -1657,7 +1784,7 @@ impl Pallet { if origin != Here.into_location() { Self::charge_fees(origin.clone(), price).map_err(|error| { log::error!( - target: "xcm::pallet_xcm::build_and_execute_xcm_transfer_type", + target: "xcm::pallet_xcm::execute_xcm_transfer", "Unable to charge fee with error {:?}", error ); Error::::FeesNotMet @@ -1842,6 +1969,8 @@ impl Pallet { ]); // handle fees Self::add_fees_to_xcm(dest, fees, weight_limit, &mut local_execute_xcm, &mut xcm_on_dest)?; + + // TODO: custom action // deposit all remaining assets in holding to `beneficiary` location xcm_on_dest .inner_mut() From 547eeee710d1596e45115e388ed974a2861bbb7d Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 13 Mar 2024 19:08:55 +0200 Subject: [PATCH 04/30] add more trace logging to XCM transport --- .../modules/xcm-bridge-hub-router/src/lib.rs | 18 +++++++++++++++++- cumulus/pallets/xcmp-queue/src/lib.rs | 5 ++++- polkadot/xcm/xcm-executor/src/lib.rs | 4 ++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs index f219be78f9e1..2e6433f7e6ec 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -191,6 +191,10 @@ pub mod pallet { impl, I: 'static> Pallet { /// Called when new message is sent (queued to local outbound XCM queue) over the bridge. pub(crate) fn on_message_sent_to_bridge(message_size: u32) { + log::trace!( + target: "xcm::xcm_bridge_hub_router::on_message_sent_to_bridge", + "message_size: {:?}", message_size, + ); let _ = Bridge::::try_mutate(|bridge| { let is_channel_with_bridge_hub_congested = T::WithBridgeHubChannel::is_congested(); let is_bridge_congested = bridge.is_congested; @@ -238,6 +242,10 @@ impl, I: 'static> ExporterFor for Pallet { remote_location: &InteriorLocation, message: &Xcm<()>, ) -> Option<(Location, Option)> { + log::trace!( + target: "xcm::xcm_bridge_hub_router::exporter_for", + "network: {:?}, remote_location: {:?}, msg: {:?}", network, remote_location, message + ); // ensure that the message is sent to the expected bridged network (if specified). if let Some(bridged_network) = T::BridgedNetworkId::get() { if *network != bridged_network { @@ -300,7 +308,7 @@ impl, I: 'static> ExporterFor for Pallet { log::info!( target: LOG_TARGET, - "Going to send message to {:?} ({} bytes) over bridge. Computed bridge fee {:?} using fee factor {}", + "Validate send message to {:?} ({} bytes) over bridge. Computed bridge fee {:?} using fee factor {}", (network, remote_location), message_size, fee, @@ -321,6 +329,10 @@ impl, I: 'static> SendXcm for Pallet { dest: &mut Option, xcm: &mut Option>, ) -> SendResult { + log::trace!( + target: "xcm::xcm_bridge_hub_router::validate", + "msg: {:?}, destination: {:?}", xcm, dest, + ); // `dest` and `xcm` are required here let dest_ref = dest.as_ref().ok_or(SendError::MissingArgument)?; let xcm_ref = xcm.as_ref().ok_or(SendError::MissingArgument)?; @@ -366,6 +378,10 @@ impl, I: 'static> SendXcm for Pallet { // increase delivery fee factor if required Self::on_message_sent_to_bridge(message_size); + log::trace!( + target: "xcm::xcm_bridge_hub_router::deliver", + "message sent, xcm_hash: {:?}", xcm_hash, + ); Ok(xcm_hash) } } diff --git a/cumulus/pallets/xcmp-queue/src/lib.rs b/cumulus/pallets/xcmp-queue/src/lib.rs index e92169be16b0..8449aaca7b28 100644 --- a/cumulus/pallets/xcmp-queue/src/lib.rs +++ b/cumulus/pallets/xcmp-queue/src/lib.rs @@ -942,7 +942,10 @@ impl SendXcm for Pallet { Self::deposit_event(Event::XcmpMessageSent { message_hash: hash }); Ok(hash) }, - Err(e) => Err(SendError::Transport(e.into())), + Err(e) => { + log::error!(target: "xcm::XcmpQueue::deliver", "error: {:?}", e); + Err(SendError::Transport(e.into())) + }, } } } diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index c61e1e1d15bc..3e9f02c731e4 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -346,6 +346,10 @@ impl XcmExecutor { msg: Xcm<()>, reason: FeeReason, ) -> Result { + log::trace!( + target: "xcm::send", "Sending msg: {:?}, to destination: {:?}, (reason: {:?})", + msg, dest, reason, + ); let (ticket, fee) = validate_send::(dest, msg)?; self.take_fee(fee, reason)?; Config::XcmSender::deliver(ticket).map_err(Into::into) From c7ee1afeb1f8fd52851b839e71dd7a11ed8def6a Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 13 Mar 2024 12:52:59 +0200 Subject: [PATCH 05/30] minor style fix --- .../runtimes/assets/common/src/matching.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/common/src/matching.rs b/cumulus/parachains/runtimes/assets/common/src/matching.rs index 478bba4565dc..3aad88e177ca 100644 --- a/cumulus/parachains/runtimes/assets/common/src/matching.rs +++ b/cumulus/parachains/runtimes/assets/common/src/matching.rs @@ -113,17 +113,14 @@ impl, Reserves: ContainsPair devolved, - Err(_) => { - log::trace!( - target: "xcm::contains", - "IsTrustedBridgedReserveLocationForConcreteAsset origin: {:?} is not remote to the universal_source: {:?}", - origin, universal_source - ); - return false - }, - }; + if ensure_is_remote(universal_source.clone(), origin.clone()).is_err() { + log::trace!( + target: "xcm::contains", + "IsTrustedBridgedReserveLocationForConcreteAsset origin: {:?} is not remote to the universal_source: {:?}", + origin, universal_source + ); + return false + } // check asset according to the configured reserve locations Reserves::contains(asset, origin) From ed77fdef759909b64ad7ddf55b9a1002388bb387 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 13 Mar 2024 12:52:25 +0200 Subject: [PATCH 06/30] integration-tests: add scenario for parachain sending asset over bridge using local asset hub as reserve --- .../parachains/testing/penpal/src/lib.rs | 5 +- .../bridges/bridge-hub-rococo/src/lib.rs | 2 +- .../src/tests/asset_transfers.rs | 205 +++++++++++++++++- .../runtimes/testing/penpal/src/xcm_config.rs | 3 +- 4 files changed, 211 insertions(+), 4 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs index 651b3a523067..a5163a0d8d3c 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs @@ -25,7 +25,8 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impl_assets_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, + impl_assets_helpers_for_parachain, impl_xcm_helpers_for_parachain, impls::Parachain, + xcm_emulator::decl_test_parachains, }; // Penpal Parachain declaration @@ -77,3 +78,5 @@ impl_assert_events_helpers_for_parachain!(PenpalA); impl_assert_events_helpers_for_parachain!(PenpalB); impl_assets_helpers_for_parachain!(PenpalA); impl_assets_helpers_for_parachain!(PenpalB); +impl_xcm_helpers_for_parachain!(PenpalA); +impl_xcm_helpers_for_parachain!(PenpalB); diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs index b5e19cf3fa3a..4b9c517f1510 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs @@ -46,7 +46,7 @@ mod imports { bridge_hub_rococo_emulated_chain::{ genesis::ED as BRIDGE_HUB_ROCOCO_ED, BridgeHubRococoParaPallet as BridgeHubRococoPallet, }, - penpal_emulated_chain::PenpalAParaPallet as PenpalAPallet, + penpal_emulated_chain::{PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner}, rococo_emulated_chain::{genesis::ED as ROCOCO_ED, RococoRelayPallet as RococoPallet}, AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver, AssetHubRococoParaSender as AssetHubRococoSender, AssetHubWestendPara as AssetHubWestend, diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs index 787a82ed32f7..e6324cfb948f 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs @@ -31,6 +31,72 @@ fn send_asset_from_asset_hub_rococo_to_asset_hub_westend(id: Location, amount: u assert_bridge_hub_westend_message_received(); } +fn send_asset_from_penpal_rococo_through_local_asset_hub_to_westend_asset_hub( + id: Location, + transfer_amount: u128, +) { + let destination = asset_hub_westend_location(); + let local_asset_hub: Location = PenpalA::sibling_location_of(AssetHubRococo::para_id()); + let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of( + AssetHubRococo::sibling_location_of(PenpalA::para_id()), + ); + let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( + Westend, + AssetHubWestend::para_id(), + ); + + // fund the AHR's SA on BHR for paying bridge transport fees + BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), 10_000_000_000_000u128); + + // set XCM versions + PenpalA::force_xcm_version(local_asset_hub.clone(), XCM_VERSION); + AssetHubRococo::force_xcm_version(destination.clone(), XCM_VERSION); + BridgeHubRococo::force_xcm_version(bridge_hub_westend_location(), XCM_VERSION); + + // send message over bridge + assert_ok!(PenpalA::execute_with(|| { + let signed_origin = ::RuntimeOrigin::signed(PenpalASender::get()); + let beneficiary: Location = + AccountId32Junction { network: None, id: AssetHubWestendReceiver::get().into() }.into(); + let fees: Asset = (id, transfer_amount).into(); + let assets: Assets = fees.clone().into(); + + ::PolkadotXcm::transfer_assets_using_reserve( + signed_origin, + bx!(destination.into()), + bx!(beneficiary.into()), + bx!(assets.into()), + bx!(fees.into()), + bx!(local_asset_hub.into()), + WeightLimit::Unlimited, + ) + })); + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + AssetHubRococo, + vec![ + // Amount to reserve transfer is withdrawn from Penpal's sovereign account + RuntimeEvent::Balances( + pallet_balances::Event::Burned { who, amount } + ) => { + who: *who == sov_penpal_on_ahr.clone().into(), + amount: *amount == transfer_amount, + }, + // Amount deposited in AHW's sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { + who: *who == sov_ahw_on_ahr.clone().into(), + }, + RuntimeEvent::XcmpQueue( + cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } + ) => {}, + ] + ); + }); + assert_bridge_hub_rococo_message_accepted(true); + assert_bridge_hub_westend_message_received(); +} + #[test] fn send_rocs_from_asset_hub_rococo_to_asset_hub_westend() { let roc_at_asset_hub_rococo: v3::Location = v3::Parent.into(); @@ -135,7 +201,7 @@ fn send_rocs_from_asset_hub_rococo_to_asset_hub_westend() { assert!(sender_rocs_before > sender_rocs_after); // Receiver's balance is increased assert!(receiver_rocs_after > receiver_rocs_before); - // Reserve balance is reduced by sent amount + // Reserve balance is increased by sent amount assert_eq!(rocs_in_reserve_on_ahr_after, rocs_in_reserve_on_ahr_before + amount); } @@ -217,3 +283,140 @@ fn send_wnds_from_asset_hub_rococo_to_asset_hub_westend() { // Reserve balance is reduced by sent amount assert_eq!(wnds_in_reserve_on_ahw_after, wnds_in_reserve_on_ahw_before - amount_to_send); } + +#[test] +fn send_rocs_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_westend() { + let roc_at_rococo_parachains: v3::Location = v3::Parent.into(); + let roc_at_asset_hub_westend = + v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Rococo)]); + let roc_at_rococo_parachains_latest: Location = roc_at_rococo_parachains.try_into().unwrap(); + let owner: AccountId = AssetHubWestend::account_id_of(ALICE); + AssetHubWestend::force_create_foreign_asset( + roc_at_asset_hub_westend, + owner, + true, + ASSET_MIN_BALANCE, + vec![], + ); + let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( + NetworkId::Westend, + AssetHubWestend::para_id(), + ); + + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // setup a pool to pay xcm fees with `roc_at_asset_hub_westend` tokens + assert_ok!(::ForeignAssets::mint( + ::RuntimeOrigin::signed(AssetHubWestendSender::get()), + roc_at_asset_hub_westend.into(), + AssetHubWestendSender::get().into(), + 3_000_000_000_000, + )); + + assert_ok!(::AssetConversion::create_pool( + ::RuntimeOrigin::signed(AssetHubWestendSender::get()), + Box::new(xcm::v3::Parent.into()), + Box::new(roc_at_asset_hub_westend), + )); + + assert_expected_events!( + AssetHubWestend, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, + ] + ); + + assert_ok!(::AssetConversion::add_liquidity( + ::RuntimeOrigin::signed(AssetHubWestendSender::get()), + Box::new(xcm::v3::Parent.into()), + Box::new(roc_at_asset_hub_westend), + 1_000_000_000_000, + 2_000_000_000_000, + 1, + 1, + AssetHubWestendSender::get().into() + )); + + assert_expected_events!( + AssetHubWestend, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {..}) => {}, + ] + ); + }); + + let penpal_location = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location); + // fund Penpal's sovereign account on AssetHub + AssetHubRococo::fund_accounts(vec![( + sov_penpal_on_ahr.into(), + ASSET_HUB_ROCOCO_ED * 10_000_001, + )]); + // fund Penpal's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + roc_at_rococo_parachains, + PenpalASender::get(), + ASSET_HUB_ROCOCO_ED * 10_000_001, + ); + + let rocs_in_reserve_on_ahr_before = + ::account_data_of(sov_ahw_on_ahr.clone()).free; + let sender_rocs_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + roc_at_rococo_parachains.into(), + &PenpalASender::get(), + ) + }); + let receiver_rocs_before = AssetHubWestend::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(roc_at_asset_hub_westend, &AssetHubWestendReceiver::get()) + }); + let amount = ASSET_HUB_ROCOCO_ED * 10_000_000; + send_asset_from_penpal_rococo_through_local_asset_hub_to_westend_asset_hub( + roc_at_rococo_parachains_latest, + amount, + ); + + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + AssetHubWestend, + vec![ + // issue ROCs on AHW + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == roc_at_rococo_parachains, + owner: *owner == AssetHubWestendReceiver::get(), + }, + // message processed successfully + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + }); + + let sender_rocs_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + roc_at_rococo_parachains.into(), + &PenpalASender::get(), + ) + }); + let receiver_rocs_after = AssetHubWestend::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(roc_at_asset_hub_westend, &AssetHubWestendReceiver::get()) + }); + let rocs_in_reserve_on_ahr_after = + ::account_data_of(sov_ahw_on_ahr.clone()).free; + + // Sender's balance is reduced + assert!(sender_rocs_after < sender_rocs_before); + // Receiver's balance is increased + assert!(receiver_rocs_after > receiver_rocs_before); + // Reserve balance is increased by sent amount (less fess) + assert!(rocs_in_reserve_on_ahr_after > rocs_in_reserve_on_ahr_before); + assert!(rocs_in_reserve_on_ahr_after <= rocs_in_reserve_on_ahr_before + amount); +} diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index bc1aa05a6177..8b37a81ede82 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -58,7 +58,8 @@ parameter_types! { pub const PenpalNativeCurrency: Location = Location::here(); pub const RelayNetwork: Option = None; pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); - pub UniversalLocation: InteriorLocation = [Parachain(ParachainInfo::parachain_id().into())].into(); + // FIXME: should also work for Westend + pub UniversalLocation: InteriorLocation = [GlobalConsensus(NetworkId::Rococo), Parachain(ParachainInfo::parachain_id().into())].into(); } /// Type for specifying how a `Location` can be converted into an `AccountId`. This is used From a7a44c9bf9af8fa570e73e918208232c973db2ae Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 14 Mar 2024 12:18:41 +0200 Subject: [PATCH 07/30] make penpal UniversalLocation configurable --- .../runtimes/testing/penpal/src/xcm_config.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index 8b37a81ede82..710da2780110 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -56,10 +56,16 @@ parameter_types! { pub const RelayLocation: Location = Location::parent(); // Local native currency which is stored in `pallet_balances`` pub const PenpalNativeCurrency: Location = Location::here(); - pub const RelayNetwork: Option = None; + // The Penpal runtime is utilized for testing with various environment setups. + // This storage item allows us to customize the `NetworkId` where Penpal is deployed. + // By default, it is set to `NetworkId::Rococo` and can be changed using `System::set_storage`. + pub storage RelayNetworkId: NetworkId = NetworkId::Rococo; + pub RelayNetwork: Option = Some(RelayNetworkId::get()); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); - // FIXME: should also work for Westend - pub UniversalLocation: InteriorLocation = [GlobalConsensus(NetworkId::Rococo), Parachain(ParachainInfo::parachain_id().into())].into(); + pub UniversalLocation: InteriorLocation = [ + GlobalConsensus(RelayNetworkId::get()), + Parachain(ParachainInfo::parachain_id().into()) + ].into(); } /// Type for specifying how a `Location` can be converted into an `AccountId`. This is used From ffa62504a0f37fee70da1dfc9e4d00c1bef8ff44 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 22 Mar 2024 14:26:29 +0200 Subject: [PATCH 08/30] penpal: charge XCM delivery fees for accurate real-world testing --- .../runtimes/testing/penpal/src/lib.rs | 19 ++++++++++++++++--- .../runtimes/testing/penpal/src/xcm_config.rs | 19 ++++++++++++++----- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index bea78e145203..5bcb66438c17 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -57,7 +57,6 @@ use parachains_common::{ impls::{AssetsToBlockAuthor, NonZeroIssuance}, message_queue::{NarrowOriginToSibling, ParaIdToSibling}, }; -use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use smallvec::smallvec; use sp_api::impl_runtime_apis; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; @@ -85,7 +84,7 @@ use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; // XCM Imports use parachains_common::{AccountId, Signature}; -use xcm::latest::prelude::BodyId; +use xcm::latest::prelude::{AssetId as AssetLocationId, BodyId}; /// Balance of an account. pub type Balance = u128; @@ -545,6 +544,20 @@ impl pallet_message_queue::Config for Runtime { impl cumulus_pallet_aura_ext::Config for Runtime {} +parameter_types! { + /// The asset ID for the asset that we use to pay for message delivery fees. + pub FeeAssetId: AssetLocationId = AssetLocationId(xcm_config::RelayLocation::get()); + /// The base fee for the message delivery fees (3 CENTS). + pub const BaseDeliveryFee: u128 = (1_000_000_000_000u128 / 100).saturating_mul(3); +} + +pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender::ExponentialPrice< + FeeAssetId, + BaseDeliveryFee, + TransactionByteFee, + XcmpQueue, +>; + impl cumulus_pallet_xcmp_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ChannelInfo = ParachainSystem; @@ -555,7 +568,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = (); - type PriceForSiblingDelivery = NoPriceForMessageDelivery; + type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } parameter_types! { diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index 710da2780110..704e44bd90b1 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -28,6 +28,7 @@ use super::{ ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, }; +use crate::{BaseDeliveryFee, FeeAssetId, TransactionByteFee}; use core::marker::PhantomData; use frame_support::{ parameter_types, @@ -36,10 +37,10 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; -use parachains_common::xcm_config::AssetFeeAsExistentialDepositMultiplier; +use parachains_common::{xcm_config::AssetFeeAsExistentialDepositMultiplier, TREASURY_PALLET_ID}; use polkadot_parachain_primitives::primitives::Sibling; -use polkadot_runtime_common::impls::ToAuthor; -use sp_runtime::traits::ConvertInto; +use polkadot_runtime_common::{impls::ToAuthor, xcm_sender::ExponentialPrice}; +use sp_runtime::traits::{AccountIdConversion, ConvertInto}; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, @@ -49,6 +50,7 @@ use xcm_builder::{ SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, StartsWith, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, + XcmFeeManagerFromComponents, XcmFeeToAccount, }; use xcm_executor::{traits::JustTry, XcmExecutor}; @@ -66,6 +68,7 @@ parameter_types! { GlobalConsensus(RelayNetworkId::get()), Parachain(ParachainInfo::parachain_id().into()) ].into(); + pub TreasuryAccount: AccountId = TREASURY_PALLET_ID.into_account_truncating(); } /// Type for specifying how a `Location` can be converted into an `AccountId`. This is used @@ -338,7 +341,10 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type AssetLocker = (); type AssetExchanger = (); - type FeeManager = (); + type FeeManager = XcmFeeManagerFromComponents< + (), + XcmFeeToAccount, + >; type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; @@ -359,11 +365,14 @@ pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger = /// No local origins on this chain are allowed to dispatch XCM sends/executions. pub type LocalOriginToLocation = SignedToAccountId32; +pub type PriceForParentDelivery = + ExponentialPrice; + /// The means for routing XCM messages which are not for local execution into the right message /// queues. pub type XcmRouter = WithUniqueTopic<( // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, )>; From 4afba9534a07df374c5493c73061ae413770f018 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 22 Mar 2024 15:33:59 +0200 Subject: [PATCH 09/30] integration-tests: fix tests for penpal charging delivery fees --- .../emulated/common/src/macros.rs | 2 +- .../tests/assets/asset-hub-rococo/src/lib.rs | 8 +- .../src/tests/reserve_transfer.rs | 73 ++++--------------- .../asset-hub-rococo/src/tests/teleport.rs | 8 +- .../tests/assets/asset-hub-westend/src/lib.rs | 9 +-- .../src/tests/reserve_transfer.rs | 71 ++++-------------- .../asset-hub-westend/src/tests/teleport.rs | 8 +- .../people-rococo/src/tests/teleport.rs | 6 +- .../people-westend/src/tests/teleport.rs | 6 +- .../assets/test-utils/src/test_cases.rs | 4 +- .../assets/test-utils/src/xcm_helpers.rs | 5 +- 11 files changed, 51 insertions(+), 149 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs index 6951de6faa72..6f6bbe41e01b 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs @@ -115,7 +115,7 @@ macro_rules! test_parachain_is_trusted_teleporter { let para_receiver_balance_after = <$receiver_para as $crate::macros::Chain>::account_data_of(receiver.clone()).free; let delivery_fees = <$sender_para>::execute_with(|| { - $crate::macros::asset_test_utils::xcm_helpers::transfer_assets_delivery_fees::< + $crate::macros::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) }); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs index 21d858f1fe51..a5a4914e21d8 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs @@ -63,17 +63,13 @@ mod imports { // Runtimes pub use asset_hub_rococo_runtime::xcm_config::{ - TokenLocation as RelayLocation, UniversalLocation as AssetHubRococoUniversalLocation, - XcmConfig as AssetHubRococoXcmConfig, + TokenLocation as RelayLocation, XcmConfig as AssetHubRococoXcmConfig, }; pub use penpal_runtime::xcm_config::{ LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub, LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub, - UniversalLocation as PenpalUniversalLocation, XcmConfig as PenpalRococoXcmConfig, - }; - pub use rococo_runtime::xcm_config::{ - UniversalLocation as RococoUniversalLocation, XcmConfig as RococoXcmConfig, }; + pub use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig; pub const ASSET_ID: u32 = 3; pub const ASSET_MIN_BALANCE: u128 = 1000; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index 705c9613b647..0a5956dedfdf 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -524,7 +524,6 @@ fn reserve_transfer_native_asset_from_relay_to_para() { let destination = Rococo::child_location_of(PenpalA::para_id()); let sender = RococoSender::get(); let amount_to_send: Balance = ROCOCO_ED * 1000; - let assets: Assets = (Here, amount_to_send).into(); // Init values fot Parachain let relay_native_asset_location = @@ -552,15 +551,6 @@ fn reserve_transfer_native_asset_from_relay_to_para() { test.set_dispatchable::(relay_to_para_reserve_transfer_assets); test.assert(); - // Calculate delivery fees - let delivery_fees = Rococo::execute_with(|| { - let reanchored_assets = - assets.reanchored(&destination, &RococoUniversalLocation::get()).unwrap(); - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - // Query final balances let sender_balance_after = test.sender.balance; let receiver_assets_after = PenpalA::execute_with(|| { @@ -568,8 +558,8 @@ fn reserve_transfer_native_asset_from_relay_to_para() { >::balance(relay_native_asset_location.into(), &receiver) }); - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); + // 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`; @@ -595,7 +585,7 @@ fn reserve_transfer_native_asset_from_para_to_relay() { ::RuntimeOrigin::signed(asset_owner), relay_native_asset_location, sender.clone(), - amount_to_send, + amount_to_send * 2, ); // Init values for Relay @@ -634,15 +624,6 @@ fn reserve_transfer_native_asset_from_para_to_relay() { test.set_dispatchable::(para_to_relay_reserve_transfer_assets); test.assert(); - // Calculate delivery fees - let delivery_fees = PenpalA::execute_with(|| { - let reanchored_assets = - assets.reanchored(&destination, &PenpalUniversalLocation::get()).unwrap(); - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - // Query final balances let sender_assets_after = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; @@ -650,8 +631,8 @@ fn reserve_transfer_native_asset_from_para_to_relay() { }); let receiver_balance_after = test.receiver.balance; - // Sender's balance is reduced - assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_after); + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_assets_after < sender_assets_before - amount_to_send); // Receiver's asset balance is increased assert!(receiver_balance_after > receiver_balance_before); // Receiver's asset balance increased by `amount_to_send - delivery_fees - bought_execution`; @@ -705,16 +686,6 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); test.assert(); - // Calculate delivery fees - let delivery_fees = AssetHubRococo::execute_with(|| { - let reanchored_assets = assets - .reanchored(&destination, &AssetHubRococoUniversalLocation::get()) - .unwrap(); - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - // Query final balances let sender_balance_after = test.sender.balance; let receiver_assets_after = PenpalA::execute_with(|| { @@ -722,8 +693,8 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { >::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); + // 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`; @@ -738,7 +709,7 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { // Init values for Parachain let destination = PenpalA::sibling_location_of(AssetHubRococo::para_id()); let sender = PenpalASender::get(); - let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; + let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 10000; let assets: Assets = (Parent, amount_to_send).into(); let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).expect("conversion works"); @@ -749,7 +720,7 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { ::RuntimeOrigin::signed(asset_owner), system_para_native_asset_location, sender.clone(), - amount_to_send, + amount_to_send * 2, ); // Init values for System Parachain @@ -788,15 +759,6 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { test.set_dispatchable::(para_to_system_para_reserve_transfer_assets); test.assert(); - // Calculate delivery fees - let delivery_fees = PenpalA::execute_with(|| { - let reanchored_assets = - assets.reanchored(&destination, &PenpalUniversalLocation::get()).unwrap(); - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - // Query final balances let sender_assets_after = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; @@ -804,8 +766,8 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { }); let receiver_balance_after = test.receiver.balance; - // Sender's balance is reduced - assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_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`; @@ -1084,7 +1046,7 @@ fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { ::RuntimeOrigin::signed(asset_owner), relay_native_asset_location, sender.clone(), - amount_to_send, + amount_to_send * 2, ); // fund the Parachain Origin's SA on Relay Chain with the native tokens held in reserve @@ -1118,13 +1080,6 @@ fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { test.set_dispatchable::(para_to_para_through_relay_limited_reserve_transfer_assets); test.assert(); - // Calculate delivery fees - let delivery_fees = PenpalA::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - // Query final balances let sender_assets_after = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; @@ -1135,8 +1090,8 @@ fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { >::balance(relay_native_asset_location, &receiver) }); - // Sender's balance is reduced - assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_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_assets_after > receiver_assets_before); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs index 01e9054e60dd..1cbb7fb8c193 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs @@ -302,7 +302,7 @@ fn limited_teleport_native_assets_from_relay_to_system_para_works() { test.assert(); let delivery_fees = Rococo::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -349,7 +349,7 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { let receiver_balance_after = test.receiver.balance; let delivery_fees = AssetHubRococo::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -390,7 +390,7 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { let receiver_balance_after = test.receiver.balance; let delivery_fees = AssetHubRococo::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -450,7 +450,7 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { ::RuntimeOrigin::signed(asset_owner.clone()), system_para_native_asset_location, sender.clone(), - fee_amount_to_send, + fee_amount_to_send * 2, ); // No need to create the asset (only mint) as it exists in genesis. PenpalA::mint_asset( diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs index 3f899d1dbdbc..a1a3888d6117 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs @@ -67,17 +67,14 @@ mod imports { // Runtimes pub use asset_hub_westend_runtime::xcm_config::{ - UniversalLocation as AssetHubWestendUniversalLocation, WestendLocation as RelayLocation, - XcmConfig as AssetHubWestendXcmConfig, + WestendLocation as RelayLocation, XcmConfig as AssetHubWestendXcmConfig, }; pub use penpal_runtime::xcm_config::{ LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub, LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub, - UniversalLocation as PenpalUniversalLocation, XcmConfig as PenpalWestendXcmConfig, - }; - pub use westend_runtime::xcm_config::{ - UniversalLocation as WestendUniversalLocation, XcmConfig as WestendXcmConfig, + XcmConfig as PenpalWestendXcmConfig, }; + pub use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig; pub const ASSET_ID: u32 = 3; pub const ASSET_MIN_BALANCE: u128 = 1000; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs index 8c836132b546..64ad15ca3121 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -524,7 +524,6 @@ fn reserve_transfer_native_asset_from_relay_to_para() { let destination = Westend::child_location_of(PenpalA::para_id()); let sender = WestendSender::get(); let amount_to_send: Balance = WESTEND_ED * 1000; - let assets: Assets = (Here, amount_to_send).into(); // Init values fot Parachain let relay_native_asset_location = @@ -552,15 +551,6 @@ fn reserve_transfer_native_asset_from_relay_to_para() { test.set_dispatchable::(relay_to_para_reserve_transfer_assets); test.assert(); - // Calculate delivery fees - let delivery_fees = Westend::execute_with(|| { - let reanchored_assets = - assets.reanchored(&destination, &WestendUniversalLocation::get()).unwrap(); - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - // Query final balances let sender_balance_after = test.sender.balance; let receiver_assets_after = PenpalA::execute_with(|| { @@ -568,8 +558,8 @@ fn reserve_transfer_native_asset_from_relay_to_para() { >::balance(relay_native_asset_location.into(), &receiver) }); - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); + // 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`; @@ -595,7 +585,7 @@ fn reserve_transfer_native_asset_from_para_to_relay() { ::RuntimeOrigin::signed(asset_owner), relay_native_asset_location, sender.clone(), - amount_to_send, + amount_to_send * 2, ); // Init values for Relay @@ -634,15 +624,6 @@ fn reserve_transfer_native_asset_from_para_to_relay() { test.set_dispatchable::(para_to_relay_reserve_transfer_assets); test.assert(); - // Calculate delivery fees - let delivery_fees = PenpalA::execute_with(|| { - let reanchored_assets = - assets.reanchored(&destination, &PenpalUniversalLocation::get()).unwrap(); - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - // Query final balances let sender_assets_after = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; @@ -650,8 +631,8 @@ fn reserve_transfer_native_asset_from_para_to_relay() { }); let receiver_balance_after = test.receiver.balance; - // Sender's balance is reduced - assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_after); + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_assets_after < sender_assets_before - amount_to_send); // Receiver's asset balance is increased assert!(receiver_balance_after > receiver_balance_before); // Receiver's asset balance increased by `amount_to_send - delivery_fees - bought_execution`; @@ -705,16 +686,6 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); test.assert(); - // Calculate delivery fees - let delivery_fees = AssetHubWestend::execute_with(|| { - let reanchored_assets = assets - .reanchored(&destination, &AssetHubWestendUniversalLocation::get()) - .unwrap(); - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - // Query final balances let sender_balance_after = test.sender.balance; let receiver_assets_after = PenpalA::execute_with(|| { @@ -722,8 +693,8 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { >::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); + // 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`; @@ -749,7 +720,7 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { ::RuntimeOrigin::signed(asset_owner), system_para_native_asset_location, sender.clone(), - amount_to_send, + amount_to_send * 2, ); // Init values for System Parachain @@ -789,15 +760,6 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { test.set_dispatchable::(para_to_system_para_reserve_transfer_assets); test.assert(); - // Calculate delivery fees - let delivery_fees = PenpalA::execute_with(|| { - let reanchored_assets = - assets.reanchored(&destination, &PenpalUniversalLocation::get()).unwrap(); - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - // Query final balances let sender_assets_after = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; @@ -805,8 +767,8 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { }); let receiver_balance_after = test.receiver.balance; - // Sender's balance is reduced - assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_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`; @@ -1086,7 +1048,7 @@ fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { ::RuntimeOrigin::signed(asset_owner), relay_native_asset_location, sender.clone(), - amount_to_send, + amount_to_send * 2, ); // fund the Parachain Origin's SA on Relay Chain with the native tokens held in reserve @@ -1120,13 +1082,6 @@ fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { test.set_dispatchable::(para_to_para_through_relay_limited_reserve_transfer_assets); test.assert(); - // Calculate delivery fees - let delivery_fees = PenpalA::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - // Query final balances let sender_assets_after = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; @@ -1137,8 +1092,8 @@ fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { >::balance(relay_native_asset_location, &receiver) }); - // Sender's balance is reduced - assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_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_assets_after > receiver_assets_before); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs index 1680d871e080..ac518d2ed4a4 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs @@ -302,7 +302,7 @@ fn limited_teleport_native_assets_from_relay_to_system_para_works() { test.assert(); let delivery_fees = Westend::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -349,7 +349,7 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { let receiver_balance_after = test.receiver.balance; let delivery_fees = AssetHubWestend::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -390,7 +390,7 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { let receiver_balance_after = test.receiver.balance; let delivery_fees = AssetHubWestend::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -450,7 +450,7 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { ::RuntimeOrigin::signed(asset_owner.clone()), system_para_native_asset_location, sender.clone(), - fee_amount_to_send, + fee_amount_to_send * 2, ); // No need to create the asset (only mint) as it exists in genesis. PenpalA::mint_asset( diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs index 3abe5c6cf66a..350d87d638ab 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs @@ -155,7 +155,7 @@ fn limited_teleport_native_assets_from_relay_to_system_para_works() { test.assert(); let delivery_fees = Rococo::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -204,7 +204,7 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { let receiver_balance_after = test.receiver.balance; let delivery_fees = PeopleRococo::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -248,7 +248,7 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { let receiver_balance_after = test.receiver.balance; let delivery_fees = PeopleRococo::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs index eef35a99a833..8697477ba769 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs @@ -155,7 +155,7 @@ fn limited_teleport_native_assets_from_relay_to_system_para_works() { test.assert(); let delivery_fees = Westend::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -204,7 +204,7 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { let receiver_balance_after = test.receiver.balance; let delivery_fees = PeopleWestend::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -248,7 +248,7 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { let receiver_balance_after = test.receiver.balance; let delivery_fees = PeopleWestend::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs index 53e10956bd0d..2f2624d8e523 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -186,7 +186,7 @@ pub fn teleports_for_native_asset_works< // Mint funds into account to ensure it has enough balance to pay delivery fees let delivery_fees = - xcm_helpers::transfer_assets_delivery_fees::( + xcm_helpers::teleport_assets_delivery_fees::( (native_asset_id.clone(), native_asset_to_teleport_away.into()).into(), 0, Unlimited, @@ -579,7 +579,7 @@ pub fn teleports_for_foreign_assets_works< // Make sure the target account has enough native asset to pay for delivery fees let delivery_fees = - xcm_helpers::transfer_assets_delivery_fees::( + xcm_helpers::teleport_assets_delivery_fees::( (foreign_asset_id_location_latest.clone(), asset_to_teleport_away).into(), 0, Unlimited, diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/xcm_helpers.rs b/cumulus/parachains/runtimes/assets/test-utils/src/xcm_helpers.rs index f509a3a8acaa..ca0e81fae42e 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/xcm_helpers.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/xcm_helpers.rs @@ -18,11 +18,10 @@ use xcm::latest::prelude::*; -/// Returns the delivery fees amount for pallet xcm's `teleport_assets` and -/// `reserve_transfer_assets` extrinsics. +/// Returns the delivery fees amount for pallet xcm's `teleport_assets` extrinsics. /// Because it returns only a `u128`, it assumes delivery fees are only paid /// in one asset and that asset is known. -pub fn transfer_assets_delivery_fees( +pub fn teleport_assets_delivery_fees( assets: Assets, fee_asset_item: u32, weight_limit: WeightLimit, From c918beaf2f320d2bf216da9b5d4ce9d45ced967a Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Sat, 23 Mar 2024 10:48:53 +0200 Subject: [PATCH 10/30] fix test --- .../bridge-hub-rococo/src/tests/asset_transfers.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs index e6324cfb948f..5db0c702d3d9 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs @@ -346,19 +346,17 @@ fn send_rocs_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_westend() ); }); + let amount = ASSET_HUB_ROCOCO_ED * 10_000_000; let penpal_location = AssetHubRococo::sibling_location_of(PenpalA::para_id()); let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location); // fund Penpal's sovereign account on AssetHub - AssetHubRococo::fund_accounts(vec![( - sov_penpal_on_ahr.into(), - ASSET_HUB_ROCOCO_ED * 10_000_001, - )]); + AssetHubRococo::fund_accounts(vec![(sov_penpal_on_ahr.into(), amount * 2)]); // fund Penpal's sender account PenpalA::mint_foreign_asset( ::RuntimeOrigin::signed(PenpalAssetOwner::get()), roc_at_rococo_parachains, PenpalASender::get(), - ASSET_HUB_ROCOCO_ED * 10_000_001, + amount * 2, ); let rocs_in_reserve_on_ahr_before = @@ -374,7 +372,6 @@ fn send_rocs_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_westend() type Assets = ::ForeignAssets; >::balance(roc_at_asset_hub_westend, &AssetHubWestendReceiver::get()) }); - let amount = ASSET_HUB_ROCOCO_ED * 10_000_000; send_asset_from_penpal_rococo_through_local_asset_hub_to_westend_asset_hub( roc_at_rococo_parachains_latest, amount, From 3db344bda8580dc0c91c08d5cf912d4312db340e Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 25 Mar 2024 15:22:58 +0200 Subject: [PATCH 11/30] add prdoc --- prdoc/pr_3695.prdoc | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 prdoc/pr_3695.prdoc diff --git a/prdoc/pr_3695.prdoc b/prdoc/pr_3695.prdoc new file mode 100644 index 000000000000..8816e910b23e --- /dev/null +++ b/prdoc/pr_3695.prdoc @@ -0,0 +1,30 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "pallet-xcm: add new extrinsic for asset transfers using explicit reserve" + +doc: + - audience: Runtime Dev + description: | + pallet-xcm's extrinsics `teleport_assets` and `reserve_transfer_assets` have been + marked as deprecated. Please change their usage to the `limited_teleport_assets` + and `limited_reserve_transfer_assets`, respectively; or use the generic/flexible + `transfer_assets` extrinsic. + - audience: Runtime User + description: | + pallet-xcm has a new extrinsic `transfer_assets_using_reserve` for transferring + assets from local chain to destination chain using an explicit reserve location + (typically the local Asset Hub). + By default, an asset's reserve is its origin chain. But sometimes we may want to + explicitly use another chain as reserve (as long as allowed by runtime IsReserve + filter). + This is very helpful for transferring assets with multiple configured reserves + (such as Asset Hub ForeignAssets), when the transfer strictly depends on the used + reserve location. + + E.g. For transferring Foreign Assets over a bridge, Asset Hub must be used as the + reserve location. Same when transferring bridged assets between parachains, the + local Asset Hub must be used as the explicit reserve location. + +crates: +- name: pallet-xcm From 10d2c40c95cdf027a9341af95ecde3c2170af0de Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 25 Mar 2024 15:26:57 +0200 Subject: [PATCH 12/30] fix clippy --- .../emulated/tests/assets/asset-hub-westend/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs index a1a3888d6117..c9f5fe0647e1 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs @@ -72,7 +72,6 @@ mod imports { pub use penpal_runtime::xcm_config::{ LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub, LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub, - XcmConfig as PenpalWestendXcmConfig, }; pub use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig; From dbe453d9709b2c8597f15f08355bf861299d2339 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 27 Mar 2024 18:22:57 +0200 Subject: [PATCH 13/30] add test for westend->rococo direction --- .../parachains/testing/penpal/src/lib.rs | 14 +- .../networks/rococo-westend-system/src/lib.rs | 7 +- .../bridges/bridge-hub-westend/src/lib.rs | 4 +- .../src/tests/asset_transfers.rs | 200 ++++++++++++++++++ .../runtimes/testing/penpal/src/xcm_config.rs | 2 +- 5 files changed, 220 insertions(+), 7 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs index 5aead08386f8..b41ed88eb117 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs @@ -16,16 +16,18 @@ mod genesis; pub use genesis::{genesis, PenpalAssetOwner, PenpalSudoAccount, ED, PARA_ID_A, PARA_ID_B}; pub use penpal_runtime::xcm_config::{ - CustomizableAssetFromSystemAssetHub, LocalTeleportableToAssetHub, XcmConfig, + CustomizableAssetFromSystemAssetHub, RelayNetworkId as PenpalRelayNetworkId, }; // Substrate use frame_support::traits::OnInitialize; +use sp_core::Encode; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impl_assets_helpers_for_parachain, impl_xcm_helpers_for_parachain, impls::Parachain, + impl_assets_helpers_for_parachain, impl_xcm_helpers_for_parachain, + impls::{NetworkId, Parachain}, xcm_emulator::decl_test_parachains, }; @@ -35,6 +37,10 @@ decl_test_parachains! { genesis = genesis(PARA_ID_A), on_init = { penpal_runtime::AuraExt::on_initialize(1); + frame_support::assert_ok!(penpal_runtime::System::set_storage( + penpal_runtime::RuntimeOrigin::root(), + vec![(PenpalRelayNetworkId::key().to_vec(), NetworkId::Rococo.encode())], + )); }, runtime = penpal_runtime, core = { @@ -54,6 +60,10 @@ decl_test_parachains! { genesis = genesis(PARA_ID_B), on_init = { penpal_runtime::AuraExt::on_initialize(1); + frame_support::assert_ok!(penpal_runtime::System::set_storage( + penpal_runtime::RuntimeOrigin::root(), + vec![(PenpalRelayNetworkId::key().to_vec(), NetworkId::Westend.encode())], + )); }, runtime = penpal_runtime, core = { diff --git a/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/src/lib.rs b/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/src/lib.rs index ee8b038a364d..d87bc5aa9633 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/src/lib.rs @@ -25,7 +25,7 @@ use asset_hub_rococo_emulated_chain::AssetHubRococo; use asset_hub_westend_emulated_chain::AssetHubWestend; use bridge_hub_rococo_emulated_chain::BridgeHubRococo; use bridge_hub_westend_emulated_chain::BridgeHubWestend; -use penpal_emulated_chain::PenpalA; +use penpal_emulated_chain::{PenpalA, PenpalB}; use rococo_emulated_chain::Rococo; use westend_emulated_chain::Westend; @@ -48,13 +48,13 @@ decl_test_networks! { PenpalA, ], bridge = RococoWestendMockBridge - }, pub struct WestendMockNet { relay_chain = Westend, parachains = vec![ AssetHubWestend, BridgeHubWestend, + PenpalB, ], bridge = WestendRococoMockBridge }, @@ -96,5 +96,6 @@ decl_test_sender_receiver_accounts_parameter_types! { WestendRelay { sender: ALICE, receiver: BOB }, AssetHubWestendPara { sender: ALICE, receiver: BOB }, BridgeHubWestendPara { sender: ALICE, receiver: BOB }, - PenpalAPara { sender: ALICE, receiver: BOB } + PenpalAPara { sender: ALICE, receiver: BOB }, + PenpalBPara { sender: ALICE, receiver: BOB } } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs index 60c31ce5a4ae..9b86396d2bc6 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs @@ -48,13 +48,15 @@ mod imports { genesis::ED as BRIDGE_HUB_WESTEND_ED, BridgeHubWestendParaPallet as BridgeHubWestendPallet, }, + penpal_emulated_chain::{PenpalAssetOwner, PenpalBParaPallet as PenpalBPallet}, westend_emulated_chain::WestendRelayPallet as WestendPallet, AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver, AssetHubRococoParaSender as AssetHubRococoSender, AssetHubWestendPara as AssetHubWestend, AssetHubWestendParaReceiver as AssetHubWestendReceiver, AssetHubWestendParaSender as AssetHubWestendSender, BridgeHubRococoPara as BridgeHubRococo, BridgeHubWestendPara as BridgeHubWestend, - BridgeHubWestendParaSender as BridgeHubWestendSender, WestendRelay as Westend, + BridgeHubWestendParaSender as BridgeHubWestendSender, PenpalBPara as PenpalB, + PenpalBParaSender as PenpalBSender, WestendRelay as Westend, }; pub const ASSET_MIN_BALANCE: u128 = 1000; diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs index 5b0990973d21..514c763d9816 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs @@ -30,6 +30,72 @@ fn send_asset_from_asset_hub_westend_to_asset_hub_rococo(id: Location, amount: u assert_bridge_hub_rococo_message_received(); } +fn send_asset_from_penpal_westend_through_local_asset_hub_to_rococo_asset_hub( + id: Location, + transfer_amount: u128, +) { + let destination = asset_hub_rococo_location(); + let local_asset_hub: Location = PenpalB::sibling_location_of(AssetHubWestend::para_id()); + let sov_penpal_on_ahw = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalB::para_id()), + ); + let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( + Rococo, + AssetHubRococo::para_id(), + ); + + // fund the AHW's SA on BHW for paying bridge transport fees + BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), 10_000_000_000_000u128); + + // set XCM versions + PenpalB::force_xcm_version(local_asset_hub.clone(), XCM_VERSION); + AssetHubWestend::force_xcm_version(destination.clone(), XCM_VERSION); + BridgeHubWestend::force_xcm_version(bridge_hub_rococo_location(), XCM_VERSION); + + // send message over bridge + assert_ok!(PenpalB::execute_with(|| { + let signed_origin = ::RuntimeOrigin::signed(PenpalBSender::get()); + let beneficiary: Location = + AccountId32Junction { network: None, id: AssetHubRococoReceiver::get().into() }.into(); + let fees: Asset = (id, transfer_amount).into(); + let assets: Assets = fees.clone().into(); + + ::PolkadotXcm::transfer_assets_using_reserve( + signed_origin, + bx!(destination.into()), + bx!(beneficiary.into()), + bx!(assets.into()), + bx!(fees.into()), + bx!(local_asset_hub.into()), + WeightLimit::Unlimited, + ) + })); + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + AssetHubWestend, + vec![ + // Amount to reserve transfer is withdrawn from Penpal's sovereign account + RuntimeEvent::Balances( + pallet_balances::Event::Burned { who, amount } + ) => { + who: *who == sov_penpal_on_ahw.clone().into(), + amount: *amount == transfer_amount, + }, + // Amount deposited in AHR's sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { + who: *who == sov_ahr_on_ahw.clone().into(), + }, + RuntimeEvent::XcmpQueue( + cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } + ) => {}, + ] + ); + }); + assert_bridge_hub_westend_message_accepted(true); + assert_bridge_hub_rococo_message_received(); +} + #[test] fn send_wnds_from_asset_hub_westend_to_asset_hub_rococo() { let wnd_at_asset_hub_westend: Location = Parent.into(); @@ -215,3 +281,137 @@ fn send_rocs_from_asset_hub_westend_to_asset_hub_rococo() { // Reserve balance is reduced by sent amount assert_eq!(rocs_in_reserve_on_ahr_after, rocs_in_reserve_on_ahr_before - amount_to_send); } + +#[test] +fn send_wnds_from_penpal_westend_through_asset_hub_westend_to_asset_hub_rococo() { + let wnd_at_westend_parachains: v3::Location = v3::Parent.into(); + let wnd_at_asset_hub_rococo = + v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Westend)]); + let wnd_at_westend_parachains_latest: Location = wnd_at_westend_parachains.try_into().unwrap(); + let owner: AccountId = AssetHubRococo::account_id_of(ALICE); + AssetHubRococo::force_create_foreign_asset( + wnd_at_asset_hub_rococo, + owner, + true, + ASSET_MIN_BALANCE, + vec![], + ); + let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( + NetworkId::Rococo, + AssetHubRococo::para_id(), + ); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // setup a pool to pay xcm fees with `wnd_at_asset_hub_rococo` tokens + assert_ok!(::ForeignAssets::mint( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), + wnd_at_asset_hub_rococo.into(), + AssetHubRococoSender::get().into(), + 3_000_000_000_000, + )); + + assert_ok!(::AssetConversion::create_pool( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), + Box::new(xcm::v3::Parent.into()), + Box::new(wnd_at_asset_hub_rococo), + )); + + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, + ] + ); + + assert_ok!(::AssetConversion::add_liquidity( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), + Box::new(xcm::v3::Parent.into()), + Box::new(wnd_at_asset_hub_rococo), + 1_000_000_000_000, + 2_000_000_000_000, + 1, + 1, + AssetHubRococoSender::get().into() + )); + + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {..}) => {}, + ] + ); + }); + + let amount = ASSET_HUB_WESTEND_ED * 10_000_000; + let penpal_location = AssetHubWestend::sibling_location_of(PenpalB::para_id()); + let sov_penpal_on_ahw = AssetHubWestend::sovereign_account_id_of(penpal_location); + // fund Penpal's sovereign account on AssetHub + AssetHubWestend::fund_accounts(vec![(sov_penpal_on_ahw.into(), amount * 2)]); + // fund Penpal's sender account + PenpalB::mint_foreign_asset( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + wnd_at_westend_parachains, + PenpalBSender::get(), + amount * 2, + ); + + let wnds_in_reserve_on_ahw_before = + ::account_data_of(sov_ahr_on_ahw.clone()).free; + let sender_wnds_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + wnd_at_westend_parachains.into(), + &PenpalBSender::get(), + ) + }); + let receiver_wnds_before = AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(wnd_at_asset_hub_rococo, &AssetHubRococoReceiver::get()) + }); + send_asset_from_penpal_westend_through_local_asset_hub_to_rococo_asset_hub( + wnd_at_westend_parachains_latest, + amount, + ); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + AssetHubRococo, + vec![ + // issue WNDs on AHR + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == wnd_at_westend_parachains, + owner: *owner == AssetHubRococoReceiver::get(), + }, + // message processed successfully + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + }); + + let sender_wnds_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + wnd_at_westend_parachains.into(), + &PenpalBSender::get(), + ) + }); + let receiver_wnds_after = AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(wnd_at_asset_hub_rococo, &AssetHubRococoReceiver::get()) + }); + let wnds_in_reserve_on_ahw_after = + ::account_data_of(sov_ahr_on_ahw.clone()).free; + + // Sender's balance is reduced + assert!(sender_wnds_after < sender_wnds_before); + // Receiver's balance is increased + assert!(receiver_wnds_after > receiver_wnds_before); + // Reserve balance is increased by sent amount (less fess) + assert!(wnds_in_reserve_on_ahw_after > wnds_in_reserve_on_ahw_before); + assert!(wnds_in_reserve_on_ahw_after <= wnds_in_reserve_on_ahw_before + amount); +} diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index a5a0cf681028..82034a583f10 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -61,7 +61,7 @@ parameter_types! { // The Penpal runtime is utilized for testing with various environment setups. // This storage item allows us to customize the `NetworkId` where Penpal is deployed. // By default, it is set to `NetworkId::Rococo` and can be changed using `System::set_storage`. - pub storage RelayNetworkId: NetworkId = NetworkId::Rococo; + pub storage RelayNetworkId: NetworkId = NetworkId::Westend; pub RelayNetwork: Option = Some(RelayNetworkId::get()); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorLocation = [ From 42e40412e43a284977faf9912e28268426abdd26 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 27 Mar 2024 19:09:14 +0200 Subject: [PATCH 14/30] nit --- .../tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs index 1804f9d4b67d..01a135e41372 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs @@ -378,10 +378,8 @@ fn send_token_from_ethereum_to_asset_hub() { #[test] fn send_weth_asset_from_asset_hub_to_ethereum() { use asset_hub_rococo_runtime::xcm_config::bridging::to_ethereum::DefaultBridgeHubEthereumBaseFee; - let assethub_sovereign = BridgeHubRococo::sovereign_account_id_of(Location::new( - 1, - [Parachain(AssetHubRococo::para_id().into())], - )); + let assethub_location = BridgeHubRococo::sibling_location_of(AssetHubRococo::para_id()); + let assethub_sovereign = BridgeHubRococo::sovereign_account_id_of(assethub_location); AssetHubRococo::force_default_xcm_version(Some(XCM_VERSION)); BridgeHubRococo::force_default_xcm_version(Some(XCM_VERSION)); From 81dc911e477fee0472d5a0c4aa62f3e64f5c096e Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 3 Apr 2024 15:53:33 +0300 Subject: [PATCH 15/30] pallet-xcm: specify explicit transfer type --- polkadot/xcm/pallet-xcm/src/lib.rs | 172 +++++++++--------- .../xcm-executor/src/traits/asset_transfer.rs | 6 +- 2 files changed, 88 insertions(+), 90 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 55f625e5e8d8..7f8b24689b9c 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1304,67 +1304,23 @@ pub mod pallet { ); ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::::TooManyAssets); - let mut assets = assets.into_inner(); + let assets = assets.into_inner(); let fee_asset_item = fee_asset_item as usize; let fees = assets.get(fee_asset_item as usize).ok_or(Error::::Empty)?.clone(); // Find transfer types for fee and non-fee assets. let (fees_transfer_type, assets_transfer_type) = Self::find_fee_and_assets_transfer_types(&assets, fee_asset_item, &dest)?; - // local and remote XCM programs to potentially handle fees separately - let fees = if fees_transfer_type == assets_transfer_type { - // no need for custom fees instructions, fees are batched with assets - FeesHandling::Batched { fees } - } else { - // Disallow _remote reserves_ unless assets & fees have same remote reserve (covered - // by branch above). The reason for this is that we'd need to send XCMs to separate - // chains with no guarantee of delivery order on final destination; therefore we - // cannot guarantee to have fees in place on final destination chain to pay for - // assets transfer. - ensure!( - !matches!(assets_transfer_type, TransferType::RemoteReserve(_)), - Error::::InvalidAssetUnsupportedReserve - ); - let weight_limit = weight_limit.clone(); - // remove `fees` from `assets` and build separate fees transfer instructions to be - // added to assets transfers XCM programs - let fees = assets.remove(fee_asset_item); - let (local_xcm, remote_xcm) = match fees_transfer_type { - TransferType::LocalReserve => Self::local_reserve_fees_instructions( - origin.clone(), - dest.clone(), - fees, - weight_limit, - )?, - TransferType::DestinationReserve => - Self::destination_reserve_fees_instructions( - origin.clone(), - dest.clone(), - fees, - weight_limit, - )?, - TransferType::Teleport => Self::teleport_fees_instructions( - origin.clone(), - dest.clone(), - fees, - weight_limit, - )?, - TransferType::RemoteReserve(_) => - return Err(Error::::InvalidAssetUnsupportedReserve.into()), - }; - FeesHandling::Separate { local_xcm, remote_xcm } - }; - - let (local_xcm, remote_xcm) = Self::build_xcm_transfer_type( - origin.clone(), - dest.clone(), + Self::do_transfer_assets( + origin, + dest, beneficiary, assets, assets_transfer_type, fees, + fees_transfer_type, weight_limit, - )?; - Self::execute_xcm_transfer(origin, dest, local_xcm, remote_xcm) + ) } /// Claims assets trapped on this pallet because of leftover assets during XCM execution. @@ -1491,8 +1447,9 @@ pub mod pallet { dest: Box, beneficiary: Box, assets: Box, + assets_transfer_type: Box, fees: Box, - using_reserve: Box, + fees_transfer_type: Box, weight_limit: WeightLimit, ) -> DispatchResult { let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; @@ -1501,18 +1458,14 @@ pub mod pallet { (*beneficiary).try_into().map_err(|()| Error::::BadVersion)?; let assets: Assets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; let fees: Asset = (*fees).try_into().map_err(|()| Error::::BadVersion)?; - let reserve: Location = - (*using_reserve).try_into().map_err(|()| Error::::BadVersion)?; log::debug!( target: "xcm::pallet_xcm::transfer_assets_using_reserve", - "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, fees {:?}, using reserve {:?}", - origin_location, dest, beneficiary, assets, fees, reserve, + "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?} through {:?}, fees {:?} through {:?}", + origin_location, dest, beneficiary, assets, assets_transfer_type, fees, fees_transfer_type, ); + let assets = assets.into_inner(); ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::::TooManyAssets); - let value = (origin_location, assets.into_inner()); - ensure!(T::XcmReserveTransferFilter::contains(&value), Error::::Filtered); - let (origin, assets) = value; let fee_asset_index = assets.iter().position(|a| a.id == fees.id).ok_or(Error::::FeesNotMet)?; @@ -1522,38 +1475,16 @@ pub mod pallet { Error::::FeesNotMet ); - // Find transfer types for fee and non-fee assets, to get to the explicit reserve. - let (fees_transfer_type, mut assets_transfer_type) = - Self::find_fee_and_assets_transfer_types(&assets, fee_asset_index, &reserve)?; - // Ensure `reserve` is configured reserve for `assets`. - // Future enhancement: also support teleports to local reserve chain. - ensure!( - matches!(assets_transfer_type, TransferType::DestinationReserve), - Error::::InvalidAssetUnsupportedReserve - ); - - // local and remote XCM programs to potentially handle fees separately - let fees = if fees_transfer_type == assets_transfer_type { - // no need for custom fees instructions, fees are batched with assets, and we are - // doing classic remote reserve transfer - assets_transfer_type = TransferType::RemoteReserve(reserve); - FeesHandling::Batched { fees } - } else { - // Future enhancement: also support combinations of reserve and teleport for assets - // and fees. - return Err(Error::::Filtered.into()) - }; - - let (local_xcm, remote_xcm) = Self::build_xcm_transfer_type( - origin.clone(), - dest.clone(), + Self::do_transfer_assets( + origin_location, + dest, beneficiary, assets, - assets_transfer_type, + *assets_transfer_type, fees, + *fees_transfer_type, weight_limit, - )?; - Self::execute_xcm_transfer(origin, dest, local_xcm, remote_xcm) + ) } } } @@ -1773,6 +1704,73 @@ impl Pallet { Self::execute_xcm_transfer(origin_location, dest, local_xcm, remote_xcm) } + fn do_transfer_assets( + origin: Location, + dest: Location, + beneficiary: Location, + mut assets: Vec, + assets_transfer_type: TransferType, + fees: Asset, + fees_transfer_type: TransferType, + weight_limit: WeightLimit, + ) -> DispatchResult { + // local and remote XCM programs to potentially handle fees separately + let fees = if fees_transfer_type == assets_transfer_type { + // no need for custom fees instructions, fees are batched with assets + FeesHandling::Batched { fees } + } else { + // Disallow _remote reserves_ unless assets & fees have same remote reserve (covered + // by branch above). The reason for this is that we'd need to send XCMs to separate + // chains with no guarantee of delivery order on final destination; therefore we + // cannot guarantee to have fees in place on final destination chain to pay for + // assets transfer. + ensure!( + !matches!(assets_transfer_type, TransferType::RemoteReserve(_)), + Error::::InvalidAssetUnsupportedReserve + ); + let weight_limit = weight_limit.clone(); + // remove `fees` from `assets` and build separate fees transfer instructions to be + // added to assets transfers XCM programs + let fee_asset_index = + assets.iter().position(|a| a.id == fees.id).ok_or(Error::::FeesNotMet)?; + let fees = assets.remove(fee_asset_index); + let (local_xcm, remote_xcm) = match fees_transfer_type { + TransferType::LocalReserve => Self::local_reserve_fees_instructions( + origin.clone(), + dest.clone(), + fees, + weight_limit, + )?, + TransferType::DestinationReserve => Self::destination_reserve_fees_instructions( + origin.clone(), + dest.clone(), + fees, + weight_limit, + )?, + TransferType::Teleport => Self::teleport_fees_instructions( + origin.clone(), + dest.clone(), + fees, + weight_limit, + )?, + TransferType::RemoteReserve(_) => + return Err(Error::::InvalidAssetUnsupportedReserve.into()), + }; + FeesHandling::Separate { local_xcm, remote_xcm } + }; + + let (local_xcm, remote_xcm) = Self::build_xcm_transfer_type( + origin.clone(), + dest.clone(), + beneficiary, + assets, + assets_transfer_type, + fees, + weight_limit, + )?; + Self::execute_xcm_transfer(origin, dest, local_xcm, remote_xcm) + } + fn build_xcm_transfer_type( origin: Location, dest: Location, @@ -1818,7 +1816,7 @@ impl Pallet { }; let local = Self::remote_reserve_transfer_program( origin.clone(), - reserve, + reserve.try_into().map_err(|()| Error::::BadVersion)?, dest.clone(), beneficiary, assets, diff --git a/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs b/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs index 5da3d1da37c8..6d72eaf680fd 100644 --- a/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs +++ b/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs @@ -30,7 +30,7 @@ pub enum Error { } /// Specify which type of asset transfer is required for a particular `(asset, dest)` combination. -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, Encode, Decode, PartialEq, Debug, TypeInfo)] pub enum TransferType { /// should teleport `asset` to `dest` Teleport, @@ -39,7 +39,7 @@ pub enum TransferType { /// should reserve-transfer `asset` to `dest`, using `dest` as reserve DestinationReserve, /// should reserve-transfer `asset` to `dest`, using remote chain `Location` as reserve - RemoteReserve(Location), + RemoteReserve(VersionedLocation), } /// A trait for identifying asset transfer type based on `IsTeleporter` and `IsReserve` @@ -77,7 +77,7 @@ pub trait XcmAssetTransfers { Ok(TransferType::LocalReserve) } else if Self::IsReserve::contains(asset, &asset_location) { // remote location that is recognized as reserve location for asset - Ok(TransferType::RemoteReserve(asset_location)) + Ok(TransferType::RemoteReserve(asset_location.into())) } else { // remote location that is not configured either as teleporter or reserve => cannot // determine asset reserve From e1dbf7a4f48d5783a7ecb3fa91bc58c6220a81f0 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 3 Apr 2024 16:46:59 +0300 Subject: [PATCH 16/30] add more tests --- .../parachains/testing/penpal/src/genesis.rs | 5 +- .../tests/assets/asset-hub-rococo/src/lib.rs | 1 + .../src/tests/reserve_transfer.rs | 356 +++++++++++++++--- .../assets/asset-hub-rococo/src/tests/swap.rs | 5 +- .../asset-hub-rococo/src/tests/teleport.rs | 11 +- .../src/tests/reserve_transfer.rs | 56 ++- .../asset-hub-westend/src/tests/swap.rs | 3 +- .../asset-hub-westend/src/tests/teleport.rs | 11 +- .../src/tests/asset_transfers.rs | 55 +-- 9 files changed, 337 insertions(+), 166 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs index d81ab8143ddb..6bcf0f004b69 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs @@ -80,15 +80,14 @@ pub fn genesis(para_id: u32) -> Storage { assets: vec![ // Relay Native asset representation ( - Location::try_from(RelayLocation::get()).expect("conversion works"), + Location::try_from(RelayLocation::get()).unwrap(), PenpalAssetOwner::get(), true, ED, ), // Sufficient AssetHub asset representation ( - Location::try_from(LocalReservableFromAssetHub::get()) - .expect("conversion works"), + Location::try_from(LocalReservableFromAssetHub::get()).unwrap(), PenpalAssetOwner::get(), true, ED, diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs index a5a4914e21d8..2758546d6d90 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs @@ -81,6 +81,7 @@ mod imports { pub type SystemParaToParaTest = Test; pub type ParaToSystemParaTest = Test; pub type ParaToParaThroughRelayTest = Test; + pub type ParaToParaThroughAHTest = Test; } #[cfg(test)] diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index a0738839087a..881673cbb90a 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -14,6 +14,7 @@ // limitations under the License. use crate::imports::*; +use xcm_executor::traits::TransferType; fn relay_to_para_sender_assertions(t: RelayToParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -47,7 +48,7 @@ fn para_to_relay_sender_assertions(t: ParaToRelayTest) { RuntimeEvent::ForeignAssets( pallet_assets::Event::Burned { asset_id, owner, balance, .. } ) => { - asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).expect("conversion works"), + asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).unwrap(), owner: *owner == t.sender.account_id, balance: *balance == t.args.amount, }, @@ -87,8 +88,7 @@ fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { fn system_para_to_para_receiver_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; - let system_para_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); PenpalA::assert_xcmp_queue_success(None); @@ -113,7 +113,7 @@ fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { RuntimeEvent::ForeignAssets( pallet_assets::Event::Burned { asset_id, owner, balance, .. } ) => { - asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).expect("conversion works"), + asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).unwrap(), owner: *owner == t.sender.account_id, balance: *balance == t.args.amount, }, @@ -212,10 +212,9 @@ fn system_para_to_para_assets_sender_assertions(t: SystemParaToParaTest) { fn para_to_system_para_assets_sender_assertions(t: ParaToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; - let system_para_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); let reservable_asset_location = - v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("conversion works"); + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).unwrap(); PenpalA::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8799))); assert_expected_events!( PenpalA, @@ -246,13 +245,13 @@ fn para_to_system_para_assets_sender_assertions(t: ParaToSystemParaTest) { fn system_para_to_para_assets_receiver_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; let system_para_asset_location = - v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("conversion works"); + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).unwrap(); PenpalA::assert_xcmp_queue_success(None); assert_expected_events!( PenpalA, vec![ RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).expect("conversion works"), + asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).unwrap(), owner: *owner == t.receiver.account_id, }, RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { @@ -304,7 +303,7 @@ fn relay_to_para_assets_receiver_assertions(t: RelayToParaTest) { PenpalA, vec![ RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).expect("conversion works"), + asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).unwrap(), owner: *owner == t.receiver.account_id, }, RuntimeEvent::MessageQueue( @@ -314,29 +313,27 @@ fn relay_to_para_assets_receiver_assertions(t: RelayToParaTest) { ); } -fn para_to_para_through_relay_sender_assertions(t: ParaToParaThroughRelayTest) { +fn para_to_para_through_hop_sender_assertions(t: Test) { type RuntimeEvent = ::RuntimeEvent; - let relay_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); - PenpalA::assert_xcm_pallet_attempted_complete(None); - // XCM sent to relay reserve - PenpalA::assert_parachain_system_ump_sent(); - - assert_expected_events!( - PenpalA, - vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::ForeignAssets( - pallet_assets::Event::Burned { asset_id, owner, balance }, - ) => { - asset_id: *asset_id == relay_asset_location, - owner: *owner == t.sender.account_id, - balance: *balance == t.args.amount, - }, - ] - ); + 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: ParaToParaThroughRelayTest) { @@ -369,24 +366,56 @@ fn para_to_para_relay_hop_assertions(t: ParaToParaThroughRelayTest) { ); } -fn para_to_para_through_relay_receiver_assertions(t: ParaToParaThroughRelayTest) { - type RuntimeEvent = ::RuntimeEvent; - let relay_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); - - PenpalB::assert_xcmp_queue_success(None); +fn para_to_para_assethub_hop_assertions(t: ParaToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + let sov_penpal_a_on_ah = AssetHubRococo::sovereign_account_id_of( + AssetHubRococo::sibling_location_of(PenpalA::para_id()), + ); + let sov_penpal_b_on_ah = AssetHubRococo::sovereign_account_id_of( + AssetHubRococo::sibling_location_of(PenpalB::para_id()), + ); assert_expected_events!( - PenpalB, + AssetHubRococo, vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == relay_asset_location, - owner: *owner == t.receiver.account_id, + // 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 para_to_para_through_hop_receiver_assertions(t: Test) { + 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_reserve_transfer_assets(t: RelayToParaTest) -> DispatchResult { ::XcmPallet::limited_reserve_transfer_assets( t.signed_origin, @@ -444,6 +473,22 @@ fn para_to_para_through_relay_limited_reserve_transfer_assets( ) } +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(AssetHubRococo::para_id()); + ::PolkadotXcm::transfer_assets_using_reserve( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), + bx!(fee.into()), + bx!(TransferType::RemoteReserve(asset_hub_location.into())), + t.args.weight_limit, + ) +} + /// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work #[test] fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { @@ -526,8 +571,7 @@ fn reserve_transfer_native_asset_from_relay_to_para() { let amount_to_send: Balance = ROCOCO_ED * 1000; // Init values fot Parachain - let relay_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let relay_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); let receiver = PenpalAReceiver::get(); // Init Test @@ -577,8 +621,7 @@ fn reserve_transfer_native_asset_from_para_to_relay() { let amount_to_send: Balance = ROCOCO_ED * 1000; let assets: Assets = (Parent, amount_to_send).into(); let asset_owner = PenpalAssetOwner::get(); - let relay_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let relay_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); // fund Parachain's sender account PenpalA::mint_foreign_asset( @@ -654,8 +697,7 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { let assets: Assets = (Parent, amount_to_send).into(); // Init values for Parachain - let system_para_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); let receiver = PenpalAReceiver::get(); // Init Test @@ -711,8 +753,7 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { let sender = PenpalASender::get(); let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 10000; let assets: Assets = (Parent, amount_to_send).into(); - let system_para_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); let asset_owner = PenpalAssetOwner::get(); // fund Parachain's sender account @@ -817,10 +858,9 @@ fn reserve_transfer_assets_from_system_para_to_para() { // Init values for Parachain let receiver = PenpalAReceiver::get(); - let system_para_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); let system_para_foreign_asset_location = - v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("conversion works"); + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).unwrap(); // Init Test let para_test_args = TestContext { @@ -905,10 +945,9 @@ fn reserve_transfer_assets_from_para_to_system_para() { let penpal_asset_owner = PenpalAssetOwner::get(); let penpal_asset_owner_signer = ::RuntimeOrigin::signed(penpal_asset_owner); let asset_location_on_penpal = - v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("conversion works"); + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).unwrap(); let asset_location_on_penpal_latest: Location = asset_location_on_penpal.try_into().unwrap(); - let system_asset_location_on_penpal = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_asset_location_on_penpal = v3::Location::try_from(RelayLocation::get()).unwrap(); let assets: Assets = vec![ (Parent, fee_amount_to_send).into(), (asset_location_on_penpal_latest, asset_amount_to_send).into(), @@ -938,10 +977,9 @@ fn reserve_transfer_assets_from_para_to_system_para() { let receiver = AssetHubRococoReceiver::get(); let penpal_location_as_seen_by_ahr = AssetHubRococo::sibling_location_of(PenpalA::para_id()); let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location_as_seen_by_ahr); - let system_para_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); let system_para_foreign_asset_location = - v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("conversion works"); + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).unwrap(); let ah_asset_owner = AssetHubRococoAssetOwner::get(); let ah_asset_owner_signer = ::RuntimeOrigin::signed(ah_asset_owner); @@ -1029,15 +1067,14 @@ fn reserve_transfer_assets_from_para_to_system_para() { /// Reserve Transfers of native asset from Parachain to Parachain (through Relay reserve) should /// work #[test] -fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { +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 sender = PenpalASender::get(); let amount_to_send: Balance = ROCOCO_ED * 10000; let asset_owner = PenpalAssetOwner::get(); let assets = (Parent, amount_to_send).into(); - let relay_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let relay_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); let sender_as_seen_by_relay = Rococo::child_location_of(PenpalA::para_id()); let sov_of_sender_on_relay = Rococo::sovereign_account_id_of(sender_as_seen_by_relay); @@ -1074,9 +1111,9 @@ fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { }); // Set assertions and dispatchables - test.set_assertion::(para_to_para_through_relay_sender_assertions); + 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_through_relay_receiver_assertions); + test.set_assertion::(para_to_para_through_hop_receiver_assertions); test.set_dispatchable::(para_to_para_through_relay_limited_reserve_transfer_assets); test.assert(); @@ -1095,3 +1132,198 @@ fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { // Receiver's balance is increased assert!(receiver_assets_after > receiver_assets_before); } + +// ====================================================================================== +// ===== Reserve Transfers - Native + Bridged Asset - Parachain<>AssetHub<>Parachain ==== +// ====================================================================================== +/// Reserve Transfers of native asset plus bridged asset from Parachain to Parachain +/// (through AssetHub reserve) should work - fees are paid using native asset +#[test] +fn reserve_transfer_native_asset_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 = ROCOCO_ED * 10000; + let penpal_roc_owner = PenpalAssetOwner::get(); + let roc_location = v3::Location::try_from(RelayLocation::get()).unwrap(); + let roc_location_latest: Location = roc_location.try_into().unwrap(); + let sender_as_seen_by_ah = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let sov_of_sender_on_ah = AssetHubRococo::sovereign_account_id_of(sender_as_seen_by_ah); + let receiver_as_seen_by_ah = AssetHubRococo::sibling_location_of(PenpalB::para_id()); + let sov_of_receiver_on_ah = AssetHubRococo::sovereign_account_id_of(receiver_as_seen_by_ah); + let wnd_to_send = ASSET_HUB_ROCOCO_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![( + penpal_runtime::xcm_config::CustomizableAssetFromSystemAssetHub::key().to_vec(), + Location::new(2, [GlobalConsensus(Westend)]).encode(), + )], + )); + }); + + // Register WND as foreign asset and transfer it around the Rococo ecosystem + let wnd_at_rococo_parachains = + v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Westend)]); + let wnd_at_rococo_parachains_latest: Location = wnd_at_rococo_parachains.try_into().unwrap(); + let owner = AssetHubRococo::account_id_of(emulated_integration_tests_common::accounts::ALICE); + AssetHubRococo::force_create_foreign_asset( + wnd_at_rococo_parachains, + owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + PenpalA::force_create_foreign_asset( + wnd_at_rococo_parachains, + owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + PenpalB::force_create_foreign_asset( + wnd_at_rococo_parachains, + owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(penpal_roc_owner), + roc_location, + sender.clone(), + roc_to_send * 2, + ); + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(owner.clone()), + wnd_at_rococo_parachains, + sender.clone(), + wnd_to_send * 2, + ); + // fund the Parachain Origin's SA on Asset Hub with the assets held in reserve + AssetHubRococo::fund_accounts(vec![(sov_of_sender_on_ah.clone().into(), roc_to_send * 2)]); + AssetHubRococo::mint_foreign_asset( + ::RuntimeOrigin::signed(owner.clone()), + wnd_at_rococo_parachains, + 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_latest.clone(), roc_to_send).into(), + (wnd_at_rococo_parachains_latest, wnd_to_send).into(), + ]; + let fee_asset_id: AssetId = roc_location_latest.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, &sender) + }); + let sender_wnds_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &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 = AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &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 = AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &sov_of_receiver_on_ah) + }); + let receiver_rocs_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_location, &receiver) + }); + let receiver_wnds_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &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, &sender) + }); + let sender_wnds_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &sender) + }); + let wnds_in_sender_reserve_on_ahr_after = AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &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 = AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &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); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs index e13300b7c114..cea1b8aefbd5 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs @@ -112,10 +112,9 @@ fn swap_locally_on_chain_using_local_assets() { #[test] fn swap_locally_on_chain_using_foreign_assets() { - let asset_native = - Box::new(v3::Location::try_from(RelayLocation::get()).expect("conversion works")); + let asset_native = Box::new(v3::Location::try_from(RelayLocation::get()).unwrap()); let asset_location_on_penpal = - v3::Location::try_from(PenpalLocalTeleportableToAssetHub::get()).expect("conversion works"); + v3::Location::try_from(PenpalLocalTeleportableToAssetHub::get()).unwrap(); let foreign_asset_at_asset_hub_rococo = v3::Location::new(1, [v3::Junction::Parachain(PenpalA::para_id().into())]) .appended_with(asset_location_on_penpal) diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs index 1cbb7fb8c193..5bda6a8a2af6 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs @@ -110,8 +110,7 @@ fn para_dest_assertions(t: RelayToSystemParaTest) { fn penpal_to_ah_foreign_assets_sender_assertions(t: ParaToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; - let system_para_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); 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(); @@ -204,8 +203,7 @@ 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 = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); PenpalA::assert_xcmp_queue_success(None); @@ -421,15 +419,14 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { // Init values for Parachain let fee_amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 10000; let asset_location_on_penpal = - v3::Location::try_from(PenpalLocalTeleportableToAssetHub::get()).expect("conversion works"); + v3::Location::try_from(PenpalLocalTeleportableToAssetHub::get()).unwrap(); let asset_id_on_penpal = match asset_location_on_penpal.last() { Some(v3::Junction::GeneralIndex(id)) => *id as u32, _ => unreachable!(), }; let asset_amount_to_send = ASSET_HUB_ROCOCO_ED * 1000; let asset_owner = PenpalAssetOwner::get(); - let system_para_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); let sender = PenpalASender::get(); let penpal_check_account = ::PolkadotXcm::check_account(); let ah_as_seen_by_penpal = PenpalA::sibling_location_of(AssetHubRococo::para_id()); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs index a26dfef8e8e7..7428d7fa53a2 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -47,7 +47,7 @@ fn para_to_relay_sender_assertions(t: ParaToRelayTest) { RuntimeEvent::ForeignAssets( pallet_assets::Event::Burned { asset_id, owner, balance, .. } ) => { - asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).expect("conversion works"), + asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).unwrap(), owner: *owner == t.sender.account_id, balance: *balance == t.args.amount, }, @@ -87,8 +87,7 @@ fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { fn system_para_to_para_receiver_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; - let system_para_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); PenpalA::assert_xcmp_queue_success(None); @@ -113,7 +112,7 @@ fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { RuntimeEvent::ForeignAssets( pallet_assets::Event::Burned { asset_id, owner, balance, .. } ) => { - asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).expect("conversion works"), + asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).unwrap(), owner: *owner == t.sender.account_id, balance: *balance == t.args.amount, }, @@ -212,10 +211,9 @@ fn system_para_to_para_assets_sender_assertions(t: SystemParaToParaTest) { fn para_to_system_para_assets_sender_assertions(t: ParaToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; - let system_para_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); let reservable_asset_location = - v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("conversion works"); + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).unwrap(); PenpalA::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8799))); assert_expected_events!( PenpalA, @@ -246,13 +244,13 @@ fn para_to_system_para_assets_sender_assertions(t: ParaToSystemParaTest) { fn system_para_to_para_assets_receiver_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; let system_para_asset_location = - v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("conversion works"); + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).unwrap(); PenpalA::assert_xcmp_queue_success(None); assert_expected_events!( PenpalA, vec![ RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).expect("conversion works"), + asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).unwrap(), owner: *owner == t.receiver.account_id, }, RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { @@ -304,7 +302,7 @@ fn relay_to_para_assets_receiver_assertions(t: RelayToParaTest) { PenpalA, vec![ RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).expect("conversion works"), + asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).unwrap(), owner: *owner == t.receiver.account_id, }, RuntimeEvent::MessageQueue( @@ -317,8 +315,7 @@ fn relay_to_para_assets_receiver_assertions(t: RelayToParaTest) { fn para_to_para_through_relay_sender_assertions(t: ParaToParaThroughRelayTest) { type RuntimeEvent = ::RuntimeEvent; - let relay_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let relay_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); PenpalA::assert_xcm_pallet_attempted_complete(None); // XCM sent to relay reserve @@ -371,8 +368,7 @@ fn para_to_para_relay_hop_assertions(t: ParaToParaThroughRelayTest) { fn para_to_para_through_relay_receiver_assertions(t: ParaToParaThroughRelayTest) { type RuntimeEvent = ::RuntimeEvent; - let relay_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let relay_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); PenpalB::assert_xcmp_queue_success(None); @@ -526,8 +522,7 @@ fn reserve_transfer_native_asset_from_relay_to_para() { let amount_to_send: Balance = WESTEND_ED * 1000; // Init values fot Parachain - let relay_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let relay_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); let receiver = PenpalAReceiver::get(); // Init Test @@ -577,8 +572,7 @@ fn reserve_transfer_native_asset_from_para_to_relay() { let amount_to_send: Balance = WESTEND_ED * 1000; let assets: Assets = (Parent, amount_to_send).into(); let asset_owner = PenpalAssetOwner::get(); - let relay_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let relay_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); // fund Parachain's sender account PenpalA::mint_foreign_asset( @@ -654,8 +648,7 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { let assets: Assets = (Parent, amount_to_send).into(); // Init values for Parachain - let system_para_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); let receiver = PenpalAReceiver::get(); // Init Test @@ -711,8 +704,7 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { let sender = PenpalASender::get(); let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; let assets: Assets = (Parent, amount_to_send).into(); - let system_para_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); let asset_owner = PenpalAssetOwner::get(); // fund Parachain's sender account @@ -818,10 +810,9 @@ fn reserve_transfer_assets_from_system_para_to_para() { // Init values for Parachain let receiver = PenpalAReceiver::get(); - let system_para_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); let system_para_foreign_asset_location = - v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("conversion works"); + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).unwrap(); // Init Test let para_test_args = TestContext { @@ -906,10 +897,9 @@ fn reserve_transfer_assets_from_para_to_system_para() { let penpal_asset_owner = PenpalAssetOwner::get(); let penpal_asset_owner_signer = ::RuntimeOrigin::signed(penpal_asset_owner); let asset_location_on_penpal = - v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("conversion works"); + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).unwrap(); let asset_location_on_penpal_latest: Location = asset_location_on_penpal.try_into().unwrap(); - let system_asset_location_on_penpal = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_asset_location_on_penpal = v3::Location::try_from(RelayLocation::get()).unwrap(); let assets: Assets = vec![ (Parent, fee_amount_to_send).into(), (asset_location_on_penpal_latest, asset_amount_to_send).into(), @@ -940,10 +930,9 @@ fn reserve_transfer_assets_from_para_to_system_para() { let penpal_location_as_seen_by_ahr = AssetHubWestend::sibling_location_of(PenpalA::para_id()); let sov_penpal_on_ahr = AssetHubWestend::sovereign_account_id_of(penpal_location_as_seen_by_ahr); - let system_para_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); let system_para_foreign_asset_location = - v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("conversion works"); + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).unwrap(); let ah_asset_owner = AssetHubWestendAssetOwner::get(); let ah_asset_owner_signer = ::RuntimeOrigin::signed(ah_asset_owner); @@ -1031,15 +1020,14 @@ fn reserve_transfer_assets_from_para_to_system_para() { /// Reserve Transfers of native asset from Parachain to Parachain (through Relay reserve) should /// work #[test] -fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { +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 sender = PenpalASender::get(); let amount_to_send: Balance = WESTEND_ED * 10000; let asset_owner = PenpalAssetOwner::get(); let assets = (Parent, amount_to_send).into(); - let relay_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let relay_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); let sender_as_seen_by_relay = Westend::child_location_of(PenpalA::para_id()); let sov_of_sender_on_relay = Westend::sovereign_account_id_of(sender_as_seen_by_relay); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs index aa673c03483a..8996893f0f12 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs @@ -111,8 +111,7 @@ fn swap_locally_on_chain_using_local_assets() { #[test] fn swap_locally_on_chain_using_foreign_assets() { - let asset_native = - Box::new(v3::Location::try_from(RelayLocation::get()).expect("conversion works")); + let asset_native = Box::new(v3::Location::try_from(RelayLocation::get()).unwrap()); let asset_location_on_penpal = v3::Location::try_from(PenpalLocalTeleportableToAssetHub::get()).expect("conversion_works"); let foreign_asset_at_asset_hub_westend = diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs index ac518d2ed4a4..125ffb220a87 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs @@ -110,8 +110,7 @@ fn para_dest_assertions(t: RelayToSystemParaTest) { fn penpal_to_ah_foreign_assets_sender_assertions(t: ParaToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; - let system_para_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); 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(); @@ -204,8 +203,7 @@ 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 = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); PenpalA::assert_xcmp_queue_success(None); @@ -421,15 +419,14 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { // Init values for Parachain let fee_amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 100; let asset_location_on_penpal = - v3::Location::try_from(PenpalLocalTeleportableToAssetHub::get()).expect("conversion works"); + v3::Location::try_from(PenpalLocalTeleportableToAssetHub::get()).unwrap(); let asset_id_on_penpal = match asset_location_on_penpal.last() { Some(v3::Junction::GeneralIndex(id)) => *id as u32, _ => unreachable!(), }; let asset_amount_to_send = ASSET_HUB_WESTEND_ED * 100; let asset_owner = PenpalAssetOwner::get(); - let system_para_native_asset_location = - v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); let sender = PenpalASender::get(); let penpal_check_account = ::PolkadotXcm::check_account(); let ah_as_seen_by_penpal = PenpalA::sibling_location_of(AssetHubWestend::para_id()); diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs index 5db0c702d3d9..499adce1f2d2 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs @@ -14,6 +14,7 @@ // limitations under the License. use crate::tests::*; +use xcm_executor::traits::TransferType; fn send_asset_from_asset_hub_rococo_to_asset_hub_westend(id: Location, amount: u128) { let destination = asset_hub_westend_location(); @@ -58,16 +59,17 @@ fn send_asset_from_penpal_rococo_through_local_asset_hub_to_westend_asset_hub( let signed_origin = ::RuntimeOrigin::signed(PenpalASender::get()); let beneficiary: Location = AccountId32Junction { network: None, id: AssetHubWestendReceiver::get().into() }.into(); - let fees: Asset = (id, transfer_amount).into(); - let assets: Assets = fees.clone().into(); + let fees: Asset = (id.clone(), transfer_amount).into(); + let assets: Assets = vec![fees.clone()].into(); ::PolkadotXcm::transfer_assets_using_reserve( signed_origin, bx!(destination.into()), bx!(beneficiary.into()), - bx!(assets.into()), + bx!(assets.clone().into()), + bx!(TransferType::RemoteReserve(local_asset_hub.clone().into())), bx!(fees.into()), - bx!(local_asset_hub.into()), + bx!(TransferType::RemoteReserve(local_asset_hub.into())), WeightLimit::Unlimited, ) })); @@ -210,7 +212,7 @@ fn send_wnds_from_asset_hub_rococo_to_asset_hub_westend() { let prefund_amount = 10_000_000_000_000u128; let wnd_at_asset_hub_rococo = v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Westend)]); - let owner: AccountId = AssetHubWestend::account_id_of(ALICE); + let owner: AccountId = AssetHubRococo::account_id_of(ALICE); AssetHubRococo::force_create_foreign_asset( wnd_at_asset_hub_rococo, owner, @@ -303,49 +305,6 @@ fn send_rocs_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_westend() AssetHubWestend::para_id(), ); - AssetHubWestend::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - // setup a pool to pay xcm fees with `roc_at_asset_hub_westend` tokens - assert_ok!(::ForeignAssets::mint( - ::RuntimeOrigin::signed(AssetHubWestendSender::get()), - roc_at_asset_hub_westend.into(), - AssetHubWestendSender::get().into(), - 3_000_000_000_000, - )); - - assert_ok!(::AssetConversion::create_pool( - ::RuntimeOrigin::signed(AssetHubWestendSender::get()), - Box::new(xcm::v3::Parent.into()), - Box::new(roc_at_asset_hub_westend), - )); - - assert_expected_events!( - AssetHubWestend, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, - ] - ); - - assert_ok!(::AssetConversion::add_liquidity( - ::RuntimeOrigin::signed(AssetHubWestendSender::get()), - Box::new(xcm::v3::Parent.into()), - Box::new(roc_at_asset_hub_westend), - 1_000_000_000_000, - 2_000_000_000_000, - 1, - 1, - AssetHubWestendSender::get().into() - )); - - assert_expected_events!( - AssetHubWestend, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {..}) => {}, - ] - ); - }); - let amount = ASSET_HUB_ROCOCO_ED * 10_000_000; let penpal_location = AssetHubRococo::sibling_location_of(PenpalA::para_id()); let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location); From ef83eabdb2a2bde3688974790de2c54c795122e5 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 4 Apr 2024 16:06:28 +0300 Subject: [PATCH 17/30] fix prdoc --- prdoc/pr_3695.prdoc | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/prdoc/pr_3695.prdoc b/prdoc/pr_3695.prdoc index 8816e910b23e..c592e02d0146 100644 --- a/prdoc/pr_3695.prdoc +++ b/prdoc/pr_3695.prdoc @@ -4,12 +4,6 @@ title: "pallet-xcm: add new extrinsic for asset transfers using explicit reserve" doc: - - audience: Runtime Dev - description: | - pallet-xcm's extrinsics `teleport_assets` and `reserve_transfer_assets` have been - marked as deprecated. Please change their usage to the `limited_teleport_assets` - and `limited_reserve_transfer_assets`, respectively; or use the generic/flexible - `transfer_assets` extrinsic. - audience: Runtime User description: | pallet-xcm has a new extrinsic `transfer_assets_using_reserve` for transferring @@ -22,9 +16,11 @@ doc: (such as Asset Hub ForeignAssets), when the transfer strictly depends on the used reserve location. - E.g. For transferring Foreign Assets over a bridge, Asset Hub must be used as the - reserve location. Same when transferring bridged assets between parachains, the - local Asset Hub must be used as the explicit reserve location. + E.g. For transferring a bridged Foreign Assets between local parachains, Asset Hub + or the parachain that bridged the asset over must be used as the reserve location. + Same when transferring bridged assets back across the bridge, the local bridging + parachain must be used as the explicit reserve location. crates: - name: pallet-xcm + bump: minor From 42506924ec4360021c05d2689f125af8e6c92924 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 4 Apr 2024 16:19:40 +0300 Subject: [PATCH 18/30] refactor tests --- .../tests/assets/asset-hub-rococo/src/lib.rs | 1 + .../src/tests/foreign_assets_transfers.rs | 262 ++++++++++++++++++ .../assets/asset-hub-rococo/src/tests/mod.rs | 1 + .../src/tests/reserve_transfer.rs | 248 +---------------- 4 files changed, 266 insertions(+), 246 deletions(-) create mode 100644 cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs index 2758546d6d90..322c6cf1f228 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs @@ -30,6 +30,7 @@ mod imports { prelude::{AccountId32 as AccountId32Junction, *}, v3, }; + pub use xcm_executor::traits::TransferType; // Cumulus pub use asset_test_utils::xcm_helpers; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs new file mode 100644 index 000000000000..da787717268d --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs @@ -0,0 +1,262 @@ +// 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::{ + para_to_para_through_hop_receiver_assertions, para_to_para_through_hop_sender_assertions, +}; +use crate::imports::*; + +fn para_to_para_assethub_hop_assertions(t: ParaToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + let sov_penpal_a_on_ah = AssetHubRococo::sovereign_account_id_of( + AssetHubRococo::sibling_location_of(PenpalA::para_id()), + ); + let sov_penpal_b_on_ah = AssetHubRococo::sovereign_account_id_of( + AssetHubRococo::sibling_location_of(PenpalB::para_id()), + ); + + assert_expected_events!( + AssetHubRococo, + 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 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(AssetHubRococo::para_id()); + ::PolkadotXcm::transfer_assets_using_reserve( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), + bx!(fee.into()), + bx!(TransferType::RemoteReserve(asset_hub_location.into())), + t.args.weight_limit, + ) +} + +// ====================================================================================== +// ===== Reserve Transfers - Native + Bridged Asset - Parachain<>AssetHub<>Parachain ==== +// ====================================================================================== +/// Reserve Transfers of native asset plus bridged asset from Parachain to Parachain +/// (through AssetHub reserve) should work - fees are paid using native asset +#[test] +fn reserve_transfer_native_asset_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 = ROCOCO_ED * 10000; + let penpal_roc_owner = PenpalAssetOwner::get(); + let roc_location = v3::Location::try_from(RelayLocation::get()).unwrap(); + let roc_location_latest: Location = roc_location.try_into().unwrap(); + let sender_as_seen_by_ah = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let sov_of_sender_on_ah = AssetHubRococo::sovereign_account_id_of(sender_as_seen_by_ah); + let receiver_as_seen_by_ah = AssetHubRococo::sibling_location_of(PenpalB::para_id()); + let sov_of_receiver_on_ah = AssetHubRococo::sovereign_account_id_of(receiver_as_seen_by_ah); + let wnd_to_send = ASSET_HUB_ROCOCO_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![( + penpal_runtime::xcm_config::CustomizableAssetFromSystemAssetHub::key().to_vec(), + Location::new(2, [GlobalConsensus(Westend)]).encode(), + )], + )); + }); + + // Register WND as foreign asset and transfer it around the Rococo ecosystem + let wnd_at_rococo_parachains = + v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Westend)]); + let wnd_at_rococo_parachains_latest: Location = wnd_at_rococo_parachains.try_into().unwrap(); + let owner = AssetHubRococo::account_id_of(emulated_integration_tests_common::accounts::ALICE); + AssetHubRococo::force_create_foreign_asset( + wnd_at_rococo_parachains, + owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + PenpalA::force_create_foreign_asset( + wnd_at_rococo_parachains, + owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + PenpalB::force_create_foreign_asset( + wnd_at_rococo_parachains, + owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(penpal_roc_owner), + roc_location, + sender.clone(), + roc_to_send * 2, + ); + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(owner.clone()), + wnd_at_rococo_parachains, + sender.clone(), + wnd_to_send * 2, + ); + // fund the Parachain Origin's SA on Asset Hub with the assets held in reserve + AssetHubRococo::fund_accounts(vec![(sov_of_sender_on_ah.clone().into(), roc_to_send * 2)]); + AssetHubRococo::mint_foreign_asset( + ::RuntimeOrigin::signed(owner.clone()), + wnd_at_rococo_parachains, + 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_latest.clone(), roc_to_send).into(), + (wnd_at_rococo_parachains_latest, wnd_to_send).into(), + ]; + let fee_asset_id: AssetId = roc_location_latest.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, &sender) + }); + let sender_wnds_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &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 = AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &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 = AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &sov_of_receiver_on_ah) + }); + let receiver_rocs_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_location, &receiver) + }); + let receiver_wnds_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &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, &sender) + }); + let sender_wnds_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &sender) + }); + let wnds_in_sender_reserve_on_ahr_after = AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &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 = AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &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); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs index b3841af0e6c3..2402989225af 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +mod foreign_assets_transfers; mod reserve_transfer; mod send; mod set_xcm_versions; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index 881673cbb90a..d5926a0592c8 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -14,7 +14,6 @@ // limitations under the License. use crate::imports::*; -use xcm_executor::traits::TransferType; fn relay_to_para_sender_assertions(t: RelayToParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -313,7 +312,7 @@ fn relay_to_para_assets_receiver_assertions(t: RelayToParaTest) { ); } -fn para_to_para_through_hop_sender_assertions(t: Test) { +pub fn para_to_para_through_hop_sender_assertions(t: Test) { type RuntimeEvent = ::RuntimeEvent; PenpalA::assert_xcm_pallet_attempted_complete(None); @@ -366,39 +365,7 @@ fn para_to_para_relay_hop_assertions(t: ParaToParaThroughRelayTest) { ); } -fn para_to_para_assethub_hop_assertions(t: ParaToParaThroughAHTest) { - type RuntimeEvent = ::RuntimeEvent; - let sov_penpal_a_on_ah = AssetHubRococo::sovereign_account_id_of( - AssetHubRococo::sibling_location_of(PenpalA::para_id()), - ); - let sov_penpal_b_on_ah = AssetHubRococo::sovereign_account_id_of( - AssetHubRococo::sibling_location_of(PenpalB::para_id()), - ); - - assert_expected_events!( - AssetHubRococo, - 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 para_to_para_through_hop_receiver_assertions(t: Test) { +pub fn para_to_para_through_hop_receiver_assertions(t: Test) { type RuntimeEvent = ::RuntimeEvent; PenpalB::assert_xcmp_queue_success(None); @@ -473,22 +440,6 @@ fn para_to_para_through_relay_limited_reserve_transfer_assets( ) } -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(AssetHubRococo::para_id()); - ::PolkadotXcm::transfer_assets_using_reserve( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), - bx!(fee.into()), - bx!(TransferType::RemoteReserve(asset_hub_location.into())), - t.args.weight_limit, - ) -} - /// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work #[test] fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { @@ -1132,198 +1083,3 @@ fn reserve_transfer_native_asset_from_para_to_para_through_relay() { // Receiver's balance is increased assert!(receiver_assets_after > receiver_assets_before); } - -// ====================================================================================== -// ===== Reserve Transfers - Native + Bridged Asset - Parachain<>AssetHub<>Parachain ==== -// ====================================================================================== -/// Reserve Transfers of native asset plus bridged asset from Parachain to Parachain -/// (through AssetHub reserve) should work - fees are paid using native asset -#[test] -fn reserve_transfer_native_asset_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 = ROCOCO_ED * 10000; - let penpal_roc_owner = PenpalAssetOwner::get(); - let roc_location = v3::Location::try_from(RelayLocation::get()).unwrap(); - let roc_location_latest: Location = roc_location.try_into().unwrap(); - let sender_as_seen_by_ah = AssetHubRococo::sibling_location_of(PenpalA::para_id()); - let sov_of_sender_on_ah = AssetHubRococo::sovereign_account_id_of(sender_as_seen_by_ah); - let receiver_as_seen_by_ah = AssetHubRococo::sibling_location_of(PenpalB::para_id()); - let sov_of_receiver_on_ah = AssetHubRococo::sovereign_account_id_of(receiver_as_seen_by_ah); - let wnd_to_send = ASSET_HUB_ROCOCO_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![( - penpal_runtime::xcm_config::CustomizableAssetFromSystemAssetHub::key().to_vec(), - Location::new(2, [GlobalConsensus(Westend)]).encode(), - )], - )); - }); - - // Register WND as foreign asset and transfer it around the Rococo ecosystem - let wnd_at_rococo_parachains = - v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Westend)]); - let wnd_at_rococo_parachains_latest: Location = wnd_at_rococo_parachains.try_into().unwrap(); - let owner = AssetHubRococo::account_id_of(emulated_integration_tests_common::accounts::ALICE); - AssetHubRococo::force_create_foreign_asset( - wnd_at_rococo_parachains, - owner.clone(), - false, - ASSET_MIN_BALANCE, - vec![], - ); - PenpalA::force_create_foreign_asset( - wnd_at_rococo_parachains, - owner.clone(), - false, - ASSET_MIN_BALANCE, - vec![], - ); - PenpalB::force_create_foreign_asset( - wnd_at_rococo_parachains, - owner.clone(), - false, - ASSET_MIN_BALANCE, - vec![], - ); - - // fund Parachain's sender account - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(penpal_roc_owner), - roc_location, - sender.clone(), - roc_to_send * 2, - ); - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(owner.clone()), - wnd_at_rococo_parachains, - sender.clone(), - wnd_to_send * 2, - ); - // fund the Parachain Origin's SA on Asset Hub with the assets held in reserve - AssetHubRococo::fund_accounts(vec![(sov_of_sender_on_ah.clone().into(), roc_to_send * 2)]); - AssetHubRococo::mint_foreign_asset( - ::RuntimeOrigin::signed(owner.clone()), - wnd_at_rococo_parachains, - 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_latest.clone(), roc_to_send).into(), - (wnd_at_rococo_parachains_latest, wnd_to_send).into(), - ]; - let fee_asset_id: AssetId = roc_location_latest.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, &sender) - }); - let sender_wnds_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(wnd_at_rococo_parachains, &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 = AssetHubRococo::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(wnd_at_rococo_parachains, &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 = AssetHubRococo::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(wnd_at_rococo_parachains, &sov_of_receiver_on_ah) - }); - let receiver_rocs_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(roc_location, &receiver) - }); - let receiver_wnds_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(wnd_at_rococo_parachains, &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, &sender) - }); - let sender_wnds_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(wnd_at_rococo_parachains, &sender) - }); - let wnds_in_sender_reserve_on_ahr_after = AssetHubRococo::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(wnd_at_rococo_parachains, &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 = AssetHubRococo::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(wnd_at_rococo_parachains, &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); -} From 888d403207550b243af7e5b21d2a9ff060384269 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 4 Apr 2024 17:05:31 +0300 Subject: [PATCH 19/30] even more tests --- .../src/tests/foreign_assets_transfers.rs | 169 ++++++++++++++++-- .../src/tests/reserve_transfer.rs | 77 +++++--- 2 files changed, 202 insertions(+), 44 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs index da787717268d..bbfca67a3558 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs @@ -13,9 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use super::reserve_transfer::{ - para_to_para_through_hop_receiver_assertions, para_to_para_through_hop_sender_assertions, -}; +use super::reserve_transfer::*; use crate::imports::*; fn para_to_para_assethub_hop_assertions(t: ParaToParaThroughAHTest) { @@ -50,6 +48,21 @@ fn para_to_para_assethub_hop_assertions(t: ParaToParaThroughAHTest) { ); } +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(); + ::PolkadotXcm::transfer_assets_using_reserve( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + bx!(TransferType::LocalReserve), + bx!(fee.into()), + bx!(TransferType::LocalReserve), + 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(); @@ -66,18 +79,141 @@ fn para_to_para_transfer_assets_through_ah(t: ParaToParaThroughAHTest) -> Dispat ) } -// ====================================================================================== -// ===== Reserve Transfers - Native + Bridged Asset - Parachain<>AssetHub<>Parachain ==== -// ====================================================================================== -/// Reserve Transfers of native asset plus bridged asset from Parachain to Parachain -/// (through AssetHub reserve) should work - fees are paid using native asset +// =========================================================================== +// ======= 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 = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let sender = AssetHubRococoSender::get(); + let native_amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 10000; + let native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); + let receiver = PenpalAReceiver::get(); + let assets_owner = PenpalAssetOwner::get(); + // Foreign asset used: bridged WND + let foreign_amount_to_send = ASSET_HUB_ROCOCO_ED * 10_000_000; + let wnd_at_rococo_parachains = + v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Westend)]); + let wnd_at_rococo_parachains_latest: Location = wnd_at_rococo_parachains.try_into().unwrap(); + + // Configure destination chain to trust AH as reserve of WND + PenpalA::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + penpal_runtime::xcm_config::CustomizableAssetFromSystemAssetHub::key().to_vec(), + Location::new(2, [GlobalConsensus(Westend)]).encode(), + )], + )); + }); + PenpalA::force_create_foreign_asset( + wnd_at_rococo_parachains, + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + AssetHubRococo::force_create_foreign_asset( + wnd_at_rococo_parachains, + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + AssetHubRococo::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner), + wnd_at_rococo_parachains, + sender.clone(), + foreign_amount_to_send * 2, + ); + + // Assets to send + let assets: Vec = vec![ + (Parent, native_amount_to_send).into(), + (wnd_at_rococo_parachains_latest, 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 = AssetHubRococo::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &sender) + }); + let receiver_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(native_asset_location.into(), &receiver) + }); + let receiver_wnds_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &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 = AssetHubRococo::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &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); +} + +// ============================================================================== +// ===== 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 reserve_transfer_native_asset_from_para_to_para_through_asset_hub() { +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 = ROCOCO_ED * 10000; - let penpal_roc_owner = PenpalAssetOwner::get(); + let assets_owner = PenpalAssetOwner::get(); let roc_location = v3::Location::try_from(RelayLocation::get()).unwrap(); let roc_location_latest: Location = roc_location.try_into().unwrap(); let sender_as_seen_by_ah = AssetHubRococo::sibling_location_of(PenpalA::para_id()); @@ -101,24 +237,23 @@ fn reserve_transfer_native_asset_from_para_to_para_through_asset_hub() { let wnd_at_rococo_parachains = v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Westend)]); let wnd_at_rococo_parachains_latest: Location = wnd_at_rococo_parachains.try_into().unwrap(); - let owner = AssetHubRococo::account_id_of(emulated_integration_tests_common::accounts::ALICE); AssetHubRococo::force_create_foreign_asset( wnd_at_rococo_parachains, - owner.clone(), + assets_owner.clone(), false, ASSET_MIN_BALANCE, vec![], ); PenpalA::force_create_foreign_asset( wnd_at_rococo_parachains, - owner.clone(), + assets_owner.clone(), false, ASSET_MIN_BALANCE, vec![], ); PenpalB::force_create_foreign_asset( wnd_at_rococo_parachains, - owner.clone(), + assets_owner.clone(), false, ASSET_MIN_BALANCE, vec![], @@ -126,13 +261,13 @@ fn reserve_transfer_native_asset_from_para_to_para_through_asset_hub() { // fund Parachain's sender account PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(penpal_roc_owner), + ::RuntimeOrigin::signed(assets_owner.clone()), roc_location, sender.clone(), roc_to_send * 2, ); PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(owner.clone()), + ::RuntimeOrigin::signed(assets_owner.clone()), wnd_at_rococo_parachains, sender.clone(), wnd_to_send * 2, @@ -140,7 +275,7 @@ fn reserve_transfer_native_asset_from_para_to_para_through_asset_hub() { // fund the Parachain Origin's SA on Asset Hub with the assets held in reserve AssetHubRococo::fund_accounts(vec![(sov_of_sender_on_ah.clone().into(), roc_to_send * 2)]); AssetHubRococo::mint_foreign_asset( - ::RuntimeOrigin::signed(owner.clone()), + ::RuntimeOrigin::signed(assets_owner), wnd_at_rococo_parachains, sov_of_sender_on_ah.clone(), wnd_to_send * 2, diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index d5926a0592c8..024488c928bd 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -55,27 +55,49 @@ fn para_to_relay_sender_assertions(t: ParaToRelayTest) { ); } -fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { +pub fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; - AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 864_610_000, - 8_799, - ))); + AssetHubRococo::assert_xcm_pallet_attempted_complete(None); + let sov_acc_of_dest = AssetHubRococo::sovereign_account_id_of(t.args.dest.clone()); + for (idx, asset) in t.args.assets.into_inner().into_iter().enumerate() { + let expected_id = asset.id.0.clone().try_into().unwrap(); + let asset_amount = if let Fungible(a) = asset.fun { Some(a) } else { None }.unwrap(); + if idx == t.args.fee_asset_item as usize { + assert_expected_events!( + AssetHubRococo, + vec![ + // Amount of native asset is transferred to Parachain's Sovereign account + RuntimeEvent::Balances( + pallet_balances::Event::Transfer { from, to, amount } + ) => { + from: *from == t.sender.account_id, + to: *to == sov_acc_of_dest, + amount: *amount == asset_amount, + }, + ] + ); + } else { + assert_expected_events!( + AssetHubRococo, + vec![ + // Amount of foreign asset is transferred to Parachain's Sovereign account + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Transferred { asset_id, from, to, amount }, + ) => { + asset_id: *asset_id == expected_id, + from: *from == t.sender.account_id, + to: *to == sov_acc_of_dest, + amount: *amount == asset_amount, + }, + ] + ); + } + } assert_expected_events!( AssetHubRococo, vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Transfer { from, to, amount } - ) => { - from: *from == t.sender.account_id, - to: *to == AssetHubRococo::sovereign_account_id_of( - t.args.dest.clone() - ), - amount: *amount == t.args.amount, - }, // Transport fees are paid RuntimeEvent::PolkadotXcm( pallet_xcm::Event::FeesPaid { .. } @@ -85,21 +107,22 @@ fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { AssetHubRococo::assert_xcm_pallet_sent(); } -fn system_para_to_para_receiver_assertions(t: SystemParaToParaTest) { +pub fn system_para_to_para_receiver_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; - let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); PenpalA::assert_xcmp_queue_success(None); - - assert_expected_events!( - PenpalA, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == system_para_native_asset_location, - owner: *owner == t.receiver.account_id, - }, - ] - ); + 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 para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { From 1c86e6ee7edb6f0ba8becce5198bfafa072a1dbc Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 4 Apr 2024 17:45:20 +0300 Subject: [PATCH 20/30] another test --- .../src/tests/foreign_assets_transfers.rs | 165 ++++++++++++++++++ .../src/tests/reserve_transfer.rs | 92 +++++++--- 2 files changed, 229 insertions(+), 28 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs index bbfca67a3558..32895c7cf446 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs @@ -63,6 +63,21 @@ fn ah_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { ) } +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(); + ::PolkadotXcm::transfer_assets_using_reserve( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + bx!(TransferType::DestinationReserve), + bx!(fee.into()), + bx!(TransferType::DestinationReserve), + 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(); @@ -202,6 +217,156 @@ fn transfer_foreign_assets_from_asset_hub_to_para() { 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(AssetHubRococo::para_id()); + let sender = PenpalASender::get(); + let native_amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 10000; + let native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); + let assets_owner = PenpalAssetOwner::get(); + + // Foreign asset used: bridged WND + let foreign_amount_to_send = ASSET_HUB_ROCOCO_ED * 10_000_000; + let wnd_at_rococo_parachains = + v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Westend)]); + let wnd_at_rococo_parachains_latest: Location = wnd_at_rococo_parachains.try_into().unwrap(); + + // Configure destination chain to trust AH as reserve of WND + PenpalA::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + penpal_runtime::xcm_config::CustomizableAssetFromSystemAssetHub::key().to_vec(), + Location::new(2, [GlobalConsensus(Westend)]).encode(), + )], + )); + }); + PenpalA::force_create_foreign_asset( + wnd_at_rococo_parachains, + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + AssetHubRococo::force_create_foreign_asset( + wnd_at_rococo_parachains, + 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, + sender.clone(), + native_amount_to_send * 2, + ); + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner.clone()), + wnd_at_rococo_parachains, + sender.clone(), + foreign_amount_to_send * 2, + ); + + // Init values for System Parachain + let receiver = AssetHubRococoReceiver::get(); + let penpal_location_as_seen_by_ahr = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location_as_seen_by_ahr); + + // fund Parachain's SA on AssetHub with the assets held in reserve + AssetHubRococo::fund_accounts(vec![( + sov_penpal_on_ahr.clone().into(), + native_amount_to_send * 2, + )]); + AssetHubRococo::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner), + wnd_at_rococo_parachains, + 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_latest, 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, &sender) + }); + let sender_wnds_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &sender) + }); + let receiver_native_before = test.receiver.balance; + let receiver_wnds_before = AssetHubRococo::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &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, &sender) + }); + let receiver_native_after = test.receiver.balance; + let receiver_wnds_after = AssetHubRococo::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_at_rococo_parachains, &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 ==== // ============================================================================== diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index 024488c928bd..d10bc810dfb5 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -125,22 +125,26 @@ pub fn system_para_to_para_receiver_assertions(t: SystemParaToParaTest) { } } -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::ForeignAssets( - pallet_assets::Event::Burned { asset_id, owner, balance, .. } - ) => { - asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).unwrap(), - owner: *owner == t.sender.account_id, - balance: *balance == 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.try_into().unwrap(); + 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_relay_receiver_assertions(t: ParaToRelayTest) { @@ -172,25 +176,57 @@ fn para_to_relay_receiver_assertions(t: ParaToRelayTest) { ); } -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_ahr = AssetHubRococo::sovereign_account_id_of( - AssetHubRococo::sibling_location_of(PenpalA::para_id()), - ); - AssetHubRococo::assert_xcmp_queue_success(None); + let sov_acc_of_penpal = AssetHubRococo::sovereign_account_id_of(t.args.dest.clone()); + for (idx, asset) in t.args.assets.into_inner().into_iter().enumerate() { + let expected_id = asset.id.0.clone().try_into().unwrap(); + let asset_amount = if let Fungible(a) = asset.fun { Some(a) } else { None }.unwrap(); + if idx == t.args.fee_asset_item as usize { + assert_expected_events!( + AssetHubRococo, + vec![ + // Amount of native is withdrawn from Parachain's Sovereign account + RuntimeEvent::Balances( + pallet_balances::Event::Burned { who, amount } + ) => { + who: *who == sov_acc_of_penpal.clone().into(), + amount: *amount == asset_amount, + }, + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { + who: *who == t.receiver.account_id, + }, + ] + ); + } else { + assert_expected_events!( + AssetHubRococo, + vec![ + // Amount of foreign asset is transferred from Parachain's Sovereign account + // to Receiver's account + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, balance }, + ) => { + asset_id: *asset_id == expected_id, + owner: *owner == sov_acc_of_penpal, + balance: *balance == asset_amount, + }, + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Issued { asset_id, owner, amount }, + ) => { + asset_id: *asset_id == expected_id, + owner: *owner == t.receiver.account_id, + amount: *amount == asset_amount, + }, + ] + ); + } + } assert_expected_events!( AssetHubRococo, vec![ - // Amount to reserve transfer is withdrawn from Parachain's Sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } - ) => { - who: *who == sov_penpal_on_ahr.clone().into(), - amount: *amount == t.args.amount, - }, - RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, RuntimeEvent::MessageQueue( pallet_message_queue::Event::Processed { success: true, .. } ) => {}, From b82d0b90ec9e21ac5deac89a6be298a1bef58e0b Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 4 Apr 2024 18:25:39 +0300 Subject: [PATCH 21/30] add teleport test as well --- .../src/tests/foreign_assets_transfers.rs | 48 ++++++++++++++++++- .../src/tests/reserve_transfer.rs | 6 +-- .../asset-hub-rococo/src/tests/teleport.rs | 24 +++++++--- 3 files changed, 68 insertions(+), 10 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs index 32895c7cf446..67d08df9db36 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs @@ -14,7 +14,10 @@ // limitations under the License. use super::reserve_transfer::*; -use crate::imports::*; +use crate::{ + imports::*, + tests::teleport::do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt, +}; fn para_to_para_assethub_hop_assertions(t: ParaToParaThroughAHTest) { type RuntimeEvent = ::RuntimeEvent; @@ -94,6 +97,36 @@ fn para_to_para_transfer_assets_through_ah(t: ParaToParaThroughAHTest) -> Dispat ) } +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(); + ::PolkadotXcm::transfer_assets_using_reserve( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + bx!(TransferType::Teleport), + bx!(fee.into()), + bx!(TransferType::DestinationReserve), + 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(); + ::PolkadotXcm::transfer_assets_using_reserve( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + bx!(TransferType::Teleport), + bx!(fee.into()), + bx!(TransferType::LocalReserve), + t.args.weight_limit, + ) +} + // =========================================================================== // ======= Transfer - Native + Bridged Assets - AssetHub->Parachain ========== // =========================================================================== @@ -560,3 +593,16 @@ fn transfer_foreign_assets_from_para_to_para_through_asset_hub() { 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, + ); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index d10bc810dfb5..77e009e9652a 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -827,9 +827,9 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { assert!(receiver_balance_after < receiver_balance_before + amount_to_send); } -// ========================================================================= -// ======= Reserve Transfers - Non-system Asset - AssetHub<>Parachain ====== -// ========================================================================= +// ================================================================================== +// ======= Reserve Transfers - Native + Non-system Asset - AssetHub<>Parachain ====== +// ================================================================================== /// Reserve Transfers of a local asset and native asset from System Parachain to Parachain should /// work #[test] diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs index 5bda6a8a2af6..dbfd7c50f61a 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs @@ -412,10 +412,12 @@ 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() { +/// 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_ROCOCO_ED * 10000; let asset_location_on_penpal = @@ -512,7 +514,7 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { 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 = PenpalA::execute_with(|| { @@ -619,7 +621,7 @@ 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; @@ -657,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, + ); +} From f4e88daec2901d3dc1177f21b95f44331853f602 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 4 Apr 2024 19:04:00 +0300 Subject: [PATCH 22/30] rename xt and update docs --- .../src/tests/foreign_assets_transfers.rs | 10 ++--- .../src/tests/asset_transfers.rs | 2 +- .../src/tests/asset_transfers.rs | 5 ++- .../src/weights/pallet_xcm.rs | 2 +- .../src/weights/pallet_xcm.rs | 2 +- .../src/weights/pallet_xcm.rs | 2 +- .../src/weights/pallet_xcm.rs | 2 +- .../src/weights/pallet_xcm.rs | 2 +- .../coretime-rococo/src/weights/pallet_xcm.rs | 2 +- .../src/weights/pallet_xcm.rs | 2 +- .../people-rococo/src/weights/pallet_xcm.rs | 2 +- .../people-westend/src/weights/pallet_xcm.rs | 2 +- .../runtime/rococo/src/weights/pallet_xcm.rs | 2 +- .../runtime/westend/src/weights/pallet_xcm.rs | 2 +- polkadot/xcm/pallet-xcm/src/lib.rs | 37 +++++++++++-------- prdoc/pr_3695.prdoc | 18 +++++++-- 16 files changed, 56 insertions(+), 38 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs index 67d08df9db36..86090e89cea9 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs @@ -54,7 +54,7 @@ fn para_to_para_assethub_hop_assertions(t: ParaToParaThroughAHTest) { 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(); - ::PolkadotXcm::transfer_assets_using_reserve( + ::PolkadotXcm::transfer_assets_using_type( t.signed_origin, bx!(t.args.dest.into()), bx!(t.args.beneficiary.into()), @@ -69,7 +69,7 @@ fn ah_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { 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(); - ::PolkadotXcm::transfer_assets_using_reserve( + ::PolkadotXcm::transfer_assets_using_type( t.signed_origin, bx!(t.args.dest.into()), bx!(t.args.beneficiary.into()), @@ -85,7 +85,7 @@ fn para_to_para_transfer_assets_through_ah(t: ParaToParaThroughAHTest) -> Dispat 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(AssetHubRococo::para_id()); - ::PolkadotXcm::transfer_assets_using_reserve( + ::PolkadotXcm::transfer_assets_using_type( t.signed_origin, bx!(t.args.dest.into()), bx!(t.args.beneficiary.into()), @@ -100,7 +100,7 @@ fn para_to_para_transfer_assets_through_ah(t: ParaToParaThroughAHTest) -> Dispat 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(); - ::PolkadotXcm::transfer_assets_using_reserve( + ::PolkadotXcm::transfer_assets_using_type( t.signed_origin, bx!(t.args.dest.into()), bx!(t.args.beneficiary.into()), @@ -115,7 +115,7 @@ fn para_to_asset_hub_teleport_foreign_assets(t: ParaToSystemParaTest) -> Dispatc 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(); - ::PolkadotXcm::transfer_assets_using_reserve( + ::PolkadotXcm::transfer_assets_using_type( t.signed_origin, bx!(t.args.dest.into()), bx!(t.args.beneficiary.into()), diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs index 499adce1f2d2..ad920feaadb2 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs @@ -62,7 +62,7 @@ fn send_asset_from_penpal_rococo_through_local_asset_hub_to_westend_asset_hub( let fees: Asset = (id.clone(), transfer_amount).into(); let assets: Assets = vec![fees.clone()].into(); - ::PolkadotXcm::transfer_assets_using_reserve( + ::PolkadotXcm::transfer_assets_using_type( signed_origin, bx!(destination.into()), bx!(beneficiary.into()), diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs index 514c763d9816..930604784e06 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs @@ -60,13 +60,14 @@ fn send_asset_from_penpal_westend_through_local_asset_hub_to_rococo_asset_hub( let fees: Asset = (id, transfer_amount).into(); let assets: Assets = fees.clone().into(); - ::PolkadotXcm::transfer_assets_using_reserve( + ::PolkadotXcm::transfer_assets_using_type( signed_origin, bx!(destination.into()), bx!(beneficiary.into()), bx!(assets.into()), + bx!(TransferType::RemoteReserve(local_asset_hub.clone().into())), bx!(fees.into()), - bx!(local_asset_hub.into()), + bx!(TransferType::RemoteReserve(local_asset_hub.into())), WeightLimit::Unlimited, ) })); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs index c910b1f59b47..e7c890d67e84 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs @@ -48,7 +48,7 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets_using_reserve() -> Weight { + fn transfer_assets_using_type() -> Weight { // TODO: benchmark Weight::from_parts(0, 0) } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs index 0023c1b560d0..9cb92e267f96 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs @@ -48,7 +48,7 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets_using_reserve() -> Weight { + fn transfer_assets_using_type() -> Weight { // TODO: benchmark Weight::from_parts(0, 0) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs index 062ba4e0bd4b..2d68bd9600ae 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs @@ -48,7 +48,7 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets_using_reserve() -> Weight { + fn transfer_assets_using_type() -> Weight { // TODO: benchmark Weight::from_parts(0, 0) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs index a5901d12209e..207a95e9a7dc 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs @@ -48,7 +48,7 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets_using_reserve() -> Weight { + fn transfer_assets_using_type() -> Weight { // TODO: benchmark Weight::from_parts(0, 0) } diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs index 19aa3d3c4b55..579a3300b5e6 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs @@ -48,7 +48,7 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets_using_reserve() -> Weight { + fn transfer_assets_using_type() -> Weight { // TODO: benchmark Weight::from_parts(0, 0) } diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs index cf859ff6f9f9..6f4cda2a9083 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs @@ -48,7 +48,7 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets_using_reserve() -> Weight { + fn transfer_assets_using_type() -> Weight { // TODO: benchmark Weight::from_parts(0, 0) } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs index 826845903c2e..2e717a633d7e 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs @@ -48,7 +48,7 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets_using_reserve() -> Weight { + fn transfer_assets_using_type() -> Weight { // TODO: benchmark Weight::from_parts(0, 0) } diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs index d1bb56557aca..fb27155b2e60 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs @@ -48,7 +48,7 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets_using_reserve() -> Weight { + fn transfer_assets_using_type() -> Weight { // TODO: benchmark Weight::from_parts(0, 0) } diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs index bb53c8bee303..1dc997b8510f 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs @@ -48,7 +48,7 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets_using_reserve() -> Weight { + fn transfer_assets_using_type() -> Weight { // TODO: benchmark Weight::from_parts(0, 0) } diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs index 245224db3f90..afdb748738fe 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs @@ -372,7 +372,7 @@ impl pallet_xcm::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - fn transfer_assets_using_reserve() -> Weight { + fn transfer_assets_using_type() -> Weight { // TODO: benchmark Weight::from_parts(0, 0) } diff --git a/polkadot/runtime/westend/src/weights/pallet_xcm.rs b/polkadot/runtime/westend/src/weights/pallet_xcm.rs index 41590773f9ed..8d741ae2b93a 100644 --- a/polkadot/runtime/westend/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/westend/src/weights/pallet_xcm.rs @@ -48,7 +48,7 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets_using_reserve() -> Weight { + fn transfer_assets_using_type() -> Weight { // TODO: benchmark Weight::from_parts(0, 0) } diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index a68812008453..e5e54c86b65f 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -89,7 +89,7 @@ pub trait WeightInfo { fn claim_assets() -> Weight; fn execute_blob() -> Weight; fn send_blob() -> Weight; - fn transfer_assets_using_reserve() -> Weight; + fn transfer_assets_using_type() -> Weight; } /// fallback implementation @@ -183,7 +183,7 @@ impl WeightInfo for TestWeightInfo { Weight::from_parts(100_000_000, 0) } - fn transfer_assets_using_reserve() -> Weight { + fn transfer_assets_using_type() -> Weight { Weight::from_parts(100_000_000, 0) } } @@ -1406,26 +1406,32 @@ pub mod pallet { Ok(()) } - /// Transfer some assets from the local chain to the destination chain through using an - /// explicit reserve location (typically local Asset Hub). + /// Transfer assets from the local chain to the destination chain using explicit transfer + /// types for assets and fees. /// - /// `assets` must have same reserve location and may not be teleportable to `dest`, - /// but may be teleportable to their `force_reserve` location. - /// - `assets` have local reserve: transfer assets to sovereign account of destination + /// `assets` must have same reserve location or may be teleportable to `dest`. Caller must + /// provide the `assets_transfer_type` to be used for `assets`: + /// - `TransferType::LocalReserve`: transfer assets to sovereign account of destination /// chain and forward a notification XCM to `dest` to mint and deposit reserve-based /// assets to `beneficiary`. - /// - `assets` have destination reserve: burn local assets and forward a notification to + /// - `TransferType::DestinationReserve`: burn local assets and forward a notification to /// `dest` chain to withdraw the reserve assets from this chain's sovereign account and /// deposit them to `beneficiary`. - /// - `assets` have remote reserve: burn local assets, forward XCM to reserve chain to move - /// reserves from this chain's SA to `dest` chain's SA, and forward another XCM to `dest` - /// to mint and deposit reserve-based assets to `beneficiary`. + /// - `TransferType::RemoteReserve(reserve)`: burn local assets, forward XCM to `reserve` + /// chain to move reserves from this chain's SA to `dest` chain's SA, and forward another + /// XCM to `dest` to mint and deposit reserve-based assets to `beneficiary`. Typically + /// the remote `reserve` is Asset Hub. + /// - `TransferType::Teleport`: burn local assets and forward XCM to `dest` chain to + /// mint/teleport assets and deposit them to `beneficiary`. /// /// Fee payment on the source, destination and all intermediary hops, is specified through /// `fees`, but make sure enough of the specified `fees` asset is included in the given list /// of `assets`. `fees` should be enough to pay for `weight_limit`. If more weight is needed /// than `weight_limit`, then the operation will fail and the sent assets may be at risk. /// + /// `fees` may use different transfer type than rest of `assets` and can be specified + /// through `fees_transfer_type`. + /// /// - `origin`: Must be capable of withdrawing the `assets` and executing XCM. /// - `dest`: Destination context for the assets. Will typically be `[Parent, /// Parachain(..)]` to send from parachain to parachain, or `[Parachain(..)]` to send from @@ -1435,13 +1441,12 @@ pub mod pallet { /// generally be an `AccountId32` value. /// - `assets`: The assets to be withdrawn. This should include the assets used to pay the /// fee on the `dest` (and possibly reserve) chains. + /// - `assets_transfer_type`: The XCM `TransferType` used to transfer the `assets`. /// - `fees`: One of the included `assets` to be be used to pay fees. - /// - `using_reserve`: Forces this transfer to use `using_reserve` location as the reserve - /// location for `assets`. Will typically be `None`, or `Some(LocalAssetHubLocation)` for - /// transferring ForeignAssets going through Asset Hub. + /// - `fees_transfer_type`: The XCM `TransferType` used to transfer the `fees` assets. /// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase. #[pallet::call_index(15)] - pub fn transfer_assets_using_reserve( + pub fn transfer_assets_using_type( origin: OriginFor, dest: Box, beneficiary: Box, @@ -1458,7 +1463,7 @@ pub mod pallet { let assets: Assets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; let fees: Asset = (*fees).try_into().map_err(|()| Error::::BadVersion)?; log::debug!( - target: "xcm::pallet_xcm::transfer_assets_using_reserve", + target: "xcm::pallet_xcm::transfer_assets_using_type", "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?} through {:?}, fees {:?} through {:?}", origin_location, dest, beneficiary, assets, assets_transfer_type, fees, fees_transfer_type, ); diff --git a/prdoc/pr_3695.prdoc b/prdoc/pr_3695.prdoc index c592e02d0146..2c2c2b2e6917 100644 --- a/prdoc/pr_3695.prdoc +++ b/prdoc/pr_3695.prdoc @@ -6,9 +6,21 @@ title: "pallet-xcm: add new extrinsic for asset transfers using explicit reserve doc: - audience: Runtime User description: | - pallet-xcm has a new extrinsic `transfer_assets_using_reserve` for transferring - assets from local chain to destination chain using an explicit reserve location - (typically the local Asset Hub). + pallet-xcm has a new extrinsic `transfer_assets_using_type` for transferring + assets from local chain to destination chain using an explicit XCM transfer + types for transferring the assets and the fees: + - `TransferType::LocalReserve`: transfer assets to sovereign account of destination + chain and forward a notification XCM to `dest` to mint and deposit reserve-based + assets to `beneficiary`. + - `TransferType::DestinationReserve`: burn local assets and forward a notification to + `dest` chain to withdraw the reserve assets from this chain's sovereign account and + deposit them to `beneficiary`. + - `TransferType::RemoteReserve(reserve)`: burn local assets, forward XCM to `reserve` + chain to move reserves from this chain's SA to `dest` chain's SA, and forward another + XCM to `dest` to mint and deposit reserve-based assets to `beneficiary`. Typically + the remote `reserve` is Asset Hub. + - `TransferType::Teleport`: burn local assets and forward XCM to `dest` chain to + mint/teleport assets and deposit them to `beneficiary`. By default, an asset's reserve is its origin chain. But sometimes we may want to explicitly use another chain as reserve (as long as allowed by runtime IsReserve filter). From 4f2381cad72e8b64482f7c79a23a4f4064eeaf47 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 4 Apr 2024 19:17:23 +0300 Subject: [PATCH 23/30] fix weights --- .../assets/asset-hub-rococo/src/weights/pallet_xcm.rs | 4 ---- .../assets/asset-hub-westend/src/weights/pallet_xcm.rs | 4 ---- .../bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs | 4 ---- .../bridge-hub-westend/src/weights/pallet_xcm.rs | 4 ---- .../collectives-westend/src/weights/pallet_xcm.rs | 4 ---- .../coretime/coretime-rococo/src/weights/pallet_xcm.rs | 4 ---- .../coretime/coretime-westend/src/weights/pallet_xcm.rs | 4 ---- .../runtimes/people/people-rococo/src/weights/pallet_xcm.rs | 4 ---- .../people/people-westend/src/weights/pallet_xcm.rs | 4 ---- polkadot/runtime/rococo/src/weights/pallet_xcm.rs | 4 ---- polkadot/runtime/westend/src/weights/pallet_xcm.rs | 4 ---- polkadot/xcm/pallet-xcm/src/lib.rs | 6 +----- 12 files changed, 1 insertion(+), 49 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs index e7c890d67e84..e0e231d7da27 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs @@ -48,10 +48,6 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets_using_type() -> Weight { - // TODO: benchmark - Weight::from_parts(0, 0) - } /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs index 9cb92e267f96..a36c25f96043 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs @@ -48,10 +48,6 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets_using_type() -> Weight { - // TODO: benchmark - Weight::from_parts(0, 0) - } /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs index 2d68bd9600ae..adfaa9ea2028 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs @@ -48,10 +48,6 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets_using_type() -> Weight { - // TODO: benchmark - Weight::from_parts(0, 0) - } /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs index 207a95e9a7dc..9cf4c61466a1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs @@ -48,10 +48,6 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets_using_type() -> Weight { - // TODO: benchmark - Weight::from_parts(0, 0) - } /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs index 579a3300b5e6..0edd5dfff2b8 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs @@ -48,10 +48,6 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets_using_type() -> Weight { - // TODO: benchmark - Weight::from_parts(0, 0) - } /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs index 6f4cda2a9083..df0044089c8f 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs @@ -48,10 +48,6 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets_using_type() -> Weight { - // TODO: benchmark - Weight::from_parts(0, 0) - } /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs index 2e717a633d7e..a1701c5f1c2c 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs @@ -48,10 +48,6 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets_using_type() -> Weight { - // TODO: benchmark - Weight::from_parts(0, 0) - } /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs index fb27155b2e60..ac494fdc719f 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs @@ -48,10 +48,6 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets_using_type() -> Weight { - // TODO: benchmark - Weight::from_parts(0, 0) - } /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs index 1dc997b8510f..62a9c802808c 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs @@ -48,10 +48,6 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets_using_type() -> Weight { - // TODO: benchmark - Weight::from_parts(0, 0) - } /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs index afdb748738fe..42972baa1c83 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs @@ -372,8 +372,4 @@ impl pallet_xcm::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - fn transfer_assets_using_type() -> Weight { - // TODO: benchmark - Weight::from_parts(0, 0) - } } diff --git a/polkadot/runtime/westend/src/weights/pallet_xcm.rs b/polkadot/runtime/westend/src/weights/pallet_xcm.rs index 8d741ae2b93a..80bc551ba1e2 100644 --- a/polkadot/runtime/westend/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/westend/src/weights/pallet_xcm.rs @@ -48,10 +48,6 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { - fn transfer_assets_using_type() -> Weight { - // TODO: benchmark - Weight::from_parts(0, 0) - } /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index e5e54c86b65f..353833cc296d 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -89,7 +89,6 @@ pub trait WeightInfo { fn claim_assets() -> Weight; fn execute_blob() -> Weight; fn send_blob() -> Weight; - fn transfer_assets_using_type() -> Weight; } /// fallback implementation @@ -182,10 +181,6 @@ impl WeightInfo for TestWeightInfo { fn send_blob() -> Weight { Weight::from_parts(100_000_000, 0) } - - fn transfer_assets_using_type() -> Weight { - Weight::from_parts(100_000_000, 0) - } } #[frame_support::pallet] @@ -1446,6 +1441,7 @@ pub mod pallet { /// - `fees_transfer_type`: The XCM `TransferType` used to transfer the `fees` assets. /// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase. #[pallet::call_index(15)] + #[pallet::weight(T::WeightInfo::transfer_assets())] pub fn transfer_assets_using_type( origin: OriginFor, dest: Box, From 36af01f31dde138bc8feb24c44c8799d01cb1f84 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 4 Apr 2024 20:03:04 +0300 Subject: [PATCH 24/30] add tests to westend --- .../src/tests/reserve_transfer.rs | 7 +- .../tests/assets/asset-hub-westend/src/lib.rs | 2 + .../src/tests/foreign_assets_transfers.rs | 609 ++++++++++++++++++ .../assets/asset-hub-westend/src/tests/mod.rs | 1 + .../src/tests/reserve_transfer.rs | 242 ++++--- .../asset-hub-westend/src/tests/teleport.rs | 24 +- .../bridges/bridge-hub-rococo/src/lib.rs | 1 + .../src/tests/asset_transfers.rs | 7 +- .../bridges/bridge-hub-westend/src/lib.rs | 1 + .../src/tests/asset_transfers.rs | 49 +- 10 files changed, 787 insertions(+), 156 deletions(-) create mode 100644 cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/foreign_assets_transfers.rs diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index 77e009e9652a..2a341c2e5159 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -57,7 +57,6 @@ fn para_to_relay_sender_assertions(t: ParaToRelayTest) { pub fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; - AssetHubRococo::assert_xcm_pallet_attempted_complete(None); let sov_acc_of_dest = AssetHubRococo::sovereign_account_id_of(t.args.dest.clone()); @@ -99,9 +98,7 @@ pub fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { AssetHubRococo, vec![ // Transport fees are paid - RuntimeEvent::PolkadotXcm( - pallet_xcm::Event::FeesPaid { .. } - ) => {}, + RuntimeEvent::PolkadotXcm(pallet_xcm::Event::FeesPaid { .. }) => {}, ] ); AssetHubRococo::assert_xcm_pallet_sent(); @@ -109,7 +106,6 @@ pub fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { pub fn system_para_to_para_receiver_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; - 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(); @@ -127,7 +123,6 @@ pub fn system_para_to_para_receiver_assertions(t: SystemParaToParaTest) { pub fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; - PenpalA::assert_xcm_pallet_attempted_complete(None); for asset in t.args.assets.into_inner().into_iter() { let expected_id = asset.id.0.try_into().unwrap(); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs index c9f5fe0647e1..e687251c14f9 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs @@ -30,6 +30,7 @@ mod imports { prelude::{AccountId32 as AccountId32Junction, *}, v3, }; + pub use xcm_executor::traits::TransferType; // Cumulus pub use asset_test_utils::xcm_helpers; @@ -85,6 +86,7 @@ mod imports { pub type SystemParaToParaTest = Test; pub type ParaToSystemParaTest = Test; pub type ParaToParaThroughRelayTest = Test; + pub type ParaToParaThroughAHTest = Test; } #[cfg(test)] diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/foreign_assets_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/foreign_assets_transfers.rs new file mode 100644 index 000000000000..f463f28cda35 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/foreign_assets_transfers.rs @@ -0,0 +1,609 @@ +// 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::{ + imports::*, + tests::teleport::do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt, +}; + +fn para_to_para_assethub_hop_assertions(t: ParaToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + let sov_penpal_a_on_ah = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalA::para_id()), + ); + let sov_penpal_b_on_ah = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalB::para_id()), + ); + + assert_expected_events!( + AssetHubWestend, + 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(); + ::PolkadotXcm::transfer_assets_using_type( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + bx!(TransferType::LocalReserve), + bx!(fee.into()), + bx!(TransferType::LocalReserve), + 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(); + ::PolkadotXcm::transfer_assets_using_type( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + bx!(TransferType::DestinationReserve), + bx!(fee.into()), + bx!(TransferType::DestinationReserve), + 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(AssetHubWestend::para_id()); + ::PolkadotXcm::transfer_assets_using_type( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), + bx!(fee.into()), + bx!(TransferType::RemoteReserve(asset_hub_location.into())), + 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(); + ::PolkadotXcm::transfer_assets_using_type( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + bx!(TransferType::Teleport), + bx!(fee.into()), + bx!(TransferType::DestinationReserve), + 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(); + ::PolkadotXcm::transfer_assets_using_type( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + bx!(TransferType::Teleport), + bx!(fee.into()), + bx!(TransferType::LocalReserve), + 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 = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let sender = AssetHubWestendSender::get(); + let native_amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; + let native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); + let receiver = PenpalAReceiver::get(); + let assets_owner = PenpalAssetOwner::get(); + // Foreign asset used: bridged ROC + let foreign_amount_to_send = ASSET_HUB_WESTEND_ED * 10_000_000; + let roc_at_westend_parachains = + v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Rococo)]); + let roc_at_westend_parachains_latest: Location = roc_at_westend_parachains.try_into().unwrap(); + + // Configure destination chain to trust AH as reserve of ROC + PenpalA::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + penpal_runtime::xcm_config::CustomizableAssetFromSystemAssetHub::key().to_vec(), + Location::new(2, [GlobalConsensus(Rococo)]).encode(), + )], + )); + }); + PenpalA::force_create_foreign_asset( + roc_at_westend_parachains, + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + AssetHubWestend::force_create_foreign_asset( + roc_at_westend_parachains, + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + AssetHubWestend::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner), + roc_at_westend_parachains, + sender.clone(), + foreign_amount_to_send * 2, + ); + + // Assets to send + let assets: Vec = vec![ + (Parent, native_amount_to_send).into(), + (roc_at_westend_parachains_latest, 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_rocs_before = AssetHubWestend::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_at_westend_parachains, &sender) + }); + let receiver_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(native_asset_location.into(), &receiver) + }); + let receiver_rocs_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_at_westend_parachains, &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_rocs_after = AssetHubWestend::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_at_westend_parachains, &sender) + }); + let receiver_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(native_asset_location, &receiver) + }); + let receiver_rocs_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_at_westend_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_rocs_after, sender_rocs_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_rocs_after, receiver_rocs_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(AssetHubWestend::para_id()); + let sender = PenpalASender::get(); + let native_amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 10000; + let native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); + let assets_owner = PenpalAssetOwner::get(); + + // Foreign asset used: bridged ROC + let foreign_amount_to_send = ASSET_HUB_WESTEND_ED * 10_000_000; + let roc_at_westend_parachains = + v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Rococo)]); + let roc_at_westend_parachains_latest: Location = roc_at_westend_parachains.try_into().unwrap(); + + // Configure destination chain to trust AH as reserve of ROC + PenpalA::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + penpal_runtime::xcm_config::CustomizableAssetFromSystemAssetHub::key().to_vec(), + Location::new(2, [GlobalConsensus(Rococo)]).encode(), + )], + )); + }); + PenpalA::force_create_foreign_asset( + roc_at_westend_parachains, + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + AssetHubWestend::force_create_foreign_asset( + roc_at_westend_parachains, + 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, + sender.clone(), + native_amount_to_send * 2, + ); + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner.clone()), + roc_at_westend_parachains, + sender.clone(), + foreign_amount_to_send * 2, + ); + + // Init values for System Parachain + let receiver = AssetHubWestendReceiver::get(); + let penpal_location_as_seen_by_ahr = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ahr = + AssetHubWestend::sovereign_account_id_of(penpal_location_as_seen_by_ahr); + + // fund Parachain's SA on AssetHub with the assets held in reserve + AssetHubWestend::fund_accounts(vec![( + sov_penpal_on_ahr.clone().into(), + native_amount_to_send * 2, + )]); + AssetHubWestend::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner), + roc_at_westend_parachains, + sov_penpal_on_ahr, + foreign_amount_to_send * 2, + ); + + // Assets to send + let assets: Vec = vec![ + (Parent, native_amount_to_send).into(), + (roc_at_westend_parachains_latest, 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, &sender) + }); + let sender_rocs_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_at_westend_parachains, &sender) + }); + let receiver_native_before = test.receiver.balance; + let receiver_rocs_before = AssetHubWestend::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_at_westend_parachains, &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_rocs_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_at_westend_parachains, &sender) + }); + let receiver_native_after = test.receiver.balance; + let receiver_rocs_after = AssetHubWestend::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_at_westend_parachains, &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_rocs_after, sender_rocs_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_rocs_after, receiver_rocs_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 wnd_to_send: Balance = WESTEND_ED * 10000; + let assets_owner = PenpalAssetOwner::get(); + let wnd_location = v3::Location::try_from(RelayLocation::get()).unwrap(); + let wnd_location_latest: Location = wnd_location.try_into().unwrap(); + let sender_as_seen_by_ah = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let sov_of_sender_on_ah = AssetHubWestend::sovereign_account_id_of(sender_as_seen_by_ah); + let receiver_as_seen_by_ah = AssetHubWestend::sibling_location_of(PenpalB::para_id()); + let sov_of_receiver_on_ah = AssetHubWestend::sovereign_account_id_of(receiver_as_seen_by_ah); + let roc_to_send = ASSET_HUB_WESTEND_ED * 10_000_000; + + // Configure destination chain to trust AH as reserve of ROC + PenpalB::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + penpal_runtime::xcm_config::CustomizableAssetFromSystemAssetHub::key().to_vec(), + Location::new(2, [GlobalConsensus(Rococo)]).encode(), + )], + )); + }); + + // Register ROC as foreign asset and transfer it around the Westend ecosystem + let roc_at_westend_parachains = + v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Rococo)]); + let roc_at_westend_parachains_latest: Location = roc_at_westend_parachains.try_into().unwrap(); + AssetHubWestend::force_create_foreign_asset( + roc_at_westend_parachains, + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + PenpalA::force_create_foreign_asset( + roc_at_westend_parachains, + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + PenpalB::force_create_foreign_asset( + roc_at_westend_parachains, + assets_owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner.clone()), + wnd_location, + sender.clone(), + wnd_to_send * 2, + ); + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner.clone()), + roc_at_westend_parachains, + sender.clone(), + roc_to_send * 2, + ); + // fund the Parachain Origin's SA on Asset Hub with the assets held in reserve + AssetHubWestend::fund_accounts(vec![(sov_of_sender_on_ah.clone().into(), wnd_to_send * 2)]); + AssetHubWestend::mint_foreign_asset( + ::RuntimeOrigin::signed(assets_owner), + roc_at_westend_parachains, + sov_of_sender_on_ah.clone(), + roc_to_send * 2, + ); + + // Init values for Parachain Destination + let receiver = PenpalBReceiver::get(); + + // Assets to send + let assets: Vec = vec![ + (wnd_location_latest.clone(), wnd_to_send).into(), + (roc_at_westend_parachains_latest, roc_to_send).into(), + ]; + let fee_asset_id: AssetId = wnd_location_latest.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(), + wnd_to_send, + assets.into(), + None, + fee_asset_item, + ), + }; + let mut test = ParaToParaThroughAHTest::new(test_args); + + // Query initial balances + let sender_wnds_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_location, &sender) + }); + let sender_rocs_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_at_westend_parachains, &sender) + }); + let wnds_in_sender_reserve_on_ah_before = + ::account_data_of(sov_of_sender_on_ah.clone()).free; + let rocs_in_sender_reserve_on_ah_before = AssetHubWestend::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(roc_at_westend_parachains, &sov_of_sender_on_ah) + }); + let wnds_in_receiver_reserve_on_ah_before = + ::account_data_of(sov_of_receiver_on_ah.clone()).free; + let rocs_in_receiver_reserve_on_ah_before = AssetHubWestend::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(roc_at_westend_parachains, &sov_of_receiver_on_ah) + }); + let receiver_wnds_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_location, &receiver) + }); + let receiver_rocs_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_at_westend_parachains, &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_wnds_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_location, &sender) + }); + let sender_rocs_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_at_westend_parachains, &sender) + }); + let rocs_in_sender_reserve_on_ah_after = AssetHubWestend::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(roc_at_westend_parachains, &sov_of_sender_on_ah) + }); + let wnds_in_sender_reserve_on_ah_after = + ::account_data_of(sov_of_sender_on_ah).free; + let rocs_in_receiver_reserve_on_ah_after = AssetHubWestend::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(roc_at_westend_parachains, &sov_of_receiver_on_ah) + }); + let wnds_in_receiver_reserve_on_ah_after = + ::account_data_of(sov_of_receiver_on_ah).free; + let receiver_wnds_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(wnd_location, &receiver) + }); + let receiver_rocs_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(roc_at_westend_parachains, &receiver) + }); + + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_wnds_after < sender_wnds_before - wnd_to_send); + assert_eq!(sender_rocs_after, sender_rocs_before - roc_to_send); + // Sovereign accounts on reserve are changed accordingly + assert_eq!( + wnds_in_sender_reserve_on_ah_after, + wnds_in_sender_reserve_on_ah_before - wnd_to_send + ); + assert_eq!( + rocs_in_sender_reserve_on_ah_after, + rocs_in_sender_reserve_on_ah_before - roc_to_send + ); + assert!(wnds_in_receiver_reserve_on_ah_after > wnds_in_receiver_reserve_on_ah_before); + assert_eq!( + rocs_in_receiver_reserve_on_ah_after, + rocs_in_receiver_reserve_on_ah_before + roc_to_send + ); + // Receiver's balance is increased + assert!(receiver_wnds_after > receiver_wnds_before); + assert_eq!(receiver_rocs_after, receiver_rocs_before + roc_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, + ); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs index 3cd7c9c46d69..e463e21e9e52 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs @@ -14,6 +14,7 @@ // limitations under the License. mod fellowship_treasury; +mod foreign_assets_transfers; mod reserve_transfer; mod send; mod set_xcm_versions; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs index 7428d7fa53a2..0677a77e3447 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -55,69 +55,91 @@ fn para_to_relay_sender_assertions(t: ParaToRelayTest) { ); } -fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { +pub fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; - - AssetHubWestend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 864_610_000, - 8_799, - ))); - + AssetHubWestend::assert_xcm_pallet_attempted_complete(None); + + let sov_acc_of_dest = AssetHubWestend::sovereign_account_id_of(t.args.dest.clone()); + for (idx, asset) in t.args.assets.into_inner().into_iter().enumerate() { + let expected_id = asset.id.0.clone().try_into().unwrap(); + let asset_amount = if let Fungible(a) = asset.fun { Some(a) } else { None }.unwrap(); + if idx == t.args.fee_asset_item as usize { + assert_expected_events!( + AssetHubWestend, + vec![ + // Amount of native asset is transferred to Parachain's Sovereign account + RuntimeEvent::Balances( + pallet_balances::Event::Transfer { from, to, amount } + ) => { + from: *from == t.sender.account_id, + to: *to == sov_acc_of_dest, + amount: *amount == asset_amount, + }, + ] + ); + } else { + assert_expected_events!( + AssetHubWestend, + vec![ + // Amount of foreign asset is transferred to Parachain's Sovereign account + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Transferred { asset_id, from, to, amount }, + ) => { + asset_id: *asset_id == expected_id, + from: *from == t.sender.account_id, + to: *to == sov_acc_of_dest, + amount: *amount == asset_amount, + }, + ] + ); + } + } assert_expected_events!( AssetHubWestend, vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Transfer { from, to, amount } - ) => { - from: *from == t.sender.account_id, - to: *to == AssetHubWestend::sovereign_account_id_of( - t.args.dest.clone() - ), - amount: *amount == t.args.amount, - }, // Transport fees are paid - RuntimeEvent::PolkadotXcm( - pallet_xcm::Event::FeesPaid { .. } - ) => {}, + RuntimeEvent::PolkadotXcm(pallet_xcm::Event::FeesPaid { .. }) => {}, ] ); AssetHubWestend::assert_xcm_pallet_sent(); } -fn system_para_to_para_receiver_assertions(t: SystemParaToParaTest) { +pub fn system_para_to_para_receiver_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; - let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); - PenpalA::assert_xcmp_queue_success(None); - - assert_expected_events!( - PenpalA, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == system_para_native_asset_location, - owner: *owner == t.receiver.account_id, - }, - ] - ); + 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 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::ForeignAssets( - pallet_assets::Event::Burned { asset_id, owner, balance, .. } - ) => { - asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).unwrap(), - owner: *owner == t.sender.account_id, - balance: *balance == 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.try_into().unwrap(); + 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_relay_receiver_assertions(t: ParaToRelayTest) { @@ -149,25 +171,57 @@ fn para_to_relay_receiver_assertions(t: ParaToRelayTest) { ); } -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_ahr = AssetHubWestend::sovereign_account_id_of( - AssetHubWestend::sibling_location_of(PenpalA::para_id()), - ); - AssetHubWestend::assert_xcmp_queue_success(None); + let sov_acc_of_penpal = AssetHubWestend::sovereign_account_id_of(t.args.dest.clone()); + for (idx, asset) in t.args.assets.into_inner().into_iter().enumerate() { + let expected_id = asset.id.0.clone().try_into().unwrap(); + let asset_amount = if let Fungible(a) = asset.fun { Some(a) } else { None }.unwrap(); + if idx == t.args.fee_asset_item as usize { + assert_expected_events!( + AssetHubWestend, + vec![ + // Amount of native is withdrawn from Parachain's Sovereign account + RuntimeEvent::Balances( + pallet_balances::Event::Burned { who, amount } + ) => { + who: *who == sov_acc_of_penpal.clone().into(), + amount: *amount == asset_amount, + }, + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { + who: *who == t.receiver.account_id, + }, + ] + ); + } else { + assert_expected_events!( + AssetHubWestend, + vec![ + // Amount of foreign asset is transferred from Parachain's Sovereign account + // to Receiver's account + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, balance }, + ) => { + asset_id: *asset_id == expected_id, + owner: *owner == sov_acc_of_penpal, + balance: *balance == asset_amount, + }, + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Issued { asset_id, owner, amount }, + ) => { + asset_id: *asset_id == expected_id, + owner: *owner == t.receiver.account_id, + amount: *amount == asset_amount, + }, + ] + ); + } + } assert_expected_events!( AssetHubWestend, vec![ - // Amount to reserve transfer is withdrawn from Parachain's Sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } - ) => { - who: *who == sov_penpal_on_ahr.clone().into(), - amount: *amount == t.args.amount, - }, - RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, RuntimeEvent::MessageQueue( pallet_message_queue::Event::Processed { success: true, .. } ) => {}, @@ -312,28 +366,27 @@ fn relay_to_para_assets_receiver_assertions(t: RelayToParaTest) { ); } -fn para_to_para_through_relay_sender_assertions(t: ParaToParaThroughRelayTest) { +pub fn para_to_para_through_hop_sender_assertions(t: Test) { type RuntimeEvent = ::RuntimeEvent; - - let relay_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); - PenpalA::assert_xcm_pallet_attempted_complete(None); - // XCM sent to relay reserve - PenpalA::assert_parachain_system_ump_sent(); - assert_expected_events!( - PenpalA, - vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::ForeignAssets( - pallet_assets::Event::Burned { asset_id, owner, balance }, - ) => { - asset_id: *asset_id == relay_asset_location, - owner: *owner == t.sender.account_id, - balance: *balance == t.args.amount, - }, - ] - ); + 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: ParaToParaThroughRelayTest) { @@ -366,21 +419,22 @@ fn para_to_para_relay_hop_assertions(t: ParaToParaThroughRelayTest) { ); } -fn para_to_para_through_relay_receiver_assertions(t: ParaToParaThroughRelayTest) { +pub fn para_to_para_through_hop_receiver_assertions(t: Test) { type RuntimeEvent = ::RuntimeEvent; - let relay_asset_location = v3::Location::try_from(RelayLocation::get()).unwrap(); PenpalB::assert_xcmp_queue_success(None); - - assert_expected_events!( - PenpalB, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == relay_asset_location, - owner: *owner == t.receiver.account_id, - }, - ] - ); + 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 { @@ -1064,9 +1118,9 @@ fn reserve_transfer_native_asset_from_para_to_para_through_relay() { }); // Set assertions and dispatchables - test.set_assertion::(para_to_para_through_relay_sender_assertions); + 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_through_relay_receiver_assertions); + test.set_assertion::(para_to_para_through_hop_receiver_assertions); test.set_dispatchable::(para_to_para_through_relay_limited_reserve_transfer_assets); test.assert(); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs index 125ffb220a87..aee2c1b4001d 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs @@ -412,10 +412,12 @@ 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() { +/// 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_WESTEND_ED * 100; let asset_location_on_penpal = @@ -515,7 +517,7 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { 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 = PenpalA::execute_with(|| { @@ -622,7 +624,7 @@ 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; @@ -660,3 +662,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/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs index 4b9c517f1510..0415af580ef8 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs @@ -25,6 +25,7 @@ mod imports { prelude::{AccountId32 as AccountId32Junction, *}, v3::{self, NetworkId::Westend as WestendId}, }; + pub use xcm_executor::traits::TransferType; // Cumulus pub use emulated_integration_tests_common::{ diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs index ad920feaadb2..895fb3bd72f5 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs @@ -14,7 +14,6 @@ // limitations under the License. use crate::tests::*; -use xcm_executor::traits::TransferType; fn send_asset_from_asset_hub_rococo_to_asset_hub_westend(id: Location, amount: u128) { let destination = asset_hub_westend_location(); @@ -113,7 +112,7 @@ fn send_rocs_from_asset_hub_rococo_to_asset_hub_westend() { vec![], ); let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( - NetworkId::Westend, + Westend, AssetHubWestend::para_id(), ); @@ -223,7 +222,7 @@ fn send_wnds_from_asset_hub_rococo_to_asset_hub_westend() { // fund the AHR's SA on AHW with the WND tokens held in reserve let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( - NetworkId::Rococo, + Rococo, AssetHubRococo::para_id(), ); AssetHubWestend::fund_accounts(vec![(sov_ahr_on_ahw.clone(), prefund_amount)]); @@ -301,7 +300,7 @@ fn send_rocs_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_westend() vec![], ); let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( - NetworkId::Westend, + Westend, AssetHubWestend::para_id(), ); diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs index 9b86396d2bc6..36b846e10313 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs @@ -26,6 +26,7 @@ mod imports { v3, v4::NetworkId::Rococo as RococoId, }; + pub use xcm_executor::traits::TransferType; // Cumulus pub use emulated_integration_tests_common::{ diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs index 930604784e06..1dd48fb9b2aa 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs @@ -111,7 +111,7 @@ fn send_wnds_from_asset_hub_westend_to_asset_hub_rococo() { vec![], ); let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( - NetworkId::Rococo, + Rococo, AssetHubRococo::para_id(), ); @@ -220,7 +220,7 @@ fn send_rocs_from_asset_hub_westend_to_asset_hub_rococo() { // fund the AHW's SA on AHR with the ROC tokens held in reserve let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( - NetworkId::Westend, + Westend, AssetHubWestend::para_id(), ); AssetHubRococo::fund_accounts(vec![(sov_ahw_on_ahr.clone(), prefund_amount)]); @@ -298,53 +298,10 @@ fn send_wnds_from_penpal_westend_through_asset_hub_westend_to_asset_hub_rococo() vec![], ); let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( - NetworkId::Rococo, + Rococo, AssetHubRococo::para_id(), ); - AssetHubRococo::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - // setup a pool to pay xcm fees with `wnd_at_asset_hub_rococo` tokens - assert_ok!(::ForeignAssets::mint( - ::RuntimeOrigin::signed(AssetHubRococoSender::get()), - wnd_at_asset_hub_rococo.into(), - AssetHubRococoSender::get().into(), - 3_000_000_000_000, - )); - - assert_ok!(::AssetConversion::create_pool( - ::RuntimeOrigin::signed(AssetHubRococoSender::get()), - Box::new(xcm::v3::Parent.into()), - Box::new(wnd_at_asset_hub_rococo), - )); - - assert_expected_events!( - AssetHubRococo, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, - ] - ); - - assert_ok!(::AssetConversion::add_liquidity( - ::RuntimeOrigin::signed(AssetHubRococoSender::get()), - Box::new(xcm::v3::Parent.into()), - Box::new(wnd_at_asset_hub_rococo), - 1_000_000_000_000, - 2_000_000_000_000, - 1, - 1, - AssetHubRococoSender::get().into() - )); - - assert_expected_events!( - AssetHubRococo, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {..}) => {}, - ] - ); - }); - let amount = ASSET_HUB_WESTEND_ED * 10_000_000; let penpal_location = AssetHubWestend::sibling_location_of(PenpalB::para_id()); let sov_penpal_on_ahw = AssetHubWestend::sovereign_account_id_of(penpal_location); From 9c7bd393172ba5888ecc5b56799680f22df8571e Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 4 Apr 2024 20:11:23 +0300 Subject: [PATCH 25/30] remove leftover comment --- polkadot/xcm/pallet-xcm/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 353833cc296d..1d909b1b39b6 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -2062,7 +2062,6 @@ impl Pallet { // handle fees Self::add_fees_to_xcm(dest, fees, weight_limit, &mut local_execute_xcm, &mut xcm_on_dest)?; - // TODO: custom action // deposit all remaining assets in holding to `beneficiary` location xcm_on_dest .inner_mut() From adf5128149d36485f475e973b7dde56795500483 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 11 Apr 2024 18:34:12 +0300 Subject: [PATCH 26/30] Apply suggestions from code review Co-authored-by: Branislav Kontur --- cumulus/pallets/xcmp-queue/src/lib.rs | 2 +- polkadot/xcm/xcm-executor/src/lib.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cumulus/pallets/xcmp-queue/src/lib.rs b/cumulus/pallets/xcmp-queue/src/lib.rs index 3b9b398382dc..deced13a9e81 100644 --- a/cumulus/pallets/xcmp-queue/src/lib.rs +++ b/cumulus/pallets/xcmp-queue/src/lib.rs @@ -943,7 +943,7 @@ impl SendXcm for Pallet { Ok(hash) }, Err(e) => { - log::error!(target: "xcm::XcmpQueue::deliver", "error: {:?}", e); + log::error!(target: LOG_TARGET, "Deliver error: {e:?}"); Err(SendError::Transport(e.into())) }, } diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index c472be992b28..e673a46c4ac6 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -348,8 +348,7 @@ impl XcmExecutor { reason: FeeReason, ) -> Result { log::trace!( - target: "xcm::send", "Sending msg: {:?}, to destination: {:?}, (reason: {:?})", - msg, dest, reason, + target: "xcm::send", "Sending msg: {msg:?}, to destination: {dest:?}, (reason: {reason:?})" ); let (ticket, fee) = validate_send::(dest, msg)?; self.take_fee(fee, reason)?; From 1347f0bed99165fce785da48b5a888149036c173 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 11 Apr 2024 18:34:58 +0300 Subject: [PATCH 27/30] fix logs --- .../modules/xcm-bridge-hub-router/src/lib.rs | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs index c28abcc30533..c6008802ae9a 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -192,8 +192,8 @@ pub mod pallet { /// Called when new message is sent (queued to local outbound XCM queue) over the bridge. pub(crate) fn on_message_sent_to_bridge(message_size: u32) { log::trace!( - target: "xcm::xcm_bridge_hub_router::on_message_sent_to_bridge", - "message_size: {:?}", message_size, + target: LOG_TARGET, + "on_message_sent_to_bridge - message_size: {message_size:?}", ); let _ = Bridge::::try_mutate(|bridge| { let is_channel_with_bridge_hub_congested = T::WithBridgeHubChannel::is_congested(); @@ -243,17 +243,15 @@ impl, I: 'static> ExporterFor for Pallet { message: &Xcm<()>, ) -> Option<(Location, Option)> { log::trace!( - target: "xcm::xcm_bridge_hub_router::exporter_for", - "network: {:?}, remote_location: {:?}, msg: {:?}", network, remote_location, message + target: LOG_TARGET, + "exporter_for - network: {network:?}, remote_location: {remote_location:?}, msg: {message:?}", ); // ensure that the message is sent to the expected bridged network (if specified). if let Some(bridged_network) = T::BridgedNetworkId::get() { if *network != bridged_network { log::trace!( target: LOG_TARGET, - "Router with bridged_network_id {:?} does not support bridging to network {:?}!", - bridged_network, - network, + "Router with bridged_network_id {bridged_network:?} does not support bridging to network {network:?}!", ); return None } @@ -329,10 +327,7 @@ impl, I: 'static> SendXcm for Pallet { dest: &mut Option, xcm: &mut Option>, ) -> SendResult { - log::trace!( - target: "xcm::xcm_bridge_hub_router::validate", - "msg: {:?}, destination: {:?}", xcm, dest, - ); + log::trace!(target: LOG_TARGET, "validate - msg: {xcm:?}, destination: {dest:?}"); // `dest` and `xcm` are required here let dest_ref = dest.as_ref().ok_or(SendError::MissingArgument)?; let xcm_ref = xcm.as_ref().ok_or(SendError::MissingArgument)?; @@ -378,10 +373,7 @@ impl, I: 'static> SendXcm for Pallet { // increase delivery fee factor if required Self::on_message_sent_to_bridge(message_size); - log::trace!( - target: "xcm::xcm_bridge_hub_router::deliver", - "message sent, xcm_hash: {:?}", xcm_hash, - ); + log::trace!(target: LOG_TARGET, "deliver - message sent, xcm_hash: {xcm_hash:?}"); Ok(xcm_hash) } } From e3acff2a72b57bb10f921ea89c74e65708372fc7 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 11 Apr 2024 18:44:28 +0300 Subject: [PATCH 28/30] fix api --- .../src/tests/foreign_assets_transfers.rs | 10 +++---- .../src/tests/foreign_assets_transfers.rs | 10 +++---- .../src/tests/asset_transfers.rs | 6 ++--- .../src/tests/asset_transfers.rs | 6 ++--- polkadot/xcm/pallet-xcm/src/lib.rs | 26 +++++++------------ 5 files changed, 25 insertions(+), 33 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs index 86090e89cea9..6444e9de82e8 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs @@ -60,7 +60,7 @@ fn ah_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { bx!(t.args.beneficiary.into()), bx!(t.args.assets.into()), bx!(TransferType::LocalReserve), - bx!(fee.into()), + bx!(fee.id.into()), bx!(TransferType::LocalReserve), t.args.weight_limit, ) @@ -75,7 +75,7 @@ fn para_to_ah_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { bx!(t.args.beneficiary.into()), bx!(t.args.assets.into()), bx!(TransferType::DestinationReserve), - bx!(fee.into()), + bx!(fee.id.into()), bx!(TransferType::DestinationReserve), t.args.weight_limit, ) @@ -91,7 +91,7 @@ fn para_to_para_transfer_assets_through_ah(t: ParaToParaThroughAHTest) -> Dispat bx!(t.args.beneficiary.into()), bx!(t.args.assets.into()), bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), - bx!(fee.into()), + bx!(fee.id.into()), bx!(TransferType::RemoteReserve(asset_hub_location.into())), t.args.weight_limit, ) @@ -106,7 +106,7 @@ fn para_to_asset_hub_teleport_foreign_assets(t: ParaToSystemParaTest) -> Dispatc bx!(t.args.beneficiary.into()), bx!(t.args.assets.into()), bx!(TransferType::Teleport), - bx!(fee.into()), + bx!(fee.id.into()), bx!(TransferType::DestinationReserve), t.args.weight_limit, ) @@ -121,7 +121,7 @@ fn asset_hub_to_para_teleport_foreign_assets(t: SystemParaToParaTest) -> Dispatc bx!(t.args.beneficiary.into()), bx!(t.args.assets.into()), bx!(TransferType::Teleport), - bx!(fee.into()), + bx!(fee.id.into()), bx!(TransferType::LocalReserve), t.args.weight_limit, ) diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/foreign_assets_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/foreign_assets_transfers.rs index f463f28cda35..4f8c9bf7f9c1 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/foreign_assets_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/foreign_assets_transfers.rs @@ -60,7 +60,7 @@ fn ah_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { bx!(t.args.beneficiary.into()), bx!(t.args.assets.into()), bx!(TransferType::LocalReserve), - bx!(fee.into()), + bx!(fee.id.into()), bx!(TransferType::LocalReserve), t.args.weight_limit, ) @@ -75,7 +75,7 @@ fn para_to_ah_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { bx!(t.args.beneficiary.into()), bx!(t.args.assets.into()), bx!(TransferType::DestinationReserve), - bx!(fee.into()), + bx!(fee.id.into()), bx!(TransferType::DestinationReserve), t.args.weight_limit, ) @@ -91,7 +91,7 @@ fn para_to_para_transfer_assets_through_ah(t: ParaToParaThroughAHTest) -> Dispat bx!(t.args.beneficiary.into()), bx!(t.args.assets.into()), bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), - bx!(fee.into()), + bx!(fee.id.into()), bx!(TransferType::RemoteReserve(asset_hub_location.into())), t.args.weight_limit, ) @@ -106,7 +106,7 @@ fn para_to_asset_hub_teleport_foreign_assets(t: ParaToSystemParaTest) -> Dispatc bx!(t.args.beneficiary.into()), bx!(t.args.assets.into()), bx!(TransferType::Teleport), - bx!(fee.into()), + bx!(fee.id.into()), bx!(TransferType::DestinationReserve), t.args.weight_limit, ) @@ -121,7 +121,7 @@ fn asset_hub_to_para_teleport_foreign_assets(t: SystemParaToParaTest) -> Dispatc bx!(t.args.beneficiary.into()), bx!(t.args.assets.into()), bx!(TransferType::Teleport), - bx!(fee.into()), + bx!(fee.id.into()), bx!(TransferType::LocalReserve), t.args.weight_limit, ) diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs index 895fb3bd72f5..314f02b868c6 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs @@ -58,8 +58,8 @@ fn send_asset_from_penpal_rococo_through_local_asset_hub_to_westend_asset_hub( let signed_origin = ::RuntimeOrigin::signed(PenpalASender::get()); let beneficiary: Location = AccountId32Junction { network: None, id: AssetHubWestendReceiver::get().into() }.into(); - let fees: Asset = (id.clone(), transfer_amount).into(); - let assets: Assets = vec![fees.clone()].into(); + let assets: Assets = (id.clone(), transfer_amount).into(); + let fees_id: AssetId = id.into(); ::PolkadotXcm::transfer_assets_using_type( signed_origin, @@ -67,7 +67,7 @@ fn send_asset_from_penpal_rococo_through_local_asset_hub_to_westend_asset_hub( bx!(beneficiary.into()), bx!(assets.clone().into()), bx!(TransferType::RemoteReserve(local_asset_hub.clone().into())), - bx!(fees.into()), + bx!(fees_id.into()), bx!(TransferType::RemoteReserve(local_asset_hub.into())), WeightLimit::Unlimited, ) diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs index 1dd48fb9b2aa..f76a4224b90a 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs @@ -57,8 +57,8 @@ fn send_asset_from_penpal_westend_through_local_asset_hub_to_rococo_asset_hub( let signed_origin = ::RuntimeOrigin::signed(PenpalBSender::get()); let beneficiary: Location = AccountId32Junction { network: None, id: AssetHubRococoReceiver::get().into() }.into(); - let fees: Asset = (id, transfer_amount).into(); - let assets: Assets = fees.clone().into(); + let assets: Assets = (id.clone(), transfer_amount).into(); + let fees_id: AssetId = id.into(); ::PolkadotXcm::transfer_assets_using_type( signed_origin, @@ -66,7 +66,7 @@ fn send_asset_from_penpal_westend_through_local_asset_hub_to_rococo_asset_hub( bx!(beneficiary.into()), bx!(assets.into()), bx!(TransferType::RemoteReserve(local_asset_hub.clone().into())), - bx!(fees.into()), + bx!(fees_id.into()), bx!(TransferType::RemoteReserve(local_asset_hub.into())), WeightLimit::Unlimited, ) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 1d909b1b39b6..c38915822f7f 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1301,7 +1301,6 @@ pub mod pallet { ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::::TooManyAssets); let assets = assets.into_inner(); let fee_asset_item = fee_asset_item as usize; - let fees = assets.get(fee_asset_item as usize).ok_or(Error::::Empty)?.clone(); // Find transfer types for fee and non-fee assets. let (fees_transfer_type, assets_transfer_type) = Self::find_fee_and_assets_transfer_types(&assets, fee_asset_item, &dest)?; @@ -1312,7 +1311,7 @@ pub mod pallet { beneficiary, assets, assets_transfer_type, - fees, + fee_asset_item, fees_transfer_type, weight_limit, ) @@ -1448,7 +1447,7 @@ pub mod pallet { beneficiary: Box, assets: Box, assets_transfer_type: Box, - fees: Box, + fees_id: Box, fees_transfer_type: Box, weight_limit: WeightLimit, ) -> DispatchResult { @@ -1457,31 +1456,25 @@ pub mod pallet { let beneficiary: Location = (*beneficiary).try_into().map_err(|()| Error::::BadVersion)?; let assets: Assets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; - let fees: Asset = (*fees).try_into().map_err(|()| Error::::BadVersion)?; + let fees_id: AssetId = (*fees_id).try_into().map_err(|()| Error::::BadVersion)?; log::debug!( target: "xcm::pallet_xcm::transfer_assets_using_type", - "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?} through {:?}, fees {:?} through {:?}", - origin_location, dest, beneficiary, assets, assets_transfer_type, fees, fees_transfer_type, + "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?} through {:?}, fees-id {:?} through {:?}", + origin_location, dest, beneficiary, assets, assets_transfer_type, fees_id, fees_transfer_type, ); let assets = assets.into_inner(); ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::::TooManyAssets); let fee_asset_index = - assets.iter().position(|a| a.id == fees.id).ok_or(Error::::FeesNotMet)?; - let fee_asset = assets.get(fee_asset_index).ok_or(Error::::Empty)?; - ensure!( - matches!((&fee_asset.fun, &fees.fun), (Fungible(a), Fungible(f)) if a >= f), - Error::::FeesNotMet - ); - + assets.iter().position(|a| a.id == fees_id).ok_or(Error::::FeesNotMet)?; Self::do_transfer_assets( origin_location, dest, beneficiary, assets, *assets_transfer_type, - fees, + fee_asset_index, *fees_transfer_type, weight_limit, ) @@ -1710,12 +1703,13 @@ impl Pallet { beneficiary: Location, mut assets: Vec, assets_transfer_type: TransferType, - fees: Asset, + fee_asset_index: usize, fees_transfer_type: TransferType, weight_limit: WeightLimit, ) -> DispatchResult { // local and remote XCM programs to potentially handle fees separately let fees = if fees_transfer_type == assets_transfer_type { + let fees = assets.get(fee_asset_index).ok_or(Error::::Empty)?.clone(); // no need for custom fees instructions, fees are batched with assets FeesHandling::Batched { fees } } else { @@ -1731,8 +1725,6 @@ impl Pallet { let weight_limit = weight_limit.clone(); // remove `fees` from `assets` and build separate fees transfer instructions to be // added to assets transfers XCM programs - let fee_asset_index = - assets.iter().position(|a| a.id == fees.id).ok_or(Error::::FeesNotMet)?; let fees = assets.remove(fee_asset_index); let (local_xcm, remote_xcm) = match fees_transfer_type { TransferType::LocalReserve => Self::local_reserve_fees_instructions( From 0d407ebf98883b0a9a4770b9c77970b354cccce5 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 12 Apr 2024 12:38:44 +0300 Subject: [PATCH 29/30] Update polkadot/xcm/pallet-xcm/src/lib.rs Co-authored-by: Branislav Kontur --- polkadot/xcm/pallet-xcm/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index c38915822f7f..270394cdf598 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1419,11 +1419,11 @@ pub mod pallet { /// mint/teleport assets and deposit them to `beneficiary`. /// /// Fee payment on the source, destination and all intermediary hops, is specified through - /// `fees`, but make sure enough of the specified `fees` asset is included in the given list - /// of `assets`. `fees` should be enough to pay for `weight_limit`. If more weight is needed + /// `fees_id`, but make sure enough of the specified `fees_id` asset is included in the given list + /// of `assets`. `fees_id` should be enough to pay for `weight_limit`. If more weight is needed /// than `weight_limit`, then the operation will fail and the sent assets may be at risk. /// - /// `fees` may use different transfer type than rest of `assets` and can be specified + /// `fees_id` may use different transfer type than rest of `assets` and can be specified /// through `fees_transfer_type`. /// /// - `origin`: Must be capable of withdrawing the `assets` and executing XCM. @@ -1436,7 +1436,7 @@ pub mod pallet { /// - `assets`: The assets to be withdrawn. This should include the assets used to pay the /// fee on the `dest` (and possibly reserve) chains. /// - `assets_transfer_type`: The XCM `TransferType` used to transfer the `assets`. - /// - `fees`: One of the included `assets` to be be used to pay fees. + /// - `fees_id`: One of the included `assets` to be be used to pay fees. /// - `fees_transfer_type`: The XCM `TransferType` used to transfer the `fees` assets. /// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase. #[pallet::call_index(15)] From 22093d055d4800e3b47fd39474e6897557cc9504 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Fri, 12 Apr 2024 10:01:29 +0000 Subject: [PATCH 30/30] ".git/.scripts/commands/fmt/fmt.sh" --- polkadot/xcm/pallet-xcm/src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 270394cdf598..cf22b86cf82c 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1419,9 +1419,10 @@ pub mod pallet { /// mint/teleport assets and deposit them to `beneficiary`. /// /// Fee payment on the source, destination and all intermediary hops, is specified through - /// `fees_id`, but make sure enough of the specified `fees_id` asset is included in the given list - /// of `assets`. `fees_id` should be enough to pay for `weight_limit`. If more weight is needed - /// than `weight_limit`, then the operation will fail and the sent assets may be at risk. + /// `fees_id`, but make sure enough of the specified `fees_id` asset is included in the + /// given list of `assets`. `fees_id` should be enough to pay for `weight_limit`. If more + /// weight is needed than `weight_limit`, then the operation will fail and the sent assets + /// may be at risk. /// /// `fees_id` may use different transfer type than rest of `assets` and can be specified /// through `fees_transfer_type`.