From 43ef69484048a526398c8872ea996c85f7bd8e96 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 5 Sep 2023 19:22:36 +0300 Subject: [PATCH 01/98] asset-hubs runtimes: add xcm reserve transfer tests --- Cargo.lock | 1 + .../assets/asset-hub-kusama/tests/tests.rs | 34 ++- .../assets/asset-hub-polkadot/tests/tests.rs | 34 ++- .../assets/asset-hub-westend/tests/tests.rs | 33 ++- .../runtimes/assets/test-utils/Cargo.toml | 2 + .../runtimes/assets/test-utils/src/lib.rs | 42 ++++ .../assets/test-utils/src/test_cases.rs | 197 +++++++++++++++++- 7 files changed, 332 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e0ca0b012c64..a3a59c270c47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -960,6 +960,7 @@ dependencies = [ "sp-runtime", "sp-std", "staging-xcm", + "staging-xcm-builder", "staging-xcm-executor", "substrate-wasm-builder", ] diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs index 7d49b56e461a..31004dfc62e1 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs @@ -18,13 +18,14 @@ //! Tests for the Statemine (Kusama Assets Hub) chain. use asset_hub_kusama_runtime::xcm_config::{ - AssetFeeAsExistentialDepositMultiplierFeeCharger, KsmLocation, TrustBackedAssetsPalletLocation, + AssetFeeAsExistentialDepositMultiplierFeeCharger, KsmLocation, LocationToAccountId, + TrustBackedAssetsPalletLocation, }; pub use asset_hub_kusama_runtime::{ xcm_config::{CheckingAccount, ForeignCreatorsSovereignAccountOf, XcmConfig}, AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, - RuntimeCall, RuntimeEvent, SessionKeys, System, TrustBackedAssetsInstance, + RuntimeCall, RuntimeEvent, SessionKeys, System, TrustBackedAssetsInstance, XcmpQueue, }; use asset_test_utils::{CollatorSessionKeys, ExtBuilder}; use codec::{Decode, Encode}; @@ -632,3 +633,32 @@ asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_p assert_eq!(ForeignAssets::asset_ids().collect::>().len(), 1); }) ); + +#[test] +fn reserve_transfer_native_asset_works() { + asset_test_utils::test_cases::reserve_transfer_native_asset_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + ParachainSystem, + XcmpQueue, + LocationToAccountId, + >( + collator_session_keys(), + ExistentialDeposit::get(), + AccountId::from(ALICE), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event), + _ => None, + } + }), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), + _ => None, + } + }), + WeightLimit::Unlimited, + ); +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs index 7200ebc16a28..5dd3cbb80dec 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs @@ -19,12 +19,13 @@ use asset_hub_polkadot_runtime::xcm_config::{ AssetFeeAsExistentialDepositMultiplierFeeCharger, CheckingAccount, DotLocation, - ForeignCreatorsSovereignAccountOf, TrustBackedAssetsPalletLocation, XcmConfig, + ForeignCreatorsSovereignAccountOf, LocationToAccountId, TrustBackedAssetsPalletLocation, + XcmConfig, }; pub use asset_hub_polkadot_runtime::{ AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, - RuntimeCall, RuntimeEvent, SessionKeys, System, TrustBackedAssetsInstance, + RuntimeCall, RuntimeEvent, SessionKeys, System, TrustBackedAssetsInstance, XcmpQueue, }; use asset_test_utils::{CollatorSessionKeys, ExtBuilder}; use codec::{Decode, Encode}; @@ -657,3 +658,32 @@ asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_p assert_eq!(ForeignAssets::asset_ids().collect::>().len(), 1); }) ); + +#[test] +fn reserve_transfer_native_asset_works() { + asset_test_utils::test_cases::reserve_transfer_native_asset_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + ParachainSystem, + XcmpQueue, + LocationToAccountId, + >( + collator_session_keys(), + ExistentialDeposit::get(), + AccountId::from(ALICE), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event), + _ => None, + } + }), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), + _ => None, + } + }), + WeightLimit::Unlimited, + ); +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs index 599ff90e254a..4d8eba91b78a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -20,10 +20,10 @@ use asset_hub_westend_runtime::{ xcm_config::{ AssetFeeAsExistentialDepositMultiplierFeeCharger, ForeignCreatorsSovereignAccountOf, - WestendLocation, + LocationToAccountId, WestendLocation, }, AllPalletsWithoutSystem, MetadataDepositBase, MetadataDepositPerByte, RuntimeCall, - RuntimeEvent, + RuntimeEvent, XcmpQueue, }; pub use asset_hub_westend_runtime::{ xcm_config::{CheckingAccount, TrustBackedAssetsPalletLocation, XcmConfig}, @@ -666,3 +666,32 @@ fn plain_receive_teleported_asset_works() { assert_eq!(outcome.ensure_complete(), Ok(())); }) } + +#[test] +fn reserve_transfer_native_asset_works() { + asset_test_utils::test_cases::reserve_transfer_native_asset_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + ParachainSystem, + XcmpQueue, + LocationToAccountId, + >( + collator_session_keys(), + ExistentialDeposit::get(), + AccountId::from(ALICE), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event), + _ => None, + } + }), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), + _ => None, + } + }), + WeightLimit::Unlimited, + ); +} diff --git a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml index 0a27535ed22b..699d6b9198bd 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml @@ -35,6 +35,7 @@ parachains-runtimes-test-utils = { path = "../../test-utils", default-features = # Polkadot xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false} +xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false} xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false} pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false} @@ -71,6 +72,7 @@ std = [ "sp-io/std", "sp-runtime/std", "sp-std/std", + "xcm-builder/std", "xcm-executor/std", "xcm/std", ] diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs b/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs index 7177726e0704..f9ccb0cd61d1 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs @@ -17,4 +17,46 @@ //! Module contains predefined test-case scenarios for `Runtime` with various assets. pub mod test_cases; + +use frame_support::traits::ProcessMessageError; pub use parachains_runtimes_test_utils::*; + +use xcm::latest::prelude::*; +use xcm_builder::{CreateMatcher, MatchXcm}; + +/// Helper function to verify `xcm` contains all relevant instructions expected on destination +/// chain as part of a reserve-asset-transfer. +pub(crate) fn assert_matches_reserve_asset_deposited_instructions( + xcm: &mut Xcm, + expected_reserve_assets_deposited: &MultiAssets, + expected_beneficiary: &MultiLocation, +) { + let _ = xcm + .0 + .matcher() + .skip_inst_while(|inst| !matches!(inst, ReserveAssetDeposited(..))) + .expect("no instruction ReserveAssetDeposited?") + .match_next_inst(|instr| match instr { + ReserveAssetDeposited(reserve_assets) + if reserve_assets == expected_reserve_assets_deposited => + Ok(()), + _ => Err(ProcessMessageError::BadFormat), + }) + .expect("expected instruction ReserveAssetDeposited") + .match_next_inst(|instr| match instr { + ClearOrigin => Ok(()), + _ => Err(ProcessMessageError::BadFormat), + }) + .expect("expected instruction ClearOrigin") + .match_next_inst(|instr| match instr { + BuyExecution { .. } => Ok(()), + _ => Err(ProcessMessageError::BadFormat), + }) + .expect("expected instruction BuyExecution") + .match_next_inst(|instr| match instr { + DepositAsset { assets: _, beneficiary } if beneficiary == expected_beneficiary => + Ok(()), + _ => Err(ProcessMessageError::BadFormat), + }) + .expect("expected instruction DepositAsset"); +} 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 7a8d571403c6..fefe5863b4b0 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -15,23 +15,25 @@ //! Module contains predefined test-case scenarios for `Runtime` with various assets. +use crate::assert_matches_reserve_asset_deposited_instructions; use codec::Encode; +use cumulus_primitives_core::XcmpMessageSource; use frame_support::{ assert_noop, assert_ok, - traits::{fungibles::InspectEnumerable, Get, OnFinalize, OnInitialize, OriginTrait}, + traits::{fungibles::InspectEnumerable, Currency, Get, OnFinalize, OnInitialize, OriginTrait}, weights::Weight, }; use frame_system::pallet_prelude::BlockNumberFor; use parachains_common::{AccountId, Balance}; use parachains_runtimes_test_utils::{ - assert_metadata, assert_total, AccountIdOf, BalanceOf, CollatorSessionKeys, ExtBuilder, - ValidatorIdOf, XcmReceivedFrom, + assert_metadata, assert_total, mock_open_hrmp_channel, AccountIdOf, BalanceOf, + CollatorSessionKeys, ExtBuilder, ValidatorIdOf, XcmReceivedFrom, }; use sp_runtime::{ traits::{MaybeEquivalence, StaticLookup, Zero}, DispatchError, Saturating, }; -use xcm::latest::prelude::*; +use xcm::{latest::prelude::*, VersionedMultiAssets}; use xcm_executor::{traits::ConvertLocation, XcmExecutor}; type RuntimeHelper = @@ -1059,7 +1061,7 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor AssetId: Clone + Copy, AssetIdConverter: MaybeEquivalence, { - // foreign parachain with the same consenus currency as asset + // foreign parachain with the same consensus currency as asset let foreign_asset_id_multilocation = MultiLocation { parents: 1, interior: X2(Parachain(2222), GeneralIndex(1234567)) }; let asset_id = AssetIdConverter::convert(&foreign_asset_id_multilocation).unwrap(); @@ -1339,3 +1341,188 @@ macro_rules! include_create_and_manage_foreign_assets_for_local_consensus_parach } } ); + +/// Test-case makes sure that `Runtime` can reserve-transfer asset to other parachains +pub fn reserve_transfer_native_asset_works< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + HrmpChannelOpener, + HrmpChannelSource, + LocationToAccountId, +>( + collator_session_keys: CollatorSessionKeys, + existential_deposit: BalanceOf, + alice_account: AccountIdOf, + unwrap_pallet_xcm_event: Box) -> Option>>, + unwrap_xcmp_queue_event: Box< + dyn Fn(Vec) -> Option>, + >, + weight_limit: WeightLimit, +) where + Runtime: frame_system::Config + + pallet_balances::Config + + pallet_session::Config + + pallet_xcm::Config + + parachain_info::Config + + pallet_collator_selection::Config + + cumulus_pallet_parachain_system::Config + + cumulus_pallet_xcmp_queue::Config, + AllPalletsWithoutSystem: + OnInitialize> + OnFinalize>, + AccountIdOf: Into<[u8; 32]>, + ValidatorIdOf: From>, + BalanceOf: From, + ::Balance: From + Into, + XcmConfig: xcm_executor::Config, + LocationToAccountId: ConvertLocation>, + ::AccountId: + Into<<::RuntimeOrigin as OriginTrait>::AccountId>, + <::Lookup as StaticLookup>::Source: + From<::AccountId>, + ::AccountId: From, + HrmpChannelOpener: frame_support::inherent::ProvideInherent< + Call = cumulus_pallet_parachain_system::Call, + >, + HrmpChannelSource: XcmpMessageSource, +{ + let runtime_para_id = 1000; + ExtBuilder::::default() + .with_collators(collator_session_keys.collators()) + .with_session_keys(collator_session_keys.session_keys()) + .with_tracing() + .with_safe_xcm_version(3) + .with_para_id(runtime_para_id.into()) + .build() + .execute_with(|| { + let mut alice = [0u8; 32]; + alice[0] = 1; + let included_head = RuntimeHelper::::run_to_block( + 2, + AccountId::from(alice).into(), + ); + + // reserve-transfer native asset with local reserve to remote parachain (1234) + + let other_para_id = 1234; + let native_asset = MultiLocation::parent(); + let dest = MultiLocation::new(1, X1(Parachain(other_para_id))); + let dest_beneficiary = MultiLocation::new(1, X1(Parachain(other_para_id))) + .appended_with(AccountId32 { + network: None, + id: sp_runtime::AccountId32::new([3; 32]).into(), + }) + .unwrap(); + + let reserve_account = LocationToAccountId::convert_location(&dest) + .expect("Sovereign account for reserves"); + let balance_to_transfer = 1_000_000_000_000_u128; + + // open HRMP to other parachain + mock_open_hrmp_channel::( + runtime_para_id.into(), + other_para_id.into(), + included_head, + &alice, + ); + + // drip ED to account + let alice_account_init_balance = existential_deposit + balance_to_transfer.into(); + let _ = >::deposit_creating( + &alice_account, + alice_account_init_balance, + ); + // SA of target location needs to have at least ED, otherwise making reserve fails + let _ = >::deposit_creating( + &reserve_account, + existential_deposit, + ); + + // we just check here, that user retains enough balance after withdrawal + // and also we check if `balance_to_transfer` is more than `existential_deposit`, + assert!( + (>::free_balance(&alice_account) - + balance_to_transfer.into()) >= + existential_deposit + ); + // SA has just ED + assert_eq!( + >::free_balance(&reserve_account), + existential_deposit + ); + + // local native asset (pallet_balances) + let asset_to_transfer = MultiAsset { + fun: Fungible(balance_to_transfer.into()), + id: Concrete(native_asset), + }; + + // pallet_xcm call reserve transfer + assert_ok!(>::limited_reserve_transfer_assets( + RuntimeHelper::::origin_of(alice_account.clone()), + Box::new(dest.into_versioned()), + Box::new(dest_beneficiary.into_versioned()), + Box::new(VersionedMultiAssets::from(MultiAssets::from(asset_to_transfer))), + 0, + weight_limit, + )); + + // check alice account decreased by balance_to_transfer + // TODO:check-parameter: change and assert in tests when (https://github.com/paritytech/polkadot/pull/7005) merged + assert_eq!( + >::free_balance(&alice_account), + alice_account_init_balance - balance_to_transfer.into() + ); + + // check reserve account + // check reserve account increased by balance_to_transfer + assert_eq!( + >::free_balance(&reserve_account), + existential_deposit + balance_to_transfer.into() + ); + + // check events + // check pallet_xcm attempted + RuntimeHelper::::assert_pallet_xcm_event_outcome( + &unwrap_pallet_xcm_event, + |outcome| { + assert_ok!(outcome.ensure_complete()); + }, + ); + + // check that xcm was sent + let xcm_sent_message_hash = >::events() + .into_iter() + .filter_map(|e| unwrap_xcmp_queue_event(e.event.encode())) + .find_map(|e| match e { + cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { message_hash } => + Some(message_hash), + _ => None, + }); + + // read xcm + let xcm_sent = RuntimeHelper::::take_xcm( + other_para_id.into(), + ) + .unwrap(); + + assert_eq!( + xcm_sent_message_hash, + Some(xcm_sent.using_encoded(sp_io::hashing::blake2_256)) + ); + let mut xcm_sent: Xcm<()> = xcm_sent.try_into().expect("versioned xcm"); + + // check sent XCM Program to other parachain + println!("reserve_transfer_native_asset_works sent xcm: {:?}", xcm_sent); + let reserve_assets_deposited = MultiAssets::from(vec![MultiAsset { + id: Concrete(MultiLocation { parents: 1, interior: Here }), + fun: Fungible(1000000000000), + }]); + + assert_matches_reserve_asset_deposited_instructions( + &mut xcm_sent, + &reserve_assets_deposited, + &dest_beneficiary, + ); + }) +} From 945b34c2d6119803dfa83be544edb56b2a96eeef Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 21 Sep 2023 17:59:20 +0300 Subject: [PATCH 02/98] pallet-xcm: filter assets teleports based on XcmExecutor configuration Add AssetTransferFilter trait for configuring transfer types. Implement it for XcmExecutor based on existing executor teleports and reserves configuration. Filter assets on pallet-xcm::limited_teleport_assets() based on above. --- .../assets/asset-hub-kusama/tests/tests.rs | 6 -- .../assets/asset-hub-polkadot/tests/tests.rs | 6 -- .../assets/asset-hub-westend/tests/tests.rs | 6 -- .../assets/test-utils/src/test_cases.rs | 57 ++++++++----------- .../bridge-hub-kusama/tests/tests.rs | 6 -- .../bridge-hub-polkadot/tests/tests.rs | 6 -- .../bridge-hub-rococo/tests/tests.rs | 12 ---- polkadot/xcm/pallet-xcm/src/lib.rs | 22 ++++++- polkadot/xcm/xcm-executor/src/lib.rs | 6 ++ .../xcm-executor/src/traits/asset_transfer.rs | 29 ++++++++++ polkadot/xcm/xcm-executor/src/traits/mod.rs | 6 +- 11 files changed, 84 insertions(+), 78 deletions(-) create mode 100644 polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs index 31004dfc62e1..b8e59966b641 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs @@ -519,12 +519,6 @@ asset_test_utils::include_teleports_for_native_asset_works!( _ => None, } }), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), - _ => None, - } - }), 1000 ); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs index 5dd3cbb80dec..b232a1703302 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs @@ -532,12 +532,6 @@ asset_test_utils::include_teleports_for_native_asset_works!( _ => None, } }), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), - _ => None, - } - }), 1000 ); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs index 4d8eba91b78a..66ae2fe09aa4 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -526,12 +526,6 @@ asset_test_utils::include_teleports_for_native_asset_works!( _ => None, } }), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), - _ => None, - } - }), 1000 ); 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 fefe5863b4b0..25360171cc8f 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -42,8 +42,8 @@ type RuntimeHelper = // Re-export test_case from `parachains-runtimes-test-utils` pub use parachains_runtimes_test_utils::test_cases::change_storage_constant_by_governance_works; -/// Test-case makes sure that `Runtime` can receive native asset from relay chain -/// and can teleport it back and to the other parachains +/// Test-case makes sure that `Runtime` can receive native asset from relay chain and can teleport +/// it back pub fn teleports_for_native_asset_works< Runtime, AllPalletsWithoutSystem, @@ -56,9 +56,6 @@ pub fn teleports_for_native_asset_works< existential_deposit: BalanceOf, target_account: AccountIdOf, unwrap_pallet_xcm_event: Box) -> Option>>, - unwrap_xcmp_queue_event: Box< - dyn Fn(Vec) -> Option>, - >, runtime_para_id: u32, ) where Runtime: frame_system::Config @@ -204,7 +201,8 @@ pub fn teleports_for_native_asset_works< ); } - // 3. try to teleport asset away to other parachain (1234) + // 3. try to teleport assets away to other parachain (1234): should not work as we don't + // trust `IsTeleporter` for `(relay-native-asset, para(1234))` pair { let other_para_id = 1234; let dest = MultiLocation::new(1, X1(Parachain(other_para_id))); @@ -217,41 +215,38 @@ pub fn teleports_for_native_asset_works< let target_account_balance_before_teleport = >::free_balance(&target_account); + let native_asset_to_teleport_away = native_asset_amount_unit * 3.into(); assert!( native_asset_to_teleport_away < target_account_balance_before_teleport - existential_deposit ); - - assert_ok!(RuntimeHelper::::do_teleport_assets::( - RuntimeHelper::::origin_of(target_account.clone()), - dest, - dest_beneficiary, - (native_asset_id, native_asset_to_teleport_away.into()), - Some((runtime_para_id, other_para_id)), - included_head, - &alice, - )); + assert_eq!( + RuntimeHelper::::do_teleport_assets::( + RuntimeHelper::::origin_of(target_account.clone()), + dest, + dest_beneficiary, + (native_asset_id, native_asset_to_teleport_away.into()), + Some((runtime_para_id, other_para_id)), + included_head, + &alice, + ), + Err(DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [2, 0, 0, 0,], + message: Some("Filtered",), + },),) + ); // check balances assert_eq!( >::free_balance(&target_account), - target_account_balance_before_teleport - native_asset_to_teleport_away + target_account_balance_before_teleport ); assert_eq!( >::free_balance(&CheckingAccount::get()), 0.into() ); - - // check events - RuntimeHelper::::assert_pallet_xcm_event_outcome( - &unwrap_pallet_xcm_event, - |outcome| { - assert_ok!(outcome.ensure_complete()); - }, - ); - assert!(RuntimeHelper::::xcmp_queue_message_sent(unwrap_xcmp_queue_event) - .is_some()); } }) } @@ -268,7 +263,6 @@ macro_rules! include_teleports_for_native_asset_works( $collator_session_key:expr, $existential_deposit:expr, $unwrap_pallet_xcm_event:expr, - $unwrap_xcmp_queue_event:expr, $runtime_para_id:expr ) => { #[test] @@ -288,15 +282,14 @@ macro_rules! include_teleports_for_native_asset_works( $existential_deposit, target_account, $unwrap_pallet_xcm_event, - $unwrap_xcmp_queue_event, $runtime_para_id ) } } ); -/// Test-case makes sure that `Runtime` can receive teleported assets from sibling parachain relay -/// chain +/// Test-case makes sure that `Runtime` can receive teleported assets from sibling parachain, and +/// can teleport it back pub fn teleports_for_foreign_assets_works< Runtime, AllPalletsWithoutSystem, @@ -442,7 +435,7 @@ pub fn teleports_for_foreign_assets_works< >(foreign_asset_id_multilocation, 0, 0); assert!(teleported_foreign_asset_amount > asset_minimum_asset_balance); - // 1. process received teleported assets from relaychain + // 1. process received teleported assets from sibling parachain (foreign_para_id) let xcm = Xcm(vec![ // BuyExecution with relaychain native token WithdrawAsset(buy_execution_fee.clone().into()), diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/tests/tests.rs index 893524e12f66..36d8f0846af2 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/tests/tests.rs @@ -47,11 +47,5 @@ bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!( _ => None, } }), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), - _ => None, - } - }), 1002 ); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/tests/tests.rs index 0be87bd46fac..3156a5fe68e5 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/tests/tests.rs @@ -47,11 +47,5 @@ bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!( _ => None, } }), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), - _ => None, - } - }), 1002 ); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index e5fe67f2a8e5..cc8052008824 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -118,12 +118,6 @@ mod bridge_hub_rococo_tests { _ => None, } }), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), - _ => None, - } - }), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID ); @@ -297,12 +291,6 @@ mod bridge_hub_wococo_tests { _ => None, } }), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), - _ => None, - } - }), bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID ); diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 321bb294b88d..58adb90e1729 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -41,7 +41,7 @@ use sp_runtime::{ }; use sp_std::{boxed::Box, marker::PhantomData, prelude::*, result::Result, vec}; use xcm::{latest::QueryResponseInfo, prelude::*}; -use xcm_executor::traits::{ConvertOrigin, Properties}; +use xcm_executor::traits::{AssetTransferFilter, ConvertOrigin, Properties}; use frame_support::{ dispatch::GetDispatchInfo, pallet_prelude::*, traits::WithdrawReasons, PalletId, @@ -206,7 +206,7 @@ pub mod pallet { type XcmExecuteFilter: Contains<(MultiLocation, Xcm<::RuntimeCall>)>; /// Something to execute an XCM message. - type XcmExecutor: ExecuteXcm<::RuntimeCall>; + type XcmExecutor: ExecuteXcm<::RuntimeCall> + AssetTransferFilter; /// Our XCM filter which messages to be teleported using the dedicated extrinsic must pass. type XcmTeleportFilter: Contains<(MultiLocation, Vec)>; @@ -1212,6 +1212,18 @@ impl Pallet { let value = (origin_location, assets.into_inner()); ensure!(T::XcmReserveTransferFilter::contains(&value), Error::::Filtered); let (origin_location, assets) = value; + // Don't allow inclusion of teleportable assets in this reserve-based-transfer (other than + // fee asset). + for (idx, asset) in assets.iter().enumerate() { + ensure!( + idx == fee_asset_item as usize || + !::IsTeleporter::contains( + asset, &dest + ), + Error::::Filtered + ); + } + let context = T::UniversalLocation::get(); let fees = assets .get(fee_asset_item as usize) @@ -1256,6 +1268,12 @@ impl Pallet { let value = (origin_location, assets.into_inner()); ensure!(T::XcmTeleportFilter::contains(&value), Error::::Filtered); let (origin_location, assets) = value; + for asset in assets.iter() { + ensure!( + ::IsTeleporter::contains(asset, &dest), + Error::::Filtered + ); + } let context = T::UniversalLocation::get(); let fees = assets .get(fee_asset_item as usize) diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index a48cd3259d67..a5575b6952f1 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -38,6 +38,7 @@ use traits::{ mod assets; pub use assets::Assets; mod config; +use crate::traits::AssetTransferFilter; pub use config::Config; /// A struct to specify how fees are being paid. @@ -254,6 +255,11 @@ impl ExecuteXcm for XcmExecutor AssetTransferFilter for XcmExecutor { + type IsReserve = Config::IsReserve; + type IsTeleporter = Config::IsTeleporter; +} + #[derive(Debug)] pub struct ExecutorError { pub index: u32, diff --git a/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs b/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs new file mode 100644 index 000000000000..c8fdc582bf11 --- /dev/null +++ b/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs @@ -0,0 +1,29 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use frame_support::traits::ContainsPair; +use xcm::prelude::*; + +/// A trait for identifying asset transfer type. +pub trait AssetTransferFilter { + /// Combinations of (Asset, Location) pairs which we trust as reserves. Meaning + /// reserve-based-transfers are to be used for assets matching this filter. + type IsReserve: ContainsPair; + + /// Combinations of (Asset, Location) pairs which we trust as teleporters. Meaning teleports are + /// to be used for assets matching this filter. + type IsTeleporter: ContainsPair; +} diff --git a/polkadot/xcm/xcm-executor/src/traits/mod.rs b/polkadot/xcm/xcm-executor/src/traits/mod.rs index a9439968fa6c..201634c7bcbb 100644 --- a/polkadot/xcm/xcm-executor/src/traits/mod.rs +++ b/polkadot/xcm/xcm-executor/src/traits/mod.rs @@ -20,10 +20,12 @@ mod conversion; pub use conversion::{CallDispatcher, ConvertLocation, ConvertOrigin, WithOriginFilter}; mod drop_assets; pub use drop_assets::{ClaimAssets, DropAssets}; -mod asset_lock; -pub use asset_lock::{AssetLock, Enact, LockError}; mod asset_exchange; pub use asset_exchange::AssetExchange; +mod asset_lock; +pub use asset_lock::{AssetLock, Enact, LockError}; +mod asset_transfer; +pub use asset_transfer::AssetTransferFilter; mod export; pub use export::{export_xcm, validate_export, ExportXcm}; mod fee_manager; From ce215a1415caaa49c4b513a0d89cc6a1cdeea568 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 20 Sep 2023 15:12:47 +0300 Subject: [PATCH 03/98] xcm: MultiLocation: add .chain_location() helper function --- .../assets/test-utils/src/test_cases.rs | 2 +- polkadot/xcm/src/v3/junction.rs | 8 +++ polkadot/xcm/src/v3/multilocation.rs | 65 +++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) 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 25360171cc8f..4b5350f0e2aa 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -343,7 +343,7 @@ pub fn teleports_for_foreign_assets_works< From<::AccountId>, ForeignAssetsPalletInstance: 'static, { - // foreign parachain with the same consenus currency as asset + // foreign parachain with the same consensus currency as asset let foreign_para_id = 2222; let foreign_asset_id_multilocation = MultiLocation { parents: 1, diff --git a/polkadot/xcm/src/v3/junction.rs b/polkadot/xcm/src/v3/junction.rs index b5dd5bc7c88f..cd6d4f85dc26 100644 --- a/polkadot/xcm/src/v3/junction.rs +++ b/polkadot/xcm/src/v3/junction.rs @@ -437,6 +437,14 @@ impl Junction { _ => {}, } } + + /// Specifies whether junction identifies a chain. + pub fn is_chain_identifier(&self) -> bool { + match self { + Junction::Parachain(_) | Junction::GlobalConsensus(_) => true, + _ => false, + } + } } #[cfg(test)] diff --git a/polkadot/xcm/src/v3/multilocation.rs b/polkadot/xcm/src/v3/multilocation.rs index 8a1575d9bc95..0f226a1f1565 100644 --- a/polkadot/xcm/src/v3/multilocation.rs +++ b/polkadot/xcm/src/v3/multilocation.rs @@ -444,6 +444,20 @@ impl MultiLocation { } } } + + /// Return the MultiLocation subsection identifying the chain that `self` points to. + pub fn chain_location(mut self) -> MultiLocation { + // start popping junctions until we reach chain identifier + while let Some(j) = self.last() { + if j.is_chain_identifier() { + // return chain subsection + return self + } else { + (self, _) = self.split_last_interior(); + } + } + MultiLocation::new(self.parents, Junctions::Here) + } } impl TryFrom for MultiLocation { @@ -674,6 +688,57 @@ mod tests { assert_eq!(iter.next_back(), None); } + #[test] + fn chain_location_works() { + // Relay-chain or parachain context pointing to local resource, + let relay_to_local = MultiLocation::new(0, (PalletInstance(42), GeneralIndex(42))); + assert_eq!(relay_to_local.chain_location(), MultiLocation::here()); + + // Relay-chain context pointing to child parachain, + let relay_to_child = + MultiLocation::new(0, (Parachain(42), PalletInstance(42), GeneralIndex(42))); + let expected = MultiLocation::new(0, Parachain(42)); + assert_eq!(relay_to_child.chain_location(), expected); + + // Relay-chain context pointing to different consensus relay, + let relay_to_remote_relay = + MultiLocation::new(1, (GlobalConsensus(Kusama), PalletInstance(42), GeneralIndex(42))); + let expected = MultiLocation::new(1, GlobalConsensus(Kusama)); + assert_eq!(relay_to_remote_relay.chain_location(), expected); + + // Relay-chain context pointing to different consensus parachain, + let relay_to_remote_para = MultiLocation::new( + 1, + (GlobalConsensus(Kusama), Parachain(42), PalletInstance(42), GeneralIndex(42)), + ); + let expected = MultiLocation::new(1, (GlobalConsensus(Kusama), Parachain(42))); + assert_eq!(relay_to_remote_para.chain_location(), expected); + + // Parachain context pointing to relay chain, + let para_to_relay = MultiLocation::new(1, (PalletInstance(42), GeneralIndex(42))); + assert_eq!(para_to_relay.chain_location(), MultiLocation::parent()); + + // Parachain context pointing to sibling parachain, + let para_to_sibling = + MultiLocation::new(1, (Parachain(42), PalletInstance(42), GeneralIndex(42))); + let expected = MultiLocation::new(1, Parachain(42)); + assert_eq!(para_to_sibling.chain_location(), expected); + + // Parachain context pointing to different consensus relay, + let para_to_remote_relay = + MultiLocation::new(2, (GlobalConsensus(Kusama), PalletInstance(42), GeneralIndex(42))); + let expected = MultiLocation::new(2, GlobalConsensus(Kusama)); + assert_eq!(para_to_remote_relay.chain_location(), expected); + + // Parachain context pointing to different consensus parachain, + let para_to_remote_para = MultiLocation::new( + 2, + (GlobalConsensus(Kusama), Parachain(42), PalletInstance(42), GeneralIndex(42)), + ); + let expected = MultiLocation::new(2, (GlobalConsensus(Kusama), Parachain(42))); + assert_eq!(para_to_remote_para.chain_location(), expected); + } + #[test] fn conversion_from_other_types_works() { use crate::v2; From a5fd7460e787d8a1893aa2e47e5841a8003fc10e Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 25 Sep 2023 19:09:22 +0300 Subject: [PATCH 04/98] pallet-xcm: enchance reserve_transfer_assets() to support various reserves 'reserve_transfer_assets()' assumed all provided `assets` (fees included) have same, local reserve. This commit enhances the extrinsic to support various scenarios: - transferring assets with reserve on destination, - transferring assets with reserve on remote/third-party chain, - transferring assets with reserve different than the reserve of the asset to be used as fees - meaning can use to transfer random asset with random reserve while using DOT for fees on all involved chains, even if local chain is NOT a reserve location of DOT (aka most chains), - transferring assets with any type of local/dest/remote reserve while using fees which can be teleported between involved chains. All of the above is done by pallet inner logic without the user having to specify which scenario/reserves/teleports/etc. The correct scenario and corresponding XCM programs are identified, and respectively, built automatically based on runtime configuration of trusted teleporters and trusted reserves. Current limitations: - while `fees` and "non-fee" `assets` CAN have different reserves (or fees CAN be teleported), the remaining "non-fee" `assets` CANNOT have different reserve locations (this is also implicitly enforced by `MAX_ASSETS_FOR_TRANSFER=2`, but this can be safely increased in the future). - `fees` and "non-fee" `assets` CANNOT have **different remote** reserves (this can also be supported in the future, but adds even more complexity while possibly not being worth it - we'll see what the future holds). --- polkadot/xcm/pallet-xcm/src/lib.rs | 329 ++++++++++++++++++++++++++--- 1 file changed, 299 insertions(+), 30 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 58adb90e1729..a0788eab29fa 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -442,6 +442,10 @@ pub mod pallet { LockNotFound, /// The unlock operation cannot succeed because there are still consumers of the lock. InUse, + /// Reserve chain could not be determined for assets to be transferred. + UnknownReserve, + /// Too many assets with different reserve locations have been attempted for transfer. + TooManyReserves, } impl From for Error { @@ -1193,14 +1197,89 @@ impl QueryHandler for Pallet { } } +#[derive(Copy, Clone, PartialEq, Debug)] +enum TransferType { + Teleport, + LocalReserve, + DestinationReserve, + RemoteReserve(MultiLocation), +} + +impl TransferType { + /// Determine transfer type to be used for transferring `asset` from local chain to `dest`. + pub fn determine_for( + asset: &MultiAsset, + dest: &MultiLocation, + ) -> Result> { + if ::IsTeleporter::contains(asset, dest) { + // we trust destination for teleporting asset + return Ok(TransferType::Teleport) + } else if ::IsReserve::contains(asset, dest) { + // we trust destination as asset reserve location + return Ok(TransferType::DestinationReserve) + } + + // try to determine reserve location based on asset id/location + let asset_location = match asset.id { + Concrete(location) => Ok(location.chain_location()), + _ => Err(Error::::InvalidAsset), + }?; + if asset_location == MultiLocation::here() || + ::IsTeleporter::contains( + asset, + &asset_location, + ) { + // local asset, or remote location that allows local teleports => local reserve + Ok(TransferType::LocalReserve) + } else if ::IsReserve::contains( + asset, + &asset_location, + ) { + // remote location that is recognized as reserve location for asset + Ok(TransferType::RemoteReserve(asset_location)) + } else { + // remote location that is not configured either as teleporter or reserve => cannot + // determine asset reserve + Err(Error::::UnknownReserve) + } + } +} + impl Pallet { + /// Validate `assets` to be reserve-transferred and return their reserve location. + fn validate_assets_and_find_reserve( + assets: &[MultiAsset], + dest: &MultiLocation, + ) -> Result> { + let mut reserve = None; + for asset in assets.iter() { + // Ensure fungible asset. + ensure!( + matches!(asset.fun, Fungibility::Fungible(x) if !x.is_zero()), + Error::::InvalidAsset + ); + let transfer_type = TransferType::determine_for::(&asset, dest)?; + // Ensure asset is not teleportable to `dest`. + ensure!(transfer_type != TransferType::Teleport, Error::::Filtered); + if let Some(reserve) = reserve.as_ref() { + // Ensure transfer for multiple assets uses same reserve location (only fee may have + // different reserve location) + ensure!(reserve == &transfer_type, Error::::TooManyReserves); + } else { + // asset reserve identified + reserve = Some(transfer_type); + } + } + reserve.ok_or(Error::::Empty) + } + fn do_reserve_transfer_assets( origin: OriginFor, dest: Box, beneficiary: Box, assets: Box, fee_asset_item: u32, - weight_limit: WeightLimit, + mut weight_limit: WeightLimit, ) -> DispatchResult { let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; let dest = (*dest).try_into().map_err(|()| Error::::BadVersion)?; @@ -1211,43 +1290,215 @@ impl Pallet { 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_location, assets) = value; - // Don't allow inclusion of teleportable assets in this reserve-based-transfer (other than - // fee asset). - for (idx, asset) in assets.iter().enumerate() { - ensure!( - idx == fee_asset_item as usize || - !::IsTeleporter::contains( - asset, &dest - ), - Error::::Filtered - ); + let (origin_location, mut assets) = value; + + if fee_asset_item as usize >= assets.len() { + return Err(Error::::Empty.into()) + } + let fees = assets.swap_remove(fee_asset_item as usize); + let fees_transfer_type = TransferType::determine_for::(&fees, &dest)?; + let assets_transfer_type = if assets.is_empty() { + // Single asset to transfer (also used for fees). + fees_transfer_type.clone() + } else { + // Find reserve for non-fee assets. + Self::validate_assets_and_find_reserve(&assets, &dest)? + }; + + // Disallow (for now) different _remote_ reserves for assets and fees. + match (&fees_transfer_type, &assets_transfer_type) { + (TransferType::RemoteReserve(a), TransferType::RemoteReserve(b)) if a != b => + return Err(Error::::TooManyReserves.into()), + _ => (), + }; + + if fees_transfer_type == assets_transfer_type { + // Same reserve location (fees not teleportable), we can batch together fees and assets + // in same reserve-based-transfer. + assets.push(fees.clone()); + } else { + // Different transfer types: we have to do separate transfers for fees and assets. + // This code block handles transferring the assets *used for fees*. + + // Use only half the weight limit for fees transfer, then other half for assets + // transfer. + weight_limit = Self::halve_weight_limit(&weight_limit); + + // When assets reserve is remote chain, we need to "prefund" fees to be able to + // BuyExecution on both chains. Split fees, and deposit half at assets-reserve chain + // and half at destination. + if let TransferType::RemoteReserve(assets_reserve) = assets_transfer_type { + let (fees_for_reserve, fees_for_dest) = Self::equal_split_asset(&fees)?; + // Halve weight limit again to be used for the two fees transfers. + let quarter_weight_limit = Self::halve_weight_limit(&weight_limit); + // TODO: + // let assets_reserve_beneficiary = sov_acc_of(dest, assets_reserve); + let assets_reserve_beneficiary = beneficiary.clone(); + // Send half the `fees` to + Self::prefund_transfer_fees( + origin_location, + assets_reserve, + assets_reserve_beneficiary, + fees_for_reserve, + quarter_weight_limit.clone(), + )?; + Self::prefund_transfer_fees( + origin_location, + dest, + beneficiary, + fees_for_dest, + quarter_weight_limit, + )?; + } else { + Self::prefund_transfer_fees( + origin_location, + dest, + beneficiary, + fees.clone(), + weight_limit.clone(), + )?; + } } + // Fees have been prefunded/transferred (or batched together with assets), now do + // reserve-transfer assets. + Self::build_and_execute_xcm_transfer_type( + origin_location, + dest, + beneficiary, + assets, + assets_transfer_type, + fees, + weight_limit, + ) + } + + /// Teleport or reserve transfer `fees` - not to be used by itself, it is a helper function for + /// prefunding fees for subsequent assets transfer. + /// + /// Fees are allowed to be either teleported or reserve transferred. + fn prefund_transfer_fees( + origin: impl Into, + dest: MultiLocation, + beneficiary: MultiLocation, + asset: MultiAsset, + weight_limit: WeightLimit, + ) -> DispatchResult { + // TODO + Ok(()) + } + + fn build_and_execute_xcm_transfer_type( + origin: impl Into, + dest: MultiLocation, + beneficiary: MultiLocation, + assets: Vec, + transfer_type: TransferType, + fees: MultiAsset, + weight_limit: WeightLimit, + ) -> DispatchResult { + let mut message = match transfer_type { + TransferType::LocalReserve => + Self::local_reserve_transfer_message(dest, beneficiary, assets, fees, weight_limit), + TransferType::DestinationReserve => Self::destination_reserve_transfer_message( + dest, + beneficiary, + assets, + fees, + weight_limit, + ), + TransferType::RemoteReserve(reserve) => Self::remote_reserve_transfer_message( + reserve, + dest, + beneficiary, + assets, + fees, + weight_limit, + ), + TransferType::Teleport => todo!(), + }?; + let weight = + T::Weigher::weight(&mut message).map_err(|()| Error::::UnweighableMessage)?; + let hash = message.using_encoded(sp_io::hashing::blake2_256); + let outcome = T::XcmExecutor::execute_xcm_in_credit(origin, message, hash, weight, weight); + Self::deposit_event(Event::Attempted { outcome }); + Ok(()) + } + + fn local_reserve_transfer_message( + dest: MultiLocation, + beneficiary: MultiLocation, + assets: Vec, + fees: MultiAsset, + weight_limit: WeightLimit, + ) -> Result::RuntimeCall>, Error> { let context = T::UniversalLocation::get(); - let fees = assets - .get(fee_asset_item as usize) - .ok_or(Error::::Empty)? - .clone() - .reanchored(&dest, context) - .map_err(|_| Error::::CannotReanchor)?; + let fees = fees.reanchored(&dest, context).map_err(|_| Error::::CannotReanchor)?; let max_assets = assets.len() as u32; - let assets: MultiAssets = assets.into(); - let xcm = Xcm(vec![ + let xcm_on_dest = Xcm(vec![ BuyExecution { fees, weight_limit }, DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, ]); - let mut message = Xcm(vec![ + Ok(Xcm(vec![ SetFeesMode { jit_withdraw: true }, - TransferReserveAsset { assets, dest, xcm }, - ]); - let weight = - T::Weigher::weight(&mut message).map_err(|()| Error::::UnweighableMessage)?; - let hash = message.using_encoded(sp_io::hashing::blake2_256); - let outcome = - T::XcmExecutor::execute_xcm_in_credit(origin_location, message, hash, weight, weight); - Self::deposit_event(Event::Attempted { outcome }); - Ok(()) + TransferReserveAsset { assets: assets.into(), dest, xcm: xcm_on_dest }, + ])) + } + + fn destination_reserve_transfer_message( + dest: MultiLocation, + beneficiary: MultiLocation, + assets: Vec, + fees: MultiAsset, + weight_limit: WeightLimit, + ) -> Result::RuntimeCall>, Error> { + // let context = T::UniversalLocation::get(); + // let fees = assets.get(fee_asset_item as usize).reanchored(&dest, context); + // Ok(Xcm(vec![ + // WithdrawAsset(assets), + // InitiateReserveWithdraw { + // assets: Wild(AllCounted(max_assets)), + // reserve: dest, + // xcm: Xcm(vec![ + // BuyExecution { fees, weight_limit }, + // DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, + // ]), + // }, + // ])) + todo!() + } + + fn remote_reserve_transfer_message( + reserve: MultiLocation, + dest: MultiLocation, + beneficiary: MultiLocation, + assets: Vec, + fees: MultiAsset, + weight_limit: WeightLimit, + ) -> Result::RuntimeCall>, Error> { + // let context = T::UniversalLocation::get(); + // let reserve_fees = assets.get(fee_asset_item as usize).reanchored(&reserve, context); + // let dest_fees = assets.get(fee_asset_item as usize).reanchored(&dest, context); + // let dest = dest.reanchored(&reserve, context); + // Ok(Xcm(vec![ + // WithdrawAsset(assets), + // InitiateReserveWithdraw { + // assets: Wild(AllCounted(max_assets)), + // reserve, + // xcm: Xcm(vec![ + // BuyExecution { fees: reserve_fees, weight_limit }, + // DepositReserveAsset { + // assets: Wild(AllCounted(max_assets)), + // dest, + // xcm: Xcm(vec![ + // BuyExecution { fees: dest_fees, weight_limit }, + // DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, + // ]), + // }, + // ]), + // }, + // ])) + todo!() } fn do_teleport_assets( @@ -1635,6 +1886,24 @@ impl Pallet { Self::deposit_event(Event::FeesPaid { paying: location, fees: assets }); Ok(()) } + + /// Return `WeightLimit` with half the given weight `limit`. + fn halve_weight_limit(limit: &WeightLimit) -> WeightLimit { + match limit { + Unlimited => Unlimited, + Limited(w) => Limited(w.saturating_div(2)), + } + } + + /// Split fungible `asset` in two equal `MultiAsset`s. + fn equal_split_asset(asset: &MultiAsset) -> Result<(MultiAsset, MultiAsset), Error> { + let half_amount = match &asset.fun { + Fungible(amount) => amount.saturating_div(2), + NonFungible(_) => return Err(Error::::InvalidAsset), + }; + let half = MultiAsset { fun: Fungible(half_amount), id: asset.id }; + Ok((half.clone(), half)) + } } pub struct LockTicket { From c581d763cfc9b154003cb611c88981b35776226e Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 25 Sep 2023 19:55:36 +0300 Subject: [PATCH 05/98] use correct fees beneficiary on assets reserve chain --- polkadot/xcm/pallet-xcm/src/lib.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index a0788eab29fa..98b30d212f1e 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1331,10 +1331,12 @@ impl Pallet { let (fees_for_reserve, fees_for_dest) = Self::equal_split_asset(&fees)?; // Halve weight limit again to be used for the two fees transfers. let quarter_weight_limit = Self::halve_weight_limit(&weight_limit); - // TODO: - // let assets_reserve_beneficiary = sov_acc_of(dest, assets_reserve); - let assets_reserve_beneficiary = beneficiary.clone(); - // Send half the `fees` to + let context = T::UniversalLocation::get(); + // Send half the `fees` to the Sovereign Account of `dest` on assets-reserve chain. + let assets_reserve_beneficiary = dest + .clone() + .reanchored(&assets_reserve, context) + .map_err(|_| Error::::CannotReanchor)?; Self::prefund_transfer_fees( origin_location, assets_reserve, From fe52d4807f9d27348e394910f93445debc7aa718 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 26 Sep 2023 14:44:44 +0300 Subject: [PATCH 06/98] build dest-reserve and remote-reserve XCM programs --- polkadot/xcm/pallet-xcm/src/lib.rs | 104 ++++++++++++++++------------- 1 file changed, 57 insertions(+), 47 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 98b30d212f1e..7ae28d43f495 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1352,6 +1352,10 @@ impl Pallet { quarter_weight_limit, )?; } else { + if let TransferType::RemoteReserve(_fees_reserve) = fees_transfer_type { + // TODO: change beneficiary on `fee_reserve` to be SA-of-Here. + // But beneficiary on `dest` should stay unchanged... + } Self::prefund_transfer_fees( origin_location, dest, @@ -1380,14 +1384,13 @@ impl Pallet { /// /// Fees are allowed to be either teleported or reserve transferred. fn prefund_transfer_fees( - origin: impl Into, - dest: MultiLocation, - beneficiary: MultiLocation, - asset: MultiAsset, - weight_limit: WeightLimit, + _origin: impl Into, + _dest: MultiLocation, + _beneficiary: MultiLocation, + _asset: MultiAsset, + _weight_limit: WeightLimit, ) -> DispatchResult { - // TODO - Ok(()) + todo!() } fn build_and_execute_xcm_transfer_type( @@ -1431,11 +1434,11 @@ impl Pallet { dest: MultiLocation, beneficiary: MultiLocation, assets: Vec, - fees: MultiAsset, + mut fees: MultiAsset, weight_limit: WeightLimit, ) -> Result::RuntimeCall>, Error> { let context = T::UniversalLocation::get(); - let fees = fees.reanchored(&dest, context).map_err(|_| Error::::CannotReanchor)?; + fees.reanchor(&dest, context).map_err(|_| Error::::CannotReanchor)?; let max_assets = assets.len() as u32; let xcm_on_dest = Xcm(vec![ BuyExecution { fees, weight_limit }, @@ -1451,23 +1454,24 @@ impl Pallet { dest: MultiLocation, beneficiary: MultiLocation, assets: Vec, - fees: MultiAsset, + mut fees: MultiAsset, weight_limit: WeightLimit, ) -> Result::RuntimeCall>, Error> { - // let context = T::UniversalLocation::get(); - // let fees = assets.get(fee_asset_item as usize).reanchored(&dest, context); - // Ok(Xcm(vec![ - // WithdrawAsset(assets), - // InitiateReserveWithdraw { - // assets: Wild(AllCounted(max_assets)), - // reserve: dest, - // xcm: Xcm(vec![ - // BuyExecution { fees, weight_limit }, - // DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, - // ]), - // }, - // ])) - todo!() + let context = T::UniversalLocation::get(); + fees.reanchor(&dest, context).map_err(|_| Error::::CannotReanchor)?; + let max_assets = assets.len() as u32; + let xcm_on_dest = Xcm(vec![ + BuyExecution { fees, weight_limit }, + DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, + ]); + Ok(Xcm(vec![ + WithdrawAsset(assets.into()), + InitiateReserveWithdraw { + assets: Wild(AllCounted(max_assets)), + reserve: dest, + xcm: xcm_on_dest, + }, + ])) } fn remote_reserve_transfer_message( @@ -1478,29 +1482,35 @@ impl Pallet { fees: MultiAsset, weight_limit: WeightLimit, ) -> Result::RuntimeCall>, Error> { - // let context = T::UniversalLocation::get(); - // let reserve_fees = assets.get(fee_asset_item as usize).reanchored(&reserve, context); - // let dest_fees = assets.get(fee_asset_item as usize).reanchored(&dest, context); - // let dest = dest.reanchored(&reserve, context); - // Ok(Xcm(vec![ - // WithdrawAsset(assets), - // InitiateReserveWithdraw { - // assets: Wild(AllCounted(max_assets)), - // reserve, - // xcm: Xcm(vec![ - // BuyExecution { fees: reserve_fees, weight_limit }, - // DepositReserveAsset { - // assets: Wild(AllCounted(max_assets)), - // dest, - // xcm: Xcm(vec![ - // BuyExecution { fees: dest_fees, weight_limit }, - // DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, - // ]), - // }, - // ]), - // }, - // ])) - todo!() + let max_assets = assets.len() as u32; + let context = T::UniversalLocation::get(); + // identifies fee item as seen by `reserve` - to be used at reserve chain + let reserve_fees = fees + .clone() + .reanchored(&reserve, context) + .map_err(|_| Error::::CannotReanchor)?; + // identifies fee item as seen by `dest` - to be used at destination chain + let dest_fees = fees.reanchored(&dest, context).map_err(|_| Error::::CannotReanchor)?; + // identifies `dest` as seen by `reserve` + let dest = dest.reanchored(&reserve, context).map_err(|_| Error::::CannotReanchor)?; + // xcm to be executed at dest + let xcm_on_dest = Xcm(vec![ + BuyExecution { fees: dest_fees, weight_limit: weight_limit.clone() }, + DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, + ]); + // xcm to be executed on reserve + let xcm_on_reserve = Xcm(vec![ + BuyExecution { fees: reserve_fees, weight_limit }, + DepositReserveAsset { assets: Wild(AllCounted(max_assets)), dest, xcm: xcm_on_dest }, + ]); + Ok(Xcm(vec![ + WithdrawAsset(assets.into()), + InitiateReserveWithdraw { + assets: Wild(AllCounted(max_assets)), + reserve, + xcm: xcm_on_reserve, + }, + ])) } fn do_teleport_assets( From 5d847e35f02a823585700752d55fca9f0d8bb8f5 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 26 Sep 2023 15:12:27 +0300 Subject: [PATCH 07/98] deduplicate teleport and reserve transfer tests --- polkadot/xcm/pallet-xcm/src/mock.rs | 4 +- polkadot/xcm/pallet-xcm/src/tests.rs | 274 +++++++++------------------ 2 files changed, 90 insertions(+), 188 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index b09bcb80ed67..9895249148ef 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -370,10 +370,10 @@ pub(crate) fn buy_execution(fees: impl Into) -> Instruction { pub(crate) fn buy_limited_execution( fees: impl Into, - weight: Weight, + weight_limit: WeightLimit, ) -> Instruction { use xcm::latest::prelude::*; - BuyExecution { fees: fees.into(), weight_limit: Limited(weight) } + BuyExecution { fees: fees.into(), weight_limit } } pub(crate) fn new_test_ext_with_balances( diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index 5d8aee8d665f..522ca00a2886 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -346,12 +346,12 @@ fn send_fails_when_xcm_router_blocks() { }); } -/// Test `teleport_assets` -/// -/// Asserts that the sender's balance is decreased as a result of execution of -/// local effects. -#[test] -fn teleport_assets_works() { +// Helper function to deduplicate testing different teleport types. +fn do_test_and_verify_teleport_assets( + dest: MultiLocation, + call: Call, + expected_weight_limit: WeightLimit, +) { let balances = vec![ (ALICE, INITIAL_BALANCE), (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), @@ -359,14 +359,8 @@ fn teleport_assets_works() { new_test_ext_with_balances(balances).execute_with(|| { let weight = BaseXcmWeight::get() * 3; assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); - let dest: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into(); - assert_ok!(XcmPallet::teleport_assets( - RuntimeOrigin::signed(ALICE), - Box::new(RelayLocation::get().into()), - Box::new(dest.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - )); + // call extrinsic + call(); assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); assert_eq!( sent_xcm(), @@ -375,7 +369,7 @@ fn teleport_assets_works() { Xcm(vec![ ReceiveTeleportedAsset((Here, SEND_AMOUNT).into()), ClearOrigin, - buy_execution((Here, SEND_AMOUNT)), + buy_limited_execution((Here, SEND_AMOUNT), expected_weight_limit), DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, ]), )] @@ -389,113 +383,68 @@ fn teleport_assets_works() { }); } -/// Test `limited_teleport_assets` +/// Test `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 balances = vec![ - (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), - ]; - new_test_ext_with_balances(balances).execute_with(|| { - let weight = BaseXcmWeight::get() * 3; - assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); - let dest: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into(); - assert_ok!(XcmPallet::limited_teleport_assets( - RuntimeOrigin::signed(ALICE), - Box::new(RelayLocation::get().into()), - Box::new(dest.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - WeightLimit::Limited(Weight::from_parts(5000, 5000)), - )); - assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); - assert_eq!( - sent_xcm(), - vec![( - RelayLocation::get().into(), - Xcm(vec![ - ReceiveTeleportedAsset((Here, SEND_AMOUNT).into()), - ClearOrigin, - buy_limited_execution((Here, SEND_AMOUNT), Weight::from_parts(5000, 5000)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, - ]), - )] - ); - let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); - let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); - assert_eq!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) - ); - }); +fn teleport_assets_works() { + let dest: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into(); + do_test_and_verify_teleport_assets( + dest, + || { + assert_ok!(XcmPallet::teleport_assets( + RuntimeOrigin::signed(ALICE), + Box::new(RelayLocation::get().into()), + Box::new(dest.into()), + Box::new((Here, SEND_AMOUNT).into()), + 0, + )); + }, + Unlimited, + ); } -/// Test `limited_teleport_assets` with unlimited weight +/// Test `limited_teleport_assets` /// /// Asserts that the sender's balance is decreased as a result of execution of /// local effects. #[test] -fn unlimited_teleport_assets_works() { - let balances = vec![ - (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), - ]; - new_test_ext_with_balances(balances).execute_with(|| { - let weight = BaseXcmWeight::get() * 3; - assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); - let dest: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into(); - assert_ok!(XcmPallet::limited_teleport_assets( - RuntimeOrigin::signed(ALICE), - Box::new(RelayLocation::get().into()), - Box::new(dest.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - WeightLimit::Unlimited, - )); - assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); - assert_eq!( - sent_xcm(), - vec![( - RelayLocation::get().into(), - Xcm(vec![ - ReceiveTeleportedAsset((Here, SEND_AMOUNT).into()), - ClearOrigin, - buy_execution((Here, SEND_AMOUNT)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, - ]), - )] - ); - assert_eq!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) - ); - }); +fn limited_teleport_assets_works() { + let dest: MultiLocation = 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( + dest, + || { + assert_ok!(XcmPallet::limited_teleport_assets( + RuntimeOrigin::signed(ALICE), + Box::new(RelayLocation::get().into()), + Box::new(dest.into()), + Box::new((Here, SEND_AMOUNT).into()), + 0, + weight_limit, + )); + }, + expected_weight_limit, + ); } -/// Test `reserve_transfer_assets` -/// -/// Asserts that the sender's balance is decreased and the beneficiary's balance -/// is increased. Verifies the correct message is sent and event is emitted. -#[test] -fn reserve_transfer_assets_works() { +// Helper function to deduplicate testing different reserve-transfer types. +fn do_test_and_verify_reserve_transfer_assets( + dest: MultiLocation, + call: Call, + expected_weight_limit: WeightLimit, +) { let balances = vec![ (ALICE, INITIAL_BALANCE), (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; new_test_ext_with_balances(balances).execute_with(|| { let weight = BaseXcmWeight::get() * 2; - let dest: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); - assert_ok!(XcmPallet::reserve_transfer_assets( - RuntimeOrigin::signed(ALICE), - Box::new(Parachain(PARA_ID).into()), - Box::new(dest.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - )); + // call extrinsic + call(); // Alice spent amount assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); // Destination account (parachain account) has amount @@ -508,7 +457,7 @@ fn reserve_transfer_assets_works() { Xcm(vec![ ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), ClearOrigin, - buy_execution((Parent, SEND_AMOUNT)), + buy_limited_execution((Parent, SEND_AMOUNT), expected_weight_limit), DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, ]), )] @@ -522,98 +471,51 @@ fn reserve_transfer_assets_works() { }); } -/// Test `limited_reserve_transfer_assets` +/// Test `reserve_transfer_assets` /// /// Asserts that the sender's balance is decreased and the beneficiary's balance /// is increased. Verifies the correct message is sent and event is emitted. #[test] -fn limited_reserve_transfer_assets_works() { - let balances = vec![ - (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), - ]; - new_test_ext_with_balances(balances).execute_with(|| { - let weight = BaseXcmWeight::get() * 2; - let dest: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); - assert_ok!(XcmPallet::limited_reserve_transfer_assets( - RuntimeOrigin::signed(ALICE), - Box::new(Parachain(PARA_ID).into()), - Box::new(dest.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - WeightLimit::Limited(Weight::from_parts(5000, 5000)), - )); - // Alice spent amount - assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); - // Destination account (parachain account) has amount - let para_acc: AccountId = ParaId::from(PARA_ID).into_account_truncating(); - assert_eq!(Balances::free_balance(para_acc), INITIAL_BALANCE + SEND_AMOUNT); - assert_eq!( - sent_xcm(), - vec![( - Parachain(PARA_ID).into(), - Xcm(vec![ - ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), - ClearOrigin, - buy_limited_execution((Parent, SEND_AMOUNT), Weight::from_parts(5000, 5000)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, - ]), - )] - ); - let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); - let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); - assert_eq!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) - ); - }); +fn reserve_transfer_assets_works() { + let dest: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + do_test_and_verify_reserve_transfer_assets( + dest, + || { + assert_ok!(XcmPallet::reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(Parachain(PARA_ID).into()), + Box::new(dest.into()), + Box::new((Here, SEND_AMOUNT).into()), + 0, + )); + }, + Unlimited, + ); } -/// Test `limited_reserve_transfer_assets` with unlimited weight purchasing +/// Test `limited_reserve_transfer_assets` /// /// Asserts that the sender's balance is decreased and the beneficiary's balance /// is increased. Verifies the correct message is sent and event is emitted. #[test] -fn unlimited_reserve_transfer_assets_works() { - let balances = vec![ - (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), - ]; - new_test_ext_with_balances(balances).execute_with(|| { - let weight = BaseXcmWeight::get() * 2; - let dest: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); - assert_ok!(XcmPallet::limited_reserve_transfer_assets( - RuntimeOrigin::signed(ALICE), - Box::new(Parachain(PARA_ID).into()), - Box::new(dest.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - WeightLimit::Unlimited, - )); - // Alice spent amount - assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); - // Destination account (parachain account) has amount - let para_acc: AccountId = ParaId::from(PARA_ID).into_account_truncating(); - assert_eq!(Balances::free_balance(para_acc), INITIAL_BALANCE + SEND_AMOUNT); - assert_eq!( - sent_xcm(), - vec![( - Parachain(PARA_ID).into(), - Xcm(vec![ - ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), - ClearOrigin, - buy_execution((Parent, SEND_AMOUNT)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, - ]), - )] - ); - assert_eq!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) - ); - }); +fn limited_reserve_transfer_assets_works() { + let dest: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let weight_limit = WeightLimit::Limited(Weight::from_parts(5000, 5000)); + let expected_weight_limit = weight_limit.clone(); + do_test_and_verify_reserve_transfer_assets( + dest, + || { + assert_ok!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(Parachain(PARA_ID).into()), + Box::new(dest.into()), + Box::new((Here, SEND_AMOUNT).into()), + 0, + weight_limit, + )); + }, + expected_weight_limit, + ); } /// Test local execution of XCM From 026a779fe21bb53f6c2dcd71de7fc60e642b7e5c Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 26 Sep 2023 15:46:19 +0300 Subject: [PATCH 08/98] add test cases plan --- polkadot/xcm/pallet-xcm/src/lib.rs | 3 +- polkadot/xcm/pallet-xcm/src/tests.rs | 171 +++++++++++++++++++++++---- 2 files changed, 149 insertions(+), 25 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 7ae28d43f495..c23f08198aaf 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1299,7 +1299,7 @@ impl Pallet { let fees_transfer_type = TransferType::determine_for::(&fees, &dest)?; let assets_transfer_type = if assets.is_empty() { // Single asset to transfer (also used for fees). - fees_transfer_type.clone() + fees_transfer_type } else { // Find reserve for non-fee assets. Self::validate_assets_and_find_reserve(&assets, &dest)? @@ -1334,7 +1334,6 @@ impl Pallet { let context = T::UniversalLocation::get(); // Send half the `fees` to the Sovereign Account of `dest` on assets-reserve chain. let assets_reserve_beneficiary = dest - .clone() .reanchored(&assets_reserve, context) .map_err(|_| Error::::CannotReanchor)?; Self::prefund_transfer_fees( diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index 522ca00a2886..cce09f2af9a2 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -348,7 +348,7 @@ fn send_fails_when_xcm_router_blocks() { // Helper function to deduplicate testing different teleport types. fn do_test_and_verify_teleport_assets( - dest: MultiLocation, + expected_beneficiary: MultiLocation, call: Call, expected_weight_limit: WeightLimit, ) { @@ -370,7 +370,10 @@ fn do_test_and_verify_teleport_assets( ReceiveTeleportedAsset((Here, SEND_AMOUNT).into()), ClearOrigin, buy_limited_execution((Here, SEND_AMOUNT), expected_weight_limit), - DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, + DepositAsset { + assets: AllCounted(1).into(), + beneficiary: expected_beneficiary + }, ]), )] ); @@ -389,14 +392,14 @@ fn do_test_and_verify_teleport_assets( /// local effects. #[test] fn teleport_assets_works() { - let dest: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into(); + let beneficiary: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into(); do_test_and_verify_teleport_assets( - dest, + beneficiary, || { assert_ok!(XcmPallet::teleport_assets( RuntimeOrigin::signed(ALICE), Box::new(RelayLocation::get().into()), - Box::new(dest.into()), + Box::new(beneficiary.into()), Box::new((Here, SEND_AMOUNT).into()), 0, )); @@ -411,16 +414,16 @@ fn teleport_assets_works() { /// local effects. #[test] fn limited_teleport_assets_works() { - let dest: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into(); + let beneficiary: MultiLocation = 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( - dest, + beneficiary, || { assert_ok!(XcmPallet::limited_teleport_assets( RuntimeOrigin::signed(ALICE), Box::new(RelayLocation::get().into()), - Box::new(dest.into()), + Box::new(beneficiary.into()), Box::new((Here, SEND_AMOUNT).into()), 0, weight_limit, @@ -430,9 +433,27 @@ fn limited_teleport_assets_works() { ); } +// For reserve-based transfers, we want to support: +// - non-fee assets reserve: +// - local reserve +// - destination reserve +// - remote reserve +// - fee assests: +// - reserve-transferred with reserve: +// - local reserve +// - destination reserve +// - remote reserve +// - teleported +// +// Bringing unique scenarios total to 3*4 = 12. So, following reserve-transfer tests try to cover +// the happy-case for each of these 12 scenarios. +// +// TODO: also add negative tests for testing various error conditions. + // Helper function to deduplicate testing different reserve-transfer types. -fn do_test_and_verify_reserve_transfer_assets( - dest: MultiLocation, +// Currently hardcoded for AssetsReserve=Local and FeeReserve=Local. +fn do_test_and_verify_reserve_transfer_assets_local_ar_local_fr( + expected_beneficiary: MultiLocation, call: Call, expected_weight_limit: WeightLimit, ) { @@ -458,7 +479,10 @@ fn do_test_and_verify_reserve_transfer_assets( ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), ClearOrigin, buy_limited_execution((Parent, SEND_AMOUNT), expected_weight_limit), - DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, + DepositAsset { + assets: AllCounted(1).into(), + beneficiary: expected_beneficiary + }, ]), )] ); @@ -471,20 +495,21 @@ fn do_test_and_verify_reserve_transfer_assets( }); } -/// Test `reserve_transfer_assets` +/// Test `reserve_transfer_assets` with local asset reserve and local fee reserve. /// /// Asserts that the sender's balance is decreased and the beneficiary's balance /// is increased. Verifies the correct message is sent and event is emitted. #[test] -fn reserve_transfer_assets_works() { - let dest: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - do_test_and_verify_reserve_transfer_assets( - dest, +fn reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserve_works() { + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + do_test_and_verify_reserve_transfer_assets_local_ar_local_fr( + beneficiary, || { assert_ok!(XcmPallet::reserve_transfer_assets( RuntimeOrigin::signed(ALICE), Box::new(Parachain(PARA_ID).into()), - Box::new(dest.into()), + Box::new(beneficiary.into()), Box::new((Here, SEND_AMOUNT).into()), 0, )); @@ -493,22 +518,23 @@ fn reserve_transfer_assets_works() { ); } -/// Test `limited_reserve_transfer_assets` +/// Test `limited_reserve_transfer_assets` with local asset reserve and local fee reserve. /// /// Asserts that the sender's balance is decreased and the beneficiary's balance /// is increased. Verifies the correct message is sent and event is emitted. #[test] -fn limited_reserve_transfer_assets_works() { - let dest: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); +fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserve_works() { + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); let weight_limit = WeightLimit::Limited(Weight::from_parts(5000, 5000)); let expected_weight_limit = weight_limit.clone(); - do_test_and_verify_reserve_transfer_assets( - dest, + do_test_and_verify_reserve_transfer_assets_local_ar_local_fr( + beneficiary, || { assert_ok!(XcmPallet::limited_reserve_transfer_assets( RuntimeOrigin::signed(ALICE), Box::new(Parachain(PARA_ID).into()), - Box::new(dest.into()), + Box::new(beneficiary.into()), Box::new((Here, SEND_AMOUNT).into()), 0, weight_limit, @@ -518,6 +544,105 @@ fn limited_reserve_transfer_assets_works() { ); } +/// Test `reserve_transfer_assets` with destination asset reserve and local fee reserve. +/// +/// Asserts that the sender's balance is decreased and the beneficiary's balance +/// is increased. Verifies the correct message is sent and event is emitted. +#[test] +fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_works() { + todo!() +} + +/// Test `reserve_transfer_assets` with remote asset reserve and local fee reserve. +/// +/// Asserts that the sender's balance is decreased and the beneficiary's balance +/// is increased. Verifies the correct message is sent and event is emitted. +#[test] +fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_works() { + todo!() +} + +/// Test `reserve_transfer_assets` with local asset reserve and destination fee reserve. +/// +/// Asserts that the sender's balance is decreased and the beneficiary's balance +/// is increased. Verifies the correct message is sent and event is emitted. +#[test] +fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_works() { + todo!() +} + +/// Test `reserve_transfer_assets` with destination asset reserve and destination fee reserve. +/// +/// Asserts that the sender's balance is decreased and the beneficiary's balance +/// is increased. Verifies the correct message is sent and event is emitted. +#[test] +fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_reserve_works() { + todo!() +} + +/// Test `reserve_transfer_assets` with remote asset reserve and destination fee reserve. +/// +/// Asserts that the sender's balance is decreased and the beneficiary's balance +/// is increased. Verifies the correct message is sent and event is emitted. +#[test] +fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve_works() { + todo!() +} + +/// Test `reserve_transfer_assets` with local asset reserve and remote fee reserve. +/// +/// Asserts that the sender's balance is decreased and the beneficiary's balance +/// is increased. Verifies the correct message is sent and event is emitted. +#[test] +fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works() { + todo!() +} + +/// Test `reserve_transfer_assets` with destination asset reserve and local fee reserve. +/// +/// Asserts that the sender's balance is decreased and the beneficiary's balance +/// is increased. Verifies the correct message is sent and event is emitted. +#[test] +fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve_works() { + todo!() +} + +/// Test `reserve_transfer_assets` with remote asset reserve and local fee reserve. +/// +/// Asserts that the sender's balance is decreased and the beneficiary's balance +/// is increased. Verifies the correct message is sent and event is emitted. +#[test] +fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_works() { + todo!() +} + +/// Test `reserve_transfer_assets` with local asset reserve and teleported fee. +/// +/// Asserts that the sender's balance is decreased and the beneficiary's balance +/// is increased. Verifies the correct message is sent and event is emitted. +#[test] +fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { + todo!() +} + +/// Test `reserve_transfer_assets` with destination asset reserve and teleported fee. +/// +/// Asserts that the sender's balance is decreased and the beneficiary's balance +/// is increased. Verifies the correct message is sent and event is emitted. +#[test] +fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_works() { + todo!() +} + +/// Test `reserve_transfer_assets` with remote asset reserve and teleported fee. +/// +/// Asserts that the sender's balance is decreased and the beneficiary's balance +/// is increased. Verifies the correct message is sent and event is emitted. +#[test] +fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_works() { + todo!() +} + /// Test local execution of XCM /// /// Asserts that the sender's balance is decreased and the beneficiary's balance From 4465c6535c4837fb3df4e3367bd26dfab663fe09 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 26 Sep 2023 17:05:11 +0300 Subject: [PATCH 09/98] add pallet-assets to mock test runtime --- Cargo.lock | 1 + polkadot/xcm/pallet-xcm/Cargo.toml | 3 +++ polkadot/xcm/pallet-xcm/src/mock.rs | 26 +++++++++++++++++++++++++- polkadot/xcm/pallet-xcm/src/tests.rs | 4 ++-- 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a3a59c270c47..8a7168b86388 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10662,6 +10662,7 @@ dependencies = [ "frame-support", "frame-system", "log", + "pallet-assets", "pallet-balances", "parity-scale-codec", "polkadot-parachain-primitives", diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index 4946a8d11ce9..2b45c984728a 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -25,6 +25,7 @@ xcm = { package = "staging-xcm", path = "..", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false } [dev-dependencies] +pallet-assets = { path = "../../../substrate/frame/assets" } pallet-balances = { path = "../../../substrate/frame/balances" } polkadot-runtime-parachains = { path = "../../runtime/parachains" } polkadot-parachain-primitives = { path = "../../parachain" } @@ -51,6 +52,7 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", @@ -61,6 +63,7 @@ runtime-benchmarks = [ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", + "pallet-assets/try-runtime", "pallet-balances/try-runtime", "polkadot-runtime-parachains/try-runtime", "sp-runtime/try-runtime", diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 9895249148ef..6884e201944e 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -17,7 +17,7 @@ use codec::Encode; use frame_support::{ construct_runtime, parameter_types, - traits::{ConstU32, Everything, Nothing}, + traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, Everything, Nothing}, weights::Weight, }; use frame_system::EnsureRoot; @@ -135,6 +135,7 @@ construct_runtime!( { System: frame_system::{Pallet, Call, Storage, Config, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + Assets: pallet_assets::{Pallet, Call, Storage, Config, Event}, ParasOrigin: origin::{Pallet, Origin}, XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event, Origin, Config}, TestNotifier: pallet_test_notifier::{Pallet, Call, Event}, @@ -245,6 +246,29 @@ impl pallet_balances::Config for Test { type MaxFreezes = ConstU32<0>; } +impl pallet_assets::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Balance = u64; + type AssetId = u32; + type AssetIdParameter = u32; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = EnsureRoot; + type AssetDeposit = ConstU128<1>; + type AssetAccountDeposit = ConstU128<10>; + type MetadataDepositBase = ConstU128<1>; + type MetadataDepositPerByte = ConstU128<1>; + type ApprovalDeposit = ConstU128<1>; + type StringLimit = ConstU32<50>; + type Freezer = (); + type WeightInfo = (); + type CallbackHandle = (); + type Extra = (); + type RemoveItemsLimit = ConstU32<5>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); +} + parameter_types! { pub const RelayLocation: MultiLocation = Here.into_location(); pub const AnyNetwork: Option = None; diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index cce09f2af9a2..17374814c19d 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -75,7 +75,7 @@ fn report_outcome_notify_works() { let querier: MultiLocation = Here.into(); let status = QueryStatus::Pending { responder: MultiLocation::from(Parachain(PARA_ID)).into(), - maybe_notify: Some((4, 2)), + maybe_notify: Some((5, 2)), timeout: 100, maybe_match_querier: Some(querier.into()), }; @@ -105,7 +105,7 @@ fn report_outcome_notify_works() { )), RuntimeEvent::XcmPallet(crate::Event::Notified { query_id: 0, - pallet_index: 4, + pallet_index: 5, call_index: 2 }), ] From 2392dd915a662a499865cebe954786e335688ea4 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 26 Sep 2023 17:53:28 +0300 Subject: [PATCH 10/98] fix add assets to mock pallet-xcm runtime --- polkadot/xcm/pallet-xcm/src/mock.rs | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 6884e201944e..f1a60c7ed34a 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -31,8 +31,8 @@ use xcm_builder::{ AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, Case, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible, - FixedWeightBounds, IsConcrete, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, + FixedWeightBounds, IsConcrete, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, }; use xcm_executor::XcmExecutor; @@ -249,8 +249,8 @@ impl pallet_balances::Config for Test { impl pallet_assets::Config for Test { type RuntimeEvent = RuntimeEvent; type Balance = u64; - type AssetId = u32; - type AssetIdParameter = u32; + type AssetId = MultiLocation; + type AssetIdParameter = MultiLocation; type Currency = Balances; type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = EnsureRoot; @@ -276,8 +276,11 @@ parameter_types! { pub UnitWeightCost: u64 = 1_000; } -pub type SovereignAccountOf = - (ChildParachainConvertsVia, AccountId32Aliases); +pub type SovereignAccountOf = ( + ChildParachainConvertsVia, + AccountId32Aliases, + SiblingParachainConvertsVia, +); pub type LocalAssetTransactor = XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>; @@ -289,10 +292,19 @@ type LocalOriginConverter = ( ChildSystemParachainAsSuperuser, ); +// This sibling parachain acts as trusted reserve for its assets in tests. +pub const RESERVE_PARA_ID: u32 = 2001; +// This sibling parachain is not configured as trusted reserve or teleport location for any assets. +pub const OTHER_PARA_ID: u32 = 2009; + parameter_types! { pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000); pub CurrencyPerSecondPerByte: (AssetId, u128, u128) = (Concrete(RelayLocation::get()), 1, 1); pub TrustedAssets: (MultiAssetFilter, MultiLocation) = (All.into(), Here.into()); + pub TrustedReserves: (MultiAssetFilter, MultiLocation) = ( + All.into(), + MultiLocation { parents: 1, interior: X1(Parachain(RESERVE_PARA_ID)) } + ); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; } @@ -310,7 +322,7 @@ impl xcm_executor::Config for XcmConfig { type XcmSender = TestSendXcm; type AssetTransactor = LocalAssetTransactor; type OriginConverter = LocalOriginConverter; - type IsReserve = (); + type IsReserve = Case; type IsTeleporter = Case; type UniversalLocation = UniversalLocation; type Barrier = Barrier; From 67daafe2f903f4f14340a9046b3f74fd677ff88d Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 27 Sep 2023 13:30:57 +0300 Subject: [PATCH 11/98] add test for asset-reserve and fee-reserve both at destination --- polkadot/xcm/pallet-xcm/src/mock.rs | 66 ++++++++++++---- polkadot/xcm/pallet-xcm/src/tests.rs | 111 ++++++++++++++++++++++++--- 2 files changed, 150 insertions(+), 27 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index f1a60c7ed34a..d951520f926d 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -17,7 +17,9 @@ use codec::Encode; use frame_support::{ construct_runtime, parameter_types, - traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, Everything, Nothing}, + traits::{ + AsEnsureOriginWithArg, ConstU128, ConstU32, Contains, Everything, EverythingBut, Nothing, + }, weights::Weight, }; use frame_system::EnsureRoot; @@ -31,12 +33,16 @@ use xcm_builder::{ AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, Case, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible, - FixedWeightBounds, IsConcrete, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + FixedWeightBounds, FungiblesAdapter, IsConcrete, MatchedConvertedConcreteId, NoChecking, + SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, +}; +use xcm_executor::{ + traits::{Identity, JustTry}, + XcmExecutor, }; -use xcm_executor::XcmExecutor; -use crate::{self as pallet_xcm, TestWeightInfo}; +use crate::{self as pallet_xcm, Get, TestWeightInfo}; pub type AccountId = AccountId32; pub type Balance = u128; @@ -248,7 +254,7 @@ impl pallet_balances::Config for Test { impl pallet_assets::Config for Test { type RuntimeEvent = RuntimeEvent; - type Balance = u64; + type Balance = Balance; type AssetId = MultiLocation; type AssetIdParameter = MultiLocation; type Currency = Balances; @@ -269,11 +275,21 @@ impl pallet_assets::Config for Test { type BenchmarkHelper = (); } +// This child parachain acts as trusted reserve for its assets in tests. +pub const RESERVE_PARA_ID: u32 = 2001; +// This child parachain is not configured as trusted reserve or teleport location for any assets. +pub const OTHER_PARA_ID: u32 = 2009; + parameter_types! { pub const RelayLocation: MultiLocation = Here.into_location(); + pub const ForeignReserveLocation: MultiLocation = MultiLocation { + parents: 0, + interior: X1(Parachain(RESERVE_PARA_ID)) + }; pub const AnyNetwork: Option = None; pub UniversalLocation: InteriorMultiLocation = Here; pub UnitWeightCost: u64 = 1_000; + pub CheckingAccount: AccountId = XcmPallet::check_account(); } pub type SovereignAccountOf = ( @@ -282,8 +298,33 @@ pub type SovereignAccountOf = ( SiblingParachainConvertsVia, ); -pub type LocalAssetTransactor = - XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>; +pub struct Equals(PhantomData); +impl> Contains for Equals { + fn contains(t: &MultiLocation) -> bool { + t == &Location::get() + } +} + +pub type ForeignAssetsConvertedConcreteId = MatchedConvertedConcreteId< + MultiLocation, + Balance, + // Excludes relay/parent chain currency + EverythingBut<(Equals,)>, + Identity, + JustTry, +>; + +pub type AssetTransactors = ( + XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>, + FungiblesAdapter< + Assets, + ForeignAssetsConvertedConcreteId, + SovereignAccountOf, + AccountId, + NoChecking, + CheckingAccount, + >, +); type LocalOriginConverter = ( SovereignSignedViaLocation, @@ -292,18 +333,13 @@ type LocalOriginConverter = ( ChildSystemParachainAsSuperuser, ); -// This sibling parachain acts as trusted reserve for its assets in tests. -pub const RESERVE_PARA_ID: u32 = 2001; -// This sibling parachain is not configured as trusted reserve or teleport location for any assets. -pub const OTHER_PARA_ID: u32 = 2009; - parameter_types! { pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000); pub CurrencyPerSecondPerByte: (AssetId, u128, u128) = (Concrete(RelayLocation::get()), 1, 1); pub TrustedAssets: (MultiAssetFilter, MultiLocation) = (All.into(), Here.into()); pub TrustedReserves: (MultiAssetFilter, MultiLocation) = ( All.into(), - MultiLocation { parents: 1, interior: X1(Parachain(RESERVE_PARA_ID)) } + MultiLocation { parents: 0, interior: X1(Parachain(RESERVE_PARA_ID)) } ); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; @@ -320,7 +356,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = TestSendXcm; - type AssetTransactor = LocalAssetTransactor; + type AssetTransactor = AssetTransactors; type OriginConverter = LocalOriginConverter; type IsReserve = Case; type IsTeleporter = Case; diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index 17374814c19d..9d5a057995fd 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -29,7 +29,7 @@ use sp_runtime::traits::{AccountIdConversion, BlakeTwo256, Hash}; use xcm::{latest::QueryResponseInfo, prelude::*}; use xcm_builder::AllowKnownQueryResponses; use xcm_executor::{ - traits::{Properties, QueryHandler, QueryResponseStatus, ShouldExecute}, + traits::{ConvertLocation, Properties, QueryHandler, QueryResponseStatus, ShouldExecute}, XcmExecutor, }; @@ -550,7 +550,7 @@ fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserv /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_works() { - todo!() + // TODO } /// Test `reserve_transfer_assets` with remote asset reserve and local fee reserve. @@ -559,7 +559,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_works() { - todo!() + // TODO } /// Test `reserve_transfer_assets` with local asset reserve and destination fee reserve. @@ -568,7 +568,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_works /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_works() { - todo!() + // TODO } /// Test `reserve_transfer_assets` with destination asset reserve and destination fee reserve. @@ -577,7 +577,94 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_reserve_works() { - todo!() + // foreign creator in this case sibling parachain acting as reserve + let foreign_creator_location = + RelayLocation::get().pushed_with_interior(Parachain(RESERVE_PARA_ID)).unwrap(); + let foreign_creator_as_account_id = + SovereignAccountOf::convert_location(&foreign_creator_location).unwrap(); + + // foreign parachain with the same consensus currency as asset + let foreign_asset_id_multilocation = + foreign_creator_location.pushed_with_interior(GeneralIndex(1234567)).unwrap(); + let foreign_asset_amount = 142; + + // transfer destination is reserve location + let dest = foreign_creator_location; + let assets: MultiAssets = vec![(foreign_asset_id_multilocation, SEND_AMOUNT).into()].into(); + + let balances = + vec![(ALICE, INITIAL_BALANCE), (foreign_creator_as_account_id.clone(), INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient (to be used as fees as well) foreign asset (0 total issuance) + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + foreign_asset_id_multilocation, + BOB, + true, + 1 + )); + // this asset should have been teleported/reserve-transferred in, but for this test we just + // mint it locally. + assert_ok!(Assets::mint( + RuntimeOrigin::signed(BOB), + foreign_asset_id_multilocation, + ALICE, + foreign_asset_amount + )); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_asset_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + let expected_weight = BaseXcmWeight::get() * 2; + let mut expected_assets = assets.clone(); + expected_assets.reanchor(&dest, UniversalLocation::get()).unwrap(); + + // do the transfer + assert_ok!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + 0, + Unlimited, + )); + assert_eq!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { + outcome: Outcome::Complete(expected_weight) + }) + ); + // Alice spent (transferred) amount + assert_eq!( + Assets::balance(foreign_asset_id_multilocation, ALICE), + foreign_asset_amount - SEND_AMOUNT + ); + // Alice's native asset balance is untouched + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + // Destination account (parachain account) has expected (same) balances + assert_eq!(Balances::free_balance(foreign_creator_as_account_id.clone()), INITIAL_BALANCE); + assert_eq!( + Assets::balance(foreign_asset_id_multilocation, foreign_creator_as_account_id), + 0 + ); + + // Verify sent XCM program + assert_eq!( + sent_xcm(), + vec![( + Parachain(RESERVE_PARA_ID).into(), + Xcm(vec![ + WithdrawAsset(expected_assets.clone()), + ClearOrigin, + buy_limited_execution(expected_assets.get(0).unwrap().clone(), Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary }, + ]), + )] + ); + let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); + let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); + }); } /// Test `reserve_transfer_assets` with remote asset reserve and destination fee reserve. @@ -586,7 +673,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve_works() { - todo!() + // TODO } /// Test `reserve_transfer_assets` with local asset reserve and remote fee reserve. @@ -595,7 +682,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works() { - todo!() + // TODO } /// Test `reserve_transfer_assets` with destination asset reserve and local fee reserve. @@ -604,7 +691,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve_works() { - todo!() + // TODO } /// Test `reserve_transfer_assets` with remote asset reserve and local fee reserve. @@ -613,7 +700,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_works() { - todo!() + // TODO } /// Test `reserve_transfer_assets` with local asset reserve and teleported fee. @@ -622,7 +709,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { - todo!() + // TODO } /// Test `reserve_transfer_assets` with destination asset reserve and teleported fee. @@ -631,7 +718,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_works() { - todo!() + // TODO } /// Test `reserve_transfer_assets` with remote asset reserve and teleported fee. @@ -640,7 +727,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_wor /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_works() { - todo!() + // TODO } /// Test local execution of XCM From 88b302494db97140504d6f8f25a84b2510d1d8d6 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 27 Sep 2023 14:57:41 +0300 Subject: [PATCH 12/98] add test for asset-reserve and fee-reserve both at remote chain --- polkadot/xcm/pallet-xcm/src/tests.rs | 126 ++++++++++++++++++++++++--- 1 file changed, 114 insertions(+), 12 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index 9d5a057995fd..d993699f8d18 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -577,19 +577,19 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_reserve_works() { - // foreign creator in this case sibling parachain acting as reserve - let foreign_creator_location = + // foreign creator in this case child parachain acting as reserve + let reserve_location = RelayLocation::get().pushed_with_interior(Parachain(RESERVE_PARA_ID)).unwrap(); let foreign_creator_as_account_id = - SovereignAccountOf::convert_location(&foreign_creator_location).unwrap(); + SovereignAccountOf::convert_location(&reserve_location).unwrap(); // foreign parachain with the same consensus currency as asset let foreign_asset_id_multilocation = - foreign_creator_location.pushed_with_interior(GeneralIndex(1234567)).unwrap(); + reserve_location.pushed_with_interior(GeneralIndex(1234567)).unwrap(); let foreign_asset_amount = 142; // transfer destination is reserve location - let dest = foreign_creator_location; + let dest = reserve_location; let assets: MultiAssets = vec![(foreign_asset_id_multilocation, SEND_AMOUNT).into()].into(); let balances = @@ -616,7 +616,6 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_asset_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); - let expected_weight = BaseXcmWeight::get() * 2; let mut expected_assets = assets.clone(); expected_assets.reanchor(&dest, UniversalLocation::get()).unwrap(); @@ -629,12 +628,10 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re 0, Unlimited, )); - assert_eq!( + assert!(matches!( last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { - outcome: Outcome::Complete(expected_weight) - }) - ); + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) + )); // Alice spent (transferred) amount assert_eq!( Assets::balance(foreign_asset_id_multilocation, ALICE), @@ -700,7 +697,112 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_works() { - // TODO + // foreign creator in this case child parachain acting as reserve + let reserve_location = + RelayLocation::get().pushed_with_interior(Parachain(RESERVE_PARA_ID)).unwrap(); + let foreign_creator_as_account_id = + SovereignAccountOf::convert_location(&reserve_location).unwrap(); + + // foreign parachain with the same consensus currency as asset + let foreign_asset_id_multilocation = + reserve_location.pushed_with_interior(GeneralIndex(1234567)).unwrap(); + let foreign_asset_amount = 142; + + let assets: MultiAssets = vec![(foreign_asset_id_multilocation, SEND_AMOUNT).into()].into(); + // transfer destination is other parachain => remote reserve location (RESERVE_PARA_ID) + let dest = RelayLocation::get().pushed_with_interior(Parachain(OTHER_PARA_ID)).unwrap(); + + let balances = + vec![(ALICE, INITIAL_BALANCE), (foreign_creator_as_account_id.clone(), INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient (to be used as fees as well) foreign asset (0 total issuance) + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + foreign_asset_id_multilocation, + BOB, + true, + 1 + )); + // this asset should have been teleported/reserve-transferred in, but for this test we just + // mint it locally. + assert_ok!(Assets::mint( + RuntimeOrigin::signed(BOB), + foreign_asset_id_multilocation, + ALICE, + foreign_asset_amount + )); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_asset_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + let context = UniversalLocation::get(); + println!("assets to transfer: {:?}", assets); + let mut expected_fee_on_reserve = assets.get(0).unwrap().clone(); + expected_fee_on_reserve.reanchor(&reserve_location, context).unwrap(); + println!("expected fees on reserve (reanchored): {:?}", expected_fee_on_reserve); + let mut expected_assets = assets.clone(); + expected_assets.reanchor(&dest, context).unwrap(); + println!("assets expected to be received on dest (reanchored): {:?}", expected_assets); + let expected_dest = dest.reanchored(&reserve_location, context).unwrap(); + println!("dest location as seen by reserve (reanchored): {:?}", expected_dest); + + // do the transfer + assert_ok!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + 0, + Unlimited, + )); + assert!(matches!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) + )); + // Alice spent (transferred) amount + assert_eq!( + Assets::balance(foreign_asset_id_multilocation, ALICE), + foreign_asset_amount - SEND_AMOUNT + ); + // Alice's native asset balance is untouched + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + // Destination account (parachain account) has expected (same) balances + assert_eq!(Balances::free_balance(foreign_creator_as_account_id.clone()), INITIAL_BALANCE); + assert_eq!( + Assets::balance(foreign_asset_id_multilocation, foreign_creator_as_account_id), + 0 + ); + + // Verify sent XCM program + assert_eq!( + sent_xcm(), + vec![( + // first message sent to reserve chain + Parachain(RESERVE_PARA_ID).into(), + Xcm(vec![ + WithdrawAsset(expected_fee_on_reserve.clone().into()), + ClearOrigin, + BuyExecution { fees: expected_fee_on_reserve, weight_limit: Unlimited }, + DepositReserveAsset { + assets: Wild(AllCounted(1)), + // final destination is `dest` as seen by `reserve` + dest: expected_dest, + // message sent onward to `dest` + xcm: Xcm(vec![ + buy_limited_execution( + expected_assets.get(0).unwrap().clone(), + Unlimited + ), + DepositAsset { assets: AllCounted(1).into(), beneficiary } + ]) + } + ]) + )], + ); + let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); + let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); + }); } /// Test `reserve_transfer_assets` with local asset reserve and teleported fee. From 513e15aa3856f82361d096de61902f6040f14421 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 27 Sep 2023 16:21:24 +0300 Subject: [PATCH 13/98] add test for asset-reserve at destination while fee-reserve is local --- polkadot/xcm/pallet-xcm/src/lib.rs | 13 ++- polkadot/xcm/pallet-xcm/src/mock.rs | 17 +++- polkadot/xcm/pallet-xcm/src/tests.rs | 120 ++++++++++++++++++++++++++- 3 files changed, 140 insertions(+), 10 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index c23f08198aaf..7e1051134281 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1354,19 +1354,24 @@ impl Pallet { if let TransferType::RemoteReserve(_fees_reserve) = fees_transfer_type { // TODO: change beneficiary on `fee_reserve` to be SA-of-Here. // But beneficiary on `dest` should stay unchanged... + // Or maybe not required, fees can be used from Holding register, we'll see :D } - Self::prefund_transfer_fees( + // execute fees transfer - have to do it separately than assets because of the + // different transfer type (different XCM program required) + Self::build_and_execute_xcm_transfer_type( origin_location, dest, beneficiary, + vec![fees.clone()], + fees_transfer_type, fees.clone(), weight_limit.clone(), )?; } } - // Fees have been prefunded/transferred (or batched together with assets), now do - // reserve-transfer assets. + // Fees have been prefunded/transferred (or batched together with assets to be transferred + // here), now do reserve-transfer assets. Self::build_and_execute_xcm_transfer_type( origin_location, dest, @@ -1389,6 +1394,8 @@ impl Pallet { _asset: MultiAsset, _weight_limit: WeightLimit, ) -> DispatchResult { + // let fee_transfer_type = TransferType::determine_for::(&fee_asset, &dest)?; + // Ok(()) todo!() } diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index d951520f926d..a27a6cd51891 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -277,6 +277,8 @@ impl pallet_assets::Config for Test { // This child parachain acts as trusted reserve for its assets in tests. pub const RESERVE_PARA_ID: u32 = 2001; +// Inner junction of reserve asset on `RESERVE_PARA_ID`. +pub const RESERVE_ASSET_INNER_JUNCTION: Junction = GeneralIndex(1234567); // This child parachain is not configured as trusted reserve or teleport location for any assets. pub const OTHER_PARA_ID: u32 = 2009; @@ -333,14 +335,21 @@ type LocalOriginConverter = ( ChildSystemParachainAsSuperuser, ); +pub const RESERVE_LOCATION: MultiLocation = + MultiLocation { parents: 0, interior: X1(Parachain(RESERVE_PARA_ID)) }; +pub const RESERVE_ASSET: MultiAsset = MultiAsset { + fun: Fungible(10), + id: Concrete(MultiLocation { + parents: 0, + interior: X2(Parachain(RESERVE_PARA_ID), RESERVE_ASSET_INNER_JUNCTION), + }), +}; + parameter_types! { pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000); pub CurrencyPerSecondPerByte: (AssetId, u128, u128) = (Concrete(RelayLocation::get()), 1, 1); pub TrustedAssets: (MultiAssetFilter, MultiLocation) = (All.into(), Here.into()); - pub TrustedReserves: (MultiAssetFilter, MultiLocation) = ( - All.into(), - MultiLocation { parents: 0, interior: X1(Parachain(RESERVE_PARA_ID)) } - ); + pub TrustedReserves: (MultiAssetFilter, MultiLocation) = (vec![RESERVE_ASSET].into(), RESERVE_LOCATION); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; } diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index d993699f8d18..d0b368e1d124 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -38,6 +38,7 @@ const BOB: AccountId = AccountId::new([1u8; 32]); const PARA_ID: u32 = 2000; const INITIAL_BALANCE: u128 = 100; const SEND_AMOUNT: u128 = 10; +const FEE_AMOUNT: u128 = 1; #[test] fn report_outcome_notify_works() { @@ -550,7 +551,120 @@ fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserv /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_works() { - // TODO + // foreign creator in this case child parachain acting as reserve + let reserve_location = + RelayLocation::get().pushed_with_interior(Parachain(RESERVE_PARA_ID)).unwrap(); + let foreign_creator_as_account_id = + SovereignAccountOf::convert_location(&reserve_location).unwrap(); + + // foreign parachain with the same consensus currency as asset + let foreign_asset_id_multilocation = + reserve_location.pushed_with_interior(RESERVE_ASSET_INNER_JUNCTION).unwrap(); + let foreign_asset_amount = 142; + + // transfer destination is reserve location (no teleport trust) + let dest = reserve_location; + let assets: MultiAssets = vec![ + // native asset for fee + (MultiLocation::here(), FEE_AMOUNT).into(), + // foreign asset to transfer + (foreign_asset_id_multilocation, SEND_AMOUNT).into(), + ] + .into(); + + let balances = + vec![(ALICE, INITIAL_BALANCE), (foreign_creator_as_account_id.clone(), INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + + new_test_ext_with_balances(balances).execute_with(|| { + // create non-sufficient foreign asset (0 total issuance) + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + foreign_asset_id_multilocation, + BOB, + false, + 1 + )); + // this asset should have been teleported/reserve-transferred in, but for this test we just + // mint it locally. + assert_ok!(Assets::mint( + RuntimeOrigin::signed(BOB), + foreign_asset_id_multilocation, + ALICE, + foreign_asset_amount + )); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_asset_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + let context = UniversalLocation::get(); + let mut expected_fee = assets.get(0).unwrap().clone(); + expected_fee.reanchor(&dest, context).unwrap(); + let mut expected_asset = assets.get(1).unwrap().clone(); + expected_asset.reanchor(&dest, context).unwrap(); + + // do the transfer + assert_ok!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + 0, + Unlimited, + )); + assert!(matches!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) + )); + // Alice spent (transferred) amount + assert_eq!( + Assets::balance(foreign_asset_id_multilocation, ALICE), + foreign_asset_amount - SEND_AMOUNT + ); + // Alice used native asset for fees + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - FEE_AMOUNT); + // Destination account (parachain account) added native reserve used as fee to balances + assert_eq!( + Balances::free_balance(foreign_creator_as_account_id.clone()), + INITIAL_BALANCE + FEE_AMOUNT + ); + assert_eq!( + Assets::balance(foreign_asset_id_multilocation, foreign_creator_as_account_id), + 0 + ); + + // Verify sent XCM program + assert_eq!( + sent_xcm(), + vec![ + ( + // first message is to prefund fees on `dest` + dest, + Xcm(vec![ + // fees are being sent through local-reserve transfer because fee reserve + // is local chain + ReserveAssetDeposited((Parent, FEE_AMOUNT).into()), + ClearOrigin, + buy_limited_execution((Parent, FEE_AMOUNT), Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary }, + ]) + ), + ( + // second message is to transfer/deposit foreign assets on `dest` while paying + // using prefunded (transferred above) fees + dest, + Xcm(vec![ + WithdrawAsset(expected_asset.into()), + ClearOrigin, + buy_limited_execution(expected_fee, Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary }, + ]) + ) + ] + ); + let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); + let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); + }); } /// Test `reserve_transfer_assets` with remote asset reserve and local fee reserve. @@ -585,7 +699,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re // foreign parachain with the same consensus currency as asset let foreign_asset_id_multilocation = - reserve_location.pushed_with_interior(GeneralIndex(1234567)).unwrap(); + reserve_location.pushed_with_interior(RESERVE_ASSET_INNER_JUNCTION).unwrap(); let foreign_asset_amount = 142; // transfer destination is reserve location @@ -705,7 +819,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work // foreign parachain with the same consensus currency as asset let foreign_asset_id_multilocation = - reserve_location.pushed_with_interior(GeneralIndex(1234567)).unwrap(); + reserve_location.pushed_with_interior(RESERVE_ASSET_INNER_JUNCTION).unwrap(); let foreign_asset_amount = 142; let assets: MultiAssets = vec![(foreign_asset_id_multilocation, SEND_AMOUNT).into()].into(); From 19eec1780115025214f7fb363b1ed4a09ad0a223 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 27 Sep 2023 17:37:40 +0300 Subject: [PATCH 14/98] add test for asset local-reserve while fee-reserve is destination --- polkadot/xcm/pallet-xcm/src/tests.rs | 136 +++++++++++++++++++++++++-- 1 file changed, 129 insertions(+), 7 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index d0b368e1d124..530a77636dad 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -571,6 +571,8 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ (foreign_asset_id_multilocation, SEND_AMOUNT).into(), ] .into(); + let fee_index = 0; + let asset_index = 1; let balances = vec![(ALICE, INITIAL_BALANCE), (foreign_creator_as_account_id.clone(), INITIAL_BALANCE)]; @@ -598,9 +600,9 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); let context = UniversalLocation::get(); - let mut expected_fee = assets.get(0).unwrap().clone(); + let mut expected_fee = assets.get(fee_index).unwrap().clone(); expected_fee.reanchor(&dest, context).unwrap(); - let mut expected_asset = assets.get(1).unwrap().clone(); + let mut expected_asset = assets.get(asset_index).unwrap().clone(); expected_asset.reanchor(&dest, context).unwrap(); // do the transfer @@ -609,7 +611,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ Box::new(dest.into()), Box::new(beneficiary.into()), Box::new(assets.into()), - 0, + fee_index as u32, Unlimited, )); assert!(matches!( @@ -652,6 +654,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ ( // second message is to transfer/deposit foreign assets on `dest` while paying // using prefunded (transferred above) fees + // (dest is reserve location for `expected_asset`) dest, Xcm(vec![ WithdrawAsset(expected_asset.into()), @@ -682,7 +685,124 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_works /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_works() { - // TODO + // foreign creator in this case child parachain acting as reserve + let fee_reserve_location = + RelayLocation::get().pushed_with_interior(Parachain(RESERVE_PARA_ID)).unwrap(); + let foreign_creator_as_account_id = + SovereignAccountOf::convert_location(&fee_reserve_location).unwrap(); + + // foreign parachain with the same consensus currency as asset + let foreign_asset_id_multilocation = + fee_reserve_location.pushed_with_interior(RESERVE_ASSET_INNER_JUNCTION).unwrap(); + let foreign_asset_amount = 142; + + // transfer destination is fee reserve location (no teleport trust) + let dest = fee_reserve_location; + let assets: MultiAssets = vec![ + // native asset to transfer (not used for fees) + (MultiLocation::here(), SEND_AMOUNT).into(), + // foreign asset for fees (is sufficient on local chain too) + (foreign_asset_id_multilocation, FEE_AMOUNT).into(), + ] + .into(); + let fee_index = 1; + let asset_index = 0; + + let balances = + vec![(ALICE, INITIAL_BALANCE), (foreign_creator_as_account_id.clone(), INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + + new_test_ext_with_balances(balances).execute_with(|| { + // create non-sufficient foreign asset (0 total issuance) + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + foreign_asset_id_multilocation, + BOB, + false, + 1 + )); + // this asset should have been teleported/reserve-transferred in, but for this test we just + // mint it locally. + assert_ok!(Assets::mint( + RuntimeOrigin::signed(BOB), + foreign_asset_id_multilocation, + ALICE, + foreign_asset_amount + )); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_asset_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + let context = UniversalLocation::get(); + let mut expected_fee = assets.get(fee_index).unwrap().clone(); + expected_fee.reanchor(&dest, context).unwrap(); + let mut expected_asset = assets.get(asset_index).unwrap().clone(); + expected_asset.reanchor(&dest, context).unwrap(); + + // do the transfer + assert_ok!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + )); + assert!(matches!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) + )); + // Alice spent (fees) amount + assert_eq!( + Assets::balance(foreign_asset_id_multilocation, ALICE), + foreign_asset_amount - FEE_AMOUNT + ); + // Alice used native asset for transfer + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); + // Sovereign account of dest parachain holds `SEND_AMOUNT` native asset in local reserve + assert_eq!( + Balances::free_balance(foreign_creator_as_account_id.clone()), + INITIAL_BALANCE + SEND_AMOUNT + ); + assert_eq!( + Assets::balance(foreign_asset_id_multilocation, foreign_creator_as_account_id), + 0 + ); + + // Verify sent XCM program + assert_eq!( + sent_xcm(), + vec![ + ( + // first message is to prefund fees on `dest` + dest, + // fees are being sent through destination-reserve transfer because fee reserve + // is destination chain + Xcm(vec![ + WithdrawAsset(expected_fee.clone().into()), + ClearOrigin, + buy_limited_execution(expected_fee.clone(), Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary }, + ]) + ), + ( + // second message is to transfer/deposit foreign assets on `dest` while paying + // using prefunded (transferred above) fees + // transfer is through local-reserve transfer because `assets` (native asset) + // have local reserve + dest, + Xcm(vec![ + ReserveAssetDeposited(expected_asset.into()), + ClearOrigin, + buy_limited_execution(expected_fee, Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary }, + ]) + ) + ] + ); + let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); + let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); + }); } /// Test `reserve_transfer_assets` with destination asset reserve and destination fee reserve. @@ -705,6 +825,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re // transfer destination is reserve location let dest = reserve_location; let assets: MultiAssets = vec![(foreign_asset_id_multilocation, SEND_AMOUNT).into()].into(); + let fee_index = 0; let balances = vec![(ALICE, INITIAL_BALANCE), (foreign_creator_as_account_id.clone(), INITIAL_BALANCE)]; @@ -739,7 +860,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re Box::new(dest.into()), Box::new(beneficiary.into()), Box::new(assets.into()), - 0, + fee_index, Unlimited, )); assert!(matches!( @@ -823,6 +944,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work let foreign_asset_amount = 142; let assets: MultiAssets = vec![(foreign_asset_id_multilocation, SEND_AMOUNT).into()].into(); + let fee_index = 0; // transfer destination is other parachain => remote reserve location (RESERVE_PARA_ID) let dest = RelayLocation::get().pushed_with_interior(Parachain(OTHER_PARA_ID)).unwrap(); @@ -852,7 +974,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work let context = UniversalLocation::get(); println!("assets to transfer: {:?}", assets); - let mut expected_fee_on_reserve = assets.get(0).unwrap().clone(); + let mut expected_fee_on_reserve = assets.get(fee_index).unwrap().clone(); expected_fee_on_reserve.reanchor(&reserve_location, context).unwrap(); println!("expected fees on reserve (reanchored): {:?}", expected_fee_on_reserve); let mut expected_assets = assets.clone(); @@ -867,7 +989,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work Box::new(dest.into()), Box::new(beneficiary.into()), Box::new(assets.into()), - 0, + fee_index as u32, Unlimited, )); assert!(matches!( From 1687c533d32272787630f99b3737ec516553be55 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 27 Sep 2023 18:56:03 +0300 Subject: [PATCH 15/98] add test for asset local-reserve while fee-reserve is remote chain --- polkadot/xcm/pallet-xcm/src/tests.rs | 146 +++++++++++++++++++++++++-- 1 file changed, 135 insertions(+), 11 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index 530a77636dad..a7d4ea9e7b26 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -714,12 +714,12 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ Junction::AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { - // create non-sufficient foreign asset (0 total issuance) + // create sufficient foreign asset (0 total issuance) assert_ok!(Assets::force_create( RuntimeOrigin::root(), foreign_asset_id_multilocation, BOB, - false, + true, 1 )); // this asset should have been teleported/reserve-transferred in, but for this test we just @@ -786,11 +786,11 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ ]) ), ( - // second message is to transfer/deposit foreign assets on `dest` while paying + // second message is to transfer/deposit (native) asset on `dest` while paying // using prefunded (transferred above) fees + dest, // transfer is through local-reserve transfer because `assets` (native asset) // have local reserve - dest, Xcm(vec![ ReserveAssetDeposited(expected_asset.into()), ClearOrigin, @@ -914,7 +914,135 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works() { - // TODO + // foreign creator in this case child parachain acting as reserve + let fee_reserve_location = + RelayLocation::get().pushed_with_interior(Parachain(RESERVE_PARA_ID)).unwrap(); + let foreign_creator_as_account_id = + SovereignAccountOf::convert_location(&fee_reserve_location).unwrap(); + + // foreign parachain with the same consensus currency as asset + let foreign_asset_id_multilocation = + fee_reserve_location.pushed_with_interior(RESERVE_ASSET_INNER_JUNCTION).unwrap(); + let foreign_asset_amount = 142; + + // transfer destination is other parachain than fee reserve location (no teleport trust) + let dest = RelayLocation::get().pushed_with_interior(Parachain(OTHER_PARA_ID)).unwrap(); + let dest_as_account_id = SovereignAccountOf::convert_location(&dest).unwrap(); + let assets: MultiAssets = vec![ + // native asset to transfer (not used for fees) - local reserve + (MultiLocation::here(), SEND_AMOUNT).into(), + // foreign asset for fees (is sufficient on local chain too) - remote reserve + (foreign_asset_id_multilocation, FEE_AMOUNT).into(), + ] + .into(); + let fee_index = 1; + let asset_index = 0; + + let balances = + vec![(ALICE, INITIAL_BALANCE), (foreign_creator_as_account_id.clone(), INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient foreign asset (0 total issuance) + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + foreign_asset_id_multilocation, + BOB, + true, + 1 + )); + // this asset should have been teleported/reserve-transferred in, but for this test we just + // mint it locally. + assert_ok!(Assets::mint( + RuntimeOrigin::signed(BOB), + foreign_asset_id_multilocation, + ALICE, + foreign_asset_amount + )); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_asset_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + let context = UniversalLocation::get(); + let mut expected_fee_on_reserve = assets.get(fee_index).unwrap().clone(); + expected_fee_on_reserve.reanchor(&fee_reserve_location, context).unwrap(); + let expected_dest_on_reserve = dest.reanchored(&fee_reserve_location, context).unwrap(); + let mut expected_asset = assets.get(asset_index).unwrap().clone(); + expected_asset.reanchor(&dest, context).unwrap(); + let mut expected_fee = assets.get(fee_index).unwrap().clone(); + expected_fee.reanchor(&dest, context).unwrap(); + + // do the transfer + assert_ok!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + )); + assert!(matches!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) + )); + // Alice spent (fees) amount + assert_eq!( + Assets::balance(foreign_asset_id_multilocation, ALICE), + foreign_asset_amount - FEE_AMOUNT + ); + // Alice used native asset for transfer + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); + // Sovereign account of reserve parachain is unchanged + assert_eq!(Balances::free_balance(foreign_creator_as_account_id.clone()), INITIAL_BALANCE); + assert_eq!( + Assets::balance(foreign_asset_id_multilocation, foreign_creator_as_account_id), + 0 + ); + // Sovereign account of destination parachain holds `SEND_AMOUNT` in local reserve + assert_eq!(Balances::free_balance(dest_as_account_id), SEND_AMOUNT); + + // Verify sent XCM program + assert_eq!( + sent_xcm(), + vec![ + ( + // first message is to prefund (foreign-asset) fees on `dest` (by going through + // fee remote reserve) + fee_reserve_location, + Xcm(vec![ + WithdrawAsset(expected_fee_on_reserve.clone().into()), + ClearOrigin, + buy_limited_execution(expected_fee_on_reserve, Unlimited), + DepositReserveAsset { + assets: Wild(AllCounted(1)), + // final destination is `dest` as seen by `reserve` + dest: expected_dest_on_reserve, + // message sent onward to final `dest` to deposit/prefund fees + xcm: Xcm(vec![ + buy_limited_execution(expected_fee.clone(), Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary } + ]) + } + ]) + ), + ( + // second message is to transfer/deposit (native) asset on `dest` while paying + // using prefunded (transferred above) fees + dest, + // transfer is through local-reserve transfer because `assets` (native asset) + // have local reserve + Xcm(vec![ + ReserveAssetDeposited(expected_asset.into()), + ClearOrigin, + buy_limited_execution(expected_fee, Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary }, + ]) + ) + ] + ); + let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); + let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); + }); } /// Test `reserve_transfer_assets` with destination asset reserve and local fee reserve. @@ -973,15 +1101,11 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); let context = UniversalLocation::get(); - println!("assets to transfer: {:?}", assets); let mut expected_fee_on_reserve = assets.get(fee_index).unwrap().clone(); expected_fee_on_reserve.reanchor(&reserve_location, context).unwrap(); - println!("expected fees on reserve (reanchored): {:?}", expected_fee_on_reserve); let mut expected_assets = assets.clone(); expected_assets.reanchor(&dest, context).unwrap(); - println!("assets expected to be received on dest (reanchored): {:?}", expected_assets); - let expected_dest = dest.reanchored(&reserve_location, context).unwrap(); - println!("dest location as seen by reserve (reanchored): {:?}", expected_dest); + let expected_dest_on_reserve = dest.reanchored(&reserve_location, context).unwrap(); // do the transfer assert_ok!(XcmPallet::limited_reserve_transfer_assets( @@ -1023,7 +1147,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work DepositReserveAsset { assets: Wild(AllCounted(1)), // final destination is `dest` as seen by `reserve` - dest: expected_dest, + dest: expected_dest_on_reserve, // message sent onward to `dest` xcm: Xcm(vec![ buy_limited_execution( From abf029da8163c32eb7b5be71f160b2a488add339 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 27 Sep 2023 19:42:34 +0300 Subject: [PATCH 16/98] refactor tests using better naming and conceptual examples --- polkadot/xcm/pallet-xcm/src/mock.rs | 47 ++-- polkadot/xcm/pallet-xcm/src/tests.rs | 309 ++++++++++++++++----------- 2 files changed, 215 insertions(+), 141 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index a27a6cd51891..982df882b873 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -276,9 +276,15 @@ impl pallet_assets::Config for Test { } // This child parachain acts as trusted reserve for its assets in tests. -pub const RESERVE_PARA_ID: u32 = 2001; -// Inner junction of reserve asset on `RESERVE_PARA_ID`. -pub const RESERVE_ASSET_INNER_JUNCTION: Junction = GeneralIndex(1234567); +pub const FOREIGN_ASSET_RESERVE_PARA_ID: u32 = 2001; +// Inner junction of reserve asset on `FOREIGN_ASSET_RESERVE_PARA_ID`. +pub const FOREIGN_ASSET_INNER_JUNCTION: Junction = GeneralIndex(1234567); + +// This child parachain acts as trusted reserve for say.. USDC that can be used for fees. +pub const USDC_RESERVE_PARA_ID: u32 = 2002; +// Inner junction of reserve asset on `USDC_RESERVE_PARA_ID`. +pub const USDC_INNER_JUNCTION: Junction = PalletInstance(42); + // This child parachain is not configured as trusted reserve or teleport location for any assets. pub const OTHER_PARA_ID: u32 = 2009; @@ -286,7 +292,25 @@ parameter_types! { pub const RelayLocation: MultiLocation = Here.into_location(); pub const ForeignReserveLocation: MultiLocation = MultiLocation { parents: 0, - interior: X1(Parachain(RESERVE_PARA_ID)) + interior: X1(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID)) + }; + pub const ForeignAsset: MultiAsset = MultiAsset { + fun: Fungible(10), + id: Concrete(MultiLocation { + parents: 0, + interior: X2(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID), FOREIGN_ASSET_INNER_JUNCTION), + }), + }; + pub const UsdcReserveLocation: MultiLocation = MultiLocation { + parents: 0, + interior: X1(Parachain(USDC_RESERVE_PARA_ID)) + }; + pub const Usdc: MultiAsset = MultiAsset { + fun: Fungible(10), + id: Concrete(MultiLocation { + parents: 0, + interior: X2(Parachain(USDC_RESERVE_PARA_ID), USDC_INNER_JUNCTION), + }), }; pub const AnyNetwork: Option = None; pub UniversalLocation: InteriorMultiLocation = Here; @@ -335,21 +359,12 @@ type LocalOriginConverter = ( ChildSystemParachainAsSuperuser, ); -pub const RESERVE_LOCATION: MultiLocation = - MultiLocation { parents: 0, interior: X1(Parachain(RESERVE_PARA_ID)) }; -pub const RESERVE_ASSET: MultiAsset = MultiAsset { - fun: Fungible(10), - id: Concrete(MultiLocation { - parents: 0, - interior: X2(Parachain(RESERVE_PARA_ID), RESERVE_ASSET_INNER_JUNCTION), - }), -}; - parameter_types! { pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000); pub CurrencyPerSecondPerByte: (AssetId, u128, u128) = (Concrete(RelayLocation::get()), 1, 1); pub TrustedAssets: (MultiAssetFilter, MultiLocation) = (All.into(), Here.into()); - pub TrustedReserves: (MultiAssetFilter, MultiLocation) = (vec![RESERVE_ASSET].into(), RESERVE_LOCATION); + pub TrustedReserve1: (MultiAssetFilter, MultiLocation) = (vec![ForeignAsset::get()].into(), ForeignReserveLocation::get()); + pub TrustedReserve2: (MultiAssetFilter, MultiLocation) = (vec![Usdc::get()].into(), UsdcReserveLocation::get()); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; } @@ -367,7 +382,7 @@ impl xcm_executor::Config for XcmConfig { type XcmSender = TestSendXcm; type AssetTransactor = AssetTransactors; type OriginConverter = LocalOriginConverter; - type IsReserve = Case; + type IsReserve = (Case, Case); type IsTeleporter = Case; type UniversalLocation = UniversalLocation; type Barrier = Barrier; diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index a7d4ea9e7b26..4ac8733b4284 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -35,7 +35,6 @@ use xcm_executor::{ const ALICE: AccountId = AccountId::new([0u8; 32]); const BOB: AccountId = AccountId::new([1u8; 32]); -const PARA_ID: u32 = 2000; const INITIAL_BALANCE: u128 = 100; const SEND_AMOUNT: u128 = 10; const FEE_AMOUNT: u128 = 1; @@ -44,7 +43,7 @@ const FEE_AMOUNT: u128 = 1; fn report_outcome_notify_works() { let balances = vec![ (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); let mut message = @@ -57,7 +56,7 @@ fn report_outcome_notify_works() { new_test_ext_with_balances(balances).execute_with(|| { XcmPallet::report_outcome_notify( &mut message, - Parachain(PARA_ID).into_location(), + Parachain(OTHER_PARA_ID).into_location(), notify, 100, ) @@ -75,7 +74,7 @@ fn report_outcome_notify_works() { ); let querier: MultiLocation = Here.into(); let status = QueryStatus::Pending { - responder: MultiLocation::from(Parachain(PARA_ID)).into(), + responder: MultiLocation::from(Parachain(OTHER_PARA_ID)).into(), maybe_notify: Some((5, 2)), timeout: 100, maybe_match_querier: Some(querier.into()), @@ -90,7 +89,7 @@ fn report_outcome_notify_works() { }]); let hash = fake_message_hash(&message); let r = XcmExecutor::::execute_xcm( - Parachain(PARA_ID), + Parachain(OTHER_PARA_ID), message, hash, Weight::from_parts(1_000_000_000, 1_000_000_000), @@ -100,7 +99,7 @@ fn report_outcome_notify_works() { last_events(2), vec![ RuntimeEvent::TestNotifier(pallet_test_notifier::Event::ResponseReceived( - Parachain(PARA_ID).into(), + Parachain(OTHER_PARA_ID).into(), 0, Response::ExecutionResult(None), )), @@ -119,13 +118,14 @@ fn report_outcome_notify_works() { fn report_outcome_works() { let balances = vec![ (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); let mut message = Xcm(vec![TransferAsset { assets: (Here, SEND_AMOUNT).into(), beneficiary: sender }]); new_test_ext_with_balances(balances).execute_with(|| { - XcmPallet::report_outcome(&mut message, Parachain(PARA_ID).into_location(), 100).unwrap(); + XcmPallet::report_outcome(&mut message, Parachain(OTHER_PARA_ID).into_location(), 100) + .unwrap(); assert_eq!( message, Xcm(vec![ @@ -139,7 +139,7 @@ fn report_outcome_works() { ); let querier: MultiLocation = Here.into(); let status = QueryStatus::Pending { - responder: MultiLocation::from(Parachain(PARA_ID)).into(), + responder: MultiLocation::from(Parachain(OTHER_PARA_ID)).into(), maybe_notify: None, timeout: 100, maybe_match_querier: Some(querier.into()), @@ -154,7 +154,7 @@ fn report_outcome_works() { }]); let hash = fake_message_hash(&message); let r = XcmExecutor::::execute_xcm( - Parachain(PARA_ID), + Parachain(OTHER_PARA_ID), message, hash, Weight::from_parts(1_000_000_000, 1_000_000_000), @@ -178,7 +178,7 @@ fn report_outcome_works() { fn custom_querier_works() { let balances = vec![ (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; new_test_ext_with_balances(balances).execute_with(|| { let querier: MultiLocation = @@ -282,7 +282,7 @@ fn custom_querier_works() { fn send_works() { let balances = vec![ (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; new_test_ext_with_balances(balances).execute_with(|| { let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); @@ -326,7 +326,7 @@ fn send_works() { fn send_fails_when_xcm_router_blocks() { let balances = vec![ (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; new_test_ext_with_balances(balances).execute_with(|| { let sender: MultiLocation = @@ -355,7 +355,7 @@ fn do_test_and_verify_teleport_assets( ) { let balances = vec![ (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; new_test_ext_with_balances(balances).execute_with(|| { let weight = BaseXcmWeight::get() * 3; @@ -460,7 +460,7 @@ fn do_test_and_verify_reserve_transfer_assets_local_ar_local_fr( ) { let balances = vec![ (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; new_test_ext_with_balances(balances).execute_with(|| { let weight = BaseXcmWeight::get() * 2; @@ -470,12 +470,12 @@ fn do_test_and_verify_reserve_transfer_assets_local_ar_local_fr( // Alice spent amount assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); // Destination account (parachain account) has amount - let para_acc: AccountId = ParaId::from(PARA_ID).into_account_truncating(); + let para_acc: AccountId = ParaId::from(OTHER_PARA_ID).into_account_truncating(); assert_eq!(Balances::free_balance(para_acc), INITIAL_BALANCE + SEND_AMOUNT); assert_eq!( sent_xcm(), vec![( - Parachain(PARA_ID).into(), + Parachain(OTHER_PARA_ID).into(), Xcm(vec![ ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), ClearOrigin, @@ -498,7 +498,18 @@ fn do_test_and_verify_reserve_transfer_assets_local_ar_local_fr( /// Test `reserve_transfer_assets` with local asset reserve and local fee reserve. /// -/// Asserts that the sender's balance is decreased and the beneficiary's balance +/// Transferring native asset (local reserve) to some `OTHER_PARA_ID` (no teleport trust). +/// Using native asset for fees as well. +/// +/// Here (source) OTHER_PARA_ID (destination) +/// | `assets` reserve +/// | `fees` reserve +/// | +/// | 1. execute `TransferReserveAsset(assets_and_fees_batched_together)` +/// | \--> sends `ReserveAssetDeposited(both), ClearOrigin, BuyExecution(fees), DepositAsset` +/// \------------------------------------------> +/// +/// Asserts that the sender's balance is decreased and the destination SA balance /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserve_works() { @@ -509,7 +520,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserve_works( || { assert_ok!(XcmPallet::reserve_transfer_assets( RuntimeOrigin::signed(ALICE), - Box::new(Parachain(PARA_ID).into()), + Box::new(Parachain(OTHER_PARA_ID).into()), Box::new(beneficiary.into()), Box::new((Here, SEND_AMOUNT).into()), 0, @@ -521,7 +532,9 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserve_works( /// Test `limited_reserve_transfer_assets` with local asset reserve and local fee reserve. /// -/// Asserts that the sender's balance is decreased and the beneficiary's balance +/// Same as test above but with limited weight. +/// +/// Asserts that the sender's balance is decreased and the destination SA balance /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserve_works() { @@ -534,7 +547,7 @@ fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserv || { assert_ok!(XcmPallet::limited_reserve_transfer_assets( RuntimeOrigin::signed(ALICE), - Box::new(Parachain(PARA_ID).into()), + Box::new(Parachain(OTHER_PARA_ID).into()), Box::new(beneficiary.into()), Box::new((Here, SEND_AMOUNT).into()), 0, @@ -547,19 +560,32 @@ fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserv /// Test `reserve_transfer_assets` with destination asset reserve and local fee reserve. /// +/// Transferring foreign asset (`FOREIGN_ASSET_RESERVE_PARA_ID` reserve) to +/// `FOREIGN_ASSET_RESERVE_PARA_ID` (no teleport trust). +/// Using native asset (local reserve) for fees. +/// +/// Here (source) FOREIGN_ASSET_RESERVE_PARA_ID (destination) +/// | `fees` reserve `assets` reserve +/// | +/// | 1. execute `TransferReserveAsset(fees)` +/// | \-> sends `ReserveAssetDeposited(fees), ClearOrigin, BuyExecution(fees), DepositAsset` +/// | 2. execute `InitiateReserveWithdraw(assets)` +/// | \--> sends `WithdrawAsset(assets), ClearOrigin, BuyExecution(fees), DepositAsset` +/// \------------------------------------------> +/// /// Asserts that the sender's balance is decreased and the beneficiary's balance /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_works() { // foreign creator in this case child parachain acting as reserve - let reserve_location = - RelayLocation::get().pushed_with_interior(Parachain(RESERVE_PARA_ID)).unwrap(); + let reserve_location = RelayLocation::get() + .pushed_with_interior(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID)) + .unwrap(); let foreign_creator_as_account_id = SovereignAccountOf::convert_location(&reserve_location).unwrap(); - // foreign parachain with the same consensus currency as asset let foreign_asset_id_multilocation = - reserve_location.pushed_with_interior(RESERVE_ASSET_INNER_JUNCTION).unwrap(); + reserve_location.pushed_with_interior(FOREIGN_ASSET_INNER_JUNCTION).unwrap(); let foreign_asset_amount = 142; // transfer destination is reserve location (no teleport trust) @@ -681,43 +707,51 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_works /// Test `reserve_transfer_assets` with local asset reserve and destination fee reserve. /// -/// Asserts that the sender's balance is decreased and the beneficiary's balance -/// is increased. Verifies the correct message is sent and event is emitted. +/// Transferring native asset (local reserve) to `USDC_RESERVE_PARA_ID` (no teleport trust). Using +/// foreign asset (`USDC_RESERVE_PARA_ID` reserve) for fees. +/// +/// Here (source) USDC_RESERVE_PARA_ID (destination) +/// | `assets` reserve `fees` reserve +/// | +/// | 1. execute `InitiateReserveWithdraw(fees)` +/// | \--> sends `WithdrawAsset(fees), ClearOrigin, BuyExecution(fees), DepositAsset` +/// | 2. execute `TransferReserveAsset(assts)` +/// | \-> sends `ReserveAssetDeposited(assts), ClearOrigin, BuyExecution(fees), DepositAsset` +/// \------------------------------------------> #[test] fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_works() { - // foreign creator in this case child parachain acting as reserve - let fee_reserve_location = - RelayLocation::get().pushed_with_interior(Parachain(RESERVE_PARA_ID)).unwrap(); - let foreign_creator_as_account_id = - SovereignAccountOf::convert_location(&fee_reserve_location).unwrap(); + let usdc_reserve_location = RelayLocation::get() + .pushed_with_interior(Parachain(USDC_RESERVE_PARA_ID)) + .unwrap(); + let usdc_chain_sovereign_account = + SovereignAccountOf::convert_location(&usdc_reserve_location).unwrap(); - // foreign parachain with the same consensus currency as asset - let foreign_asset_id_multilocation = - fee_reserve_location.pushed_with_interior(RESERVE_ASSET_INNER_JUNCTION).unwrap(); - let foreign_asset_amount = 142; + let usdc_id_multilocation = + usdc_reserve_location.pushed_with_interior(USDC_INNER_JUNCTION).unwrap(); + let usdc_initial_local_amount = 142; - // transfer destination is fee reserve location (no teleport trust) - let dest = fee_reserve_location; + // native assets transfer destination is same as fee reserve location (no teleport trust) + let dest = usdc_reserve_location; let assets: MultiAssets = vec![ // native asset to transfer (not used for fees) (MultiLocation::here(), SEND_AMOUNT).into(), - // foreign asset for fees (is sufficient on local chain too) - (foreign_asset_id_multilocation, FEE_AMOUNT).into(), + // usdc for fees (is sufficient on local chain too) + (usdc_id_multilocation, FEE_AMOUNT).into(), ] .into(); let fee_index = 1; let asset_index = 0; let balances = - vec![(ALICE, INITIAL_BALANCE), (foreign_creator_as_account_id.clone(), INITIAL_BALANCE)]; + vec![(ALICE, INITIAL_BALANCE), (usdc_chain_sovereign_account.clone(), INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { - // create sufficient foreign asset (0 total issuance) + // create sufficient foreign asset USDC (0 total issuance) assert_ok!(Assets::force_create( RuntimeOrigin::root(), - foreign_asset_id_multilocation, + usdc_id_multilocation, BOB, true, 1 @@ -726,11 +760,11 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ // mint it locally. assert_ok!(Assets::mint( RuntimeOrigin::signed(BOB), - foreign_asset_id_multilocation, + usdc_id_multilocation, ALICE, - foreign_asset_amount + usdc_initial_local_amount )); - assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_asset_amount); + assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); let context = UniversalLocation::get(); @@ -754,20 +788,17 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ )); // Alice spent (fees) amount assert_eq!( - Assets::balance(foreign_asset_id_multilocation, ALICE), - foreign_asset_amount - FEE_AMOUNT + Assets::balance(usdc_id_multilocation, ALICE), + usdc_initial_local_amount - FEE_AMOUNT ); // Alice used native asset for transfer assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); // Sovereign account of dest parachain holds `SEND_AMOUNT` native asset in local reserve assert_eq!( - Balances::free_balance(foreign_creator_as_account_id.clone()), + Balances::free_balance(usdc_chain_sovereign_account.clone()), INITIAL_BALANCE + SEND_AMOUNT ); - assert_eq!( - Assets::balance(foreign_asset_id_multilocation, foreign_creator_as_account_id), - 0 - ); + assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); // Verify sent XCM program assert_eq!( @@ -807,19 +838,24 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ /// Test `reserve_transfer_assets` with destination asset reserve and destination fee reserve. /// -/// Asserts that the sender's balance is decreased and the beneficiary's balance -/// is increased. Verifies the correct message is sent and event is emitted. +/// Here (source) FOREIGN_ASSET_RESERVE_PARA_ID (destination) +/// | `fees` reserve +/// | `assets` reserve +/// | +/// | 1. execute `InitiateReserveWithdraw(assets_and_fees_batched_together)` +/// | \--> sends `WithdrawAsset(batch), ClearOrigin, BuyExecution(fees), DepositAsset` +/// \------------------------------------------> #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_reserve_works() { - // foreign creator in this case child parachain acting as reserve - let reserve_location = - RelayLocation::get().pushed_with_interior(Parachain(RESERVE_PARA_ID)).unwrap(); + // we'll send just this foreign asset back to its reserve location and use it for fees as well + let reserve_location = RelayLocation::get() + .pushed_with_interior(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID)) + .unwrap(); let foreign_creator_as_account_id = SovereignAccountOf::convert_location(&reserve_location).unwrap(); - // foreign parachain with the same consensus currency as asset let foreign_asset_id_multilocation = - reserve_location.pushed_with_interior(RESERVE_ASSET_INNER_JUNCTION).unwrap(); + reserve_location.pushed_with_interior(FOREIGN_ASSET_INNER_JUNCTION).unwrap(); let foreign_asset_amount = 142; // transfer destination is reserve location @@ -885,7 +921,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re assert_eq!( sent_xcm(), vec![( - Parachain(RESERVE_PARA_ID).into(), + Parachain(FOREIGN_ASSET_RESERVE_PARA_ID).into(), Xcm(vec![ WithdrawAsset(expected_assets.clone()), ClearOrigin, @@ -910,57 +946,67 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve /// Test `reserve_transfer_assets` with local asset reserve and remote fee reserve. /// -/// Asserts that the sender's balance is decreased and the beneficiary's balance -/// is increased. Verifies the correct message is sent and event is emitted. +/// Transferring native asset (local reserve) to `OTHER_PARA_ID` (no teleport trust). Using foreign +/// asset (`USDC_RESERVE_PARA_ID` remote reserve) for fees. +/// +/// | chain `A` | chain `C` | chain `B` +/// | Here (source) | USDC_RESERVE_PARA_ID | OTHER_PARA_ID (destination) +/// | `assets` reserve | `fees` reserve | +/// | +/// | 1. `A` executes `InitiateReserveWithdraw(fees)` dest `C` +/// | -----------------> `DepositReserveAsset(fees)` dest `B` +/// | --------------------------> `DepositAsset(fees)` +/// | 2. `A` executes `TransferReserveAsset(assets)` dest `B` +/// | --------------------------------------------------> `ReserveAssetDeposited(assets)` #[test] fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works() { // foreign creator in this case child parachain acting as reserve - let fee_reserve_location = - RelayLocation::get().pushed_with_interior(Parachain(RESERVE_PARA_ID)).unwrap(); - let foreign_creator_as_account_id = + let fee_reserve_location = RelayLocation::get() + .pushed_with_interior(Parachain(USDC_RESERVE_PARA_ID)) + .unwrap(); + let usdc_chain_sovereign_account = SovereignAccountOf::convert_location(&fee_reserve_location).unwrap(); - // foreign parachain with the same consensus currency as asset - let foreign_asset_id_multilocation = - fee_reserve_location.pushed_with_interior(RESERVE_ASSET_INNER_JUNCTION).unwrap(); - let foreign_asset_amount = 142; + let usdc_id_multilocation = + fee_reserve_location.pushed_with_interior(USDC_INNER_JUNCTION).unwrap(); + let usdc_initial_local_amount = 142; - // transfer destination is other parachain than fee reserve location (no teleport trust) + // transfer destination is some other parachain != fee reserve location (no teleport trust) let dest = RelayLocation::get().pushed_with_interior(Parachain(OTHER_PARA_ID)).unwrap(); - let dest_as_account_id = SovereignAccountOf::convert_location(&dest).unwrap(); + let dest_sovereign_account = SovereignAccountOf::convert_location(&dest).unwrap(); let assets: MultiAssets = vec![ // native asset to transfer (not used for fees) - local reserve (MultiLocation::here(), SEND_AMOUNT).into(), - // foreign asset for fees (is sufficient on local chain too) - remote reserve - (foreign_asset_id_multilocation, FEE_AMOUNT).into(), + // USDC for fees (is sufficient on local chain too) - remote reserve + (usdc_id_multilocation, FEE_AMOUNT).into(), ] .into(); let fee_index = 1; let asset_index = 0; let balances = - vec![(ALICE, INITIAL_BALANCE), (foreign_creator_as_account_id.clone(), INITIAL_BALANCE)]; + vec![(ALICE, INITIAL_BALANCE), (usdc_chain_sovereign_account.clone(), INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { - // create sufficient foreign asset (0 total issuance) + // create sufficient foreign asset USDC (0 total issuance) assert_ok!(Assets::force_create( RuntimeOrigin::root(), - foreign_asset_id_multilocation, + usdc_id_multilocation, BOB, true, 1 )); - // this asset should have been teleported/reserve-transferred in, but for this test we just + // USDC should have been teleported/reserve-transferred in, but for this test we just // mint it locally. assert_ok!(Assets::mint( RuntimeOrigin::signed(BOB), - foreign_asset_id_multilocation, + usdc_id_multilocation, ALICE, - foreign_asset_amount + usdc_initial_local_amount )); - assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_asset_amount); + assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); let context = UniversalLocation::get(); @@ -987,27 +1033,24 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works )); // Alice spent (fees) amount assert_eq!( - Assets::balance(foreign_asset_id_multilocation, ALICE), - foreign_asset_amount - FEE_AMOUNT + Assets::balance(usdc_id_multilocation, ALICE), + usdc_initial_local_amount - FEE_AMOUNT ); // Alice used native asset for transfer assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); // Sovereign account of reserve parachain is unchanged - assert_eq!(Balances::free_balance(foreign_creator_as_account_id.clone()), INITIAL_BALANCE); - assert_eq!( - Assets::balance(foreign_asset_id_multilocation, foreign_creator_as_account_id), - 0 - ); + assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), INITIAL_BALANCE); + assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); // Sovereign account of destination parachain holds `SEND_AMOUNT` in local reserve - assert_eq!(Balances::free_balance(dest_as_account_id), SEND_AMOUNT); + assert_eq!(Balances::free_balance(dest_sovereign_account), SEND_AMOUNT); // Verify sent XCM program assert_eq!( sent_xcm(), vec![ ( - // first message is to prefund (foreign-asset) fees on `dest` (by going through - // fee remote reserve) + // first message is to prefund (USDC) fees on `dest` (by going through + // fee remote (USDC) reserve) fee_reserve_location, Xcm(vec![ WithdrawAsset(expected_fee_on_reserve.clone().into()), @@ -1027,7 +1070,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works ), ( // second message is to transfer/deposit (native) asset on `dest` while paying - // using prefunded (transferred above) fees + // using prefunded (transferred above) fees/USDC dest, // transfer is through local-reserve transfer because `assets` (native asset) // have local reserve @@ -1045,46 +1088,65 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works }); } -/// Test `reserve_transfer_assets` with destination asset reserve and local fee reserve. +/// Test `reserve_transfer_assets` with destination asset reserve and remote fee reserve. /// -/// Asserts that the sender's balance is decreased and the beneficiary's balance -/// is increased. Verifies the correct message is sent and event is emitted. +/// Transferring native asset (local reserve) to `OTHER_PARA_ID` (no teleport trust). Using foreign +/// asset (`USDC_RESERVE_PARA_ID` remote reserve) for fees. +/// +/// | chain `A` | chain `C` | chain `B` +/// | Here (source) | USDC_RESERVE_PARA_ID | FOREIGN_ASSET_RESERVE_PARA_ID (destination) +/// | | `fees` reserve | `assets` reserve +/// | +/// | 1. `A` executes `InitiateReserveWithdraw(fees)` dest `C` +/// | -----------------> `DepositReserveAsset(fees)` dest `B` +/// | --------------------------> `DepositAsset(fees)` +/// | 2. `A` executes `InitiateReserveWithdraw(assets)` dest `B` +/// | --------------------------------------------------> `DepositAsset(assets)` #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve_works() { // TODO } -/// Test `reserve_transfer_assets` with remote asset reserve and local fee reserve. +/// Test `reserve_transfer_assets` with remote asset reserve and (same) remote fee reserve. /// -/// Asserts that the sender's balance is decreased and the beneficiary's balance -/// is increased. Verifies the correct message is sent and event is emitted. +/// Transferring native asset (local reserve) to `OTHER_PARA_ID` (no teleport trust). Using foreign +/// asset (`USDC_RESERVE_PARA_ID` remote reserve) for fees. +/// +/// | chain `A` | chain `C` | chain `B` +/// | Here (source) | USDC_RESERVE_PARA_ID | OTHER_PARA_ID (destination) +/// | | `fees` reserve | +/// | | `assets` reserve | +/// | +/// | 1. `A` executes `InitiateReserveWithdraw(both)` dest `C` +/// | -----------------> `DepositReserveAsset(both)` dest `B` +/// | --------------------------> `DepositAsset(both)` #[test] fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_works() { // foreign creator in this case child parachain acting as reserve - let reserve_location = - RelayLocation::get().pushed_with_interior(Parachain(RESERVE_PARA_ID)).unwrap(); - let foreign_creator_as_account_id = - SovereignAccountOf::convert_location(&reserve_location).unwrap(); + let usdc_reserve_location = RelayLocation::get() + .pushed_with_interior(Parachain(USDC_RESERVE_PARA_ID)) + .unwrap(); + let usdc_chain_sovereign_account = + SovereignAccountOf::convert_location(&usdc_reserve_location).unwrap(); - // foreign parachain with the same consensus currency as asset - let foreign_asset_id_multilocation = - reserve_location.pushed_with_interior(RESERVE_ASSET_INNER_JUNCTION).unwrap(); - let foreign_asset_amount = 142; + let usdc_id_multilocation = + usdc_reserve_location.pushed_with_interior(USDC_INNER_JUNCTION).unwrap(); + let usdc_initial_local_amount = 142; - let assets: MultiAssets = vec![(foreign_asset_id_multilocation, SEND_AMOUNT).into()].into(); + let assets: MultiAssets = vec![(usdc_id_multilocation, SEND_AMOUNT).into()].into(); let fee_index = 0; - // transfer destination is other parachain => remote reserve location (RESERVE_PARA_ID) + // transfer destination is some other parachainß let dest = RelayLocation::get().pushed_with_interior(Parachain(OTHER_PARA_ID)).unwrap(); let balances = - vec![(ALICE, INITIAL_BALANCE), (foreign_creator_as_account_id.clone(), INITIAL_BALANCE)]; + vec![(ALICE, INITIAL_BALANCE), (usdc_chain_sovereign_account.clone(), INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { - // create sufficient (to be used as fees as well) foreign asset (0 total issuance) + // create sufficient (to be used as fees as well) USDC asset (0 total issuance) assert_ok!(Assets::force_create( RuntimeOrigin::root(), - foreign_asset_id_multilocation, + usdc_id_multilocation, BOB, true, 1 @@ -1093,19 +1155,19 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work // mint it locally. assert_ok!(Assets::mint( RuntimeOrigin::signed(BOB), - foreign_asset_id_multilocation, + usdc_id_multilocation, ALICE, - foreign_asset_amount + usdc_initial_local_amount )); - assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_asset_amount); + assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); let context = UniversalLocation::get(); let mut expected_fee_on_reserve = assets.get(fee_index).unwrap().clone(); - expected_fee_on_reserve.reanchor(&reserve_location, context).unwrap(); + expected_fee_on_reserve.reanchor(&usdc_reserve_location, context).unwrap(); let mut expected_assets = assets.clone(); expected_assets.reanchor(&dest, context).unwrap(); - let expected_dest_on_reserve = dest.reanchored(&reserve_location, context).unwrap(); + let expected_dest_on_reserve = dest.reanchored(&usdc_reserve_location, context).unwrap(); // do the transfer assert_ok!(XcmPallet::limited_reserve_transfer_assets( @@ -1122,24 +1184,21 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work )); // Alice spent (transferred) amount assert_eq!( - Assets::balance(foreign_asset_id_multilocation, ALICE), - foreign_asset_amount - SEND_AMOUNT + Assets::balance(usdc_id_multilocation, ALICE), + usdc_initial_local_amount - SEND_AMOUNT ); // Alice's native asset balance is untouched assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // Destination account (parachain account) has expected (same) balances - assert_eq!(Balances::free_balance(foreign_creator_as_account_id.clone()), INITIAL_BALANCE); - assert_eq!( - Assets::balance(foreign_asset_id_multilocation, foreign_creator_as_account_id), - 0 - ); + assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), INITIAL_BALANCE); + assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); // Verify sent XCM program assert_eq!( sent_xcm(), vec![( // first message sent to reserve chain - Parachain(RESERVE_PARA_ID).into(), + usdc_reserve_location, Xcm(vec![ WithdrawAsset(expected_fee_on_reserve.clone().into()), ClearOrigin, @@ -1200,7 +1259,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_works() fn execute_withdraw_to_deposit_works() { let balances = vec![ (ALICE, INITIAL_BALANCE), - (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; new_test_ext_with_balances(balances).execute_with(|| { let weight = BaseXcmWeight::get() * 3; From 576c770b7e2f42a3e84447a116d212563975ea1b Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 28 Sep 2023 10:47:52 +0300 Subject: [PATCH 17/98] add test for asset destination-reserve while fee-reserve is remote chain --- polkadot/xcm/pallet-xcm/src/tests.rs | 157 ++++++++++++++++++++++++++- 1 file changed, 156 insertions(+), 1 deletion(-) diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index 4ac8733b4284..d7aca7b71784 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -1104,7 +1104,162 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works /// | --------------------------------------------------> `DepositAsset(assets)` #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve_works() { - // TODO + // foreign creator in this case child parachain acting as reserve + let fee_reserve_location = RelayLocation::get() + .pushed_with_interior(Parachain(USDC_RESERVE_PARA_ID)) + .unwrap(); + let usdc_chain_sovereign_account = + SovereignAccountOf::convert_location(&fee_reserve_location).unwrap(); + let usdc_id_multilocation = + fee_reserve_location.pushed_with_interior(USDC_INNER_JUNCTION).unwrap(); + let usdc_initial_local_amount = 42; + + let reserve_location = RelayLocation::get() + .pushed_with_interior(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID)) + .unwrap(); + let foreign_asset_id_multilocation = + reserve_location.pushed_with_interior(FOREIGN_ASSET_INNER_JUNCTION).unwrap(); + let foreign_asset_initial_amount = 142; + + // transfer destination is asset reserve location + let dest = reserve_location; + let dest_sovereign_account = SovereignAccountOf::convert_location(&dest).unwrap(); + let assets: MultiAssets = vec![ + // native asset to transfer (not used for fees) - destination reserve + (foreign_asset_id_multilocation, SEND_AMOUNT).into(), + // USDC for fees (is sufficient on local chain too) - remote reserve + (usdc_id_multilocation, FEE_AMOUNT).into(), + ] + .into(); + let fee_index = 1; + let asset_index = 0; + + let balances = vec![ + (ALICE, INITIAL_BALANCE), + (usdc_chain_sovereign_account.clone(), INITIAL_BALANCE), + (dest_sovereign_account.clone(), INITIAL_BALANCE), + ]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient foreign asset USDC (0 total issuance) + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + usdc_id_multilocation, + BOB, + true, + 1 + )); + // USDC should have been teleported/reserve-transferred in, but for this test we just + // mint it locally. + assert_ok!(Assets::mint( + RuntimeOrigin::signed(BOB), + usdc_id_multilocation, + ALICE, + usdc_initial_local_amount + )); + // create non-sufficient foreign asset BLA (0 total issuance) + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + foreign_asset_id_multilocation, + BOB, + false, + 1 + )); + // foreign asset BLA should have been teleported/reserve-transferred in, but for this test + // we just mint it locally. + assert_ok!(Assets::mint( + RuntimeOrigin::signed(BOB), + foreign_asset_id_multilocation, + ALICE, + foreign_asset_initial_amount + )); + assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + let context = UniversalLocation::get(); + let mut expected_fee_on_reserve = assets.get(fee_index).unwrap().clone(); + expected_fee_on_reserve.reanchor(&fee_reserve_location, context).unwrap(); + let expected_dest_on_reserve = dest.reanchored(&fee_reserve_location, context).unwrap(); + let mut expected_asset = assets.get(asset_index).unwrap().clone(); + expected_asset.reanchor(&dest, context).unwrap(); + let mut expected_fee = assets.get(fee_index).unwrap().clone(); + expected_fee.reanchor(&dest, context).unwrap(); + + // do the transfer + assert_ok!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + )); + assert!(matches!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) + )); + // Alice native asset untouched + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + // Alice spent USDC for fees + assert_eq!( + Assets::balance(usdc_id_multilocation, ALICE), + usdc_initial_local_amount - FEE_AMOUNT + ); + // Alice transferred BLA + assert_eq!( + Assets::balance(foreign_asset_id_multilocation, ALICE), + foreign_asset_initial_amount - SEND_AMOUNT + ); + // Verify balances of USDC reserve parachain + assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), INITIAL_BALANCE); + assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); + // Verify balances of transferred-asset reserve parachain + assert_eq!(Balances::free_balance(dest_sovereign_account.clone()), INITIAL_BALANCE); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, dest_sovereign_account), 0); + + // Verify sent XCM program + assert_eq!( + sent_xcm(), + vec![ + ( + // first message is to prefund (USDC) fees on `dest` (by going through + // fee remote (USDC) reserve) + fee_reserve_location, + Xcm(vec![ + WithdrawAsset(expected_fee_on_reserve.clone().into()), + ClearOrigin, + buy_limited_execution(expected_fee_on_reserve, Unlimited), + DepositReserveAsset { + assets: Wild(AllCounted(1)), + // final destination is `dest` as seen by `reserve` + dest: expected_dest_on_reserve, + // message sent onward to final `dest` to deposit/prefund fees + xcm: Xcm(vec![ + buy_limited_execution(expected_fee.clone(), Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary } + ]) + } + ]) + ), + ( + // second message is to transfer/deposit foreign assets on `dest` while paying + // using prefunded (transferred above) fees (USDC) + // (dest is reserve location for `expected_asset`) + dest, + Xcm(vec![ + WithdrawAsset(expected_asset.into()), + ClearOrigin, + buy_limited_execution(expected_fee, Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary }, + ]) + ) + ] + ); + let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); + let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); + }); } /// Test `reserve_transfer_assets` with remote asset reserve and (same) remote fee reserve. From 280c4b1216442439d1591e7253a2cda53e280344 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 28 Sep 2023 10:48:21 +0300 Subject: [PATCH 18/98] fix some typos --- .../emulated/assets/asset-hub-westend/src/lib.rs | 4 ++-- .../assets/asset-hub-westend/src/tests/reserve_transfer.rs | 2 +- .../emulated/bridges/bridge-hub-rococo/src/lib.rs | 2 +- polkadot/runtime/parachains/src/paras/mod.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs index 6e0f3434aedf..e0a296df03f3 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs @@ -51,7 +51,7 @@ pub type RelayToSystemParaTest = Test; pub type SystemParaToRelayTest = Test; pub type SystemParaToParaTest = Test; -/// Returns a `TestArgs` instance to de used for the Relay Chain accross integraton tests +/// Returns a `TestArgs` instance to de used for the Relay Chain across integration tests pub fn relay_test_args(amount: Balance) -> TestArgs { TestArgs { dest: Westend::child_location_of(AssetHubWestend::para_id()), @@ -68,7 +68,7 @@ pub fn relay_test_args(amount: Balance) -> TestArgs { } } -/// Returns a `TestArgs` instance to de used for the System Parachain accross integraton tests +/// Returns a `TestArgs` instance to de used for the System Parachain across integration tests pub fn system_para_test_args( dest: MultiLocation, beneficiary_id: AccountId32, diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs index 51fac43be125..491343692e9f 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -189,7 +189,7 @@ fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() { assert_eq!(receiver_balance_before, receiver_balance_after); } -/// Limited Reserve Transfers of native asset from System Parachain to Relay Chain shoudln't work +/// Limited Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work #[test] fn limited_reserve_transfer_native_asset_from_system_para_to_relay_fails() { // Init values for System Parachain diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/lib.rs index 1c73124c5125..f1993c392fd2 100644 --- a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/lib.rs @@ -45,7 +45,7 @@ pub type RelayToSystemParaTest = Test; pub type SystemParaToRelayTest = Test; pub type SystemParaToParaTest = Test; -/// Returns a `TestArgs` instance to de used for the Relay Chain accross integraton tests +/// Returns a `TestArgs` instance to de used for the Relay Chain across integration tests pub fn relay_test_args(amount: Balance) -> TestArgs { TestArgs { dest: Rococo::child_location_of(AssetHubRococo::para_id()), diff --git a/polkadot/runtime/parachains/src/paras/mod.rs b/polkadot/runtime/parachains/src/paras/mod.rs index 2f370b5bfe47..828dcf7d6f04 100644 --- a/polkadot/runtime/parachains/src/paras/mod.rs +++ b/polkadot/runtime/parachains/src/paras/mod.rs @@ -2036,7 +2036,7 @@ impl Pallet { } /// Submits a given PVF check statement with corresponding signature as an unsigned transaction - /// into the memory pool. Ultimately, that disseminates the transaction accross the network. + /// into the memory pool. Ultimately, that disseminates the transaction across the network. /// /// This function expects an offchain context and cannot be callable from the on-chain logic. /// From bab8fc24e74e298bca5de80096766ecab9f059ef Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 28 Sep 2023 11:10:20 +0300 Subject: [PATCH 19/98] deduplicate code for do_teleport_assets() --- polkadot/xcm/pallet-xcm/src/lib.rs | 92 ++++++++++++++++-------------- 1 file changed, 49 insertions(+), 43 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 7e1051134281..a094e9781cdc 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1383,6 +1383,41 @@ impl Pallet { ) } + fn do_teleport_assets( + origin: OriginFor, + dest: Box, + beneficiary: Box, + assets: Box, + fee_asset_item: u32, + weight_limit: WeightLimit, + ) -> DispatchResult { + let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; + let dest = (*dest).try_into().map_err(|()| Error::::BadVersion)?; + let beneficiary: MultiLocation = + (*beneficiary).try_into().map_err(|()| Error::::BadVersion)?; + let assets: MultiAssets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; + + ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::::TooManyAssets); + let value = (origin_location, assets.into_inner()); + ensure!(T::XcmTeleportFilter::contains(&value), Error::::Filtered); + let (origin_location, assets) = value; + for asset in assets.iter() { + let transfer_type = TransferType::determine_for::(asset, &dest)?; + ensure!(matches!(transfer_type, TransferType::Teleport), Error::::Filtered); + } + let fees = assets.get(fee_asset_item as usize).ok_or(Error::::Empty)?.clone(); + + Self::build_and_execute_xcm_transfer_type( + origin_location, + dest, + beneficiary, + assets, + TransferType::Teleport, + fees, + weight_limit, + ) + } + /// Teleport or reserve transfer `fees` - not to be used by itself, it is a helper function for /// prefunding fees for subsequent assets transfer. /// @@ -1426,7 +1461,8 @@ impl Pallet { fees, weight_limit, ), - TransferType::Teleport => todo!(), + TransferType::Teleport => + Self::teleport_asset_message(dest, beneficiary, assets, fees, weight_limit), }?; let weight = T::Weigher::weight(&mut message).map_err(|()| Error::::UnweighableMessage)?; @@ -1519,55 +1555,25 @@ impl Pallet { ])) } - fn do_teleport_assets( - origin: OriginFor, - dest: Box, - beneficiary: Box, - assets: Box, - fee_asset_item: u32, + fn teleport_asset_message( + dest: MultiLocation, + beneficiary: MultiLocation, + assets: Vec, + mut fees: MultiAsset, weight_limit: WeightLimit, - ) -> DispatchResult { - let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; - let dest = (*dest).try_into().map_err(|()| Error::::BadVersion)?; - let beneficiary: MultiLocation = - (*beneficiary).try_into().map_err(|()| Error::::BadVersion)?; - let assets: MultiAssets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; - - ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::::TooManyAssets); - let value = (origin_location, assets.into_inner()); - ensure!(T::XcmTeleportFilter::contains(&value), Error::::Filtered); - let (origin_location, assets) = value; - for asset in assets.iter() { - ensure!( - ::IsTeleporter::contains(asset, &dest), - Error::::Filtered - ); - } + ) -> Result::RuntimeCall>, Error> { let context = T::UniversalLocation::get(); - let fees = assets - .get(fee_asset_item as usize) - .ok_or(Error::::Empty)? - .clone() - .reanchored(&dest, context) - .map_err(|_| Error::::CannotReanchor)?; + fees.reanchor(&dest, context).map_err(|_| Error::::CannotReanchor)?; let max_assets = assets.len() as u32; - let assets: MultiAssets = assets.into(); - let xcm = Xcm(vec![ + let xcm_on_dest = Xcm(vec![ BuyExecution { fees, weight_limit }, DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, ]); - let mut message = Xcm(vec![ - WithdrawAsset(assets), + Ok(Xcm(vec![ + WithdrawAsset(assets.into()), SetFeesMode { jit_withdraw: true }, - InitiateTeleport { assets: Wild(AllCounted(max_assets)), dest, xcm }, - ]); - let weight = - T::Weigher::weight(&mut message).map_err(|()| Error::::UnweighableMessage)?; - let hash = message.using_encoded(sp_io::hashing::blake2_256); - let outcome = - T::XcmExecutor::execute_xcm_in_credit(origin_location, message, hash, weight, weight); - Self::deposit_event(Event::Attempted { outcome }); - Ok(()) + InitiateTeleport { assets: Wild(AllCounted(max_assets)), dest, xcm: xcm_on_dest }, + ])) } /// Will always make progress, and will do its best not to use much more than `weight_cutoff` From f7a4a2e3cf54ee47a23d09211a7c1dfc446f7106 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 28 Sep 2023 12:20:10 +0300 Subject: [PATCH 20/98] add test for asset local-reserve while teleporting fees --- polkadot/xcm/pallet-xcm/src/mock.rs | 26 +++- polkadot/xcm/pallet-xcm/src/tests.rs | 204 ++++++++++++++++++++++++++- 2 files changed, 221 insertions(+), 9 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 982df882b873..29c34afb0f17 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -285,6 +285,10 @@ pub const USDC_RESERVE_PARA_ID: u32 = 2002; // Inner junction of reserve asset on `USDC_RESERVE_PARA_ID`. pub const USDC_INNER_JUNCTION: Junction = PalletInstance(42); +// This child parachain is a trusted teleporter for say.. USDT (T from Teleport :)). +// We'll use USDT in tests that teleport fees. +pub const USDT_PARA_ID: u32 = 2003; + // This child parachain is not configured as trusted reserve or teleport location for any assets. pub const OTHER_PARA_ID: u32 = 2009; @@ -312,6 +316,17 @@ parameter_types! { interior: X2(Parachain(USDC_RESERVE_PARA_ID), USDC_INNER_JUNCTION), }), }; + pub const UsdtTeleportLocation: MultiLocation = MultiLocation { + parents: 0, + interior: X1(Parachain(USDT_PARA_ID)) + }; + pub const Usdt: MultiAsset = MultiAsset { + fun: Fungible(10), + id: Concrete(MultiLocation { + parents: 0, + interior: X1(Parachain(USDT_PARA_ID)), + }), + }; pub const AnyNetwork: Option = None; pub UniversalLocation: InteriorMultiLocation = Here; pub UnitWeightCost: u64 = 1_000; @@ -362,9 +377,10 @@ type LocalOriginConverter = ( parameter_types! { pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000); pub CurrencyPerSecondPerByte: (AssetId, u128, u128) = (Concrete(RelayLocation::get()), 1, 1); - pub TrustedAssets: (MultiAssetFilter, MultiLocation) = (All.into(), Here.into()); - pub TrustedReserve1: (MultiAssetFilter, MultiLocation) = (vec![ForeignAsset::get()].into(), ForeignReserveLocation::get()); - pub TrustedReserve2: (MultiAssetFilter, MultiLocation) = (vec![Usdc::get()].into(), UsdcReserveLocation::get()); + pub TrustedLocal: (MultiAssetFilter, MultiLocation) = (All.into(), Here.into()); + pub TrustedUsdt: (MultiAssetFilter, MultiLocation) = (vec![Usdt::get()].into(), UsdtTeleportLocation::get()); + pub TrustedForeign: (MultiAssetFilter, MultiLocation) = (vec![ForeignAsset::get()].into(), ForeignReserveLocation::get()); + pub TrustedUsdc: (MultiAssetFilter, MultiLocation) = (vec![Usdc::get()].into(), UsdcReserveLocation::get()); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; } @@ -382,8 +398,8 @@ impl xcm_executor::Config for XcmConfig { type XcmSender = TestSendXcm; type AssetTransactor = AssetTransactors; type OriginConverter = LocalOriginConverter; - type IsReserve = (Case, Case); - type IsTeleporter = Case; + type IsReserve = (Case, Case); + type IsTeleporter = (Case, Case); type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = FixedWeightBounds; diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index d7aca7b71784..702d3ac92c18 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -21,7 +21,7 @@ use crate::{ }; use frame_support::{ assert_noop, assert_ok, - traits::{Currency, Hooks}, + traits::{tokens::fungibles::Inspect, Currency, Hooks}, weights::Weight, }; use polkadot_parachain_primitives::primitives::Id as ParaId; @@ -660,6 +660,16 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ Assets::balance(foreign_asset_id_multilocation, foreign_creator_as_account_id), 0 ); + // Verify total and active issuance of foreign BLA have decreased (reserve-based + // (local-instance) BLA was burned) + assert_eq!( + Assets::total_issuance(foreign_asset_id_multilocation), + foreign_asset_amount - SEND_AMOUNT + ); + assert_eq!( + Assets::active_issuance(foreign_asset_id_multilocation), + foreign_asset_amount - SEND_AMOUNT + ); // Verify sent XCM program assert_eq!( @@ -799,6 +809,16 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ INITIAL_BALANCE + SEND_AMOUNT ); assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); + // Verify total and active issuance of USDC have decreased (reserve-based (local-instance) + // USDC was burned) + assert_eq!( + Assets::total_issuance(usdc_id_multilocation), + usdc_initial_local_amount - FEE_AMOUNT + ); + assert_eq!( + Assets::active_issuance(usdc_id_multilocation), + usdc_initial_local_amount - FEE_AMOUNT + ); // Verify sent XCM program assert_eq!( @@ -916,6 +936,16 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re Assets::balance(foreign_asset_id_multilocation, foreign_creator_as_account_id), 0 ); + // Verify total and active issuance of foreign BLA have decreased (reserve-based + // (local-instance) BLA was burned) + assert_eq!( + Assets::total_issuance(foreign_asset_id_multilocation), + foreign_asset_amount - SEND_AMOUNT + ); + assert_eq!( + Assets::active_issuance(foreign_asset_id_multilocation), + foreign_asset_amount - SEND_AMOUNT + ); // Verify sent XCM program assert_eq!( @@ -1043,6 +1073,16 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); // Sovereign account of destination parachain holds `SEND_AMOUNT` in local reserve assert_eq!(Balances::free_balance(dest_sovereign_account), SEND_AMOUNT); + // Verify total and active issuance of USDC have decreased (reserve-based (local-instance) + // USDC was burned) + assert_eq!( + Assets::total_issuance(usdc_id_multilocation), + usdc_initial_local_amount - FEE_AMOUNT + ); + assert_eq!( + Assets::active_issuance(usdc_id_multilocation), + usdc_initial_local_amount - FEE_AMOUNT + ); // Verify sent XCM program assert_eq!( @@ -1218,6 +1258,26 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve // Verify balances of transferred-asset reserve parachain assert_eq!(Balances::free_balance(dest_sovereign_account.clone()), INITIAL_BALANCE); assert_eq!(Assets::balance(foreign_asset_id_multilocation, dest_sovereign_account), 0); + // Verify total and active issuance of USDC have decreased (reserve-based (local-instance) + // USDC was burned) + assert_eq!( + Assets::total_issuance(usdc_id_multilocation), + usdc_initial_local_amount - FEE_AMOUNT + ); + assert_eq!( + Assets::active_issuance(usdc_id_multilocation), + usdc_initial_local_amount - FEE_AMOUNT + ); + // Verify total and active issuance of foreign BLA asset have decreased (reserve-based + // (local-instance) asset was burned) + assert_eq!( + Assets::total_issuance(foreign_asset_id_multilocation), + foreign_asset_initial_amount - SEND_AMOUNT + ); + assert_eq!( + Assets::active_issuance(foreign_asset_id_multilocation), + foreign_asset_initial_amount - SEND_AMOUNT + ); // Verify sent XCM program assert_eq!( @@ -1347,6 +1407,16 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work // Destination account (parachain account) has expected (same) balances assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), INITIAL_BALANCE); assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); + // Verify total and active issuance of USDC have decreased (reserve-based (local-instance) + // USDC was burned) + assert_eq!( + Assets::total_issuance(usdc_id_multilocation), + usdc_initial_local_amount - SEND_AMOUNT + ); + assert_eq!( + Assets::active_issuance(usdc_id_multilocation), + usdc_initial_local_amount - SEND_AMOUNT + ); // Verify sent XCM program assert_eq!( @@ -1381,11 +1451,137 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work /// Test `reserve_transfer_assets` with local asset reserve and teleported fee. /// -/// Asserts that the sender's balance is decreased and the beneficiary's balance -/// is increased. Verifies the correct message is sent and event is emitted. +/// Transferring native asset (local reserve) to `USDT_PARA_ID`. Using teleport-trusted USDT for +/// fees. +/// +/// Here (source) USDT_PARA_ID (destination) +/// | `assets` reserve `fees` teleport-trust +/// | +/// | 1. execute `InitiateTeleport(fees)` +/// | \--> sends `ReceiveTeleportedAsset(fees), .., DepositAsset(fees)` +/// | 2. execute `TransferReserveAsset(assts)` +/// | \-> sends `ReserveAssetDeposited(assts), ClearOrigin, BuyExecution(fees), DepositAsset` +/// \------------------------------------------> #[test] fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { - // TODO + let usdt_location = RelayLocation::get().pushed_with_interior(Parachain(USDT_PARA_ID)).unwrap(); + let usdt_chain_sovereign_account = + SovereignAccountOf::convert_location(&usdt_location).unwrap(); + + let usdt_id_multilocation = usdt_location; + let usdt_initial_local_amount = 42; + + // native assets transfer destination is USDT chain (teleport trust only for USDT) + let dest = usdt_location; + let assets: MultiAssets = vec![ + // native asset to transfer (not used for fees) + (MultiLocation::here(), SEND_AMOUNT).into(), + // usdc for fees (is sufficient on local chain too) + (usdt_id_multilocation, FEE_AMOUNT).into(), + ] + .into(); + let fee_index = 1; + let asset_index = 0; + + let balances = + vec![(ALICE, INITIAL_BALANCE), (usdt_chain_sovereign_account.clone(), INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient foreign asset USDT (0 total issuance) + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + usdt_id_multilocation, + BOB, + true, + 1 + )); + // this asset should have been teleported in, but for this test we just mint it locally. + assert_ok!(Assets::mint( + RuntimeOrigin::signed(BOB), + usdt_id_multilocation, + ALICE, + usdt_initial_local_amount + )); + assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + let context = UniversalLocation::get(); + let mut expected_fee = assets.get(fee_index).unwrap().clone(); + expected_fee.reanchor(&dest, context).unwrap(); + let mut expected_asset = assets.get(asset_index).unwrap().clone(); + expected_asset.reanchor(&dest, context).unwrap(); + + // do the transfer + assert_ok!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + )); + assert!(matches!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) + )); + // Alice spent (fees) amount + assert_eq!( + Assets::balance(usdt_id_multilocation, ALICE), + usdt_initial_local_amount - FEE_AMOUNT + ); + // Alice used native asset for transfer + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); + // Sovereign account of dest parachain holds `SEND_AMOUNT` native asset in local reserve + assert_eq!( + Balances::free_balance(usdt_chain_sovereign_account.clone()), + INITIAL_BALANCE + SEND_AMOUNT + ); + assert_eq!(Assets::balance(usdt_id_multilocation, usdt_chain_sovereign_account), 0); + // Verify total and active issuance have decreased + assert_eq!( + Assets::total_issuance(usdt_id_multilocation), + usdt_initial_local_amount - FEE_AMOUNT + ); + assert_eq!( + Assets::active_issuance(usdt_id_multilocation), + usdt_initial_local_amount - FEE_AMOUNT + ); + + // Verify sent XCM program + assert_eq!( + sent_xcm(), + vec![ + ( + // first message is to prefund fees on `dest` + dest, + // fees are teleported to destination chain + Xcm(vec![ + ReceiveTeleportedAsset(expected_fee.clone().into()), + ClearOrigin, + buy_limited_execution(expected_fee.clone(), Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary }, + ]) + ), + ( + // second message is to transfer/deposit (native) asset on `dest` while paying + // using prefunded (transferred above) fees + dest, + // transfer is through local-reserve transfer because `assets` (native asset) + // have local reserve + Xcm(vec![ + ReserveAssetDeposited(expected_asset.into()), + ClearOrigin, + buy_limited_execution(expected_fee, Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary }, + ]) + ) + ] + ); + let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); + let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); + }); } /// Test `reserve_transfer_assets` with destination asset reserve and teleported fee. From f88de5e74dcb0dd8c3fe7e9cbeedb34eb23e7181 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 28 Sep 2023 14:16:57 +0300 Subject: [PATCH 21/98] add test for asset destination-reserve while teleporting fees --- polkadot/xcm/pallet-xcm/src/mock.rs | 4 +- polkadot/xcm/pallet-xcm/src/tests.rs | 317 +++++++++++++++++++++++---- 2 files changed, 272 insertions(+), 49 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 29c34afb0f17..b269fcea394b 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -276,6 +276,7 @@ impl pallet_assets::Config for Test { } // This child parachain acts as trusted reserve for its assets in tests. +// USDT allowed to teleport to/from here. pub const FOREIGN_ASSET_RESERVE_PARA_ID: u32 = 2001; // Inner junction of reserve asset on `FOREIGN_ASSET_RESERVE_PARA_ID`. pub const FOREIGN_ASSET_INNER_JUNCTION: Junction = GeneralIndex(1234567); @@ -379,6 +380,7 @@ parameter_types! { pub CurrencyPerSecondPerByte: (AssetId, u128, u128) = (Concrete(RelayLocation::get()), 1, 1); pub TrustedLocal: (MultiAssetFilter, MultiLocation) = (All.into(), Here.into()); pub TrustedUsdt: (MultiAssetFilter, MultiLocation) = (vec![Usdt::get()].into(), UsdtTeleportLocation::get()); + pub TeleportUsdtToForeign: (MultiAssetFilter, MultiLocation) = (vec![Usdt::get()].into(), ForeignReserveLocation::get()); pub TrustedForeign: (MultiAssetFilter, MultiLocation) = (vec![ForeignAsset::get()].into(), ForeignReserveLocation::get()); pub TrustedUsdc: (MultiAssetFilter, MultiLocation) = (vec![Usdc::get()].into(), UsdcReserveLocation::get()); pub const MaxInstructions: u32 = 100; @@ -399,7 +401,7 @@ impl xcm_executor::Config for XcmConfig { type AssetTransactor = AssetTransactors; type OriginConverter = LocalOriginConverter; type IsReserve = (Case, Case); - type IsTeleporter = (Case, Case); + type IsTeleporter = (Case, Case, Case); type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = FixedWeightBounds; diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index 702d3ac92c18..1fccafc7ebcf 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -501,6 +501,7 @@ fn do_test_and_verify_reserve_transfer_assets_local_ar_local_fr( /// Transferring native asset (local reserve) to some `OTHER_PARA_ID` (no teleport trust). /// Using native asset for fees as well. /// +/// ```nocompile /// Here (source) OTHER_PARA_ID (destination) /// | `assets` reserve /// | `fees` reserve @@ -508,6 +509,7 @@ fn do_test_and_verify_reserve_transfer_assets_local_ar_local_fr( /// | 1. execute `TransferReserveAsset(assets_and_fees_batched_together)` /// | \--> sends `ReserveAssetDeposited(both), ClearOrigin, BuyExecution(fees), DepositAsset` /// \------------------------------------------> +/// ``` /// /// Asserts that the sender's balance is decreased and the destination SA balance /// is increased. Verifies the correct message is sent and event is emitted. @@ -564,6 +566,7 @@ fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserv /// `FOREIGN_ASSET_RESERVE_PARA_ID` (no teleport trust). /// Using native asset (local reserve) for fees. /// +/// ```nocompile /// Here (source) FOREIGN_ASSET_RESERVE_PARA_ID (destination) /// | `fees` reserve `assets` reserve /// | @@ -572,6 +575,7 @@ fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserv /// | 2. execute `InitiateReserveWithdraw(assets)` /// | \--> sends `WithdrawAsset(assets), ClearOrigin, BuyExecution(fees), DepositAsset` /// \------------------------------------------> +/// ``` /// /// Asserts that the sender's balance is decreased and the beneficiary's balance /// is increased. Verifies the correct message is sent and event is emitted. @@ -600,6 +604,18 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ let fee_index = 0; let asset_index = 1; + let context = UniversalLocation::get(); + let mut expected_fee = assets.get(fee_index).unwrap().clone(); + let mut expected_asset = assets.get(asset_index).unwrap().clone(); + + // sanity check indices are still ok after sort() done by `vec![MultiAsset].into()`. + assert_eq!(expected_fee.id, MultiLocation::here().into()); + assert_eq!(expected_asset.id, foreign_asset_id_multilocation.into()); + + // reanchor according to test-case. + expected_fee.reanchor(&dest, context).unwrap(); + expected_asset.reanchor(&dest, context).unwrap(); + let balances = vec![(ALICE, INITIAL_BALANCE), (foreign_creator_as_account_id.clone(), INITIAL_BALANCE)]; let beneficiary: MultiLocation = @@ -625,12 +641,6 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_asset_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); - let context = UniversalLocation::get(); - let mut expected_fee = assets.get(fee_index).unwrap().clone(); - expected_fee.reanchor(&dest, context).unwrap(); - let mut expected_asset = assets.get(asset_index).unwrap().clone(); - expected_asset.reanchor(&dest, context).unwrap(); - // do the transfer assert_ok!(XcmPallet::limited_reserve_transfer_assets( RuntimeOrigin::signed(ALICE), @@ -720,6 +730,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_works /// Transferring native asset (local reserve) to `USDC_RESERVE_PARA_ID` (no teleport trust). Using /// foreign asset (`USDC_RESERVE_PARA_ID` reserve) for fees. /// +/// ```nocompile /// Here (source) USDC_RESERVE_PARA_ID (destination) /// | `assets` reserve `fees` reserve /// | @@ -728,6 +739,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_works /// | 2. execute `TransferReserveAsset(assts)` /// | \-> sends `ReserveAssetDeposited(assts), ClearOrigin, BuyExecution(fees), DepositAsset` /// \------------------------------------------> +/// ``` #[test] fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_works() { let usdc_reserve_location = RelayLocation::get() @@ -752,6 +764,18 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ let fee_index = 1; let asset_index = 0; + let context = UniversalLocation::get(); + let mut expected_fee = assets.get(fee_index).unwrap().clone(); + let mut expected_asset = assets.get(asset_index).unwrap().clone(); + + // sanity check indices are still ok after sort() done by `vec![MultiAsset].into()`. + assert_eq!(expected_fee.id, usdc_id_multilocation.into()); + assert_eq!(expected_asset.id, MultiLocation::here().into()); + + // reanchor according to test-case. + expected_fee.reanchor(&dest, context).unwrap(); + expected_asset.reanchor(&dest, context).unwrap(); + let balances = vec![(ALICE, INITIAL_BALANCE), (usdc_chain_sovereign_account.clone(), INITIAL_BALANCE)]; let beneficiary: MultiLocation = @@ -777,12 +801,6 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); - let context = UniversalLocation::get(); - let mut expected_fee = assets.get(fee_index).unwrap().clone(); - expected_fee.reanchor(&dest, context).unwrap(); - let mut expected_asset = assets.get(asset_index).unwrap().clone(); - expected_asset.reanchor(&dest, context).unwrap(); - // do the transfer assert_ok!(XcmPallet::limited_reserve_transfer_assets( RuntimeOrigin::signed(ALICE), @@ -858,6 +876,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ /// Test `reserve_transfer_assets` with destination asset reserve and destination fee reserve. /// +/// ```nocompile /// Here (source) FOREIGN_ASSET_RESERVE_PARA_ID (destination) /// | `fees` reserve /// | `assets` reserve @@ -865,6 +884,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ /// | 1. execute `InitiateReserveWithdraw(assets_and_fees_batched_together)` /// | \--> sends `WithdrawAsset(batch), ClearOrigin, BuyExecution(fees), DepositAsset` /// \------------------------------------------> +/// ``` #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_reserve_works() { // we'll send just this foreign asset back to its reserve location and use it for fees as well @@ -883,6 +903,9 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re let assets: MultiAssets = vec![(foreign_asset_id_multilocation, SEND_AMOUNT).into()].into(); let fee_index = 0; + let mut expected_assets = assets.clone(); + expected_assets.reanchor(&dest, UniversalLocation::get()).unwrap(); + let balances = vec![(ALICE, INITIAL_BALANCE), (foreign_creator_as_account_id.clone(), INITIAL_BALANCE)]; let beneficiary: MultiLocation = @@ -907,9 +930,6 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_asset_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); - let mut expected_assets = assets.clone(); - expected_assets.reanchor(&dest, UniversalLocation::get()).unwrap(); - // do the transfer assert_ok!(XcmPallet::limited_reserve_transfer_assets( RuntimeOrigin::signed(ALICE), @@ -979,6 +999,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve /// Transferring native asset (local reserve) to `OTHER_PARA_ID` (no teleport trust). Using foreign /// asset (`USDC_RESERVE_PARA_ID` remote reserve) for fees. /// +/// ```nocompile /// | chain `A` | chain `C` | chain `B` /// | Here (source) | USDC_RESERVE_PARA_ID | OTHER_PARA_ID (destination) /// | `assets` reserve | `fees` reserve | @@ -988,6 +1009,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve /// | --------------------------> `DepositAsset(fees)` /// | 2. `A` executes `TransferReserveAsset(assets)` dest `B` /// | --------------------------------------------------> `ReserveAssetDeposited(assets)` +/// ``` #[test] fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works() { // foreign creator in this case child parachain acting as reserve @@ -1011,8 +1033,23 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works (usdc_id_multilocation, FEE_AMOUNT).into(), ] .into(); - let fee_index = 1; let asset_index = 0; + let fee_index = 1; + + let context = UniversalLocation::get(); + let mut expected_asset = assets.get(asset_index).unwrap().clone(); + let mut expected_fee = assets.get(fee_index).unwrap().clone(); + + // sanity check indices are still ok after sort() done by `vec![MultiAsset].into()`. + assert_eq!(expected_fee.id, usdc_id_multilocation.into()); + assert_eq!(expected_asset.id, MultiLocation::here().into()); + + // reanchor according to test-case. + let mut expected_fee_on_reserve = assets.get(fee_index).unwrap().clone(); + expected_fee_on_reserve.reanchor(&fee_reserve_location, context).unwrap(); + let expected_dest_on_reserve = dest.reanchored(&fee_reserve_location, context).unwrap(); + expected_fee.reanchor(&dest, context).unwrap(); + expected_asset.reanchor(&dest, context).unwrap(); let balances = vec![(ALICE, INITIAL_BALANCE), (usdc_chain_sovereign_account.clone(), INITIAL_BALANCE)]; @@ -1039,15 +1076,6 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); - let context = UniversalLocation::get(); - let mut expected_fee_on_reserve = assets.get(fee_index).unwrap().clone(); - expected_fee_on_reserve.reanchor(&fee_reserve_location, context).unwrap(); - let expected_dest_on_reserve = dest.reanchored(&fee_reserve_location, context).unwrap(); - let mut expected_asset = assets.get(asset_index).unwrap().clone(); - expected_asset.reanchor(&dest, context).unwrap(); - let mut expected_fee = assets.get(fee_index).unwrap().clone(); - expected_fee.reanchor(&dest, context).unwrap(); - // do the transfer assert_ok!(XcmPallet::limited_reserve_transfer_assets( RuntimeOrigin::signed(ALICE), @@ -1133,6 +1161,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works /// Transferring native asset (local reserve) to `OTHER_PARA_ID` (no teleport trust). Using foreign /// asset (`USDC_RESERVE_PARA_ID` remote reserve) for fees. /// +/// ```nocompile /// | chain `A` | chain `C` | chain `B` /// | Here (source) | USDC_RESERVE_PARA_ID | FOREIGN_ASSET_RESERVE_PARA_ID (destination) /// | | `fees` reserve | `assets` reserve @@ -1142,6 +1171,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works /// | --------------------------> `DepositAsset(fees)` /// | 2. `A` executes `InitiateReserveWithdraw(assets)` dest `B` /// | --------------------------------------------------> `DepositAsset(assets)` +/// ``` #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve_works() { // foreign creator in this case child parachain acting as reserve @@ -1165,14 +1195,29 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve let dest = reserve_location; let dest_sovereign_account = SovereignAccountOf::convert_location(&dest).unwrap(); let assets: MultiAssets = vec![ - // native asset to transfer (not used for fees) - destination reserve + // foreign asset to transfer (not used for fees) - destination reserve (foreign_asset_id_multilocation, SEND_AMOUNT).into(), // USDC for fees (is sufficient on local chain too) - remote reserve (usdc_id_multilocation, FEE_AMOUNT).into(), ] .into(); - let fee_index = 1; let asset_index = 0; + let fee_index = 1; + + let context = UniversalLocation::get(); + let mut expected_asset = assets.get(asset_index).unwrap().clone(); + let mut expected_fee = assets.get(fee_index).unwrap().clone(); + + // sanity check indices are still ok after sort() done by `vec![MultiAsset].into()`. + assert_eq!(expected_fee.id, usdc_id_multilocation.into()); + assert_eq!(expected_asset.id, foreign_asset_id_multilocation.into()); + + // reanchor according to test-case. + let mut expected_fee_on_reserve = assets.get(fee_index).unwrap().clone(); + expected_fee_on_reserve.reanchor(&fee_reserve_location, context).unwrap(); + let expected_dest_on_reserve = dest.reanchored(&fee_reserve_location, context).unwrap(); + expected_fee.reanchor(&dest, context).unwrap(); + expected_asset.reanchor(&dest, context).unwrap(); let balances = vec![ (ALICE, INITIAL_BALANCE), @@ -1218,15 +1263,6 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); - let context = UniversalLocation::get(); - let mut expected_fee_on_reserve = assets.get(fee_index).unwrap().clone(); - expected_fee_on_reserve.reanchor(&fee_reserve_location, context).unwrap(); - let expected_dest_on_reserve = dest.reanchored(&fee_reserve_location, context).unwrap(); - let mut expected_asset = assets.get(asset_index).unwrap().clone(); - expected_asset.reanchor(&dest, context).unwrap(); - let mut expected_fee = assets.get(fee_index).unwrap().clone(); - expected_fee.reanchor(&dest, context).unwrap(); - // do the transfer assert_ok!(XcmPallet::limited_reserve_transfer_assets( RuntimeOrigin::signed(ALICE), @@ -1327,6 +1363,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve /// Transferring native asset (local reserve) to `OTHER_PARA_ID` (no teleport trust). Using foreign /// asset (`USDC_RESERVE_PARA_ID` remote reserve) for fees. /// +/// ```nocompile /// | chain `A` | chain `C` | chain `B` /// | Here (source) | USDC_RESERVE_PARA_ID | OTHER_PARA_ID (destination) /// | | `fees` reserve | @@ -1335,6 +1372,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve /// | 1. `A` executes `InitiateReserveWithdraw(both)` dest `C` /// | -----------------> `DepositReserveAsset(both)` dest `B` /// | --------------------------> `DepositAsset(both)` +/// ``` #[test] fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_works() { // foreign creator in this case child parachain acting as reserve @@ -1454,6 +1492,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work /// Transferring native asset (local reserve) to `USDT_PARA_ID`. Using teleport-trusted USDT for /// fees. /// +/// ```nocompile /// Here (source) USDT_PARA_ID (destination) /// | `assets` reserve `fees` teleport-trust /// | @@ -1462,6 +1501,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work /// | 2. execute `TransferReserveAsset(assts)` /// | \-> sends `ReserveAssetDeposited(assts), ClearOrigin, BuyExecution(fees), DepositAsset` /// \------------------------------------------> +/// ``` #[test] fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { let usdt_location = RelayLocation::get().pushed_with_interior(Parachain(USDT_PARA_ID)).unwrap(); @@ -1476,12 +1516,24 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { let assets: MultiAssets = vec![ // native asset to transfer (not used for fees) (MultiLocation::here(), SEND_AMOUNT).into(), - // usdc for fees (is sufficient on local chain too) + // USDT for fees (is sufficient on local chain too) (usdt_id_multilocation, FEE_AMOUNT).into(), ] .into(); - let fee_index = 1; let asset_index = 0; + let fee_index = 1; + + let context = UniversalLocation::get(); + let mut expected_fee = assets.get(fee_index).unwrap().clone(); + let mut expected_asset = assets.get(asset_index).unwrap().clone(); + + // sanity check indices are still ok after sort() done by `vec![MultiAsset].into()`. + assert_eq!(expected_fee.id, usdt_id_multilocation.into()); + assert_eq!(expected_asset.id, MultiLocation::here().into()); + + // reanchor according to test-case. + expected_fee.reanchor(&dest, context).unwrap(); + expected_asset.reanchor(&dest, context).unwrap(); let balances = vec![(ALICE, INITIAL_BALANCE), (usdt_chain_sovereign_account.clone(), INITIAL_BALANCE)]; @@ -1507,12 +1559,6 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); - let context = UniversalLocation::get(); - let mut expected_fee = assets.get(fee_index).unwrap().clone(); - expected_fee.reanchor(&dest, context).unwrap(); - let mut expected_asset = assets.get(asset_index).unwrap().clone(); - expected_asset.reanchor(&dest, context).unwrap(); - // do the transfer assert_ok!(XcmPallet::limited_reserve_transfer_assets( RuntimeOrigin::signed(ALICE), @@ -1539,7 +1585,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { INITIAL_BALANCE + SEND_AMOUNT ); assert_eq!(Assets::balance(usdt_id_multilocation, usdt_chain_sovereign_account), 0); - // Verify total and active issuance have decreased + // Verify total and active issuance have decreased (teleported) assert_eq!( Assets::total_issuance(usdt_id_multilocation), usdt_initial_local_amount - FEE_AMOUNT @@ -1586,11 +1632,186 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { /// Test `reserve_transfer_assets` with destination asset reserve and teleported fee. /// -/// Asserts that the sender's balance is decreased and the beneficiary's balance -/// is increased. Verifies the correct message is sent and event is emitted. +/// Transferring native asset (local reserve) to `FOREIGN_ASSET_RESERVE_PARA_ID`. Using +/// teleport-trusted USDT for fees. +/// +/// ```nocompile +/// Here (source) FOREIGN_ASSET_RESERVE_PARA_ID (destination) +/// | `fees` (USDT) teleport-trust +/// | `assets` reserve +/// | +/// | 1. execute `InitiateTeleport(fees)` +/// | \--> sends `ReceiveTeleportedAsset(fees), .., DepositAsset(fees)` +/// | 2. execute `InitiateReserveWithdraw(assets)` +/// | \--> sends `WithdrawAsset(asset), ClearOrigin, BuyExecution(fees), DepositAsset` +/// \------------------------------------------> +/// ``` #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_works() { - // TODO + let usdt_chain = RelayLocation::get().pushed_with_interior(Parachain(USDT_PARA_ID)).unwrap(); + let usdt_chain_sovereign_account = SovereignAccountOf::convert_location(&usdt_chain).unwrap(); + let usdt_id_multilocation = usdt_chain; + let usdt_initial_local_amount = 42; + + let reserve_location = RelayLocation::get() + .pushed_with_interior(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID)) + .unwrap(); + let foreign_asset_id_multilocation = + reserve_location.pushed_with_interior(FOREIGN_ASSET_INNER_JUNCTION).unwrap(); + let foreign_asset_initial_amount = 142; + + // transfer destination is asset reserve location + let dest = reserve_location; + let dest_sovereign_account = SovereignAccountOf::convert_location(&dest).unwrap(); + let assets: MultiAssets = vec![ + // USDT for fees (is sufficient on local chain too) + (usdt_id_multilocation, FEE_AMOUNT).into(), + // foreign asset to transfer (not used for fees) - destination reserve + (foreign_asset_id_multilocation, SEND_AMOUNT).into(), + ] + .into(); + let fee_index = 0; + let asset_index = 1; + + let context = UniversalLocation::get(); + let mut expected_fee = assets.get(fee_index).unwrap().clone(); + let mut expected_asset = assets.get(asset_index).unwrap().clone(); + + // sanity check indices are still ok after sort() done by `vec![MultiAsset].into()`. + assert_eq!(expected_fee.id, usdt_id_multilocation.into()); + assert_eq!(expected_asset.id, foreign_asset_id_multilocation.into()); + + // reanchor according to test-case. + expected_fee.reanchor(&dest, context).unwrap(); + expected_asset.reanchor(&dest, context).unwrap(); + + let balances = vec![ + (ALICE, INITIAL_BALANCE), + (usdt_chain_sovereign_account.clone(), INITIAL_BALANCE), + (dest_sovereign_account.clone(), INITIAL_BALANCE), + ]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient foreign asset USDT (0 total issuance) + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + usdt_id_multilocation, + BOB, + true, + 1 + )); + // USDT should have been teleported/reserve-transferred in, but for this test we just + // mint it locally. + assert_ok!(Assets::mint( + RuntimeOrigin::signed(BOB), + usdt_id_multilocation, + ALICE, + usdt_initial_local_amount + )); + // create non-sufficient foreign asset BLA (0 total issuance) + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + foreign_asset_id_multilocation, + BOB, + false, + 1 + )); + // foreign asset BLA should have been teleported/reserve-transferred in, but for this test + // we just mint it locally. + assert_ok!(Assets::mint( + RuntimeOrigin::signed(BOB), + foreign_asset_id_multilocation, + ALICE, + foreign_asset_initial_amount + )); + assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // do the transfer + assert_ok!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + )); + assert!(matches!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) + )); + // Alice native asset untouched + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + // Alice spent USDT for fees + assert_eq!( + Assets::balance(usdt_id_multilocation, ALICE), + usdt_initial_local_amount - FEE_AMOUNT + ); + // Alice transferred BLA + assert_eq!( + Assets::balance(foreign_asset_id_multilocation, ALICE), + foreign_asset_initial_amount - SEND_AMOUNT + ); + // Verify balances of USDT reserve parachain + assert_eq!(Balances::free_balance(usdt_chain_sovereign_account.clone()), INITIAL_BALANCE); + assert_eq!(Assets::balance(usdt_id_multilocation, usdt_chain_sovereign_account), 0); + // Verify balances of transferred-asset reserve parachain + assert_eq!(Balances::free_balance(dest_sovereign_account.clone()), INITIAL_BALANCE); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, dest_sovereign_account), 0); + // Verify total and active issuance of USDT have decreased (teleported) + assert_eq!( + Assets::total_issuance(usdt_id_multilocation), + usdt_initial_local_amount - FEE_AMOUNT + ); + assert_eq!( + Assets::active_issuance(usdt_id_multilocation), + usdt_initial_local_amount - FEE_AMOUNT + ); + // Verify total and active issuance of foreign BLA asset have decreased (reserve-based + // (local-instance) asset was burned) + assert_eq!( + Assets::total_issuance(foreign_asset_id_multilocation), + foreign_asset_initial_amount - SEND_AMOUNT + ); + assert_eq!( + Assets::active_issuance(foreign_asset_id_multilocation), + foreign_asset_initial_amount - SEND_AMOUNT + ); + + // Verify sent XCM program + assert_eq!( + sent_xcm(), + vec![ + ( + // first message is to prefund fees on `dest` + dest, + // fees are teleported to destination chain + Xcm(vec![ + ReceiveTeleportedAsset(expected_fee.clone().into()), + ClearOrigin, + buy_limited_execution(expected_fee.clone(), Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary }, + ]) + ), + ( + // second message is to transfer/deposit foreign assets on `dest` while paying + // using prefunded (transferred above) fees (USDT) + // (dest is reserve location for `expected_asset`) + dest, + Xcm(vec![ + WithdrawAsset(expected_asset.into()), + ClearOrigin, + buy_limited_execution(expected_fee, Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary }, + ]) + ) + ] + ); + let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); + let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); + }); } /// Test `reserve_transfer_assets` with remote asset reserve and teleported fee. From f7abb0ac61f4d3ac5e87ee4cd986f56b3f8a667b Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 28 Sep 2023 15:58:02 +0300 Subject: [PATCH 22/98] fix cases when asset reserve is remote, add test remote-asset and teleported fee --- polkadot/xcm/pallet-xcm/src/lib.rs | 64 +++----- polkadot/xcm/pallet-xcm/src/tests.rs | 230 +++++++++++++++++++++++++-- 2 files changed, 244 insertions(+), 50 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index a094e9781cdc..99d5d80027c6 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1295,7 +1295,7 @@ impl Pallet { if fee_asset_item as usize >= assets.len() { return Err(Error::::Empty.into()) } - let fees = assets.swap_remove(fee_asset_item as usize); + let mut fees = assets.swap_remove(fee_asset_item as usize); let fees_transfer_type = TransferType::determine_for::(&fees, &dest)?; let assets_transfer_type = if assets.is_empty() { // Single asset to transfer (also used for fees). @@ -1328,34 +1328,31 @@ impl Pallet { // BuyExecution on both chains. Split fees, and deposit half at assets-reserve chain // and half at destination. if let TransferType::RemoteReserve(assets_reserve) = assets_transfer_type { - let (fees_for_reserve, fees_for_dest) = Self::equal_split_asset(&fees)?; + // Halve amount of fees, each half will be sent to one chain. + Self::halve_fungible_asset(&mut fees)?; // Halve weight limit again to be used for the two fees transfers. let quarter_weight_limit = Self::halve_weight_limit(&weight_limit); - let context = T::UniversalLocation::get(); - // Send half the `fees` to the Sovereign Account of `dest` on assets-reserve chain. - let assets_reserve_beneficiary = dest - .reanchored(&assets_reserve, context) - .map_err(|_| Error::::CannotReanchor)?; - Self::prefund_transfer_fees( + // Send half the `fees` to `beneficiary` on assets-reserve chain. + Self::build_and_execute_xcm_transfer_type( origin_location, assets_reserve, - assets_reserve_beneficiary, - fees_for_reserve, + beneficiary, + vec![fees.clone()], + TransferType::determine_for::(&fees, &assets_reserve)?, + fees.clone(), quarter_weight_limit.clone(), )?; - Self::prefund_transfer_fees( + // Send the other half of the `fees` to `beneficiary` on dest chain. + Self::build_and_execute_xcm_transfer_type( origin_location, dest, beneficiary, - fees_for_dest, + vec![fees.clone()], + fees_transfer_type, + fees.clone(), quarter_weight_limit, )?; } else { - if let TransferType::RemoteReserve(_fees_reserve) = fees_transfer_type { - // TODO: change beneficiary on `fee_reserve` to be SA-of-Here. - // But beneficiary on `dest` should stay unchanged... - // Or maybe not required, fees can be used from Holding register, we'll see :D - } // execute fees transfer - have to do it separately than assets because of the // different transfer type (different XCM program required) Self::build_and_execute_xcm_transfer_type( @@ -1418,22 +1415,6 @@ impl Pallet { ) } - /// Teleport or reserve transfer `fees` - not to be used by itself, it is a helper function for - /// prefunding fees for subsequent assets transfer. - /// - /// Fees are allowed to be either teleported or reserve transferred. - fn prefund_transfer_fees( - _origin: impl Into, - _dest: MultiLocation, - _beneficiary: MultiLocation, - _asset: MultiAsset, - _weight_limit: WeightLimit, - ) -> DispatchResult { - // let fee_transfer_type = TransferType::determine_for::(&fee_asset, &dest)?; - // Ok(()) - todo!() - } - fn build_and_execute_xcm_transfer_type( origin: impl Into, dest: MultiLocation, @@ -1919,14 +1900,15 @@ impl Pallet { } } - /// Split fungible `asset` in two equal `MultiAsset`s. - fn equal_split_asset(asset: &MultiAsset) -> Result<(MultiAsset, MultiAsset), Error> { - let half_amount = match &asset.fun { - Fungible(amount) => amount.saturating_div(2), - NonFungible(_) => return Err(Error::::InvalidAsset), - }; - let half = MultiAsset { fun: Fungible(half_amount), id: asset.id }; - Ok((half.clone(), half)) + /// Halve `asset`s fungible amount. + pub(crate) fn halve_fungible_asset(asset: &mut MultiAsset) -> Result<(), Error> { + match &mut asset.fun { + Fungible(amount) => { + *amount = amount.saturating_div(2); + Ok(()) + }, + NonFungible(_) => Err(Error::::InvalidAsset), + } } } diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index 1fccafc7ebcf..dca80a14e8c9 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -37,7 +37,7 @@ const ALICE: AccountId = AccountId::new([0u8; 32]); const BOB: AccountId = AccountId::new([1u8; 32]); const INITIAL_BALANCE: u128 = 100; const SEND_AMOUNT: u128 = 10; -const FEE_AMOUNT: u128 = 1; +const FEE_AMOUNT: u128 = 2; #[test] fn report_outcome_notify_works() { @@ -1045,9 +1045,9 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works assert_eq!(expected_asset.id, MultiLocation::here().into()); // reanchor according to test-case. - let mut expected_fee_on_reserve = assets.get(fee_index).unwrap().clone(); - expected_fee_on_reserve.reanchor(&fee_reserve_location, context).unwrap(); let expected_dest_on_reserve = dest.reanchored(&fee_reserve_location, context).unwrap(); + let mut expected_fee_on_reserve = expected_fee.clone(); + expected_fee_on_reserve.reanchor(&fee_reserve_location, context).unwrap(); expected_fee.reanchor(&dest, context).unwrap(); expected_asset.reanchor(&dest, context).unwrap(); @@ -1213,9 +1213,9 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve assert_eq!(expected_asset.id, foreign_asset_id_multilocation.into()); // reanchor according to test-case. - let mut expected_fee_on_reserve = assets.get(fee_index).unwrap().clone(); - expected_fee_on_reserve.reanchor(&fee_reserve_location, context).unwrap(); let expected_dest_on_reserve = dest.reanchored(&fee_reserve_location, context).unwrap(); + let mut expected_fee_on_reserve = expected_fee.clone(); + expected_fee_on_reserve.reanchor(&fee_reserve_location, context).unwrap(); expected_fee.reanchor(&dest, context).unwrap(); expected_asset.reanchor(&dest, context).unwrap(); @@ -1632,7 +1632,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { /// Test `reserve_transfer_assets` with destination asset reserve and teleported fee. /// -/// Transferring native asset (local reserve) to `FOREIGN_ASSET_RESERVE_PARA_ID`. Using +/// Transferring foreign asset (destination reserve) to `FOREIGN_ASSET_RESERVE_PARA_ID`. Using /// teleport-trusted USDT for fees. /// /// ```nocompile @@ -1816,11 +1816,223 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_wor /// Test `reserve_transfer_assets` with remote asset reserve and teleported fee. /// -/// Asserts that the sender's balance is decreased and the beneficiary's balance -/// is increased. Verifies the correct message is sent and event is emitted. +/// Transferring foreign asset (reserve on `FOREIGN_ASSET_RESERVE_PARA_ID`) to `USDT_PARA_ID`. Using +/// teleport-trusted USDT for fees. +/// +/// ```nocompile +/// | chain `A` | chain `C` | chain `B` +/// | Here (source) | FOREIGN_ASSET_RESERVE_PARA_ID | USDT_PARA_ID (destination) +/// | | `assets` reserve | `fees` (USDT) teleport-trust +/// | +/// | 1. `A` executes `InitiateTeleport(fees)` dest `C` +/// | \----------> `C` executes `ReceiveTeleportedAsset(fees), .., DepositAsset(fees)` +/// | +/// | 2. `A` executes `InitiateTeleport(fees)` dest `B` +/// | \-------------------------------------------------> `B` executes: +/// | `ReceiveTeleportedAsset(fees), .., DepositAsset(fees)` +/// | +/// | 3. `A` executes `InitiateReserveWithdraw(assets)` dest `B` +/// | --------------------------------------------------> `DepositAsset(assets)` +/// ``` #[test] fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_works() { - // TODO + let usdt_chain = RelayLocation::get().pushed_with_interior(Parachain(USDT_PARA_ID)).unwrap(); + let usdt_chain_sovereign_account = SovereignAccountOf::convert_location(&usdt_chain).unwrap(); + let usdt_id_multilocation = usdt_chain; + let usdt_initial_local_amount = 42; + + let reserve_location = RelayLocation::get() + .pushed_with_interior(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID)) + .unwrap(); + let foreign_asset_id_multilocation = + reserve_location.pushed_with_interior(FOREIGN_ASSET_INNER_JUNCTION).unwrap(); + let foreign_asset_initial_amount = 142; + let reserve_sovereign_account = + SovereignAccountOf::convert_location(&reserve_location).unwrap(); + + // transfer destination is USDT chain (foreign asset needs to go through its reserve chain) + let dest = usdt_chain; + let assets: MultiAssets = vec![ + // USDT for fees (is sufficient on local chain too) + (usdt_id_multilocation, FEE_AMOUNT).into(), + // foreign asset to transfer (not used for fees) - remote reserve + (foreign_asset_id_multilocation, SEND_AMOUNT).into(), + ] + .into(); + let fee_index = 0; + let asset_index = 1; + + let context = UniversalLocation::get(); + let mut expected_fee = assets.get(fee_index).unwrap().clone(); + let mut expected_asset = assets.get(asset_index).unwrap().clone(); + + // sanity check indices are still ok after sort() done by `vec![MultiAsset].into()`. + assert_eq!(expected_fee.id, usdt_id_multilocation.into()); + assert_eq!(expected_asset.id, foreign_asset_id_multilocation.into()); + + // reanchor according to test-case. + let expected_dest_on_reserve = dest.reanchored(&reserve_location, context).unwrap(); + let mut expected_fee_on_reserve = expected_fee.clone(); + let mut expected_asset_on_reserve = expected_asset.clone(); + expected_fee_on_reserve.reanchor(&reserve_location, context).unwrap(); + expected_asset_on_reserve.reanchor(&reserve_location, context).unwrap(); + expected_fee.reanchor(&dest, context).unwrap(); + expected_asset.reanchor(&dest, context).unwrap(); + + // fees are split between the asset-reserve chain and the destination chain + crate::Pallet::::halve_fungible_asset(&mut expected_fee_on_reserve).unwrap(); + crate::Pallet::::halve_fungible_asset(&mut expected_fee).unwrap(); + + let balances = vec![ + (ALICE, INITIAL_BALANCE), + (usdt_chain_sovereign_account.clone(), INITIAL_BALANCE), + (reserve_sovereign_account.clone(), INITIAL_BALANCE), + ]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let expected_beneficiary_on_reserve = beneficiary; + + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient foreign asset USDT (0 total issuance) + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + usdt_id_multilocation, + BOB, + true, + 1 + )); + // USDT should have been teleported/reserve-transferred in, but for this test we just + // mint it locally. + assert_ok!(Assets::mint( + RuntimeOrigin::signed(BOB), + usdt_id_multilocation, + ALICE, + usdt_initial_local_amount + )); + // create non-sufficient foreign asset BLA (0 total issuance) + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + foreign_asset_id_multilocation, + BOB, + false, + 1 + )); + // foreign asset BLA should have been teleported/reserve-transferred in, but for this test + // we just mint it locally. + assert_ok!(Assets::mint( + RuntimeOrigin::signed(BOB), + foreign_asset_id_multilocation, + ALICE, + foreign_asset_initial_amount + )); + assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // do the transfer + assert_ok!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + )); + assert!(matches!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) + )); + // Alice native asset untouched + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + // Alice spent USDT for fees + assert_eq!( + Assets::balance(usdt_id_multilocation, ALICE), + usdt_initial_local_amount - FEE_AMOUNT + ); + // Alice transferred BLA + assert_eq!( + Assets::balance(foreign_asset_id_multilocation, ALICE), + foreign_asset_initial_amount - SEND_AMOUNT + ); + // Verify balances of USDT reserve parachain + assert_eq!(Balances::free_balance(usdt_chain_sovereign_account.clone()), INITIAL_BALANCE); + assert_eq!(Assets::balance(usdt_id_multilocation, usdt_chain_sovereign_account), 0); + // Verify balances of transferred-asset reserve parachain + assert_eq!(Balances::free_balance(reserve_sovereign_account.clone()), INITIAL_BALANCE); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, reserve_sovereign_account), 0); + // Verify total and active issuance of USDT have decreased (teleported) + assert_eq!( + Assets::total_issuance(usdt_id_multilocation), + usdt_initial_local_amount - FEE_AMOUNT + ); + assert_eq!( + Assets::active_issuance(usdt_id_multilocation), + usdt_initial_local_amount - FEE_AMOUNT + ); + // Verify total and active issuance of foreign BLA asset have decreased (reserve-based + // (local-instance) asset was burned) + assert_eq!( + Assets::total_issuance(foreign_asset_id_multilocation), + foreign_asset_initial_amount - SEND_AMOUNT + ); + assert_eq!( + Assets::active_issuance(foreign_asset_id_multilocation), + foreign_asset_initial_amount - SEND_AMOUNT + ); + + // Verify sent XCM program + assert_eq!( + sent_xcm(), + vec![ + ( + // first message is to prefund fees on `reserve` + reserve_location, + // fees are teleported to reserve chain + Xcm(vec![ + ReceiveTeleportedAsset(expected_fee_on_reserve.clone().into()), + ClearOrigin, + buy_limited_execution(expected_fee_on_reserve.clone(), Unlimited), + DepositAsset { + assets: AllCounted(1).into(), + beneficiary: expected_beneficiary_on_reserve + }, + ]) + ), + ( + // second message is to prefund fees on `dest` + dest, + // fees are teleported to destination chain + Xcm(vec![ + ReceiveTeleportedAsset(expected_fee.clone().into()), + ClearOrigin, + buy_limited_execution(expected_fee.clone(), Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary }, + ]) + ), + ( + // third message is to transfer/deposit foreign assets on `dest` by going + // through `reserve` while paying using prefunded (teleported above) fees + reserve_location, + Xcm(vec![ + WithdrawAsset(expected_asset_on_reserve.into()), + ClearOrigin, + buy_limited_execution(expected_fee_on_reserve, Unlimited), + DepositReserveAsset { + assets: Wild(AllCounted(1)), + // final destination is `dest` as seen by `reserve` + dest: expected_dest_on_reserve, + // message sent onward to final `dest` to deposit/prefund fees + xcm: Xcm(vec![ + buy_limited_execution(expected_fee, Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary } + ]) + } + ]) + ) + ] + ); + let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); + let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); + }); } /// Test local execution of XCM From 7b920ec767d3fb3f1c46bc9eb589d90dc4acfcc3 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 28 Sep 2023 17:08:57 +0300 Subject: [PATCH 23/98] add test for transfer asset remote reserve and fee local reserve --- polkadot/xcm/pallet-xcm/src/tests.rs | 212 +++++++++++++++++++++++++-- 1 file changed, 202 insertions(+), 10 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index dca80a14e8c9..4806b1419d36 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -688,9 +688,9 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ ( // first message is to prefund fees on `dest` dest, + // fees are being sent through local-reserve transfer because fee reserve is + // local chain Xcm(vec![ - // fees are being sent through local-reserve transfer because fee reserve - // is local chain ReserveAssetDeposited((Parent, FEE_AMOUNT).into()), ClearOrigin, buy_limited_execution((Parent, FEE_AMOUNT), Unlimited), @@ -718,11 +718,201 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ /// Test `reserve_transfer_assets` with remote asset reserve and local fee reserve. /// -/// Asserts that the sender's balance is decreased and the beneficiary's balance -/// is increased. Verifies the correct message is sent and event is emitted. +/// Transferring foreign asset (reserve on `FOREIGN_ASSET_RESERVE_PARA_ID`) to `OTHER_PARA_ID`. +/// Using native (local reserve) as fee. +/// +/// ```nocompile +/// | chain `A` | chain `C` | chain `B` +/// | Here (source) | FOREIGN_ASSET_RESERVE_PARA_ID | OTHER_PARA_ID (destination) +/// | `fees` reserve | `assets` reserve | no trust +/// | +/// | 1. `A` executes `TransferReserveAsset(fees)` dest `C` +/// | \----------> `C` executes `WithdrawAsset(fees), .., DepositAsset(fees)` +/// | +/// | 2. `A` executes `TransferReserveAsset(fees)` dest `B` +/// | \-------------------------------------------------> `B` executes: +/// | `WithdrawAsset(fees), .., DepositAsset(fees)` +/// | +/// | 3. `A` executes `InitiateReserveWithdraw(assets)` dest `C` +/// | -----------------> `C` executes `DepositReserveAsset(assets)` dest `B` +/// | --------------------------> `DepositAsset(assets)` +/// | all of which at step 3. being paid with fees prefunded in steps 1 & 2 +/// ``` #[test] fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_works() { - // TODO + let reserve_location = RelayLocation::get() + .pushed_with_interior(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID)) + .unwrap(); + let foreign_asset_id_multilocation = + reserve_location.pushed_with_interior(FOREIGN_ASSET_INNER_JUNCTION).unwrap(); + let foreign_asset_initial_amount = 142; + let reserve_sovereign_account = + SovereignAccountOf::convert_location(&reserve_location).unwrap(); + + // transfer destination is OTHER_PARA_ID (foreign asset needs to go through its reserve chain) + let dest = RelayLocation::get().pushed_with_interior(Parachain(OTHER_PARA_ID)).unwrap(); + let dest_sovereign_account = SovereignAccountOf::convert_location(&dest).unwrap(); + + let assets: MultiAssets = vec![ + // native asset for fees + (MultiLocation::here(), FEE_AMOUNT).into(), + // foreign asset to transfer (not used for fees) - remote reserve + (foreign_asset_id_multilocation, SEND_AMOUNT).into(), + ] + .into(); + let fee_index = 0; + let asset_index = 1; + + let context = UniversalLocation::get(); + let mut expected_fee = assets.get(fee_index).unwrap().clone(); + let mut expected_asset = assets.get(asset_index).unwrap().clone(); + + // sanity check indices are still ok after sort() done by `vec![MultiAsset].into()`. + assert_eq!(expected_fee.id, MultiLocation::here().into()); + assert_eq!(expected_asset.id, foreign_asset_id_multilocation.into()); + + // reanchor according to test-case. + let expected_dest_on_reserve = dest.reanchored(&reserve_location, context).unwrap(); + let mut expected_fee_on_reserve = expected_fee.clone(); + let mut expected_asset_on_reserve = expected_asset.clone(); + expected_fee_on_reserve.reanchor(&reserve_location, context).unwrap(); + expected_asset_on_reserve.reanchor(&reserve_location, context).unwrap(); + expected_fee.reanchor(&dest, context).unwrap(); + expected_asset.reanchor(&dest, context).unwrap(); + + // fees are split between the asset-reserve chain and the destination chain + crate::Pallet::::halve_fungible_asset(&mut expected_fee_on_reserve).unwrap(); + crate::Pallet::::halve_fungible_asset(&mut expected_fee).unwrap(); + + let balances = vec![ + (ALICE, INITIAL_BALANCE), + (dest_sovereign_account.clone(), INITIAL_BALANCE), + (reserve_sovereign_account.clone(), INITIAL_BALANCE), + ]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let expected_beneficiary_on_reserve = beneficiary; + + new_test_ext_with_balances(balances).execute_with(|| { + // create non-sufficient foreign asset BLA (0 total issuance) + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + foreign_asset_id_multilocation, + BOB, + false, + 1 + )); + // foreign asset BLA should have been teleported/reserve-transferred in, but for this test + // we just mint it locally. + assert_ok!(Assets::mint( + RuntimeOrigin::signed(BOB), + foreign_asset_id_multilocation, + ALICE, + foreign_asset_initial_amount + )); + assert_eq!( + Assets::balance(foreign_asset_id_multilocation, ALICE), + foreign_asset_initial_amount + ); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // do the transfer + assert_ok!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + )); + assert!(matches!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) + )); + // Alice transferred BLA + assert_eq!( + Assets::balance(foreign_asset_id_multilocation, ALICE), + foreign_asset_initial_amount - SEND_AMOUNT + ); + // Alice spent native asset for fees + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - FEE_AMOUNT); + // Half the fee went to reserve chain + assert_eq!( + Balances::free_balance(reserve_sovereign_account.clone()), + INITIAL_BALANCE + FEE_AMOUNT / 2 + ); + // Other half went to dest chain + assert_eq!( + Balances::free_balance(dest_sovereign_account.clone()), + INITIAL_BALANCE + FEE_AMOUNT / 2 + ); + // Verify total and active issuance of foreign BLA asset have decreased (reserve-based + // (local-instance) asset was burned) + assert_eq!( + Assets::total_issuance(foreign_asset_id_multilocation), + foreign_asset_initial_amount - SEND_AMOUNT + ); + assert_eq!( + Assets::active_issuance(foreign_asset_id_multilocation), + foreign_asset_initial_amount - SEND_AMOUNT + ); + + // Verify sent XCM program + assert_eq!( + sent_xcm(), + vec![ + ( + // first message is to prefund fees on `reserve` + reserve_location, + // fees are being sent through local-reserve transfer because fee reserve is + // local chain + Xcm(vec![ + ReserveAssetDeposited(expected_fee_on_reserve.clone().into()), + ClearOrigin, + buy_limited_execution(expected_fee_on_reserve.clone(), Unlimited), + DepositAsset { + assets: AllCounted(1).into(), + beneficiary: expected_beneficiary_on_reserve + }, + ]) + ), + ( + // second message is to prefund fees on `dest` + dest, + // fees are being sent through local-reserve transfer because fee reserve + // is local chain + Xcm(vec![ + ReserveAssetDeposited(expected_fee.clone().into()), + ClearOrigin, + buy_limited_execution(expected_fee.clone(), Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary }, + ]) + ), + ( + // third message is to transfer/deposit foreign assets on `dest` by going + // through `reserve` while paying using prefunded (teleported above) fees + reserve_location, + Xcm(vec![ + WithdrawAsset(expected_asset_on_reserve.into()), + ClearOrigin, + buy_limited_execution(expected_fee_on_reserve, Unlimited), + DepositReserveAsset { + assets: Wild(AllCounted(1)), + // final destination is `dest` as seen by `reserve` + dest: expected_dest_on_reserve, + // message sent onward to final `dest` to deposit/prefund fees + xcm: Xcm(vec![ + buy_limited_execution(expected_fee, Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary } + ]) + } + ]) + ) + ] + ); + let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); + let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); + }); } /// Test `reserve_transfer_assets` with local asset reserve and destination fee reserve. @@ -1005,7 +1195,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve /// | `assets` reserve | `fees` reserve | /// | /// | 1. `A` executes `InitiateReserveWithdraw(fees)` dest `C` -/// | -----------------> `DepositReserveAsset(fees)` dest `B` +/// | -----------------> `C` executes `DepositReserveAsset(fees)` dest `B` /// | --------------------------> `DepositAsset(fees)` /// | 2. `A` executes `TransferReserveAsset(assets)` dest `B` /// | --------------------------------------------------> `ReserveAssetDeposited(assets)` @@ -1167,7 +1357,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works /// | | `fees` reserve | `assets` reserve /// | /// | 1. `A` executes `InitiateReserveWithdraw(fees)` dest `C` -/// | -----------------> `DepositReserveAsset(fees)` dest `B` +/// | -----------------> `C` executes `DepositReserveAsset(fees)` dest `B` /// | --------------------------> `DepositAsset(fees)` /// | 2. `A` executes `InitiateReserveWithdraw(assets)` dest `B` /// | --------------------------------------------------> `DepositAsset(assets)` @@ -1370,7 +1560,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve /// | | `assets` reserve | /// | /// | 1. `A` executes `InitiateReserveWithdraw(both)` dest `C` -/// | -----------------> `DepositReserveAsset(both)` dest `B` +/// | -----------------> `C` executes `DepositReserveAsset(both)` dest `B` /// | --------------------------> `DepositAsset(both)` /// ``` #[test] @@ -1831,8 +2021,10 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_wor /// | \-------------------------------------------------> `B` executes: /// | `ReceiveTeleportedAsset(fees), .., DepositAsset(fees)` /// | -/// | 3. `A` executes `InitiateReserveWithdraw(assets)` dest `B` -/// | --------------------------------------------------> `DepositAsset(assets)` +/// | 3. `A` executes `InitiateReserveWithdraw(assets)` dest `C` +/// | -----------------> `C` executes `DepositReserveAsset(assets)` dest `B` +/// | --------------------------> `DepositAsset(assets)` +/// | all of which at step 3. being paid with fees prefunded in steps 1 & 2 /// ``` #[test] fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_works() { From 313056631641d06879973fac9a837e319a383afa Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 28 Sep 2023 17:47:13 +0300 Subject: [PATCH 24/98] add test for transfer asset remote reserve and fee destination reserve --- polkadot/xcm/pallet-xcm/src/tests.rs | 259 ++++++++++++++++++++++++--- 1 file changed, 236 insertions(+), 23 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index 4806b1419d36..80a08011ab59 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -670,8 +670,8 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ Assets::balance(foreign_asset_id_multilocation, foreign_creator_as_account_id), 0 ); - // Verify total and active issuance of foreign BLA have decreased (reserve-based - // (local-instance) BLA was burned) + // Verify total and active issuance of foreign BLA have decreased (burned on + // reserve-withdraw) assert_eq!( Assets::total_issuance(foreign_asset_id_multilocation), foreign_asset_amount - SEND_AMOUNT @@ -846,8 +846,8 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_works Balances::free_balance(dest_sovereign_account.clone()), INITIAL_BALANCE + FEE_AMOUNT / 2 ); - // Verify total and active issuance of foreign BLA asset have decreased (reserve-based - // (local-instance) asset was burned) + // Verify total and active issuance of foreign BLA asset have decreased (burned on + // reserve-withdraw) assert_eq!( Assets::total_issuance(foreign_asset_id_multilocation), foreign_asset_initial_amount - SEND_AMOUNT @@ -1017,8 +1017,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ INITIAL_BALANCE + SEND_AMOUNT ); assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); - // Verify total and active issuance of USDC have decreased (reserve-based (local-instance) - // USDC was burned) + // Verify total and active issuance of USDC have decreased (burned on reserve-withdraw) assert_eq!( Assets::total_issuance(usdc_id_multilocation), usdc_initial_local_amount - FEE_AMOUNT @@ -1146,8 +1145,8 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re Assets::balance(foreign_asset_id_multilocation, foreign_creator_as_account_id), 0 ); - // Verify total and active issuance of foreign BLA have decreased (reserve-based - // (local-instance) BLA was burned) + // Verify total and active issuance of foreign BLA have decreased (burned on + // reserve-withdraw) assert_eq!( Assets::total_issuance(foreign_asset_id_multilocation), foreign_asset_amount - SEND_AMOUNT @@ -1177,11 +1176,228 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re /// Test `reserve_transfer_assets` with remote asset reserve and destination fee reserve. /// -/// Asserts that the sender's balance is decreased and the beneficiary's balance -/// is increased. Verifies the correct message is sent and event is emitted. +/// Transferring foreign asset (reserve on `FOREIGN_ASSET_RESERVE_PARA_ID`) to +/// `USDC_RESERVE_PARA_ID`. Using USDC (destination reserve) as fee. +/// +/// ```nocompile +/// | chain `A` | chain `C` | chain `B` +/// | Here (source) | FOREIGN_ASSET_RESERVE_PARA_ID | USDC_RESERVE_PARA_ID (destination) +/// | | `assets` reserve | `fees` reserve +/// +/// 1. `A` executes `InitiateReserveWithdraw(fees)` dest `B` +/// ---------------------------------------------------> `B` executes: +/// `WithdrawAsset(fees), ClearOrigin` +/// `BuyExecution(fees)` +/// `DepositReserveAsset(fees)` dest `C` +/// `C` executes `DepositAsset(fees)` <---------------------------- +/// +/// 2. `A` executes `InitiateReserveWithdraw(fees)` dest `B` +/// ---------------------------------------------------> `B` executes: +/// `WithdrawAsset(fees), .., DepositAsset(fees)` +/// +/// 3. `A` executes `InitiateReserveWithdraw(assets)` dest `C` +/// --------------> `C` executes `DepositReserveAsset(assets)` dest `B` +/// ----------------------------> `B` executes: +/// WithdrawAsset(assets), .., DepositAsset(assets)` +/// +/// all of which at step 3. being paid with fees prefunded in steps 1 & 2 +/// ``` #[test] fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve_works() { - // TODO + let usdc_chain = RelayLocation::get() + .pushed_with_interior(Parachain(USDC_RESERVE_PARA_ID)) + .unwrap(); + let usdc_id_multilocation = usdc_chain.pushed_with_interior(USDC_INNER_JUNCTION).unwrap(); + let usdc_initial_local_amount = 42; + + let reserve_location = RelayLocation::get() + .pushed_with_interior(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID)) + .unwrap(); + let foreign_asset_id_multilocation = + reserve_location.pushed_with_interior(FOREIGN_ASSET_INNER_JUNCTION).unwrap(); + let foreign_asset_initial_amount = 142; + + // transfer destination is USDC chain (foreign asset needs to go through its reserve chain) + let dest = usdc_chain; + let assets: MultiAssets = vec![ + // foreign asset to transfer (not used for fees) - remote reserve + (foreign_asset_id_multilocation, SEND_AMOUNT).into(), + // USDC for fees (is sufficient on local chain too) + (usdc_id_multilocation, FEE_AMOUNT).into(), + ] + .into(); + let asset_index = 0; + let fee_index = 1; + + let context = UniversalLocation::get(); + let mut expected_fee = assets.get(fee_index).unwrap().clone(); + let mut expected_asset = assets.get(asset_index).unwrap().clone(); + + // sanity check indices are still ok after sort() done by `vec![MultiAsset].into()`. + assert_eq!(expected_fee.id, usdc_id_multilocation.into()); + assert_eq!(expected_asset.id, foreign_asset_id_multilocation.into()); + + // reanchor according to test-case. + let expected_dest_on_reserve = dest.reanchored(&reserve_location, context).unwrap(); + let expected_reserve_on_dest = reserve_location.reanchored(&dest, context).unwrap(); + let mut expected_fee_on_reserve = expected_fee.clone(); + let mut expected_asset_on_reserve = expected_asset.clone(); + expected_fee_on_reserve.reanchor(&reserve_location, context).unwrap(); + expected_asset_on_reserve.reanchor(&reserve_location, context).unwrap(); + expected_fee.reanchor(&dest, context).unwrap(); + expected_asset.reanchor(&dest, context).unwrap(); + + // fees are split between the asset-reserve chain and the destination chain + crate::Pallet::::halve_fungible_asset(&mut expected_fee_on_reserve).unwrap(); + crate::Pallet::::halve_fungible_asset(&mut expected_fee).unwrap(); + + let balances = vec![(ALICE, INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient foreign asset USDC (0 total issuance) + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + usdc_id_multilocation, + BOB, + true, + 1 + )); + // USDC should have been teleported/reserve-transferred in, but for this test we just + // mint it locally. + assert_ok!(Assets::mint( + RuntimeOrigin::signed(BOB), + usdc_id_multilocation, + ALICE, + usdc_initial_local_amount + )); + // create non-sufficient foreign asset BLA (0 total issuance) + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + foreign_asset_id_multilocation, + BOB, + false, + 1 + )); + // foreign asset BLA should have been teleported/reserve-transferred in, but for this test + // we just mint it locally. + assert_ok!(Assets::mint( + RuntimeOrigin::signed(BOB), + foreign_asset_id_multilocation, + ALICE, + foreign_asset_initial_amount + )); + assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // do the transfer + assert_ok!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + )); + assert!(matches!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) + )); + // Alice native asset untouched + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + // Alice spent USDC for fees + assert_eq!( + Assets::balance(usdc_id_multilocation, ALICE), + usdc_initial_local_amount - FEE_AMOUNT + ); + // Alice transferred BLA + assert_eq!( + Assets::balance(foreign_asset_id_multilocation, ALICE), + foreign_asset_initial_amount - SEND_AMOUNT + ); + // Verify total and active issuance of USDC have decreased (burned on reserve-withdraw) + assert_eq!( + Assets::total_issuance(usdc_id_multilocation), + usdc_initial_local_amount - FEE_AMOUNT + ); + assert_eq!( + Assets::active_issuance(usdc_id_multilocation), + usdc_initial_local_amount - FEE_AMOUNT + ); + // Verify total and active issuance of foreign BLA asset have decreased (burned on + // reserve-withdraw) + assert_eq!( + Assets::total_issuance(foreign_asset_id_multilocation), + foreign_asset_initial_amount - SEND_AMOUNT + ); + assert_eq!( + Assets::active_issuance(foreign_asset_id_multilocation), + foreign_asset_initial_amount - SEND_AMOUNT + ); + + // Verify sent XCM program + assert_eq!( + sent_xcm(), + vec![ + ( + // first message is to prefund fees on `reserve`, but we need to go through + // `fee_reserve == dest` to get them there + dest, + // fees are reserve-withdrawn on `dest` chain then reserve-deposited to + // `asset_reserve` chain + Xcm(vec![ + WithdrawAsset(expected_fee.clone().into()), + ClearOrigin, + buy_limited_execution(expected_fee.clone(), Unlimited), + DepositReserveAsset { + assets: Wild(AllCounted(1)), + // final fees destination is `asset_reserve` as seen by `dest` + dest: expected_reserve_on_dest, + // message sent onward to final `dest` to deposit/prefund fees + xcm: Xcm(vec![ + buy_limited_execution(expected_fee_on_reserve.clone(), Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary } + ]) + } + ]) + ), + ( + // second message is to prefund fees on `dest` + dest, + // fees are reserve-withdrawn on destination chain + Xcm(vec![ + WithdrawAsset(expected_fee.clone().into()), + ClearOrigin, + buy_limited_execution(expected_fee.clone(), Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary }, + ]) + ), + ( + // third message is to transfer/deposit foreign assets on `dest` by going + // through `reserve` while paying using prefunded (teleported above) fees + reserve_location, + Xcm(vec![ + WithdrawAsset(expected_asset_on_reserve.into()), + ClearOrigin, + buy_limited_execution(expected_fee_on_reserve, Unlimited), + DepositReserveAsset { + assets: Wild(AllCounted(1)), + // final destination is `dest` as seen by `reserve` + dest: expected_dest_on_reserve, + // message sent onward to final `dest` to deposit/prefund fees + xcm: Xcm(vec![ + buy_limited_execution(expected_fee, Unlimited), + DepositAsset { assets: AllCounted(1).into(), beneficiary } + ]) + } + ]) + ) + ] + ); + let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); + let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); + }); } /// Test `reserve_transfer_assets` with local asset reserve and remote fee reserve. @@ -1291,8 +1507,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); // Sovereign account of destination parachain holds `SEND_AMOUNT` in local reserve assert_eq!(Balances::free_balance(dest_sovereign_account), SEND_AMOUNT); - // Verify total and active issuance of USDC have decreased (reserve-based (local-instance) - // USDC was burned) + // Verify total and active issuance of USDC have decreased (burned on reserve-withdraw) assert_eq!( Assets::total_issuance(usdc_id_multilocation), usdc_initial_local_amount - FEE_AMOUNT @@ -1484,8 +1699,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve // Verify balances of transferred-asset reserve parachain assert_eq!(Balances::free_balance(dest_sovereign_account.clone()), INITIAL_BALANCE); assert_eq!(Assets::balance(foreign_asset_id_multilocation, dest_sovereign_account), 0); - // Verify total and active issuance of USDC have decreased (reserve-based (local-instance) - // USDC was burned) + // Verify total and active issuance of USDC have decreased (burned on reserve-withdraw) assert_eq!( Assets::total_issuance(usdc_id_multilocation), usdc_initial_local_amount - FEE_AMOUNT @@ -1494,8 +1708,8 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve Assets::active_issuance(usdc_id_multilocation), usdc_initial_local_amount - FEE_AMOUNT ); - // Verify total and active issuance of foreign BLA asset have decreased (reserve-based - // (local-instance) asset was burned) + // Verify total and active issuance of foreign BLA asset have decreased (burned on + // reserve-withdraw) assert_eq!( Assets::total_issuance(foreign_asset_id_multilocation), foreign_asset_initial_amount - SEND_AMOUNT @@ -1635,8 +1849,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work // Destination account (parachain account) has expected (same) balances assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), INITIAL_BALANCE); assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); - // Verify total and active issuance of USDC have decreased (reserve-based (local-instance) - // USDC was burned) + // Verify total and active issuance of USDC have decreased (burned on reserve-withdraw) assert_eq!( Assets::total_issuance(usdc_id_multilocation), usdc_initial_local_amount - SEND_AMOUNT @@ -1959,8 +2172,8 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_wor Assets::active_issuance(usdt_id_multilocation), usdt_initial_local_amount - FEE_AMOUNT ); - // Verify total and active issuance of foreign BLA asset have decreased (reserve-based - // (local-instance) asset was burned) + // Verify total and active issuance of foreign BLA asset have decreased (burned on + // reserve-withdraw) assert_eq!( Assets::total_issuance(foreign_asset_id_multilocation), foreign_asset_initial_amount - SEND_AMOUNT @@ -2160,8 +2373,8 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_works() Assets::active_issuance(usdt_id_multilocation), usdt_initial_local_amount - FEE_AMOUNT ); - // Verify total and active issuance of foreign BLA asset have decreased (reserve-based - // (local-instance) asset was burned) + // Verify total and active issuance of foreign BLA asset have decreased (burned on + // reserve-withdraw) assert_eq!( Assets::total_issuance(foreign_asset_id_multilocation), foreign_asset_initial_amount - SEND_AMOUNT From 1b17e844391a1ead91870e5357e96ca235f77951 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 29 Sep 2023 09:40:36 +0300 Subject: [PATCH 25/98] disallow teleportable assets in reserve-transfer, add regression test --- polkadot/xcm/pallet-xcm/src/lib.rs | 3 +- polkadot/xcm/pallet-xcm/src/tests.rs | 73 +++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 99d5d80027c6..832e630e637d 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1298,7 +1298,8 @@ impl Pallet { let mut fees = assets.swap_remove(fee_asset_item as usize); let fees_transfer_type = TransferType::determine_for::(&fees, &dest)?; let assets_transfer_type = if assets.is_empty() { - // Single asset to transfer (also used for fees). + // Single asset to transfer (one used for fees where transfer type is determined above). + ensure!(fees_transfer_type != TransferType::Teleport, Error::::Filtered); fees_transfer_type } else { // Find reserve for non-fee assets. diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index 80a08011ab59..c6899f129668 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -25,7 +25,10 @@ use frame_support::{ weights::Weight, }; use polkadot_parachain_primitives::primitives::Id as ParaId; -use sp_runtime::traits::{AccountIdConversion, BlakeTwo256, Hash}; +use sp_runtime::{ + traits::{AccountIdConversion, BlakeTwo256, Hash}, + DispatchError, ModuleError, +}; use xcm::{latest::QueryResponseInfo, prelude::*}; use xcm_builder::AllowKnownQueryResponses; use xcm_executor::{ @@ -2217,6 +2220,74 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_wor }); } +/// Test `reserve_transfer_assets` single asset which is also teleportable - should fail. +/// +/// Attempting to reserve-transfer teleport-trusted USDT to `USDT_PARA_ID` should fail. +#[test] +fn reserve_transfer_assets_with_teleportable_asset_fails() { + let usdt_chain = RelayLocation::get().pushed_with_interior(Parachain(USDT_PARA_ID)).unwrap(); + let usdt_chain_sovereign_account = SovereignAccountOf::convert_location(&usdt_chain).unwrap(); + let usdt_id_multilocation = usdt_chain; + let usdt_initial_local_amount = 42; + + // transfer destination is USDT chain (foreign asset needs to go through its reserve chain) + let dest = usdt_chain; + let assets: MultiAssets = vec![(usdt_id_multilocation, FEE_AMOUNT).into()].into(); + let fee_index = 0; + + let balances = vec![(ALICE, INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient foreign asset USDT (0 total issuance) + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + usdt_id_multilocation, + BOB, + true, + 1 + )); + // USDT should have been teleported/reserve-transferred in, but for this test we just + // mint it locally. + assert_ok!(Assets::mint( + RuntimeOrigin::signed(BOB), + usdt_id_multilocation, + ALICE, + usdt_initial_local_amount + )); + assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // do the transfer + let res = XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + ); + assert_eq!( + res, + Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered") + })) + ); + // Alice native asset is still same + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + // Alice USDT balance is still same + assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); + // No USDT moved to sovereign account of reserve parachain + assert_eq!(Assets::balance(usdt_id_multilocation, usdt_chain_sovereign_account), 0); + // Verify total and active issuance of USDT are still the same + assert_eq!(Assets::total_issuance(usdt_id_multilocation), usdt_initial_local_amount); + assert_eq!(Assets::active_issuance(usdt_id_multilocation), usdt_initial_local_amount); + }); +} + /// Test `reserve_transfer_assets` with remote asset reserve and teleported fee. /// /// Transferring foreign asset (reserve on `FOREIGN_ASSET_RESERVE_PARA_ID`) to `USDT_PARA_ID`. Using From 84e213a68db0fe7d0f2bf0cc99dfd3bc47c429f9 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 29 Sep 2023 17:16:34 +0300 Subject: [PATCH 26/98] asset-hubs: fix emulated tests and deduplicate code --- .../src/tests/reserve_transfer.rs | 258 ++++++------------ cumulus/xcm/xcm-emulator/src/lib.rs | 10 +- 2 files changed, 92 insertions(+), 176 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs index 491343692e9f..d0af568929cf 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -15,37 +15,6 @@ use crate::*; -fn relay_origin_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - Westend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(629_384_000, 6_196))); - - assert_expected_events!( - Westend, - vec![ - // Amount to reserve transfer is transferred to System Parachain's Sovereign account - RuntimeEvent::Balances(pallet_balances::Event::Transfer { from, to, amount }) => { - from: *from == t.sender.account_id, - to: *to == Westend::sovereign_account_id_of( - t.args.dest - ), - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn system_para_dest_assertions_incomplete(_t: RelayToSystemParaTest) { - AssetHubWestend::assert_dmp_queue_incomplete( - Some(Weight::from_parts(1_000_000_000, 0)), - Some(Error::UntrustedReserveLocation), - ); -} - -fn system_para_to_relay_assertions(_t: SystemParaToRelayTest) { - AssetHubWestend::assert_xcm_pallet_attempted_error(Some(XcmError::Barrier)) -} - fn system_para_to_para_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -97,48 +66,6 @@ fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { ); } -fn relay_limited_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::limited_reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -fn relay_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - -fn system_para_limited_reserve_transfer_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::limited_reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -fn system_para_reserve_transfer_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { ::PolkadotXcm::limited_reserve_transfer_assets( t.signed_origin, @@ -160,123 +87,112 @@ fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> Dispa ) } +fn do_reserve_transfer_native_asset_from_relay_to_system_para_fails(limited: bool) { + let signed_origin = ::RuntimeOrigin::signed(WestendSender::get().into()); + let destination = Westend::child_location_of(AssetHubWestend::para_id()); + let beneficiary: MultiLocation = + AccountId32Junction { network: None, id: AssetHubWestendReceiver::get().into() }.into(); + let amount_to_send: Balance = WESTEND_ED * 1000; + let assets: MultiAssets = (Here, amount_to_send).into(); + let fee_asset_item = 0; + + // this should fail + Westend::execute_with(|| { + let result = if limited { + ::XcmPallet::reserve_transfer_assets( + signed_origin, + bx!(destination.into()), + bx!(beneficiary.into()), + bx!(assets.into()), + fee_asset_item, + ) + } else { + ::XcmPallet::limited_reserve_transfer_assets( + signed_origin, + bx!(destination.into()), + bx!(beneficiary.into()), + bx!(assets.into()), + fee_asset_item, + WeightLimit::Unlimited, + ) + }; + assert_err!( + result, + DispatchError::Module(sp_runtime::ModuleError { + index: 99, + error: [2, 0, 0, 0], + message: Some("Filtered") + }) + ); + }); +} + /// Limited Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't /// work #[test] fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() { - // Init values for Relay Chain - let amount_to_send: Balance = WESTEND_ED * 1000; - let test_args = TestContext { - sender: WestendSender::get(), - receiver: AssetHubWestendReceiver::get(), - args: relay_test_args(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::(system_para_dest_assertions_incomplete); - test.set_dispatchable::(relay_limited_reserve_transfer_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); - assert_eq!(receiver_balance_before, receiver_balance_after); + do_reserve_transfer_native_asset_from_relay_to_system_para_fails(true); } -/// Limited Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work +/// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work #[test] -fn limited_reserve_transfer_native_asset_from_system_para_to_relay_fails() { +fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { + do_reserve_transfer_native_asset_from_relay_to_system_para_fails(false); +} + +fn do_reserve_transfer_native_asset_from_system_para_to_relay_fails(limited: bool) { // Init values for System Parachain + let signed_origin = + ::RuntimeOrigin::signed(AssetHubWestendSender::get().into()); let destination = AssetHubWestend::parent_location(); let beneficiary_id = WestendReceiver::get(); + let beneficiary: MultiLocation = + AccountId32Junction { network: None, id: beneficiary_id.into() }.into(); let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubWestendSender::get(), - receiver: WestendReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(system_para_to_relay_assertions); - test.set_dispatchable::(system_para_limited_reserve_transfer_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - assert_eq!(sender_balance_before, sender_balance_after); - assert_eq!(receiver_balance_before, receiver_balance_after); + let assets: MultiAssets = (Parent, amount_to_send).into(); + let fee_asset_item = 0; + + // this should fail + AssetHubWestend::execute_with(|| { + let result = if limited { + ::PolkadotXcm::reserve_transfer_assets( + signed_origin, + bx!(destination.into()), + bx!(beneficiary.into()), + bx!(assets.into()), + fee_asset_item, + ) + } else { + ::PolkadotXcm::limited_reserve_transfer_assets( + signed_origin, + bx!(destination.into()), + bx!(beneficiary.into()), + bx!(assets.into()), + fee_asset_item, + WeightLimit::Unlimited, + ) + }; + assert_err!( + result, + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [2, 0, 0, 0], + message: Some("Filtered") + }) + ); + }); } -/// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work +/// Limited Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work #[test] -fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { - // Init values for Relay Chain - let amount_to_send: Balance = WESTEND_ED * 1000; - let test_args = TestContext { - sender: WestendSender::get(), - receiver: AssetHubWestendReceiver::get(), - args: relay_test_args(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::(system_para_dest_assertions_incomplete); - test.set_dispatchable::(relay_reserve_transfer_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); - assert_eq!(receiver_balance_before, receiver_balance_after); +fn limited_reserve_transfer_native_asset_from_system_para_to_relay_fails() { + do_reserve_transfer_native_asset_from_system_para_to_relay_fails(true); } /// Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work #[test] fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { - // Init values for System Parachain - let destination = AssetHubWestend::parent_location(); - let beneficiary_id = WestendReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubWestendSender::get(), - receiver: WestendReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(system_para_to_relay_assertions); - test.set_dispatchable::(system_para_reserve_transfer_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - assert_eq!(sender_balance_before, sender_balance_after); - assert_eq!(receiver_balance_before, receiver_balance_after); + do_reserve_transfer_native_asset_from_system_para_to_relay_fails(false); } /// Limited Reserve Transfers of native asset from System Parachain to Parachain should work diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index 9fda0632bae4..ce1b6329fb2c 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -1332,14 +1332,14 @@ pub struct TestContext { pub args: T, } -/// Struct that help with tests where either dispatchables or assertions need +/// Struct that helps with tests where either dispatchables or assertions need /// to be reused. The struct keeps the test's arguments of your choice in the generic `Args`. /// These arguments can be easily reused and shared between the assertions functions /// and dispatchables functions, which are also stored in `Test`. /// `Origin` corresponds to the chain where the XCM interaction starts with an initial execution. -/// `Destination` corresponds to the last chain where an effect of the intial execution is expected -/// happen. `Hops` refer all the ordered intermediary chains an initial XCM execution can provoke -/// some effect. +/// `Destination` corresponds to the last chain where an effect of the initial execution is expected +/// to happen. `Hops` refer to all the ordered intermediary chains an initial XCM execution can +/// provoke some effect on. #[derive(Clone)] pub struct Test where @@ -1393,7 +1393,7 @@ where let chain_name = std::any::type_name::(); self.hops_assertion.insert(chain_name.to_string(), assertion); } - /// Stores an assertion in a particular Chain + /// Stores a dispatchable in a particular Chain pub fn set_dispatchable(&mut self, dispatchable: fn(Self) -> DispatchResult) { let chain_name = std::any::type_name::(); self.hops_dispatchable.insert(chain_name.to_string(), dispatchable); From ce00c285ba34192084bb3f4d5c67a7afff95906f Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 29 Sep 2023 17:40:06 +0300 Subject: [PATCH 27/98] asset-hubs: use non-system para IDs in tests where non-system paras are intended --- .../assets/asset-hub-kusama/tests/tests.rs | 4 ++-- .../assets/asset-hub-polkadot/tests/tests.rs | 4 ++-- .../assets/asset-hub-westend/tests/tests.rs | 4 ++-- .../runtimes/assets/test-utils/src/test_cases.rs | 15 ++++++++------- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs index b8e59966b641..cdd4290770fd 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/tests/tests.rs @@ -629,8 +629,8 @@ asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_p ); #[test] -fn reserve_transfer_native_asset_works() { - asset_test_utils::test_cases::reserve_transfer_native_asset_works::< +fn reserve_transfer_native_asset_to_non_teleport_para_works() { + asset_test_utils::test_cases::reserve_transfer_native_asset_to_non_teleport_para_works::< Runtime, AllPalletsWithoutSystem, XcmConfig, diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs index b232a1703302..b7e44646ece7 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs @@ -654,8 +654,8 @@ asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_p ); #[test] -fn reserve_transfer_native_asset_works() { - asset_test_utils::test_cases::reserve_transfer_native_asset_works::< +fn reserve_transfer_native_asset_to_non_teleport_para_works() { + asset_test_utils::test_cases::reserve_transfer_native_asset_to_non_teleport_para_works::< Runtime, AllPalletsWithoutSystem, XcmConfig, diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs index 66ae2fe09aa4..5502ebc1e47f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -662,8 +662,8 @@ fn plain_receive_teleported_asset_works() { } #[test] -fn reserve_transfer_native_asset_works() { - asset_test_utils::test_cases::reserve_transfer_native_asset_works::< +fn reserve_transfer_native_asset_to_non_teleport_para_works() { + asset_test_utils::test_cases::reserve_transfer_native_asset_to_non_teleport_para_works::< Runtime, AllPalletsWithoutSystem, XcmConfig, 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 4b5350f0e2aa..9ac68e2fbddf 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -201,10 +201,10 @@ pub fn teleports_for_native_asset_works< ); } - // 3. try to teleport assets away to other parachain (1234): should not work as we don't - // trust `IsTeleporter` for `(relay-native-asset, para(1234))` pair + // 3. try to teleport assets away to other parachain (2345): should not work as we don't + // trust `IsTeleporter` for `(relay-native-asset, para(2345))` pair { - let other_para_id = 1234; + let other_para_id = 2345; let dest = MultiLocation::new(1, X1(Parachain(other_para_id))); let dest_beneficiary = MultiLocation::new(1, X1(Parachain(other_para_id))) .appended_with(AccountId32 { @@ -1335,8 +1335,9 @@ macro_rules! include_create_and_manage_foreign_assets_for_local_consensus_parach } ); -/// Test-case makes sure that `Runtime` can reserve-transfer asset to other parachains -pub fn reserve_transfer_native_asset_works< +/// Test-case makes sure that `Runtime` can reserve-transfer asset to other parachains (where +/// teleport is not trusted) +pub fn reserve_transfer_native_asset_to_non_teleport_para_works< Runtime, AllPalletsWithoutSystem, XcmConfig, @@ -1395,9 +1396,9 @@ pub fn reserve_transfer_native_asset_works< AccountId::from(alice).into(), ); - // reserve-transfer native asset with local reserve to remote parachain (1234) + // reserve-transfer native asset with local reserve to remote parachain (2345) - let other_para_id = 1234; + let other_para_id = 2345; let native_asset = MultiLocation::parent(); let dest = MultiLocation::new(1, X1(Parachain(other_para_id))); let dest_beneficiary = MultiLocation::new(1, X1(Parachain(other_para_id))) From 1dfcd01b73d42991ea81fb196f291f24f6628e2b Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 29 Sep 2023 20:41:30 +0300 Subject: [PATCH 28/98] pallet-xcm: refactor newly added tests --- polkadot/xcm/pallet-xcm/src/tests.rs | 1444 ++++++++++---------------- 1 file changed, 530 insertions(+), 914 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index c6899f129668..3b343e6a3977 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -454,8 +454,69 @@ fn limited_teleport_assets_works() { // // TODO: also add negative tests for testing various error conditions. -// Helper function to deduplicate testing different reserve-transfer types. -// Currently hardcoded for AssetsReserve=Local and FeeReserve=Local. +fn set_up_foreign_asset( + reserve_para_id: u32, + inner_junction: Option, + initial_amount: u128, + is_sufficient: bool, +) -> (MultiLocation, AccountId, MultiLocation) { + let reserve_location = + RelayLocation::get().pushed_with_interior(Parachain(reserve_para_id)).unwrap(); + let reserve_sovereign_account = + SovereignAccountOf::convert_location(&reserve_location).unwrap(); + + let foreign_asset_id_multilocation = if let Some(junction) = inner_junction { + reserve_location.pushed_with_interior(junction).unwrap() + } else { + reserve_location + }; + + // create sufficient (to be used as fees as well) foreign asset (0 total issuance) + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + foreign_asset_id_multilocation, + BOB, + is_sufficient, + 1 + )); + // this asset should have been teleported/reserve-transferred in, but for this test we just + // mint it locally. + assert_ok!(Assets::mint( + RuntimeOrigin::signed(BOB), + foreign_asset_id_multilocation, + ALICE, + initial_amount + )); + + (reserve_location, reserve_sovereign_account, foreign_asset_id_multilocation) +} + +// Helper function that provides correct `fee_index` after `sort()` done by +// `vec![MultiAsset, MultiAsset].into()`. +fn into_multiassets_checked( + fee_asset: MultiAsset, + transfer_asset: MultiAsset, +) -> (MultiAssets, usize, MultiAsset, MultiAsset) { + let assets: MultiAssets = vec![fee_asset.clone(), transfer_asset.clone()].into(); + let fee_index = if assets.get(0).unwrap().eq(&fee_asset) { 0 } else { 1 }; + (assets, fee_index, fee_asset, transfer_asset) +} + +/// Helper function to test `reserve_transfer_assets` with local asset reserve and local fee +/// reserve. +/// +/// Transferring native asset (local reserve) to some `OTHER_PARA_ID` (no teleport trust). +/// Using native asset for fees as well. +/// +/// ```nocompile +/// Here (source) OTHER_PARA_ID (destination) +/// | `assets` reserve +/// | `fees` reserve +/// | +/// | 1. execute `TransferReserveAsset(assets_and_fees_batched_together)` +/// | \--> sends `ReserveAssetDeposited(both), ClearOrigin, BuyExecution(fees), DepositAsset` +/// \------------------------------------------> +/// ``` fn do_test_and_verify_reserve_transfer_assets_local_ar_local_fr( expected_beneficiary: MultiLocation, call: Call, @@ -513,9 +574,6 @@ fn do_test_and_verify_reserve_transfer_assets_local_ar_local_fr( /// | \--> sends `ReserveAssetDeposited(both), ClearOrigin, BuyExecution(fees), DepositAsset` /// \------------------------------------------> /// ``` -/// -/// Asserts that the sender's balance is decreased and the destination SA balance -/// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserve_works() { let beneficiary: MultiLocation = @@ -538,9 +596,6 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserve_works( /// Test `limited_reserve_transfer_assets` with local asset reserve and local fee reserve. /// /// Same as test above but with limited weight. -/// -/// Asserts that the sender's balance is decreased and the destination SA balance -/// is increased. Verifies the correct message is sent and event is emitted. #[test] fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserve_works() { let beneficiary: MultiLocation = @@ -584,64 +639,37 @@ fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserv /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_works() { - // foreign creator in this case child parachain acting as reserve - let reserve_location = RelayLocation::get() - .pushed_with_interior(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID)) - .unwrap(); - let foreign_creator_as_account_id = - SovereignAccountOf::convert_location(&reserve_location).unwrap(); - - let foreign_asset_id_multilocation = - reserve_location.pushed_with_interior(FOREIGN_ASSET_INNER_JUNCTION).unwrap(); - let foreign_asset_amount = 142; - - // transfer destination is reserve location (no teleport trust) - let dest = reserve_location; - let assets: MultiAssets = vec![ - // native asset for fee - (MultiLocation::here(), FEE_AMOUNT).into(), - // foreign asset to transfer - (foreign_asset_id_multilocation, SEND_AMOUNT).into(), - ] - .into(); - let fee_index = 0; - let asset_index = 1; - - let context = UniversalLocation::get(); - let mut expected_fee = assets.get(fee_index).unwrap().clone(); - let mut expected_asset = assets.get(asset_index).unwrap().clone(); - - // sanity check indices are still ok after sort() done by `vec![MultiAsset].into()`. - assert_eq!(expected_fee.id, MultiLocation::here().into()); - assert_eq!(expected_asset.id, foreign_asset_id_multilocation.into()); - - // reanchor according to test-case. - expected_fee.reanchor(&dest, context).unwrap(); - expected_asset.reanchor(&dest, context).unwrap(); - - let balances = - vec![(ALICE, INITIAL_BALANCE), (foreign_creator_as_account_id.clone(), INITIAL_BALANCE)]; + let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - new_test_ext_with_balances(balances).execute_with(|| { - // create non-sufficient foreign asset (0 total issuance) - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - foreign_asset_id_multilocation, - BOB, - false, - 1 - )); - // this asset should have been teleported/reserve-transferred in, but for this test we just - // mint it locally. - assert_ok!(Assets::mint( - RuntimeOrigin::signed(BOB), - foreign_asset_id_multilocation, - ALICE, - foreign_asset_amount - )); - assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_asset_amount); + // create non-sufficient foreign asset BLA (0 total issuance) + let foreign_initial_amount = 142; + let (reserve_location, reserve_sovereign_account, foreign_asset_id_multilocation) = + set_up_foreign_asset( + FOREIGN_ASSET_RESERVE_PARA_ID, + Some(FOREIGN_ASSET_INNER_JUNCTION), + foreign_initial_amount, + false, + ); + + // transfer destination is reserve location (no teleport trust) + let dest = reserve_location; + + let (assets, fee_index, fee_asset, xfer_asset) = into_multiassets_checked( + // native asset for fee - local reserve + (MultiLocation::here(), FEE_AMOUNT).into(), + // foreign asset to transfer - destination reserve + (foreign_asset_id_multilocation, SEND_AMOUNT).into(), + ); + + // reanchor according to test-case + let context = UniversalLocation::get(); + let expected_fee = fee_asset.reanchored(&dest, context).unwrap(); + let expected_asset = xfer_asset.reanchored(&dest, context).unwrap(); + + // balances checks before + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_initial_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // do the transfer @@ -657,32 +685,22 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ last_event(), RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) )); + // Alice spent (transferred) amount assert_eq!( Assets::balance(foreign_asset_id_multilocation, ALICE), - foreign_asset_amount - SEND_AMOUNT + foreign_initial_amount - SEND_AMOUNT ); // Alice used native asset for fees assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - FEE_AMOUNT); // Destination account (parachain account) added native reserve used as fee to balances - assert_eq!( - Balances::free_balance(foreign_creator_as_account_id.clone()), - INITIAL_BALANCE + FEE_AMOUNT - ); - assert_eq!( - Assets::balance(foreign_asset_id_multilocation, foreign_creator_as_account_id), - 0 - ); + assert_eq!(Balances::free_balance(reserve_sovereign_account.clone()), FEE_AMOUNT); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, reserve_sovereign_account), 0); // Verify total and active issuance of foreign BLA have decreased (burned on // reserve-withdraw) - assert_eq!( - Assets::total_issuance(foreign_asset_id_multilocation), - foreign_asset_amount - SEND_AMOUNT - ); - assert_eq!( - Assets::active_issuance(foreign_asset_id_multilocation), - foreign_asset_amount - SEND_AMOUNT - ); + let expected_issuance = foreign_initial_amount - SEND_AMOUNT; + assert_eq!(Assets::total_issuance(foreign_asset_id_multilocation), expected_issuance); + assert_eq!(Assets::active_issuance(foreign_asset_id_multilocation), expected_issuance); // Verify sent XCM program assert_eq!( @@ -743,80 +761,48 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ /// ``` #[test] fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_works() { - let reserve_location = RelayLocation::get() - .pushed_with_interior(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID)) - .unwrap(); - let foreign_asset_id_multilocation = - reserve_location.pushed_with_interior(FOREIGN_ASSET_INNER_JUNCTION).unwrap(); - let foreign_asset_initial_amount = 142; - let reserve_sovereign_account = - SovereignAccountOf::convert_location(&reserve_location).unwrap(); - - // transfer destination is OTHER_PARA_ID (foreign asset needs to go through its reserve chain) - let dest = RelayLocation::get().pushed_with_interior(Parachain(OTHER_PARA_ID)).unwrap(); - let dest_sovereign_account = SovereignAccountOf::convert_location(&dest).unwrap(); - - let assets: MultiAssets = vec![ - // native asset for fees - (MultiLocation::here(), FEE_AMOUNT).into(), - // foreign asset to transfer (not used for fees) - remote reserve - (foreign_asset_id_multilocation, SEND_AMOUNT).into(), - ] - .into(); - let fee_index = 0; - let asset_index = 1; - - let context = UniversalLocation::get(); - let mut expected_fee = assets.get(fee_index).unwrap().clone(); - let mut expected_asset = assets.get(asset_index).unwrap().clone(); - - // sanity check indices are still ok after sort() done by `vec![MultiAsset].into()`. - assert_eq!(expected_fee.id, MultiLocation::here().into()); - assert_eq!(expected_asset.id, foreign_asset_id_multilocation.into()); - - // reanchor according to test-case. - let expected_dest_on_reserve = dest.reanchored(&reserve_location, context).unwrap(); - let mut expected_fee_on_reserve = expected_fee.clone(); - let mut expected_asset_on_reserve = expected_asset.clone(); - expected_fee_on_reserve.reanchor(&reserve_location, context).unwrap(); - expected_asset_on_reserve.reanchor(&reserve_location, context).unwrap(); - expected_fee.reanchor(&dest, context).unwrap(); - expected_asset.reanchor(&dest, context).unwrap(); - - // fees are split between the asset-reserve chain and the destination chain - crate::Pallet::::halve_fungible_asset(&mut expected_fee_on_reserve).unwrap(); - crate::Pallet::::halve_fungible_asset(&mut expected_fee).unwrap(); - - let balances = vec![ - (ALICE, INITIAL_BALANCE), - (dest_sovereign_account.clone(), INITIAL_BALANCE), - (reserve_sovereign_account.clone(), INITIAL_BALANCE), - ]; + let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); let expected_beneficiary_on_reserve = beneficiary; - new_test_ext_with_balances(balances).execute_with(|| { // create non-sufficient foreign asset BLA (0 total issuance) - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - foreign_asset_id_multilocation, - BOB, - false, - 1 - )); - // foreign asset BLA should have been teleported/reserve-transferred in, but for this test - // we just mint it locally. - assert_ok!(Assets::mint( - RuntimeOrigin::signed(BOB), - foreign_asset_id_multilocation, - ALICE, - foreign_asset_initial_amount - )); - assert_eq!( - Assets::balance(foreign_asset_id_multilocation, ALICE), - foreign_asset_initial_amount - ); + let foreign_initial_amount = 142; + let (reserve_location, reserve_sovereign_account, foreign_asset_id_multilocation) = + set_up_foreign_asset( + FOREIGN_ASSET_RESERVE_PARA_ID, + Some(FOREIGN_ASSET_INNER_JUNCTION), + foreign_initial_amount, + false, + ); + + // transfer destination is OTHER_PARA_ID (foreign asset needs to go through its reserve + // chain) + let dest = RelayLocation::get().pushed_with_interior(Parachain(OTHER_PARA_ID)).unwrap(); + let dest_sovereign_account = SovereignAccountOf::convert_location(&dest).unwrap(); + + let (assets, fee_index, fee_asset, xfer_asset) = into_multiassets_checked( + // native asset for fee - local reserve + (MultiLocation::here(), FEE_AMOUNT).into(), + // foreign asset to transfer - remote reserve + (foreign_asset_id_multilocation, SEND_AMOUNT).into(), + ); + + // reanchor according to test-case + let context = UniversalLocation::get(); + let expected_dest_on_reserve = dest.reanchored(&reserve_location, context).unwrap(); + let mut expected_fee_on_reserve = + fee_asset.clone().reanchored(&reserve_location, context).unwrap(); + let expected_asset_on_reserve = + xfer_asset.clone().reanchored(&reserve_location, context).unwrap(); + let mut expected_fee = fee_asset.reanchored(&dest, context).unwrap(); + + // fees are split between the asset-reserve chain and the destination chain + crate::Pallet::::halve_fungible_asset(&mut expected_fee_on_reserve).unwrap(); + crate::Pallet::::halve_fungible_asset(&mut expected_fee).unwrap(); + + // balances checks before + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_initial_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // do the transfer @@ -832,33 +818,23 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_works last_event(), RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) )); + // Alice transferred BLA assert_eq!( Assets::balance(foreign_asset_id_multilocation, ALICE), - foreign_asset_initial_amount - SEND_AMOUNT + foreign_initial_amount - SEND_AMOUNT ); // Alice spent native asset for fees assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - FEE_AMOUNT); // Half the fee went to reserve chain - assert_eq!( - Balances::free_balance(reserve_sovereign_account.clone()), - INITIAL_BALANCE + FEE_AMOUNT / 2 - ); + assert_eq!(Balances::free_balance(reserve_sovereign_account.clone()), FEE_AMOUNT / 2); // Other half went to dest chain - assert_eq!( - Balances::free_balance(dest_sovereign_account.clone()), - INITIAL_BALANCE + FEE_AMOUNT / 2 - ); + assert_eq!(Balances::free_balance(dest_sovereign_account.clone()), FEE_AMOUNT / 2); // Verify total and active issuance of foreign BLA asset have decreased (burned on // reserve-withdraw) - assert_eq!( - Assets::total_issuance(foreign_asset_id_multilocation), - foreign_asset_initial_amount - SEND_AMOUNT - ); - assert_eq!( - Assets::active_issuance(foreign_asset_id_multilocation), - foreign_asset_initial_amount - SEND_AMOUNT - ); + let expected_issuance = foreign_initial_amount - SEND_AMOUNT; + assert_eq!(Assets::total_issuance(foreign_asset_id_multilocation), expected_issuance); + assert_eq!(Assets::active_issuance(foreign_asset_id_multilocation), expected_issuance); // Verify sent XCM program assert_eq!( @@ -935,62 +911,36 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_works /// ``` #[test] fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_works() { - let usdc_reserve_location = RelayLocation::get() - .pushed_with_interior(Parachain(USDC_RESERVE_PARA_ID)) - .unwrap(); - let usdc_chain_sovereign_account = - SovereignAccountOf::convert_location(&usdc_reserve_location).unwrap(); - - let usdc_id_multilocation = - usdc_reserve_location.pushed_with_interior(USDC_INNER_JUNCTION).unwrap(); - let usdc_initial_local_amount = 142; - - // native assets transfer destination is same as fee reserve location (no teleport trust) - let dest = usdc_reserve_location; - let assets: MultiAssets = vec![ - // native asset to transfer (not used for fees) - (MultiLocation::here(), SEND_AMOUNT).into(), - // usdc for fees (is sufficient on local chain too) - (usdc_id_multilocation, FEE_AMOUNT).into(), - ] - .into(); - let fee_index = 1; - let asset_index = 0; - - let context = UniversalLocation::get(); - let mut expected_fee = assets.get(fee_index).unwrap().clone(); - let mut expected_asset = assets.get(asset_index).unwrap().clone(); - - // sanity check indices are still ok after sort() done by `vec![MultiAsset].into()`. - assert_eq!(expected_fee.id, usdc_id_multilocation.into()); - assert_eq!(expected_asset.id, MultiLocation::here().into()); - - // reanchor according to test-case. - expected_fee.reanchor(&dest, context).unwrap(); - expected_asset.reanchor(&dest, context).unwrap(); - - let balances = - vec![(ALICE, INITIAL_BALANCE), (usdc_chain_sovereign_account.clone(), INITIAL_BALANCE)]; + let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - new_test_ext_with_balances(balances).execute_with(|| { // create sufficient foreign asset USDC (0 total issuance) - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - usdc_id_multilocation, - BOB, - true, - 1 - )); - // this asset should have been teleported/reserve-transferred in, but for this test we just - // mint it locally. - assert_ok!(Assets::mint( - RuntimeOrigin::signed(BOB), - usdc_id_multilocation, - ALICE, - usdc_initial_local_amount - )); + let usdc_initial_local_amount = 142; + let (usdc_reserve_location, usdc_chain_sovereign_account, usdc_id_multilocation) = + set_up_foreign_asset( + USDC_RESERVE_PARA_ID, + Some(USDC_INNER_JUNCTION), + usdc_initial_local_amount, + true, + ); + + // native assets transfer to fee reserve location (no teleport trust) + let dest = usdc_reserve_location; + + let (assets, fee_index, fee_asset, xfer_asset) = into_multiassets_checked( + // usdc for fees (is sufficient on local chain too) - destination reserve + (usdc_id_multilocation, FEE_AMOUNT).into(), + // native asset to transfer (not used for fees) - local reserve + (MultiLocation::here(), SEND_AMOUNT).into(), + ); + + // reanchor according to test-case + let context = UniversalLocation::get(); + let expected_fee = fee_asset.reanchored(&dest, context).unwrap(); + let expected_asset = xfer_asset.reanchored(&dest, context).unwrap(); + + // balances checks before assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); @@ -1007,6 +957,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ last_event(), RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) )); + // Alice spent (fees) amount assert_eq!( Assets::balance(usdc_id_multilocation, ALICE), @@ -1015,20 +966,12 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ // Alice used native asset for transfer assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); // Sovereign account of dest parachain holds `SEND_AMOUNT` native asset in local reserve - assert_eq!( - Balances::free_balance(usdc_chain_sovereign_account.clone()), - INITIAL_BALANCE + SEND_AMOUNT - ); + assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), SEND_AMOUNT); assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); // Verify total and active issuance of USDC have decreased (burned on reserve-withdraw) - assert_eq!( - Assets::total_issuance(usdc_id_multilocation), - usdc_initial_local_amount - FEE_AMOUNT - ); - assert_eq!( - Assets::active_issuance(usdc_id_multilocation), - usdc_initial_local_amount - FEE_AMOUNT - ); + let expected_issuance = usdc_initial_local_amount - FEE_AMOUNT; + assert_eq!(Assets::total_issuance(usdc_id_multilocation), expected_issuance); + assert_eq!(Assets::active_issuance(usdc_id_multilocation), expected_issuance); // Verify sent XCM program assert_eq!( @@ -1079,47 +1022,32 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ /// ``` #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_reserve_works() { - // we'll send just this foreign asset back to its reserve location and use it for fees as well - let reserve_location = RelayLocation::get() - .pushed_with_interior(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID)) - .unwrap(); - let foreign_creator_as_account_id = - SovereignAccountOf::convert_location(&reserve_location).unwrap(); - - let foreign_asset_id_multilocation = - reserve_location.pushed_with_interior(FOREIGN_ASSET_INNER_JUNCTION).unwrap(); - let foreign_asset_amount = 142; - - // transfer destination is reserve location - let dest = reserve_location; - let assets: MultiAssets = vec![(foreign_asset_id_multilocation, SEND_AMOUNT).into()].into(); - let fee_index = 0; - - let mut expected_assets = assets.clone(); - expected_assets.reanchor(&dest, UniversalLocation::get()).unwrap(); - - let balances = - vec![(ALICE, INITIAL_BALANCE), (foreign_creator_as_account_id.clone(), INITIAL_BALANCE)]; + let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { - // create sufficient (to be used as fees as well) foreign asset (0 total issuance) - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - foreign_asset_id_multilocation, - BOB, - true, - 1 - )); - // this asset should have been teleported/reserve-transferred in, but for this test we just - // mint it locally. - assert_ok!(Assets::mint( - RuntimeOrigin::signed(BOB), - foreign_asset_id_multilocation, - ALICE, - foreign_asset_amount - )); - assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_asset_amount); + // we'll send just this foreign asset back to its reserve location and use it for fees as + // well + let foreign_initial_amount = 142; + let (reserve_location, reserve_sovereign_account, foreign_asset_id_multilocation) = + set_up_foreign_asset( + FOREIGN_ASSET_RESERVE_PARA_ID, + Some(FOREIGN_ASSET_INNER_JUNCTION), + foreign_initial_amount, + true, + ); + + // transfer destination is reserve location + let dest = reserve_location; + let assets: MultiAssets = vec![(foreign_asset_id_multilocation, SEND_AMOUNT).into()].into(); + let fee_index = 0; + + // reanchor according to test-case + let mut expected_assets = assets.clone(); + expected_assets.reanchor(&dest, UniversalLocation::get()).unwrap(); + + // balances checks before + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_initial_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // do the transfer @@ -1135,29 +1063,22 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re last_event(), RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) )); + // Alice spent (transferred) amount assert_eq!( Assets::balance(foreign_asset_id_multilocation, ALICE), - foreign_asset_amount - SEND_AMOUNT + foreign_initial_amount - SEND_AMOUNT ); // Alice's native asset balance is untouched assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); - // Destination account (parachain account) has expected (same) balances - assert_eq!(Balances::free_balance(foreign_creator_as_account_id.clone()), INITIAL_BALANCE); - assert_eq!( - Assets::balance(foreign_asset_id_multilocation, foreign_creator_as_account_id), - 0 - ); + // Reserve sovereign account has same balances + assert_eq!(Balances::free_balance(reserve_sovereign_account.clone()), 0); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, reserve_sovereign_account), 0); // Verify total and active issuance of foreign BLA have decreased (burned on // reserve-withdraw) - assert_eq!( - Assets::total_issuance(foreign_asset_id_multilocation), - foreign_asset_amount - SEND_AMOUNT - ); - assert_eq!( - Assets::active_issuance(foreign_asset_id_multilocation), - foreign_asset_amount - SEND_AMOUNT - ); + let expected_issuance = foreign_initial_amount - SEND_AMOUNT; + assert_eq!(Assets::total_issuance(foreign_asset_id_multilocation), expected_issuance); + assert_eq!(Assets::active_issuance(foreign_asset_id_multilocation), expected_issuance); // Verify sent XCM program assert_eq!( @@ -1207,91 +1128,56 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re /// ``` #[test] fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve_works() { - let usdc_chain = RelayLocation::get() - .pushed_with_interior(Parachain(USDC_RESERVE_PARA_ID)) - .unwrap(); - let usdc_id_multilocation = usdc_chain.pushed_with_interior(USDC_INNER_JUNCTION).unwrap(); - let usdc_initial_local_amount = 42; - - let reserve_location = RelayLocation::get() - .pushed_with_interior(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID)) - .unwrap(); - let foreign_asset_id_multilocation = - reserve_location.pushed_with_interior(FOREIGN_ASSET_INNER_JUNCTION).unwrap(); - let foreign_asset_initial_amount = 142; - - // transfer destination is USDC chain (foreign asset needs to go through its reserve chain) - let dest = usdc_chain; - let assets: MultiAssets = vec![ - // foreign asset to transfer (not used for fees) - remote reserve - (foreign_asset_id_multilocation, SEND_AMOUNT).into(), - // USDC for fees (is sufficient on local chain too) - (usdc_id_multilocation, FEE_AMOUNT).into(), - ] - .into(); - let asset_index = 0; - let fee_index = 1; - - let context = UniversalLocation::get(); - let mut expected_fee = assets.get(fee_index).unwrap().clone(); - let mut expected_asset = assets.get(asset_index).unwrap().clone(); - - // sanity check indices are still ok after sort() done by `vec![MultiAsset].into()`. - assert_eq!(expected_fee.id, usdc_id_multilocation.into()); - assert_eq!(expected_asset.id, foreign_asset_id_multilocation.into()); - - // reanchor according to test-case. - let expected_dest_on_reserve = dest.reanchored(&reserve_location, context).unwrap(); - let expected_reserve_on_dest = reserve_location.reanchored(&dest, context).unwrap(); - let mut expected_fee_on_reserve = expected_fee.clone(); - let mut expected_asset_on_reserve = expected_asset.clone(); - expected_fee_on_reserve.reanchor(&reserve_location, context).unwrap(); - expected_asset_on_reserve.reanchor(&reserve_location, context).unwrap(); - expected_fee.reanchor(&dest, context).unwrap(); - expected_asset.reanchor(&dest, context).unwrap(); - - // fees are split between the asset-reserve chain and the destination chain - crate::Pallet::::halve_fungible_asset(&mut expected_fee_on_reserve).unwrap(); - crate::Pallet::::halve_fungible_asset(&mut expected_fee).unwrap(); - let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - new_test_ext_with_balances(balances).execute_with(|| { // create sufficient foreign asset USDC (0 total issuance) - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - usdc_id_multilocation, - BOB, + let usdc_initial_local_amount = 42; + let (usdc_chain, _, usdc_id_multilocation) = set_up_foreign_asset( + USDC_RESERVE_PARA_ID, + Some(USDC_INNER_JUNCTION), + usdc_initial_local_amount, true, - 1 - )); - // USDC should have been teleported/reserve-transferred in, but for this test we just - // mint it locally. - assert_ok!(Assets::mint( - RuntimeOrigin::signed(BOB), - usdc_id_multilocation, - ALICE, - usdc_initial_local_amount - )); + ); + // create non-sufficient foreign asset BLA (0 total issuance) - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - foreign_asset_id_multilocation, - BOB, + let foreign_initial_amount = 142; + let (reserve_location, _, foreign_asset_id_multilocation) = set_up_foreign_asset( + FOREIGN_ASSET_RESERVE_PARA_ID, + Some(FOREIGN_ASSET_INNER_JUNCTION), + foreign_initial_amount, false, - 1 - )); - // foreign asset BLA should have been teleported/reserve-transferred in, but for this test - // we just mint it locally. - assert_ok!(Assets::mint( - RuntimeOrigin::signed(BOB), - foreign_asset_id_multilocation, - ALICE, - foreign_asset_initial_amount - )); + ); + + // transfer destination is USDC chain (foreign asset BLA needs to go through its separate + // reserve chain) + let dest = usdc_chain; + + let (assets, fee_index, fee_asset, xfer_asset) = into_multiassets_checked( + // USDC for fees (is sufficient on local chain too) - destination reserve + (usdc_id_multilocation, FEE_AMOUNT).into(), + // foreign asset to transfer (not used for fees) - remote reserve + (foreign_asset_id_multilocation, SEND_AMOUNT).into(), + ); + + // reanchor according to test-case + let context = UniversalLocation::get(); + let expected_dest_on_reserve = dest.reanchored(&reserve_location, context).unwrap(); + let expected_reserve_on_dest = reserve_location.reanchored(&dest, context).unwrap(); + let mut expected_fee_on_reserve = + fee_asset.clone().reanchored(&reserve_location, context).unwrap(); + let expected_asset_on_reserve = + xfer_asset.clone().reanchored(&reserve_location, context).unwrap(); + let mut expected_fee = fee_asset.reanchored(&dest, context).unwrap(); + + // fees are split between the asset-reserve chain and the destination chain + crate::Pallet::::halve_fungible_asset(&mut expected_fee_on_reserve).unwrap(); + crate::Pallet::::halve_fungible_asset(&mut expected_fee).unwrap(); + + // balances checks before assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_initial_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // do the transfer @@ -1307,6 +1193,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve last_event(), RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) )); + // Alice native asset untouched assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // Alice spent USDC for fees @@ -1317,27 +1204,17 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve // Alice transferred BLA assert_eq!( Assets::balance(foreign_asset_id_multilocation, ALICE), - foreign_asset_initial_amount - SEND_AMOUNT + foreign_initial_amount - SEND_AMOUNT ); // Verify total and active issuance of USDC have decreased (burned on reserve-withdraw) - assert_eq!( - Assets::total_issuance(usdc_id_multilocation), - usdc_initial_local_amount - FEE_AMOUNT - ); - assert_eq!( - Assets::active_issuance(usdc_id_multilocation), - usdc_initial_local_amount - FEE_AMOUNT - ); + let expected_usdc_issuance = usdc_initial_local_amount - FEE_AMOUNT; + assert_eq!(Assets::total_issuance(usdc_id_multilocation), expected_usdc_issuance); + assert_eq!(Assets::active_issuance(usdc_id_multilocation), expected_usdc_issuance); // Verify total and active issuance of foreign BLA asset have decreased (burned on // reserve-withdraw) - assert_eq!( - Assets::total_issuance(foreign_asset_id_multilocation), - foreign_asset_initial_amount - SEND_AMOUNT - ); - assert_eq!( - Assets::active_issuance(foreign_asset_id_multilocation), - foreign_asset_initial_amount - SEND_AMOUNT - ); + let expected_bla_issuance = foreign_initial_amount - SEND_AMOUNT; + assert_eq!(Assets::total_issuance(foreign_asset_id_multilocation), expected_bla_issuance); + assert_eq!(Assets::active_issuance(foreign_asset_id_multilocation), expected_bla_issuance); // Verify sent XCM program assert_eq!( @@ -1421,67 +1298,40 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve /// ``` #[test] fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works() { - // foreign creator in this case child parachain acting as reserve - let fee_reserve_location = RelayLocation::get() - .pushed_with_interior(Parachain(USDC_RESERVE_PARA_ID)) - .unwrap(); - let usdc_chain_sovereign_account = - SovereignAccountOf::convert_location(&fee_reserve_location).unwrap(); - - let usdc_id_multilocation = - fee_reserve_location.pushed_with_interior(USDC_INNER_JUNCTION).unwrap(); - let usdc_initial_local_amount = 142; - - // transfer destination is some other parachain != fee reserve location (no teleport trust) - let dest = RelayLocation::get().pushed_with_interior(Parachain(OTHER_PARA_ID)).unwrap(); - let dest_sovereign_account = SovereignAccountOf::convert_location(&dest).unwrap(); - let assets: MultiAssets = vec![ - // native asset to transfer (not used for fees) - local reserve - (MultiLocation::here(), SEND_AMOUNT).into(), - // USDC for fees (is sufficient on local chain too) - remote reserve - (usdc_id_multilocation, FEE_AMOUNT).into(), - ] - .into(); - let asset_index = 0; - let fee_index = 1; - - let context = UniversalLocation::get(); - let mut expected_asset = assets.get(asset_index).unwrap().clone(); - let mut expected_fee = assets.get(fee_index).unwrap().clone(); - - // sanity check indices are still ok after sort() done by `vec![MultiAsset].into()`. - assert_eq!(expected_fee.id, usdc_id_multilocation.into()); - assert_eq!(expected_asset.id, MultiLocation::here().into()); - - // reanchor according to test-case. - let expected_dest_on_reserve = dest.reanchored(&fee_reserve_location, context).unwrap(); - let mut expected_fee_on_reserve = expected_fee.clone(); - expected_fee_on_reserve.reanchor(&fee_reserve_location, context).unwrap(); - expected_fee.reanchor(&dest, context).unwrap(); - expected_asset.reanchor(&dest, context).unwrap(); - - let balances = - vec![(ALICE, INITIAL_BALANCE), (usdc_chain_sovereign_account.clone(), INITIAL_BALANCE)]; + let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - new_test_ext_with_balances(balances).execute_with(|| { // create sufficient foreign asset USDC (0 total issuance) - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - usdc_id_multilocation, - BOB, - true, - 1 - )); - // USDC should have been teleported/reserve-transferred in, but for this test we just - // mint it locally. - assert_ok!(Assets::mint( - RuntimeOrigin::signed(BOB), - usdc_id_multilocation, - ALICE, - usdc_initial_local_amount - )); + let usdc_initial_local_amount = 142; + let (fee_reserve_location, usdc_chain_sovereign_account, usdc_id_multilocation) = + set_up_foreign_asset( + USDC_RESERVE_PARA_ID, + Some(USDC_INNER_JUNCTION), + usdc_initial_local_amount, + true, + ); + + // transfer destination is some other parachain != fee reserve location (no teleport trust) + let dest = RelayLocation::get().pushed_with_interior(Parachain(OTHER_PARA_ID)).unwrap(); + let dest_sovereign_account = SovereignAccountOf::convert_location(&dest).unwrap(); + + let (assets, fee_index, fee_asset, xfer_asset) = into_multiassets_checked( + // USDC for fees (is sufficient on local chain too) - remote reserve + (usdc_id_multilocation, FEE_AMOUNT).into(), + // native asset to transfer (not used for fees) - local reserve + (MultiLocation::here(), SEND_AMOUNT).into(), + ); + + // reanchor according to test-case + let context = UniversalLocation::get(); + let expected_dest_on_reserve = dest.reanchored(&fee_reserve_location, context).unwrap(); + let expected_fee_on_reserve = + fee_asset.clone().reanchored(&fee_reserve_location, context).unwrap(); + let expected_fee = fee_asset.reanchored(&dest, context).unwrap(); + let expected_asset = xfer_asset.reanchored(&dest, context).unwrap(); + + // balances checks before assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); @@ -1506,19 +1356,14 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works // Alice used native asset for transfer assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); // Sovereign account of reserve parachain is unchanged - assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), INITIAL_BALANCE); + assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), 0); assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); // Sovereign account of destination parachain holds `SEND_AMOUNT` in local reserve assert_eq!(Balances::free_balance(dest_sovereign_account), SEND_AMOUNT); // Verify total and active issuance of USDC have decreased (burned on reserve-withdraw) - assert_eq!( - Assets::total_issuance(usdc_id_multilocation), - usdc_initial_local_amount - FEE_AMOUNT - ); - assert_eq!( - Assets::active_issuance(usdc_id_multilocation), - usdc_initial_local_amount - FEE_AMOUNT - ); + let expected_usdc_issuance = usdc_initial_local_amount - FEE_AMOUNT; + assert_eq!(Assets::total_issuance(usdc_id_multilocation), expected_usdc_issuance); + assert_eq!(Assets::active_issuance(usdc_id_multilocation), expected_usdc_issuance); // Verify sent XCM program assert_eq!( @@ -1582,92 +1427,50 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works /// ``` #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve_works() { - // foreign creator in this case child parachain acting as reserve - let fee_reserve_location = RelayLocation::get() - .pushed_with_interior(Parachain(USDC_RESERVE_PARA_ID)) - .unwrap(); - let usdc_chain_sovereign_account = - SovereignAccountOf::convert_location(&fee_reserve_location).unwrap(); - let usdc_id_multilocation = - fee_reserve_location.pushed_with_interior(USDC_INNER_JUNCTION).unwrap(); - let usdc_initial_local_amount = 42; - - let reserve_location = RelayLocation::get() - .pushed_with_interior(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID)) - .unwrap(); - let foreign_asset_id_multilocation = - reserve_location.pushed_with_interior(FOREIGN_ASSET_INNER_JUNCTION).unwrap(); - let foreign_asset_initial_amount = 142; - - // transfer destination is asset reserve location - let dest = reserve_location; - let dest_sovereign_account = SovereignAccountOf::convert_location(&dest).unwrap(); - let assets: MultiAssets = vec![ - // foreign asset to transfer (not used for fees) - destination reserve - (foreign_asset_id_multilocation, SEND_AMOUNT).into(), - // USDC for fees (is sufficient on local chain too) - remote reserve - (usdc_id_multilocation, FEE_AMOUNT).into(), - ] - .into(); - let asset_index = 0; - let fee_index = 1; - - let context = UniversalLocation::get(); - let mut expected_asset = assets.get(asset_index).unwrap().clone(); - let mut expected_fee = assets.get(fee_index).unwrap().clone(); - - // sanity check indices are still ok after sort() done by `vec![MultiAsset].into()`. - assert_eq!(expected_fee.id, usdc_id_multilocation.into()); - assert_eq!(expected_asset.id, foreign_asset_id_multilocation.into()); - - // reanchor according to test-case. - let expected_dest_on_reserve = dest.reanchored(&fee_reserve_location, context).unwrap(); - let mut expected_fee_on_reserve = expected_fee.clone(); - expected_fee_on_reserve.reanchor(&fee_reserve_location, context).unwrap(); - expected_fee.reanchor(&dest, context).unwrap(); - expected_asset.reanchor(&dest, context).unwrap(); - - let balances = vec![ - (ALICE, INITIAL_BALANCE), - (usdc_chain_sovereign_account.clone(), INITIAL_BALANCE), - (dest_sovereign_account.clone(), INITIAL_BALANCE), - ]; + let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - new_test_ext_with_balances(balances).execute_with(|| { // create sufficient foreign asset USDC (0 total issuance) - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - usdc_id_multilocation, - BOB, - true, - 1 - )); - // USDC should have been teleported/reserve-transferred in, but for this test we just - // mint it locally. - assert_ok!(Assets::mint( - RuntimeOrigin::signed(BOB), - usdc_id_multilocation, - ALICE, - usdc_initial_local_amount - )); + let usdc_initial_local_amount = 42; + let (fee_reserve_location, usdc_chain_sovereign_account, usdc_id_multilocation) = + set_up_foreign_asset( + USDC_RESERVE_PARA_ID, + Some(USDC_INNER_JUNCTION), + usdc_initial_local_amount, + true, + ); + // create non-sufficient foreign asset BLA (0 total issuance) - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - foreign_asset_id_multilocation, - BOB, - false, - 1 - )); - // foreign asset BLA should have been teleported/reserve-transferred in, but for this test - // we just mint it locally. - assert_ok!(Assets::mint( - RuntimeOrigin::signed(BOB), - foreign_asset_id_multilocation, - ALICE, - foreign_asset_initial_amount - )); + let foreign_initial_amount = 142; + let (reserve_location, foreign_sovereign_account, foreign_asset_id_multilocation) = + set_up_foreign_asset( + FOREIGN_ASSET_RESERVE_PARA_ID, + Some(FOREIGN_ASSET_INNER_JUNCTION), + foreign_initial_amount, + false, + ); + + // transfer destination is asset reserve location + let dest = reserve_location; + let dest_sovereign_account = foreign_sovereign_account; + + let (assets, fee_index, fee_asset, xfer_asset) = into_multiassets_checked( + // USDC for fees (is sufficient on local chain too) - remote reserve + (usdc_id_multilocation, FEE_AMOUNT).into(), + // foreign asset to transfer (not used for fees) - destination reserve + (foreign_asset_id_multilocation, SEND_AMOUNT).into(), + ); + + // reanchor according to test-case + let context = UniversalLocation::get(); + let expected_dest_on_reserve = dest.reanchored(&fee_reserve_location, context).unwrap(); + let expected_fee_on_reserve = + fee_asset.clone().reanchored(&fee_reserve_location, context).unwrap(); + let expected_fee = fee_asset.reanchored(&dest, context).unwrap(); + let expected_asset = xfer_asset.reanchored(&dest, context).unwrap(); + + // balances checks before assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); @@ -1694,33 +1497,23 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve // Alice transferred BLA assert_eq!( Assets::balance(foreign_asset_id_multilocation, ALICE), - foreign_asset_initial_amount - SEND_AMOUNT + foreign_initial_amount - SEND_AMOUNT ); // Verify balances of USDC reserve parachain - assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), INITIAL_BALANCE); + assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), 0); assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); // Verify balances of transferred-asset reserve parachain - assert_eq!(Balances::free_balance(dest_sovereign_account.clone()), INITIAL_BALANCE); + assert_eq!(Balances::free_balance(dest_sovereign_account.clone()), 0); assert_eq!(Assets::balance(foreign_asset_id_multilocation, dest_sovereign_account), 0); // Verify total and active issuance of USDC have decreased (burned on reserve-withdraw) - assert_eq!( - Assets::total_issuance(usdc_id_multilocation), - usdc_initial_local_amount - FEE_AMOUNT - ); - assert_eq!( - Assets::active_issuance(usdc_id_multilocation), - usdc_initial_local_amount - FEE_AMOUNT - ); + let expected_usdc_issuance = usdc_initial_local_amount - FEE_AMOUNT; + assert_eq!(Assets::total_issuance(usdc_id_multilocation), expected_usdc_issuance); + assert_eq!(Assets::active_issuance(usdc_id_multilocation), expected_usdc_issuance); // Verify total and active issuance of foreign BLA asset have decreased (burned on // reserve-withdraw) - assert_eq!( - Assets::total_issuance(foreign_asset_id_multilocation), - foreign_asset_initial_amount - SEND_AMOUNT - ); - assert_eq!( - Assets::active_issuance(foreign_asset_id_multilocation), - foreign_asset_initial_amount - SEND_AMOUNT - ); + let expected_bla_issuance = foreign_initial_amount - SEND_AMOUNT; + assert_eq!(Assets::total_issuance(foreign_asset_id_multilocation), expected_bla_issuance); + assert_eq!(Assets::active_issuance(foreign_asset_id_multilocation), expected_bla_issuance); // Verify sent XCM program assert_eq!( @@ -1782,52 +1575,37 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve /// ``` #[test] fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_works() { - // foreign creator in this case child parachain acting as reserve - let usdc_reserve_location = RelayLocation::get() - .pushed_with_interior(Parachain(USDC_RESERVE_PARA_ID)) - .unwrap(); - let usdc_chain_sovereign_account = - SovereignAccountOf::convert_location(&usdc_reserve_location).unwrap(); - - let usdc_id_multilocation = - usdc_reserve_location.pushed_with_interior(USDC_INNER_JUNCTION).unwrap(); - let usdc_initial_local_amount = 142; - - let assets: MultiAssets = vec![(usdc_id_multilocation, SEND_AMOUNT).into()].into(); - let fee_index = 0; - // transfer destination is some other parachainß - let dest = RelayLocation::get().pushed_with_interior(Parachain(OTHER_PARA_ID)).unwrap(); - - let balances = - vec![(ALICE, INITIAL_BALANCE), (usdc_chain_sovereign_account.clone(), INITIAL_BALANCE)]; + let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { - // create sufficient (to be used as fees as well) USDC asset (0 total issuance) - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - usdc_id_multilocation, - BOB, - true, - 1 - )); - // this asset should have been teleported/reserve-transferred in, but for this test we just - // mint it locally. - assert_ok!(Assets::mint( - RuntimeOrigin::signed(BOB), - usdc_id_multilocation, - ALICE, - usdc_initial_local_amount - )); - assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); - assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); - + // create sufficient foreign asset USDC (0 total issuance) + let usdc_initial_local_amount = 142; + let (usdc_chain, usdc_chain_sovereign_account, usdc_id_multilocation) = + set_up_foreign_asset( + USDC_RESERVE_PARA_ID, + Some(USDC_INNER_JUNCTION), + usdc_initial_local_amount, + true, + ); + + // transfer destination is some other parachain + let dest = RelayLocation::get().pushed_with_interior(Parachain(OTHER_PARA_ID)).unwrap(); + + let assets: MultiAssets = vec![(usdc_id_multilocation, SEND_AMOUNT).into()].into(); + let fee_index = 0; + + // reanchor according to test-case let context = UniversalLocation::get(); - let mut expected_fee_on_reserve = assets.get(fee_index).unwrap().clone(); - expected_fee_on_reserve.reanchor(&usdc_reserve_location, context).unwrap(); + let expected_dest_on_reserve = dest.reanchored(&usdc_chain, context).unwrap(); + let expected_fee_on_reserve = + assets.get(fee_index).unwrap().clone().reanchored(&usdc_chain, context).unwrap(); let mut expected_assets = assets.clone(); expected_assets.reanchor(&dest, context).unwrap(); - let expected_dest_on_reserve = dest.reanchored(&usdc_reserve_location, context).unwrap(); + + // balances checks before + assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // do the transfer assert_ok!(XcmPallet::limited_reserve_transfer_assets( @@ -1842,6 +1620,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work last_event(), RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) )); + // Alice spent (transferred) amount assert_eq!( Assets::balance(usdc_id_multilocation, ALICE), @@ -1850,24 +1629,19 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work // Alice's native asset balance is untouched assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // Destination account (parachain account) has expected (same) balances - assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), INITIAL_BALANCE); + assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), 0); assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); // Verify total and active issuance of USDC have decreased (burned on reserve-withdraw) - assert_eq!( - Assets::total_issuance(usdc_id_multilocation), - usdc_initial_local_amount - SEND_AMOUNT - ); - assert_eq!( - Assets::active_issuance(usdc_id_multilocation), - usdc_initial_local_amount - SEND_AMOUNT - ); + let expected_usdc_issuance = usdc_initial_local_amount - SEND_AMOUNT; + assert_eq!(Assets::total_issuance(usdc_id_multilocation), expected_usdc_issuance); + assert_eq!(Assets::active_issuance(usdc_id_multilocation), expected_usdc_issuance); // Verify sent XCM program assert_eq!( sent_xcm(), vec![( // first message sent to reserve chain - usdc_reserve_location, + usdc_chain, Xcm(vec![ WithdrawAsset(expected_fee_on_reserve.clone().into()), ClearOrigin, @@ -1910,58 +1684,31 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work /// ``` #[test] fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { - let usdt_location = RelayLocation::get().pushed_with_interior(Parachain(USDT_PARA_ID)).unwrap(); - let usdt_chain_sovereign_account = - SovereignAccountOf::convert_location(&usdt_location).unwrap(); - - let usdt_id_multilocation = usdt_location; - let usdt_initial_local_amount = 42; - - // native assets transfer destination is USDT chain (teleport trust only for USDT) - let dest = usdt_location; - let assets: MultiAssets = vec![ - // native asset to transfer (not used for fees) - (MultiLocation::here(), SEND_AMOUNT).into(), - // USDT for fees (is sufficient on local chain too) - (usdt_id_multilocation, FEE_AMOUNT).into(), - ] - .into(); - let asset_index = 0; - let fee_index = 1; - - let context = UniversalLocation::get(); - let mut expected_fee = assets.get(fee_index).unwrap().clone(); - let mut expected_asset = assets.get(asset_index).unwrap().clone(); - - // sanity check indices are still ok after sort() done by `vec![MultiAsset].into()`. - assert_eq!(expected_fee.id, usdt_id_multilocation.into()); - assert_eq!(expected_asset.id, MultiLocation::here().into()); - - // reanchor according to test-case. - expected_fee.reanchor(&dest, context).unwrap(); - expected_asset.reanchor(&dest, context).unwrap(); - - let balances = - vec![(ALICE, INITIAL_BALANCE), (usdt_chain_sovereign_account.clone(), INITIAL_BALANCE)]; + let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - new_test_ext_with_balances(balances).execute_with(|| { // create sufficient foreign asset USDT (0 total issuance) - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - usdt_id_multilocation, - BOB, - true, - 1 - )); - // this asset should have been teleported in, but for this test we just mint it locally. - assert_ok!(Assets::mint( - RuntimeOrigin::signed(BOB), - usdt_id_multilocation, - ALICE, - usdt_initial_local_amount - )); + let usdt_initial_local_amount = 42; + let (usdt_chain, usdt_chain_sovereign_account, usdt_id_multilocation) = + set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, true); + + // native assets transfer destination is USDT chain (teleport trust only for USDT) + let dest = usdt_chain; + + let (assets, fee_index, fee_asset, xfer_asset) = into_multiassets_checked( + // USDT for fees (is sufficient on local chain too) - teleported + (usdt_id_multilocation, FEE_AMOUNT).into(), + // native asset to transfer (not used for fees) - local reserve + (MultiLocation::here(), SEND_AMOUNT).into(), + ); + + // reanchor according to test-case + let context = UniversalLocation::get(); + let expected_fee = fee_asset.reanchored(&dest, context).unwrap(); + let expected_asset = xfer_asset.reanchored(&dest, context).unwrap(); + + // balances checks before assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); @@ -1986,20 +1733,12 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { // Alice used native asset for transfer assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); // Sovereign account of dest parachain holds `SEND_AMOUNT` native asset in local reserve - assert_eq!( - Balances::free_balance(usdt_chain_sovereign_account.clone()), - INITIAL_BALANCE + SEND_AMOUNT - ); + assert_eq!(Balances::free_balance(usdt_chain_sovereign_account.clone()), SEND_AMOUNT); assert_eq!(Assets::balance(usdt_id_multilocation, usdt_chain_sovereign_account), 0); // Verify total and active issuance have decreased (teleported) - assert_eq!( - Assets::total_issuance(usdt_id_multilocation), - usdt_initial_local_amount - FEE_AMOUNT - ); - assert_eq!( - Assets::active_issuance(usdt_id_multilocation), - usdt_initial_local_amount - FEE_AMOUNT - ); + let expected_usdt_issuance = usdt_initial_local_amount - FEE_AMOUNT; + assert_eq!(Assets::total_issuance(usdt_id_multilocation), expected_usdt_issuance); + assert_eq!(Assets::active_issuance(usdt_id_multilocation), expected_usdt_issuance); // Verify sent XCM program assert_eq!( @@ -2054,84 +1793,42 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { /// ``` #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_works() { - let usdt_chain = RelayLocation::get().pushed_with_interior(Parachain(USDT_PARA_ID)).unwrap(); - let usdt_chain_sovereign_account = SovereignAccountOf::convert_location(&usdt_chain).unwrap(); - let usdt_id_multilocation = usdt_chain; - let usdt_initial_local_amount = 42; - - let reserve_location = RelayLocation::get() - .pushed_with_interior(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID)) - .unwrap(); - let foreign_asset_id_multilocation = - reserve_location.pushed_with_interior(FOREIGN_ASSET_INNER_JUNCTION).unwrap(); - let foreign_asset_initial_amount = 142; - - // transfer destination is asset reserve location - let dest = reserve_location; - let dest_sovereign_account = SovereignAccountOf::convert_location(&dest).unwrap(); - let assets: MultiAssets = vec![ - // USDT for fees (is sufficient on local chain too) - (usdt_id_multilocation, FEE_AMOUNT).into(), - // foreign asset to transfer (not used for fees) - destination reserve - (foreign_asset_id_multilocation, SEND_AMOUNT).into(), - ] - .into(); - let fee_index = 0; - let asset_index = 1; - - let context = UniversalLocation::get(); - let mut expected_fee = assets.get(fee_index).unwrap().clone(); - let mut expected_asset = assets.get(asset_index).unwrap().clone(); - - // sanity check indices are still ok after sort() done by `vec![MultiAsset].into()`. - assert_eq!(expected_fee.id, usdt_id_multilocation.into()); - assert_eq!(expected_asset.id, foreign_asset_id_multilocation.into()); - - // reanchor according to test-case. - expected_fee.reanchor(&dest, context).unwrap(); - expected_asset.reanchor(&dest, context).unwrap(); - - let balances = vec![ - (ALICE, INITIAL_BALANCE), - (usdt_chain_sovereign_account.clone(), INITIAL_BALANCE), - (dest_sovereign_account.clone(), INITIAL_BALANCE), - ]; + let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - new_test_ext_with_balances(balances).execute_with(|| { // create sufficient foreign asset USDT (0 total issuance) - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - usdt_id_multilocation, - BOB, - true, - 1 - )); - // USDT should have been teleported/reserve-transferred in, but for this test we just - // mint it locally. - assert_ok!(Assets::mint( - RuntimeOrigin::signed(BOB), - usdt_id_multilocation, - ALICE, - usdt_initial_local_amount - )); + let usdt_initial_local_amount = 42; + let (_, usdt_chain_sovereign_account, usdt_id_multilocation) = + set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, true); + // create non-sufficient foreign asset BLA (0 total issuance) - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - foreign_asset_id_multilocation, - BOB, - false, - 1 - )); - // foreign asset BLA should have been teleported/reserve-transferred in, but for this test - // we just mint it locally. - assert_ok!(Assets::mint( - RuntimeOrigin::signed(BOB), - foreign_asset_id_multilocation, - ALICE, - foreign_asset_initial_amount - )); + let foreign_initial_amount = 142; + let (reserve_location, foreign_sovereign_account, foreign_asset_id_multilocation) = + set_up_foreign_asset( + FOREIGN_ASSET_RESERVE_PARA_ID, + Some(FOREIGN_ASSET_INNER_JUNCTION), + foreign_initial_amount, + false, + ); + + // transfer destination is asset reserve location + let dest = reserve_location; + let dest_sovereign_account = foreign_sovereign_account; + + let (assets, fee_index, fee_asset, xfer_asset) = into_multiassets_checked( + // USDT for fees (is sufficient on local chain too) - teleported + (usdt_id_multilocation, FEE_AMOUNT).into(), + // foreign asset to transfer (not used for fees) - destination reserve + (foreign_asset_id_multilocation, SEND_AMOUNT).into(), + ); + + // reanchor according to test-case + let context = UniversalLocation::get(); + let expected_fee = fee_asset.reanchored(&dest, context).unwrap(); + let expected_asset = xfer_asset.reanchored(&dest, context).unwrap(); + + // balances checks before assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); @@ -2158,33 +1855,23 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_wor // Alice transferred BLA assert_eq!( Assets::balance(foreign_asset_id_multilocation, ALICE), - foreign_asset_initial_amount - SEND_AMOUNT + foreign_initial_amount - SEND_AMOUNT ); // Verify balances of USDT reserve parachain - assert_eq!(Balances::free_balance(usdt_chain_sovereign_account.clone()), INITIAL_BALANCE); + assert_eq!(Balances::free_balance(usdt_chain_sovereign_account.clone()), 0); assert_eq!(Assets::balance(usdt_id_multilocation, usdt_chain_sovereign_account), 0); // Verify balances of transferred-asset reserve parachain - assert_eq!(Balances::free_balance(dest_sovereign_account.clone()), INITIAL_BALANCE); + assert_eq!(Balances::free_balance(dest_sovereign_account.clone()), 0); assert_eq!(Assets::balance(foreign_asset_id_multilocation, dest_sovereign_account), 0); // Verify total and active issuance of USDT have decreased (teleported) - assert_eq!( - Assets::total_issuance(usdt_id_multilocation), - usdt_initial_local_amount - FEE_AMOUNT - ); - assert_eq!( - Assets::active_issuance(usdt_id_multilocation), - usdt_initial_local_amount - FEE_AMOUNT - ); + let expected_usdt_issuance = usdt_initial_local_amount - FEE_AMOUNT; + assert_eq!(Assets::total_issuance(usdt_id_multilocation), expected_usdt_issuance); + assert_eq!(Assets::active_issuance(usdt_id_multilocation), expected_usdt_issuance); // Verify total and active issuance of foreign BLA asset have decreased (burned on // reserve-withdraw) - assert_eq!( - Assets::total_issuance(foreign_asset_id_multilocation), - foreign_asset_initial_amount - SEND_AMOUNT - ); - assert_eq!( - Assets::active_issuance(foreign_asset_id_multilocation), - foreign_asset_initial_amount - SEND_AMOUNT - ); + let expected_bla_issuance = foreign_initial_amount - SEND_AMOUNT; + assert_eq!(Assets::total_issuance(foreign_asset_id_multilocation), expected_bla_issuance); + assert_eq!(Assets::active_issuance(foreign_asset_id_multilocation), expected_bla_issuance); // Verify sent XCM program assert_eq!( @@ -2220,74 +1907,6 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_wor }); } -/// Test `reserve_transfer_assets` single asset which is also teleportable - should fail. -/// -/// Attempting to reserve-transfer teleport-trusted USDT to `USDT_PARA_ID` should fail. -#[test] -fn reserve_transfer_assets_with_teleportable_asset_fails() { - let usdt_chain = RelayLocation::get().pushed_with_interior(Parachain(USDT_PARA_ID)).unwrap(); - let usdt_chain_sovereign_account = SovereignAccountOf::convert_location(&usdt_chain).unwrap(); - let usdt_id_multilocation = usdt_chain; - let usdt_initial_local_amount = 42; - - // transfer destination is USDT chain (foreign asset needs to go through its reserve chain) - let dest = usdt_chain; - let assets: MultiAssets = vec![(usdt_id_multilocation, FEE_AMOUNT).into()].into(); - let fee_index = 0; - - let balances = vec![(ALICE, INITIAL_BALANCE)]; - let beneficiary: MultiLocation = - Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - - new_test_ext_with_balances(balances).execute_with(|| { - // create sufficient foreign asset USDT (0 total issuance) - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - usdt_id_multilocation, - BOB, - true, - 1 - )); - // USDT should have been teleported/reserve-transferred in, but for this test we just - // mint it locally. - assert_ok!(Assets::mint( - RuntimeOrigin::signed(BOB), - usdt_id_multilocation, - ALICE, - usdt_initial_local_amount - )); - assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); - assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); - - // do the transfer - let res = XcmPallet::limited_reserve_transfer_assets( - RuntimeOrigin::signed(ALICE), - Box::new(dest.into()), - Box::new(beneficiary.into()), - Box::new(assets.into()), - fee_index as u32, - Unlimited, - ); - assert_eq!( - res, - Err(DispatchError::Module(ModuleError { - index: 4, - error: [2, 0, 0, 0], - message: Some("Filtered") - })) - ); - // Alice native asset is still same - assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); - // Alice USDT balance is still same - assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); - // No USDT moved to sovereign account of reserve parachain - assert_eq!(Assets::balance(usdt_id_multilocation, usdt_chain_sovereign_account), 0); - // Verify total and active issuance of USDT are still the same - assert_eq!(Assets::total_issuance(usdt_id_multilocation), usdt_initial_local_amount); - assert_eq!(Assets::active_issuance(usdt_id_multilocation), usdt_initial_local_amount); - }); -} - /// Test `reserve_transfer_assets` with remote asset reserve and teleported fee. /// /// Transferring foreign asset (reserve on `FOREIGN_ASSET_RESERVE_PARA_ID`) to `USDT_PARA_ID`. Using @@ -2312,95 +1931,50 @@ fn reserve_transfer_assets_with_teleportable_asset_fails() { /// ``` #[test] fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_works() { - let usdt_chain = RelayLocation::get().pushed_with_interior(Parachain(USDT_PARA_ID)).unwrap(); - let usdt_chain_sovereign_account = SovereignAccountOf::convert_location(&usdt_chain).unwrap(); - let usdt_id_multilocation = usdt_chain; - let usdt_initial_local_amount = 42; - - let reserve_location = RelayLocation::get() - .pushed_with_interior(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID)) - .unwrap(); - let foreign_asset_id_multilocation = - reserve_location.pushed_with_interior(FOREIGN_ASSET_INNER_JUNCTION).unwrap(); - let foreign_asset_initial_amount = 142; - let reserve_sovereign_account = - SovereignAccountOf::convert_location(&reserve_location).unwrap(); - - // transfer destination is USDT chain (foreign asset needs to go through its reserve chain) - let dest = usdt_chain; - let assets: MultiAssets = vec![ - // USDT for fees (is sufficient on local chain too) - (usdt_id_multilocation, FEE_AMOUNT).into(), - // foreign asset to transfer (not used for fees) - remote reserve - (foreign_asset_id_multilocation, SEND_AMOUNT).into(), - ] - .into(); - let fee_index = 0; - let asset_index = 1; - - let context = UniversalLocation::get(); - let mut expected_fee = assets.get(fee_index).unwrap().clone(); - let mut expected_asset = assets.get(asset_index).unwrap().clone(); - - // sanity check indices are still ok after sort() done by `vec![MultiAsset].into()`. - assert_eq!(expected_fee.id, usdt_id_multilocation.into()); - assert_eq!(expected_asset.id, foreign_asset_id_multilocation.into()); - - // reanchor according to test-case. - let expected_dest_on_reserve = dest.reanchored(&reserve_location, context).unwrap(); - let mut expected_fee_on_reserve = expected_fee.clone(); - let mut expected_asset_on_reserve = expected_asset.clone(); - expected_fee_on_reserve.reanchor(&reserve_location, context).unwrap(); - expected_asset_on_reserve.reanchor(&reserve_location, context).unwrap(); - expected_fee.reanchor(&dest, context).unwrap(); - expected_asset.reanchor(&dest, context).unwrap(); - - // fees are split between the asset-reserve chain and the destination chain - crate::Pallet::::halve_fungible_asset(&mut expected_fee_on_reserve).unwrap(); - crate::Pallet::::halve_fungible_asset(&mut expected_fee).unwrap(); - - let balances = vec![ - (ALICE, INITIAL_BALANCE), - (usdt_chain_sovereign_account.clone(), INITIAL_BALANCE), - (reserve_sovereign_account.clone(), INITIAL_BALANCE), - ]; + let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); let expected_beneficiary_on_reserve = beneficiary; - new_test_ext_with_balances(balances).execute_with(|| { // create sufficient foreign asset USDT (0 total issuance) - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - usdt_id_multilocation, - BOB, - true, - 1 - )); - // USDT should have been teleported/reserve-transferred in, but for this test we just - // mint it locally. - assert_ok!(Assets::mint( - RuntimeOrigin::signed(BOB), - usdt_id_multilocation, - ALICE, - usdt_initial_local_amount - )); + let usdt_initial_local_amount = 42; + let (usdt_chain, usdt_chain_sovereign_account, usdt_id_multilocation) = + set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, true); + // create non-sufficient foreign asset BLA (0 total issuance) - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - foreign_asset_id_multilocation, - BOB, - false, - 1 - )); - // foreign asset BLA should have been teleported/reserve-transferred in, but for this test - // we just mint it locally. - assert_ok!(Assets::mint( - RuntimeOrigin::signed(BOB), - foreign_asset_id_multilocation, - ALICE, - foreign_asset_initial_amount - )); + let foreign_initial_amount = 142; + let (reserve_location, reserve_sovereign_account, foreign_asset_id_multilocation) = + set_up_foreign_asset( + FOREIGN_ASSET_RESERVE_PARA_ID, + Some(FOREIGN_ASSET_INNER_JUNCTION), + foreign_initial_amount, + false, + ); + + // transfer destination is USDT chain (foreign asset needs to go through its reserve chain) + let dest = usdt_chain; + + let (assets, fee_index, fee_asset, xfer_asset) = into_multiassets_checked( + // USDT for fees (is sufficient on local chain too) - teleported + (usdt_id_multilocation, FEE_AMOUNT).into(), + // foreign asset to transfer (not used for fees) - remote reserve + (foreign_asset_id_multilocation, SEND_AMOUNT).into(), + ); + + // reanchor according to test-case + let context = UniversalLocation::get(); + let expected_dest_on_reserve = dest.reanchored(&reserve_location, context).unwrap(); + let mut expected_fee_on_reserve = + fee_asset.clone().reanchored(&reserve_location, context).unwrap(); + let expected_asset_on_reserve = + xfer_asset.clone().reanchored(&reserve_location, context).unwrap(); + let mut expected_fee = fee_asset.reanchored(&dest, context).unwrap(); + + // fees are split between the asset-reserve chain and the destination chain + crate::Pallet::::halve_fungible_asset(&mut expected_fee_on_reserve).unwrap(); + crate::Pallet::::halve_fungible_asset(&mut expected_fee).unwrap(); + + // balances checks before assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); @@ -2427,33 +2001,23 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_works() // Alice transferred BLA assert_eq!( Assets::balance(foreign_asset_id_multilocation, ALICE), - foreign_asset_initial_amount - SEND_AMOUNT + foreign_initial_amount - SEND_AMOUNT ); // Verify balances of USDT reserve parachain - assert_eq!(Balances::free_balance(usdt_chain_sovereign_account.clone()), INITIAL_BALANCE); + assert_eq!(Balances::free_balance(usdt_chain_sovereign_account.clone()), 0); assert_eq!(Assets::balance(usdt_id_multilocation, usdt_chain_sovereign_account), 0); // Verify balances of transferred-asset reserve parachain - assert_eq!(Balances::free_balance(reserve_sovereign_account.clone()), INITIAL_BALANCE); + assert_eq!(Balances::free_balance(reserve_sovereign_account.clone()), 0); assert_eq!(Assets::balance(foreign_asset_id_multilocation, reserve_sovereign_account), 0); // Verify total and active issuance of USDT have decreased (teleported) - assert_eq!( - Assets::total_issuance(usdt_id_multilocation), - usdt_initial_local_amount - FEE_AMOUNT - ); - assert_eq!( - Assets::active_issuance(usdt_id_multilocation), - usdt_initial_local_amount - FEE_AMOUNT - ); + let expected_usdt_issuance = usdt_initial_local_amount - FEE_AMOUNT; + assert_eq!(Assets::total_issuance(usdt_id_multilocation), expected_usdt_issuance); + assert_eq!(Assets::active_issuance(usdt_id_multilocation), expected_usdt_issuance); // Verify total and active issuance of foreign BLA asset have decreased (burned on // reserve-withdraw) - assert_eq!( - Assets::total_issuance(foreign_asset_id_multilocation), - foreign_asset_initial_amount - SEND_AMOUNT - ); - assert_eq!( - Assets::active_issuance(foreign_asset_id_multilocation), - foreign_asset_initial_amount - SEND_AMOUNT - ); + let expected_bla_issuance = foreign_initial_amount - SEND_AMOUNT; + assert_eq!(Assets::total_issuance(foreign_asset_id_multilocation), expected_bla_issuance); + assert_eq!(Assets::active_issuance(foreign_asset_id_multilocation), expected_bla_issuance); // Verify sent XCM program assert_eq!( @@ -2511,6 +2075,58 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_works() }); } +/// Test `reserve_transfer_assets` single asset which is teleportable - should fail. +/// +/// Attempting to reserve-transfer teleport-trusted USDT to `USDT_PARA_ID` should fail. +#[test] +fn reserve_transfer_assets_with_teleportable_asset_fails() { + let balances = vec![(ALICE, INITIAL_BALANCE)]; + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient foreign asset USDT (0 total issuance) + let usdt_initial_local_amount = 42; + let (usdt_chain, usdt_chain_sovereign_account, usdt_id_multilocation) = + set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, true); + + // transfer destination is USDT chain (foreign asset needs to go through its reserve chain) + let dest = usdt_chain; + let assets: MultiAssets = vec![(usdt_id_multilocation, FEE_AMOUNT).into()].into(); + let fee_index = 0; + + // balances checks before + assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // do the transfer + let res = XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + ); + assert_eq!( + res, + Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered") + })) + ); + // Alice native asset is still same + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + // Alice USDT balance is still same + assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); + // No USDT moved to sovereign account of reserve parachain + assert_eq!(Assets::balance(usdt_id_multilocation, usdt_chain_sovereign_account), 0); + // Verify total and active issuance of USDT are still the same + assert_eq!(Assets::total_issuance(usdt_id_multilocation), usdt_initial_local_amount); + assert_eq!(Assets::active_issuance(usdt_id_multilocation), usdt_initial_local_amount); + }); +} + /// Test local execution of XCM /// /// Asserts that the sender's balance is decreased and the beneficiary's balance From 022ef71466df90c27802ef5109d07ccf4291b345 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 10 Oct 2023 17:33:43 +0300 Subject: [PATCH 29/98] pallet-xcm: fix benchmarks --- polkadot/runtime/westend/src/xcm_config.rs | 16 ++++++++++++- polkadot/xcm/pallet-xcm/src/benchmarking.rs | 26 ++++++++++----------- polkadot/xcm/pallet-xcm/src/lib.rs | 14 +++++++++++ polkadot/xcm/pallet-xcm/src/mock.rs | 25 ++++++++++++++++++-- 4 files changed, 64 insertions(+), 17 deletions(-) diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index 66a2e2230ccd..53a242952cd5 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -194,6 +194,16 @@ parameter_types! { #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parachain(1000).into()); + // Relay/native token can be teleported to/from AH. + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Here.into()) }.into(), + AssetHub::get(), + )); + // We can reserve transfer native token to some random parachain. + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Here.into()) }.into(), + Parachain(4321).into(), + )); } /// Type to convert the `GeneralAdmin` origin to a Plurality `MultiLocation` value. @@ -256,7 +266,11 @@ impl pallet_xcm::Config for Runtime { type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = crate::weights::pallet_xcm::WeightInfo; + type AdminOrigin = EnsureRoot; #[cfg(feature = "runtime-benchmarks")] type ReachableDest = ReachableDest; - type AdminOrigin = EnsureRoot; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs index aca4bd1fb3fa..f567691b5092 100644 --- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs @@ -40,43 +40,41 @@ benchmarks! { }: _>(send_origin, Box::new(versioned_dest), Box::new(versioned_msg)) teleport_assets { - let asset: MultiAsset = (Here, 10).into(); + let (assets, destination) = T::TeleportableAssets::get().ok_or( + BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), + )?; let send_origin = T::ExecuteXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone()) .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; - if !T::XcmTeleportFilter::contains(&(origin_location, vec![asset.clone()])) { + if !T::XcmTeleportFilter::contains(&(origin_location, assets.clone().into_inner())) { return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) } let recipient = [0u8; 32]; - let versioned_dest: VersionedMultiLocation = T::ReachableDest::get().ok_or( - BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), - )? - .into(); + let versioned_dest: VersionedMultiLocation = destination.into(); let versioned_beneficiary: VersionedMultiLocation = AccountId32 { network: None, id: recipient.into() }.into(); - let versioned_assets: VersionedMultiAssets = asset.into(); + let versioned_assets: VersionedMultiAssets = assets.into(); }: _>(send_origin, Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0) reserve_transfer_assets { - let asset: MultiAsset = (Here, 10).into(); + let (assets, destination) = T::ReserveTransferableAssets::get().ok_or( + BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), + )?; let send_origin = T::ExecuteXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone()) .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; - if !T::XcmReserveTransferFilter::contains(&(origin_location, vec![asset.clone()])) { + if !T::XcmReserveTransferFilter::contains(&(origin_location, assets.clone().into_inner())) { return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) } let recipient = [0u8; 32]; - let versioned_dest: VersionedMultiLocation = T::ReachableDest::get().ok_or( - BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), - )? - .into(); + let versioned_dest: VersionedMultiLocation = destination.into(); let versioned_beneficiary: VersionedMultiLocation = AccountId32 { network: None, id: recipient.into() }.into(); - let versioned_assets: VersionedMultiAssets = asset.into(); + let versioned_assets: VersionedMultiAssets = assets.into(); }: _>(send_origin, Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0) execute { diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 832e630e637d..d7ea85aefc52 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -265,6 +265,20 @@ pub mod pallet { /// If `None`, the benchmarks that depend on a reachable destination will be skipped. #[cfg(feature = "runtime-benchmarks")] type ReachableDest: Get>; + + /// A `(MultiAssets, MultiLocation)` pair representing assets and the destination they can + /// be teleported to. Used only in benchmarks. + /// + /// If `None`, the benchmarks that depend on `TeleportableAssets` will be skipped. + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets: Get>; + + /// A `(MultiAssets, MultiLocation)` pair representing assets and the destination they can + /// be reserve-transferred to. Used only in benchmarks. + /// + /// If `None`, the benchmarks that depend on `ReserveTransferableAssets` will be skipped. + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets: Get>; } #[pallet::event] diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index b269fcea394b..56b97bef4fba 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -252,6 +252,15 @@ impl pallet_balances::Config for Test { type MaxFreezes = ConstU32<0>; } +/// Simple conversion of `u32` into an `AssetId` for use in benchmarking. +pub struct XcmBenchmarkHelper; +#[cfg(feature = "runtime-benchmarks")] +impl pallet_assets::BenchmarkHelper for XcmBenchmarkHelper { + fn create_asset_id_parameter(id: u32) -> MultiLocation { + MultiLocation { parents: 1, interior: X1(Parachain(id)) } + } +} + impl pallet_assets::Config for Test { type RuntimeEvent = RuntimeEvent; type Balance = Balance; @@ -272,7 +281,7 @@ impl pallet_assets::Config for Test { type Extra = (); type RemoveItemsLimit = ConstU32<5>; #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); + type BenchmarkHelper = XcmBenchmarkHelper; } // This child parachain acts as trusted reserve for its assets in tests. @@ -431,6 +440,14 @@ parameter_types! { #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parachain(1000).into()); + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + vec![Usdt::get()].into(), + UsdtTeleportLocation::get(), + )); + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + vec![ForeignAsset::get()].into(), + ForeignReserveLocation::get(), + )); } impl pallet_xcm::Config for Test { @@ -448,6 +465,7 @@ impl pallet_xcm::Config for Test { type RuntimeCall = RuntimeCall; const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; type AdvertisedXcmVersion = AdvertisedXcmVersion; + type AdminOrigin = EnsureRoot; type TrustedLockers = (); type SovereignAccountOf = AccountId32Aliases<(), AccountId32>; type Currency = Balances; @@ -458,7 +476,10 @@ impl pallet_xcm::Config for Test { type WeightInfo = TestWeightInfo; #[cfg(feature = "runtime-benchmarks")] type ReachableDest = ReachableDest; - type AdminOrigin = EnsureRoot; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } impl origin::Config for Test {} From 9827c3b6201c9b40763e8dcc16cb6775763ae289 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 10 Oct 2023 18:15:24 +0300 Subject: [PATCH 30/98] fix pallet-xcm benchmarks for all runtimes --- .../runtime/src/xcm_config.rs | 15 +++++++++++++-- .../assets/asset-hub-kusama/src/xcm_config.rs | 18 ++++++++++++++++-- .../asset-hub-polkadot/src/xcm_config.rs | 18 ++++++++++++++++-- .../assets/asset-hub-westend/src/xcm_config.rs | 18 ++++++++++++++++-- .../bridge-hub-kusama/src/xcm_config.rs | 15 +++++++++++++-- .../bridge-hub-polkadot/src/xcm_config.rs | 15 +++++++++++++-- .../bridge-hub-rococo/src/xcm_config.rs | 15 +++++++++++++-- .../collectives-polkadot/src/xcm_config.rs | 15 +++++++++++++-- .../contracts-rococo/src/xcm_config.rs | 18 ++++++++++++++++-- .../runtimes/testing/penpal/src/xcm_config.rs | 15 +++++++++++++-- .../testing/rococo-parachain/src/lib.rs | 18 ++++++++++++++++-- polkadot/runtime/rococo/src/xcm_config.rs | 18 ++++++++++++++++-- .../runtime/test-runtime/src/xcm_config.rs | 8 +++++++- polkadot/xcm/xcm-builder/src/tests/pay/mock.rs | 8 +++++++- polkadot/xcm/xcm-builder/tests/mock/mod.rs | 8 +++++++- .../xcm/xcm-simulator/example/src/parachain.rs | 8 +++++++- .../xcm-simulator/example/src/relay_chain.rs | 8 +++++++- .../xcm/xcm-simulator/fuzzer/src/parachain.rs | 8 +++++++- .../xcm-simulator/fuzzer/src/relay_chain.rs | 8 +++++++- 19 files changed, 223 insertions(+), 31 deletions(-) diff --git a/cumulus/parachain-template/runtime/src/xcm_config.rs b/cumulus/parachain-template/runtime/src/xcm_config.rs index 353f68d22e35..0b82dba25f28 100644 --- a/cumulus/parachain-template/runtime/src/xcm_config.rs +++ b/cumulus/parachain-template/runtime/src/xcm_config.rs @@ -153,6 +153,13 @@ pub type XcmRouter = WithUniqueTopic<( #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parent.into()); + // Teleports are disabled + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = None; + // We can reserve transfer relay/native token between us and Relay. + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + Parent.into(), + )); } impl pallet_xcm::Config for Runtime { @@ -180,11 +187,15 @@ impl pallet_xcm::Config for Runtime { type SovereignAccountOf = LocationToAccountId; type MaxLockers = ConstU32<8>; type WeightInfo = pallet_xcm::TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs index 0c197598f889..d173dd8f338b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs @@ -540,6 +540,16 @@ pub type XcmRouter = WithUniqueTopic<( #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parent.into()); + // Relay/native token can be teleported between AH and Relay. + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + Parent.into(), + )); + // We can reserve transfer some local token to Relay. + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Here.into()) }.into(), + Parent.into(), + )); } impl pallet_xcm::Config for Runtime { @@ -571,11 +581,15 @@ impl pallet_xcm::Config for Runtime { type SovereignAccountOf = LocationToAccountId; type MaxLockers = ConstU32<8>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs index 65cf62a610f4..6195de606e51 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs @@ -464,6 +464,16 @@ pub type XcmRouter = WithUniqueTopic<( #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parent.into()); + // Relay/native token can be teleported between AH and Relay. + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + Parent.into(), + )); + // We can reserve transfer some local token to Relay. + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Here.into()) }.into(), + Parent.into(), + )); } impl pallet_xcm::Config for Runtime { @@ -495,11 +505,15 @@ impl pallet_xcm::Config for Runtime { type SovereignAccountOf = LocationToAccountId; type MaxLockers = ConstU32<8>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index a0921c50dc59..dab9a1e5773e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs @@ -550,6 +550,16 @@ pub type XcmRouter = WithUniqueTopic<( #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parent.into()); + // Relay/native token can be teleported between AH and Relay. + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + Parent.into(), + )); + // We can reserve transfer some local token to Relay. + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Here.into()) }.into(), + Parent.into(), + )); } impl pallet_xcm::Config for Runtime { @@ -577,11 +587,15 @@ impl pallet_xcm::Config for Runtime { type SovereignAccountOf = LocationToAccountId; type MaxLockers = ConstU32<8>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs index 696462be9c45..0fc4b6aab181 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs @@ -229,6 +229,13 @@ pub type XcmRouter = WithUniqueTopic<( #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parent.into()); + // Relay/native token can be teleported between BH and Relay. + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + Parent.into(), + )); + // Reserve transfers are disabled on BH. + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; } impl pallet_xcm::Config for Runtime { @@ -259,11 +266,15 @@ impl pallet_xcm::Config for Runtime { type SovereignAccountOf = LocationToAccountId; type MaxLockers = ConstU32<8>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs index 0965600c2468..22b138dfc8a0 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs @@ -233,6 +233,13 @@ pub type XcmRouter = WithUniqueTopic<( #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parent.into()); + // Relay/native token can be teleported between BH and Relay. + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + Parent.into(), + )); + // Reserve transfers are disabled on BH. + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; } impl pallet_xcm::Config for Runtime { @@ -263,11 +270,15 @@ impl pallet_xcm::Config for Runtime { type SovereignAccountOf = LocationToAccountId; type MaxLockers = ConstU32<8>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index e3d8645d49e7..989fd61111b1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs @@ -276,6 +276,13 @@ pub type XcmRouter = WithUniqueTopic<( #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parent.into()); + // Relay/native token can be teleported between BH and Relay. + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + Parent.into(), + )); + // Reserve transfers are disabled on BH. + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; } impl pallet_xcm::Config for Runtime { @@ -305,11 +312,15 @@ impl pallet_xcm::Config for Runtime { type SovereignAccountOf = LocationToAccountId; type MaxLockers = ConstU32<8>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs index f802073bfbbb..b828df5f0feb 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs @@ -288,6 +288,13 @@ pub type XcmRouter = WithUniqueTopic<( #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parent.into()); + // Relay/native token can be teleported between BH and Relay. + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + Parent.into(), + )); + // Reserve transfers are disabled on Collectives. + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; } /// Type to convert the Fellows origin to a Plurality `MultiLocation` value. @@ -317,11 +324,15 @@ impl pallet_xcm::Config for Runtime { type SovereignAccountOf = LocationToAccountId; type MaxLockers = ConstU32<8>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs index 7433b8e94d6c..ddb91a3448fb 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -188,6 +188,16 @@ pub type XcmRouter = WithUniqueTopic<( #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parent.into()); + // Relay/native token can be teleported to Relay. + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + Parent.into(), + )); + // Act as reserve for native token when sending to random parachain. + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + Parachain(4321).into(), + )); } impl pallet_xcm::Config for Runtime { @@ -216,11 +226,15 @@ impl pallet_xcm::Config for Runtime { type MaxLockers = ConstU32<8>; // FIXME: Replace with benchmarked weight info type WeightInfo = pallet_xcm::TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index f2ffc451b10e..3bcc20784b0f 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -315,6 +315,13 @@ pub type XcmRouter = WithUniqueTopic<( #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parent.into()); + // Relay/native token can be teleported to Relay. + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + Parent.into(), + )); + // Disable reserve transfers benchmarks for penpal. + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; } impl pallet_xcm::Config for Runtime { @@ -342,11 +349,15 @@ impl pallet_xcm::Config for Runtime { type SovereignAccountOf = LocationToAccountId; type MaxLockers = ConstU32<8>; type WeightInfo = pallet_xcm::TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 50c5a445c25f..e8a579430fd2 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -467,6 +467,16 @@ pub type XcmRouter = WithUniqueTopic<( #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parent.into()); + // Relay/native token can be teleported to/from Relay. + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + Parent.into(), + )); + // We can reserve transfer some AH local token to/from AH. + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(SystemAssetHubLocation::get()) }.into(), + SystemAssetHubLocation::get(), + )); } impl pallet_xcm::Config for Runtime { @@ -490,11 +500,15 @@ impl pallet_xcm::Config for Runtime { type SovereignAccountOf = LocationToAccountId; type MaxLockers = ConstU32<8>; type WeightInfo = pallet_xcm::TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index b84d2335a699..9c1b878d841c 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -206,7 +206,17 @@ parameter_types! { #[cfg(feature = "runtime-benchmarks")] parameter_types! { - pub ReachableDest: Option = Some(Parachain(1000).into()); + pub ReachableDest: Option = Some(AssetHub::get()); + // Relay/native token can be teleported to/from AH. + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Here.into()) }.into(), + AssetHub::get(), + )); + // We can reserve transfer native token to some random parachain. + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Here.into()) }.into(), + Parachain(4321).into(), + )); } /// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior @@ -262,7 +272,11 @@ impl pallet_xcm::Config for Runtime { type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = crate::weights::pallet_xcm::WeightInfo; + type AdminOrigin = EnsureRoot; #[cfg(feature = "runtime-benchmarks")] type ReachableDest = ReachableDest; - type AdminOrigin = EnsureRoot; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } diff --git a/polkadot/runtime/test-runtime/src/xcm_config.rs b/polkadot/runtime/test-runtime/src/xcm_config.rs index 2113bbae66ad..02a89a0c80f3 100644 --- a/polkadot/runtime/test-runtime/src/xcm_config.rs +++ b/polkadot/runtime/test-runtime/src/xcm_config.rs @@ -126,6 +126,8 @@ impl xcm_executor::Config for XcmConfig { #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(xcm::latest::Junctions::Here.into()); + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = None; + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; } impl pallet_xcm::Config for crate::Runtime { @@ -153,7 +155,11 @@ impl pallet_xcm::Config for crate::Runtime { type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; + type AdminOrigin = EnsureRoot; #[cfg(feature = "runtime-benchmarks")] type ReachableDest = ReachableDest; - type AdminOrigin = EnsureRoot; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } diff --git a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs index 5b6fa3ee5a0b..9bb32cb798d7 100644 --- a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs @@ -248,6 +248,8 @@ type SovereignAccountOf = ( #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parachain(1000).into()); + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = None; + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; } impl pallet_xcm::Config for Test { @@ -273,9 +275,13 @@ impl pallet_xcm::Config for Test { type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; + type AdminOrigin = EnsureRoot; #[cfg(feature = "runtime-benchmarks")] type ReachableDest = ReachableDest; - type AdminOrigin = EnsureRoot; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } pub const UNITS: Balance = 1_000_000_000_000; diff --git a/polkadot/xcm/xcm-builder/tests/mock/mod.rs b/polkadot/xcm/xcm-builder/tests/mock/mod.rs index 363748940ca6..0dd9436684e1 100644 --- a/polkadot/xcm/xcm-builder/tests/mock/mod.rs +++ b/polkadot/xcm/xcm-builder/tests/mock/mod.rs @@ -212,6 +212,8 @@ pub type LocalOriginToLocation = SignedToAccountId32 = Some(Here.into()); + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = None; + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; } impl pallet_xcm::Config for Runtime { @@ -238,9 +240,13 @@ impl pallet_xcm::Config for Runtime { type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; + type AdminOrigin = EnsureRoot; #[cfg(feature = "runtime-benchmarks")] type ReachableDest = ReachableDest; - type AdminOrigin = EnsureRoot; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } impl origin::Config for Runtime {} diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain.rs b/polkadot/xcm/xcm-simulator/example/src/parachain.rs index bc7cba313828..dac27cc27b8a 100644 --- a/polkadot/xcm/xcm-simulator/example/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/example/src/parachain.rs @@ -401,6 +401,8 @@ pub type LocalOriginToLocation = SignedToAccountId32 = Some(Parent.into()); + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = None; + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; } pub struct TrustedLockerCase(PhantomData); @@ -442,9 +444,13 @@ impl pallet_xcm::Config for Runtime { type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; + type AdminOrigin = EnsureRoot; #[cfg(feature = "runtime-benchmarks")] type ReachableDest = ReachableDest; - type AdminOrigin = EnsureRoot; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } type Block = frame_system::mocking::MockBlock; diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs index 4e9195a8454f..9fbe30319ae8 100644 --- a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs @@ -201,6 +201,8 @@ pub type LocalOriginToLocation = SignedToAccountId32 = Some(Parachain(1).into()); + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = None; + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; } impl pallet_xcm::Config for Runtime { @@ -227,9 +229,13 @@ impl pallet_xcm::Config for Runtime { type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; + type AdminOrigin = EnsureRoot; #[cfg(feature = "runtime-benchmarks")] type ReachableDest = ReachableDest; - type AdminOrigin = EnsureRoot; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } parameter_types! { diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs index 95f875eca06e..339b68d75c0f 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs @@ -315,6 +315,8 @@ pub type LocalOriginToLocation = SignedToAccountId32 = Some(Parent.into()); + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = None; + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; } impl pallet_xcm::Config for Runtime { @@ -340,9 +342,13 @@ impl pallet_xcm::Config for Runtime { type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; + type AdminOrigin = EnsureRoot; #[cfg(feature = "runtime-benchmarks")] type ReachableDest = ReachableDest; - type AdminOrigin = EnsureRoot; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } type Block = frame_system::mocking::MockBlock; diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs index a29ead9e6c3b..fe3950471ec1 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs @@ -165,6 +165,8 @@ pub type LocalOriginToLocation = SignedToAccountId32 = Some(Parachain(1).into()); + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = None; + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; } impl pallet_xcm::Config for Runtime { @@ -191,9 +193,13 @@ impl pallet_xcm::Config for Runtime { type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; + type AdminOrigin = EnsureRoot; #[cfg(feature = "runtime-benchmarks")] type ReachableDest = ReachableDest; - type AdminOrigin = EnsureRoot; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } parameter_types! { From 23588a8e3966c63b1945bffb077e6a4efc0f6bd1 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 11 Oct 2023 11:55:34 +0300 Subject: [PATCH 31/98] address review comments --- .../runtimes/assets/test-utils/src/test_cases.rs | 12 ++++++++---- polkadot/xcm/pallet-xcm/src/mock.rs | 1 + polkadot/xcm/src/v3/junction.rs | 8 -------- polkadot/xcm/src/v3/multilocation.rs | 2 +- 4 files changed, 10 insertions(+), 13 deletions(-) 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 9ac68e2fbddf..133132507a38 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -158,12 +158,13 @@ pub fn teleports_for_native_asset_works< // 2. try to teleport asset back to the relaychain { let dest = MultiLocation::parent(); - let dest_beneficiary = MultiLocation::parent() + let mut dest_beneficiary = MultiLocation::parent() .appended_with(AccountId32 { network: None, id: sp_runtime::AccountId32::new([3; 32]).into(), }) .unwrap(); + dest_beneficiary.reanchor(&dest, Here.into()).unwrap(); let target_account_balance_before_teleport = >::free_balance(&target_account); @@ -206,12 +207,13 @@ pub fn teleports_for_native_asset_works< { let other_para_id = 2345; let dest = MultiLocation::new(1, X1(Parachain(other_para_id))); - let dest_beneficiary = MultiLocation::new(1, X1(Parachain(other_para_id))) + let mut dest_beneficiary = MultiLocation::new(1, X1(Parachain(other_para_id))) .appended_with(AccountId32 { network: None, id: sp_runtime::AccountId32::new([3; 32]).into(), }) .unwrap(); + dest_beneficiary.reanchor(&dest, Here.into()).unwrap(); let target_account_balance_before_teleport = >::free_balance(&target_account); @@ -513,12 +515,13 @@ pub fn teleports_for_foreign_assets_works< // 2. try to teleport asset back to source parachain (foreign_para_id) { let dest = MultiLocation::new(1, X1(Parachain(foreign_para_id))); - let dest_beneficiary = MultiLocation::new(1, X1(Parachain(foreign_para_id))) + let mut dest_beneficiary = MultiLocation::new(1, X1(Parachain(foreign_para_id))) .appended_with(AccountId32 { network: None, id: sp_runtime::AccountId32::new([3; 32]).into(), }) .unwrap(); + dest_beneficiary.reanchor(&dest, Here.into()).unwrap(); let target_account_balance_before_teleport = >::balance( @@ -1401,12 +1404,13 @@ pub fn reserve_transfer_native_asset_to_non_teleport_para_works< let other_para_id = 2345; let native_asset = MultiLocation::parent(); let dest = MultiLocation::new(1, X1(Parachain(other_para_id))); - let dest_beneficiary = MultiLocation::new(1, X1(Parachain(other_para_id))) + let mut dest_beneficiary = MultiLocation::new(1, X1(Parachain(other_para_id))) .appended_with(AccountId32 { network: None, id: sp_runtime::AccountId32::new([3; 32]).into(), }) .unwrap(); + dest_beneficiary.reanchor(&dest, Here.into()).unwrap(); let reserve_account = LocationToAccountId::convert_location(&dest) .expect("Sovereign account for reserves"); diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 56b97bef4fba..f95d80244533 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -252,6 +252,7 @@ impl pallet_balances::Config for Test { type MaxFreezes = ConstU32<0>; } +#[cfg(feature = "runtime-benchmarks")] /// Simple conversion of `u32` into an `AssetId` for use in benchmarking. pub struct XcmBenchmarkHelper; #[cfg(feature = "runtime-benchmarks")] diff --git a/polkadot/xcm/src/v3/junction.rs b/polkadot/xcm/src/v3/junction.rs index cd6d4f85dc26..b5dd5bc7c88f 100644 --- a/polkadot/xcm/src/v3/junction.rs +++ b/polkadot/xcm/src/v3/junction.rs @@ -437,14 +437,6 @@ impl Junction { _ => {}, } } - - /// Specifies whether junction identifies a chain. - pub fn is_chain_identifier(&self) -> bool { - match self { - Junction::Parachain(_) | Junction::GlobalConsensus(_) => true, - _ => false, - } - } } #[cfg(test)] diff --git a/polkadot/xcm/src/v3/multilocation.rs b/polkadot/xcm/src/v3/multilocation.rs index 0f226a1f1565..f948340abcb5 100644 --- a/polkadot/xcm/src/v3/multilocation.rs +++ b/polkadot/xcm/src/v3/multilocation.rs @@ -449,7 +449,7 @@ impl MultiLocation { pub fn chain_location(mut self) -> MultiLocation { // start popping junctions until we reach chain identifier while let Some(j) = self.last() { - if j.is_chain_identifier() { + if matches!(j, Junction::Parachain(_) | Junction::GlobalConsensus(_)) { // return chain subsection return self } else { From 931e09371562d6ffaa2cb7fb09b9a43ea5901e0a Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 11 Oct 2023 12:35:19 +0300 Subject: [PATCH 32/98] expose TransferType through XcmExecutor::traits::AssetTransferSupport instead of pallet_xcm --- Cargo.lock | 1 + polkadot/xcm/pallet-xcm/src/lib.rs | 77 +++++-------------- polkadot/xcm/xcm-executor/Cargo.toml | 2 + polkadot/xcm/xcm-executor/src/lib.rs | 4 +- .../xcm-executor/src/traits/asset_transfer.rs | 61 ++++++++++++++- polkadot/xcm/xcm-executor/src/traits/mod.rs | 2 +- 6 files changed, 82 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 30bd4a043b80..6bdb96373676 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17718,6 +17718,7 @@ dependencies = [ "impl-trait-for-tuples", "log", "parity-scale-codec", + "scale-info", "sp-arithmetic", "sp-core", "sp-io", diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index d7ea85aefc52..f25c3964cee1 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -41,7 +41,9 @@ use sp_runtime::{ }; use sp_std::{boxed::Box, marker::PhantomData, prelude::*, result::Result, vec}; use xcm::{latest::QueryResponseInfo, prelude::*}; -use xcm_executor::traits::{AssetTransferFilter, ConvertOrigin, Properties}; +use xcm_executor::traits::{ + AssetTransferError, AssetTransferSupport, ConvertOrigin, Properties, TransferType, +}; use frame_support::{ dispatch::GetDispatchInfo, pallet_prelude::*, traits::WithdrawReasons, PalletId, @@ -206,7 +208,7 @@ pub mod pallet { type XcmExecuteFilter: Contains<(MultiLocation, Xcm<::RuntimeCall>)>; /// Something to execute an XCM message. - type XcmExecutor: ExecuteXcm<::RuntimeCall> + AssetTransferFilter; + type XcmExecutor: ExecuteXcm<::RuntimeCall> + AssetTransferSupport; /// Our XCM filter which messages to be teleported using the dedicated extrinsic must pass. type XcmTeleportFilter: Contains<(MultiLocation, Vec)>; @@ -443,7 +445,7 @@ pub mod pallet { /// The location is invalid since it already has a subscription from us. AlreadySubscribed, /// Invalid asset for the operation. - InvalidAsset, + InvalidAsset(AssetTransferError), /// The owner does not own (all) of the asset that they wish to do the operation on. LowBalance, /// The asset owner has too many locks on the asset. @@ -456,8 +458,6 @@ pub mod pallet { LockNotFound, /// The unlock operation cannot succeed because there are still consumers of the lock. InUse, - /// Reserve chain could not be determined for assets to be transferred. - UnknownReserve, /// Too many assets with different reserve locations have been attempted for transfer. TooManyReserves, } @@ -1211,54 +1211,6 @@ impl QueryHandler for Pallet { } } -#[derive(Copy, Clone, PartialEq, Debug)] -enum TransferType { - Teleport, - LocalReserve, - DestinationReserve, - RemoteReserve(MultiLocation), -} - -impl TransferType { - /// Determine transfer type to be used for transferring `asset` from local chain to `dest`. - pub fn determine_for( - asset: &MultiAsset, - dest: &MultiLocation, - ) -> Result> { - if ::IsTeleporter::contains(asset, dest) { - // we trust destination for teleporting asset - return Ok(TransferType::Teleport) - } else if ::IsReserve::contains(asset, dest) { - // we trust destination as asset reserve location - return Ok(TransferType::DestinationReserve) - } - - // try to determine reserve location based on asset id/location - let asset_location = match asset.id { - Concrete(location) => Ok(location.chain_location()), - _ => Err(Error::::InvalidAsset), - }?; - if asset_location == MultiLocation::here() || - ::IsTeleporter::contains( - asset, - &asset_location, - ) { - // local asset, or remote location that allows local teleports => local reserve - Ok(TransferType::LocalReserve) - } else if ::IsReserve::contains( - asset, - &asset_location, - ) { - // remote location that is recognized as reserve location for asset - Ok(TransferType::RemoteReserve(asset_location)) - } else { - // remote location that is not configured either as teleporter or reserve => cannot - // determine asset reserve - Err(Error::::UnknownReserve) - } - } -} - impl Pallet { /// Validate `assets` to be reserve-transferred and return their reserve location. fn validate_assets_and_find_reserve( @@ -1270,9 +1222,11 @@ impl Pallet { // Ensure fungible asset. ensure!( matches!(asset.fun, Fungibility::Fungible(x) if !x.is_zero()), - Error::::InvalidAsset + Error::::InvalidAsset(AssetTransferError::NotFungible) ); - let transfer_type = TransferType::determine_for::(&asset, dest)?; + let transfer_type = + ::determine_for(&asset, dest) + .map_err(Error::::InvalidAsset)?; // Ensure asset is not teleportable to `dest`. ensure!(transfer_type != TransferType::Teleport, Error::::Filtered); if let Some(reserve) = reserve.as_ref() { @@ -1310,7 +1264,9 @@ impl Pallet { return Err(Error::::Empty.into()) } let mut fees = assets.swap_remove(fee_asset_item as usize); - let fees_transfer_type = TransferType::determine_for::(&fees, &dest)?; + let fees_transfer_type = + ::determine_for(&fees, &dest) + .map_err(Error::::InvalidAsset)?; let assets_transfer_type = if assets.is_empty() { // Single asset to transfer (one used for fees where transfer type is determined above). ensure!(fees_transfer_type != TransferType::Teleport, Error::::Filtered); @@ -1353,7 +1309,8 @@ impl Pallet { assets_reserve, beneficiary, vec![fees.clone()], - TransferType::determine_for::(&fees, &assets_reserve)?, + ::determine_for(&fees, &assets_reserve) + .map_err(Error::::InvalidAsset)?, fees.clone(), quarter_weight_limit.clone(), )?; @@ -1414,7 +1371,9 @@ impl Pallet { ensure!(T::XcmTeleportFilter::contains(&value), Error::::Filtered); let (origin_location, assets) = value; for asset in assets.iter() { - let transfer_type = TransferType::determine_for::(asset, &dest)?; + let transfer_type = + ::determine_for(asset, &dest) + .map_err(Error::::InvalidAsset)?; ensure!(matches!(transfer_type, TransferType::Teleport), Error::::Filtered); } let fees = assets.get(fee_asset_item as usize).ok_or(Error::::Empty)?.clone(); @@ -1922,7 +1881,7 @@ impl Pallet { *amount = amount.saturating_div(2); Ok(()) }, - NonFungible(_) => Err(Error::::InvalidAsset), + NonFungible(_) => Err(Error::::InvalidAsset(AssetTransferError::NotFungible)), } } } diff --git a/polkadot/xcm/xcm-executor/Cargo.toml b/polkadot/xcm/xcm-executor/Cargo.toml index 902f55901d6c..c6f3a11fbe22 100644 --- a/polkadot/xcm/xcm-executor/Cargo.toml +++ b/polkadot/xcm/xcm-executor/Cargo.toml @@ -10,6 +10,7 @@ version = "1.0.0" impl-trait-for-tuples = "0.2.2" environmental = { version = "1.1.4", default-features = false } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive", "serde"] } xcm = { package = "staging-xcm", path = "..", default-features = false } sp-std = { path = "../../../substrate/primitives/std", default-features = false } sp-io = { path = "../../../substrate/primitives/io", default-features = false } @@ -33,6 +34,7 @@ std = [ "frame-support/std", "log/std", "parity-scale-codec/std", + "scale-info/std", "sp-arithmetic/std", "sp-core/std", "sp-io/std", diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index a5575b6952f1..bd6b1d79a11e 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -38,7 +38,7 @@ use traits::{ mod assets; pub use assets::Assets; mod config; -use crate::traits::AssetTransferFilter; +use crate::traits::AssetTransferSupport; pub use config::Config; /// A struct to specify how fees are being paid. @@ -255,7 +255,7 @@ impl ExecuteXcm for XcmExecutor AssetTransferFilter for XcmExecutor { +impl AssetTransferSupport for XcmExecutor { type IsReserve = Config::IsReserve; type IsTeleporter = Config::IsTeleporter; } diff --git a/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs b/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs index c8fdc582bf11..c75c48ead6ef 100644 --- a/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs +++ b/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs @@ -14,11 +14,36 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use frame_support::traits::ContainsPair; +use frame_support::traits::{ContainsPair, PalletError}; +use scale_info::TypeInfo; +use sp_runtime::codec::{Decode, Encode}; use xcm::prelude::*; -/// A trait for identifying asset transfer type. -pub trait AssetTransferFilter { +#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] +pub enum Error { + /// Invalid non-concrete asset. + NotConcrete, + /// Invalid non-fungible asset. + NotFungible, + /// Reserve chain could not be determined for assets. + UnknownReserve, +} + +impl PalletError for Error { + const MAX_ENCODED_SIZE: usize = 1; +} + +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum TransferType { + Teleport, + LocalReserve, + DestinationReserve, + RemoteReserve(MultiLocation), +} + +/// A trait for identifying asset transfer type based on `IsTeleporter` and `IsReserve` +/// configurations. +pub trait AssetTransferSupport { /// Combinations of (Asset, Location) pairs which we trust as reserves. Meaning /// reserve-based-transfers are to be used for assets matching this filter. type IsReserve: ContainsPair; @@ -26,4 +51,34 @@ pub trait AssetTransferFilter { /// Combinations of (Asset, Location) pairs which we trust as teleporters. Meaning teleports are /// to be used for assets matching this filter. type IsTeleporter: ContainsPair; + + /// Determine transfer type to be used for transferring `asset` from local chain to `dest`. + fn determine_for(asset: &MultiAsset, dest: &MultiLocation) -> Result { + if Self::IsTeleporter::contains(asset, dest) { + // we trust destination for teleporting asset + return Ok(TransferType::Teleport) + } else if Self::IsReserve::contains(asset, dest) { + // we trust destination as asset reserve location + return Ok(TransferType::DestinationReserve) + } + + // try to determine reserve location based on asset id/location + let asset_location = match asset.id { + Concrete(location) => Ok(location.chain_location()), + _ => Err(Error::NotConcrete), + }?; + if asset_location == MultiLocation::here() || + Self::IsTeleporter::contains(asset, &asset_location) + { + // if local asset, or remote location that allows local teleports => local reserve + 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)) + } else { + // remote location that is not configured either as teleporter or reserve => cannot + // determine asset reserve + Err(Error::UnknownReserve) + } + } } diff --git a/polkadot/xcm/xcm-executor/src/traits/mod.rs b/polkadot/xcm/xcm-executor/src/traits/mod.rs index 201634c7bcbb..1723da0c3f40 100644 --- a/polkadot/xcm/xcm-executor/src/traits/mod.rs +++ b/polkadot/xcm/xcm-executor/src/traits/mod.rs @@ -25,7 +25,7 @@ pub use asset_exchange::AssetExchange; mod asset_lock; pub use asset_lock::{AssetLock, Enact, LockError}; mod asset_transfer; -pub use asset_transfer::AssetTransferFilter; +pub use asset_transfer::{AssetTransferSupport, Error as AssetTransferError, TransferType}; mod export; pub use export::{export_xcm, validate_export, ExportXcm}; mod fee_manager; From 09badd6b0a93a43dd248179c02b50a19e805a8b5 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 13 Oct 2023 14:09:54 +0300 Subject: [PATCH 33/98] allow transfer for non-fungible assets too --- polkadot/xcm/pallet-xcm/src/lib.rs | 19 +++++++++---------- polkadot/xcm/pallet-xcm/src/tests.rs | 12 ++++++------ .../xcm-executor/src/traits/asset_transfer.rs | 9 +++++++-- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index f25c3964cee1..75ec7b041fed 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1219,11 +1219,10 @@ impl Pallet { ) -> Result> { let mut reserve = None; for asset in assets.iter() { - // Ensure fungible asset. - ensure!( - matches!(asset.fun, Fungibility::Fungible(x) if !x.is_zero()), - Error::::InvalidAsset(AssetTransferError::NotFungible) - ); + if let Fungible(x) = asset.fun { + // If fungible asset, ensure non-zero amount. + ensure!(!x.is_zero(), Error::::Empty); + } let transfer_type = ::determine_for(&asset, dest) .map_err(Error::::InvalidAsset)?; @@ -1300,7 +1299,7 @@ impl Pallet { // and half at destination. if let TransferType::RemoteReserve(assets_reserve) = assets_transfer_type { // Halve amount of fees, each half will be sent to one chain. - Self::halve_fungible_asset(&mut fees)?; + Self::halve_fees(&mut fees)?; // Halve weight limit again to be used for the two fees transfers. let quarter_weight_limit = Self::halve_weight_limit(&weight_limit); // Send half the `fees` to `beneficiary` on assets-reserve chain. @@ -1874,14 +1873,14 @@ impl Pallet { } } - /// Halve `asset`s fungible amount. - pub(crate) fn halve_fungible_asset(asset: &mut MultiAsset) -> Result<(), Error> { - match &mut asset.fun { + /// Halve `fees` fungible amount. + pub(crate) fn halve_fees(fees: &mut MultiAsset) -> Result<(), Error> { + match &mut fees.fun { Fungible(amount) => { *amount = amount.saturating_div(2); Ok(()) }, - NonFungible(_) => Err(Error::::InvalidAsset(AssetTransferError::NotFungible)), + NonFungible(_) => Err(Error::::FeesNotMet), } } } diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index 3b343e6a3977..5c8a176c47ae 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -798,8 +798,8 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_works let mut expected_fee = fee_asset.reanchored(&dest, context).unwrap(); // fees are split between the asset-reserve chain and the destination chain - crate::Pallet::::halve_fungible_asset(&mut expected_fee_on_reserve).unwrap(); - crate::Pallet::::halve_fungible_asset(&mut expected_fee).unwrap(); + crate::Pallet::::halve_fees(&mut expected_fee_on_reserve).unwrap(); + crate::Pallet::::halve_fees(&mut expected_fee).unwrap(); // balances checks before assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_initial_amount); @@ -1172,8 +1172,8 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve let mut expected_fee = fee_asset.reanchored(&dest, context).unwrap(); // fees are split between the asset-reserve chain and the destination chain - crate::Pallet::::halve_fungible_asset(&mut expected_fee_on_reserve).unwrap(); - crate::Pallet::::halve_fungible_asset(&mut expected_fee).unwrap(); + crate::Pallet::::halve_fees(&mut expected_fee_on_reserve).unwrap(); + crate::Pallet::::halve_fees(&mut expected_fee).unwrap(); // balances checks before assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); @@ -1971,8 +1971,8 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_works() let mut expected_fee = fee_asset.reanchored(&dest, context).unwrap(); // fees are split between the asset-reserve chain and the destination chain - crate::Pallet::::halve_fungible_asset(&mut expected_fee_on_reserve).unwrap(); - crate::Pallet::::halve_fungible_asset(&mut expected_fee).unwrap(); + crate::Pallet::::halve_fees(&mut expected_fee_on_reserve).unwrap(); + crate::Pallet::::halve_fees(&mut expected_fee).unwrap(); // balances checks before assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); diff --git a/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs b/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs index c75c48ead6ef..7d6609a24226 100644 --- a/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs +++ b/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs @@ -19,12 +19,11 @@ use scale_info::TypeInfo; use sp_runtime::codec::{Decode, Encode}; use xcm::prelude::*; +/// Errors related to determining asset transfer support. #[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] pub enum Error { /// Invalid non-concrete asset. NotConcrete, - /// Invalid non-fungible asset. - NotFungible, /// Reserve chain could not be determined for assets. UnknownReserve, } @@ -33,11 +32,17 @@ impl PalletError for Error { const MAX_ENCODED_SIZE: usize = 1; } +/// Specify which type of asset transfer is required for a particular `(origin, asset, dest)` +/// combination. #[derive(Copy, Clone, PartialEq, Debug)] pub enum TransferType { + /// should teleport `asset` to `dest` Teleport, + /// should reserve-transfer `asset` to `dest`, using local chain as reserve LocalReserve, + /// should reserve-transfer `asset` to `dest`, using `dest` as reserve DestinationReserve, + /// should reserve-transfer `asset` to `dest`, using remote chain `MultiLocation` as reserve RemoteReserve(MultiLocation), } From f8e8b4abe3b516ba8beb80ed8f8b6304b51ac4e8 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 20 Oct 2023 12:10:28 +0300 Subject: [PATCH 34/98] fix merge damage --- .../src/tests/reserve_transfer.rs | 323 +++--------------- .../src/tests/reserve_transfer.rs | 216 +----------- .../assets/asset-hub-rococo/tests/tests.rs | 6 - .../assets/test-utils/src/test_cases.rs | 8 - 4 files changed, 68 insertions(+), 485 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index fb25607c635e..073c93ec254a 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -15,38 +15,6 @@ use crate::*; use asset_hub_rococo_runtime::xcm_config::XcmConfig as AssetHubRococoXcmConfig; -use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig; - -fn relay_origin_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - Rococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(630_092_000, 6_196))); - - assert_expected_events!( - Rococo, - vec![ - // Amount to reserve transfer is transferred to System Parachain's Sovereign account - RuntimeEvent::Balances(pallet_balances::Event::Transfer { from, to, amount }) => { - from: *from == t.sender.account_id, - to: *to == Rococo::sovereign_account_id_of( - t.args.dest - ), - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn system_para_dest_assertions_incomplete(_t: RelayToSystemParaTest) { - AssetHubRococo::assert_dmp_queue_incomplete( - Some(Weight::from_parts(1_000_000_000, 0)), - Some(Error::UntrustedReserveLocation), - ); -} - -fn system_para_to_relay_assertions(_t: SystemParaToRelayTest) { - AssetHubRococo::assert_xcm_pallet_attempted_error(Some(XcmError::Barrier)) -} fn system_para_to_para_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -99,48 +67,6 @@ fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { ); } -fn relay_limited_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::limited_reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -fn relay_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - -fn system_para_limited_reserve_transfer_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::limited_reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -fn system_para_reserve_transfer_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { ::PolkadotXcm::limited_reserve_transfer_assets( t.signed_origin, @@ -152,145 +78,74 @@ fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) ) } -fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { - ::PolkadotXcm::reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - /// Limited Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't /// work #[test] fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() { - // Init values for Relay Chain + let signed_origin = ::RuntimeOrigin::signed(RococoSender::get().into()); + let destination = Rococo::child_location_of(AssetHubRococo::para_id()); + let beneficiary: MultiLocation = + AccountId32Junction { network: None, id: AssetHubRococoReceiver::get().into() }.into(); let amount_to_send: Balance = ROCOCO_ED * 1000; - let test_args = TestContext { - sender: RococoSender::get(), - receiver: AssetHubRococoReceiver::get(), - args: relay_test_args(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::(system_para_dest_assertions_incomplete); - test.set_dispatchable::(relay_limited_reserve_transfer_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 assets: MultiAssets = (Here, amount_to_send).into(); + let fee_asset_item = 0; + + // this should fail + Rococo::execute_with(|| { + let result = ::XcmPallet::limited_reserve_transfer_assets( + signed_origin, + bx!(destination.into()), + bx!(beneficiary.into()), + bx!(assets.into()), + fee_asset_item, + WeightLimit::Unlimited, + ); + assert_err!( + result, + DispatchError::Module(sp_runtime::ModuleError { + index: 99, + error: [2, 0, 0, 0], + message: Some("Filtered") + }) + ); }); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - assert_eq!(receiver_balance_before, receiver_balance_after); } -/// Limited Reserve Transfers of native asset from System Parachain to Relay Chain shoudln't work +/// Limited Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work #[test] fn limited_reserve_transfer_native_asset_from_system_para_to_relay_fails() { // Init values for System Parachain + let signed_origin = + ::RuntimeOrigin::signed(AssetHubRococoSender::get().into()); let destination = AssetHubRococo::parent_location(); let beneficiary_id = RococoReceiver::get(); + let beneficiary: MultiLocation = + AccountId32Junction { network: None, id: beneficiary_id.into() }.into(); let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubRococoSender::get(), - receiver: RococoReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(system_para_to_relay_assertions); - test.set_dispatchable::(system_para_limited_reserve_transfer_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - assert_eq!(sender_balance_before, sender_balance_after); - assert_eq!(receiver_balance_before, receiver_balance_after); -} - -/// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work -#[test] -fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { - // Init values for Relay Chain - let amount_to_send: Balance = ROCOCO_ED * 1000; - let test_args = TestContext { - sender: RococoSender::get(), - receiver: AssetHubRococoReceiver::get(), - args: relay_test_args(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::(system_para_dest_assertions_incomplete); - test.set_dispatchable::(relay_reserve_transfer_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - 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 assets: MultiAssets = (Parent, amount_to_send).into(); + let fee_asset_item = 0; + + // this should fail + AssetHubRococo::execute_with(|| { + let result = + ::PolkadotXcm::limited_reserve_transfer_assets( + signed_origin, + bx!(destination.into()), + bx!(beneficiary.into()), + bx!(assets.into()), + fee_asset_item, + WeightLimit::Unlimited, + ); + assert_err!( + result, + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [2, 0, 0, 0], + message: Some("Filtered") + }) + ); }); - - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - assert_eq!(receiver_balance_before, receiver_balance_after); -} - -/// Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work -#[test] -fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { - // Init values for System Parachain - let destination = AssetHubRococo::parent_location(); - let beneficiary_id = RococoReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubRococoSender::get(), - receiver: RococoReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(system_para_to_relay_assertions); - test.set_dispatchable::(system_para_reserve_transfer_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - assert_eq!(sender_balance_before, sender_balance_after); - assert_eq!(receiver_balance_before, receiver_balance_after); } /// Limited Reserve Transfers of native asset from System Parachain to Parachain should work @@ -331,44 +186,6 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { // transfers } -/// Reserve Transfers of native asset from System Parachain to Parachain should work -#[test] -fn reserve_transfer_native_asset_from_system_para_to_para() { - // Init values for System Parachain - let destination = AssetHubRococo::sibling_location_of(PenpalRococoA::para_id()); - let beneficiary_id = PenpalRococoAReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubRococoSender::get(), - receiver: PenpalRococoAReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), - }; - - let mut test = SystemParaToParaTest::new(test_args); - - let sender_balance_before = test.sender.balance; - - test.set_assertion::(system_para_to_para_assertions); - // TODO: Add assertion for Penpal runtime. Right now message is failing with - // `UntrustedReserveLocation` - test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); - test.assert(); - - let sender_balance_after = test.sender.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) - }); - - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve - // transfers -} - /// Limited Reserve Transfers of a local asset from System Parachain to Parachain should work #[test] fn limited_reserve_transfer_asset_from_system_para_to_para() { @@ -404,39 +221,3 @@ fn limited_reserve_transfer_asset_from_system_para_to_para() { .set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); system_para_test.assert(); } - -/// Reserve Transfers of a local asset from System Parachain to Parachain should work -#[test] -fn reserve_transfer_asset_from_system_para_to_para() { - // Force create asset from Relay Chain and mint assets for System Parachain's sender account - AssetHubRococo::force_create_and_mint_asset( - ASSET_ID, - ASSET_MIN_BALANCE, - true, - AssetHubRococoSender::get(), - Some(Weight::from_parts(1_019_445_000, 200_000)), - ASSET_MIN_BALANCE * 1000000, - ); - - // Init values for System Parachain - let destination = AssetHubRococo::sibling_location_of(PenpalRococoA::para_id()); - let beneficiary_id = PenpalRococoAReceiver::get(); - let amount_to_send = ASSET_MIN_BALANCE * 1000; - let assets = - (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send) - .into(); - - let system_para_test_args = TestContext { - sender: AssetHubRococoSender::get(), - receiver: PenpalRococoAReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), - }; - - let mut system_para_test = SystemParaToParaTest::new(system_para_test_args); - - system_para_test.set_assertion::(system_para_to_para_assets_assertions); - // TODO: Add assertions when Penpal is able to manage assets - system_para_test - .set_dispatchable::(system_para_to_para_reserve_transfer_assets); - system_para_test.assert(); -} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs index 701106fcb72c..c7a25dde78d3 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -15,7 +15,6 @@ use crate::*; use asset_hub_westend_runtime::xcm_config::XcmConfig; -use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig; fn system_para_to_para_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -79,17 +78,10 @@ fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) ) } -fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { - ::PolkadotXcm::reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - -fn do_reserve_transfer_native_asset_from_relay_to_system_para_fails(limited: bool) { +/// Limited Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't +/// work +#[test] +fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() { let signed_origin = ::RuntimeOrigin::signed(WestendSender::get().into()); let destination = Westend::child_location_of(AssetHubWestend::para_id()); let beneficiary: MultiLocation = @@ -100,24 +92,14 @@ fn do_reserve_transfer_native_asset_from_relay_to_system_para_fails(limited: boo // this should fail Westend::execute_with(|| { - let result = if limited { - ::XcmPallet::reserve_transfer_assets( - signed_origin, - bx!(destination.into()), - bx!(beneficiary.into()), - bx!(assets.into()), - fee_asset_item, - ) - } else { - ::XcmPallet::limited_reserve_transfer_assets( - signed_origin, - bx!(destination.into()), - bx!(beneficiary.into()), - bx!(assets.into()), - fee_asset_item, - WeightLimit::Unlimited, - ) - }; + let result = ::XcmPallet::limited_reserve_transfer_assets( + signed_origin, + bx!(destination.into()), + bx!(beneficiary.into()), + bx!(assets.into()), + fee_asset_item, + WeightLimit::Unlimited, + ); assert_err!( result, DispatchError::Module(sp_runtime::ModuleError { @@ -129,48 +111,9 @@ fn do_reserve_transfer_native_asset_from_relay_to_system_para_fails(limited: boo }); } -/// Limited Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't -/// work -#[test] -fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() { - // Init values for Relay Chain - let amount_to_send: Balance = WESTEND_ED * 1000; - let test_args = TestContext { - sender: WestendSender::get(), - receiver: AssetHubWestendReceiver::get(), - args: relay_test_args(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::(system_para_dest_assertions); - test.set_dispatchable::(relay_limited_reserve_transfer_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; - - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - assert_eq!(receiver_balance_before, receiver_balance_after); -} - -/// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work +/// Limited Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work #[test] -fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { - do_reserve_transfer_native_asset_from_relay_to_system_para_fails(false); -} - -fn do_reserve_transfer_native_asset_from_system_para_to_relay_fails(limited: bool) { +fn limited_reserve_transfer_native_asset_from_system_para_to_relay_fails() { // Init values for System Parachain let signed_origin = ::RuntimeOrigin::signed(AssetHubWestendSender::get().into()); @@ -184,15 +127,7 @@ fn do_reserve_transfer_native_asset_from_system_para_to_relay_fails(limited: boo // this should fail AssetHubWestend::execute_with(|| { - let result = if limited { - ::PolkadotXcm::reserve_transfer_assets( - signed_origin, - bx!(destination.into()), - bx!(beneficiary.into()), - bx!(assets.into()), - fee_asset_item, - ) - } else { + let result = ::PolkadotXcm::limited_reserve_transfer_assets( signed_origin, bx!(destination.into()), @@ -200,8 +135,7 @@ fn do_reserve_transfer_native_asset_from_system_para_to_relay_fails(limited: boo bx!(assets.into()), fee_asset_item, WeightLimit::Unlimited, - ) - }; + ); assert_err!( result, DispatchError::Module(sp_runtime::ModuleError { @@ -213,46 +147,6 @@ fn do_reserve_transfer_native_asset_from_system_para_to_relay_fails(limited: boo }); } -/// Limited Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work -#[test] -fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { - // Init values for Relay Chain - let amount_to_send: Balance = WESTEND_ED * 1000; - let test_args = TestContext { - sender: WestendSender::get(), - receiver: AssetHubWestendReceiver::get(), - args: relay_test_args(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::(system_para_dest_assertions); - test.set_dispatchable::(relay_reserve_transfer_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; - - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - assert_eq!(receiver_balance_before, receiver_balance_after); -} - -/// Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work -#[test] -fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { - do_reserve_transfer_native_asset_from_system_para_to_relay_fails(false); -} - /// Limited Reserve Transfers of native asset from System Parachain to Parachain should work #[test] fn limited_reserve_transfer_native_asset_from_system_para_to_para() { @@ -295,48 +189,6 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { // transfers } -/// Reserve Transfers of native asset from System Parachain to Parachain should work -#[test] -fn reserve_transfer_native_asset_from_system_para_to_para() { - // Init values for System Parachain - let destination = AssetHubWestend::sibling_location_of(PenpalWestendA::para_id()); - let beneficiary_id = PenpalWestendAReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubWestendSender::get(), - receiver: PenpalWestendAReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), - }; - - let mut test = SystemParaToParaTest::new(test_args); - - let sender_balance_before = test.sender.balance; - - test.set_assertion::(system_para_to_para_assertions); - // TODO: Add assertion for Penpal runtime. Right now message is failing with - // `UntrustedReserveLocation` - test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); - test.assert(); - - let sender_balance_after = test.sender.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, - ) - }); - - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve - // transfers -} - /// Limited Reserve Transfers of a local asset from System Parachain to Parachain should work #[test] fn limited_reserve_transfer_asset_from_system_para_to_para() { @@ -372,39 +224,3 @@ fn limited_reserve_transfer_asset_from_system_para_to_para() { .set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); system_para_test.assert(); } - -/// Reserve Transfers of a local asset from System Parachain to Parachain should work -#[test] -fn reserve_transfer_asset_from_system_para_to_para() { - // Force create asset from Relay Chain and mint assets for System Parachain's sender account - AssetHubWestend::force_create_and_mint_asset( - ASSET_ID, - ASSET_MIN_BALANCE, - true, - AssetHubWestendSender::get(), - Some(Weight::from_parts(1_019_445_000, 200_000)), - ASSET_MIN_BALANCE * 1000000, - ); - - // Init values for System Parachain - let destination = AssetHubWestend::sibling_location_of(PenpalWestendA::para_id()); - let beneficiary_id = PenpalWestendAReceiver::get(); - let amount_to_send = ASSET_MIN_BALANCE * 1000; - let assets = - (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send) - .into(); - - let system_para_test_args = TestContext { - sender: AssetHubWestendSender::get(), - receiver: PenpalWestendAReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), - }; - - let mut system_para_test = SystemParaToParaTest::new(system_para_test_args); - - system_para_test.set_assertion::(system_para_to_para_assets_assertions); - // TODO: Add assertions when Penpal is able to manage assets - system_para_test - .set_dispatchable::(system_para_to_para_reserve_transfer_assets); - system_para_test.assert(); -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs index 7f48d5762883..19087387c092 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -527,12 +527,6 @@ asset_test_utils::include_teleports_for_native_asset_works!( _ => None, } }), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), - _ => None, - } - }), 1000 ); 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 12228d8fe5c3..79c8abceeb04 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -261,14 +261,6 @@ pub fn teleports_for_native_asset_works< },),) ); - let delivery_fees = - xcm_helpers::transfer_assets_delivery_fees::( - (native_asset_id, native_asset_to_teleport_away.into()).into(), - 0, - Unlimited, - dest_beneficiary, - dest, - ); // check balances assert_eq!( From 71bd4b305ebb648fc44b0c2c52ce70e2eb0bfea2 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 23 Oct 2023 12:22:48 +0300 Subject: [PATCH 35/98] fmt --- cumulus/pallets/xcmp-queue/src/bridging.rs | 4 +++- cumulus/pallets/xcmp-queue/src/tests.rs | 22 ++++++++++++------- .../assets/test-utils/src/test_cases.rs | 1 - .../procedural/src/pallet/expand/warnings.rs | 8 ++----- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/cumulus/pallets/xcmp-queue/src/bridging.rs b/cumulus/pallets/xcmp-queue/src/bridging.rs index 0fc3f1f39ea3..53238fe2bf7a 100644 --- a/cumulus/pallets/xcmp-queue/src/bridging.rs +++ b/cumulus/pallets/xcmp-queue/src/bridging.rs @@ -55,7 +55,9 @@ impl, Runtime: crate::Config> let sibling_bridge_hub_id: ParaId = SiblingBridgeHubParaId::get(); // let's find the channel's state with the sibling parachain, - let Some((outbound_state, queued_pages)) = pallet::Pallet::::outbound_channel_state(sibling_bridge_hub_id) else { + let Some((outbound_state, queued_pages)) = + pallet::Pallet::::outbound_channel_state(sibling_bridge_hub_id) + else { return false }; // suspended channel => it is congested diff --git a/cumulus/pallets/xcmp-queue/src/tests.rs b/cumulus/pallets/xcmp-queue/src/tests.rs index cf6d947609d2..bab7e92ca2de 100644 --- a/cumulus/pallets/xcmp-queue/src/tests.rs +++ b/cumulus/pallets/xcmp-queue/src/tests.rs @@ -410,9 +410,11 @@ fn verify_fee_factor_increase_and_decrease() { assert_eq!(DeliveryFeeFactor::::get(sibling_para_id), initial); // Sending the message right now is cheap - let (_, delivery_fees) = validate_send::(destination, xcm.clone()) - .expect("message can be sent; qed"); - let Fungible(delivery_fee_amount) = delivery_fees.inner()[0].fun else { unreachable!("asset is fungible; qed"); }; + let (_, delivery_fees) = + validate_send::(destination, xcm.clone()).expect("message can be sent; qed"); + let Fungible(delivery_fee_amount) = delivery_fees.inner()[0].fun else { + unreachable!("asset is fungible; qed"); + }; assert_eq!(delivery_fee_amount, 402_000_000); let smaller_xcm = Xcm(vec![ClearOrigin; 30]); @@ -422,19 +424,23 @@ fn verify_fee_factor_increase_and_decrease() { assert_ok!(send_xcm::(destination, xcm.clone())); // Size 520 assert_eq!(DeliveryFeeFactor::::get(sibling_para_id), FixedU128::from_float(1.05)); - for _ in 0..12 { // We finish at size 929 + for _ in 0..12 { + // We finish at size 929 assert_ok!(send_xcm::(destination, smaller_xcm.clone())); } assert!(DeliveryFeeFactor::::get(sibling_para_id) > FixedU128::from_float(1.88)); // Sending the message right now is expensive - let (_, delivery_fees) = validate_send::(destination, xcm.clone()) - .expect("message can be sent; qed"); - let Fungible(delivery_fee_amount) = delivery_fees.inner()[0].fun else { unreachable!("asset is fungible; qed"); }; + let (_, delivery_fees) = + validate_send::(destination, xcm.clone()).expect("message can be sent; qed"); + let Fungible(delivery_fee_amount) = delivery_fees.inner()[0].fun else { + unreachable!("asset is fungible; qed"); + }; assert_eq!(delivery_fee_amount, 758_030_955); // Fee factor only decreases in `take_outbound_messages` - for _ in 0..5 { // We take 5 100 byte pages + for _ in 0..5 { + // We take 5 100 byte pages XcmpQueue::take_outbound_messages(1); } assert!(DeliveryFeeFactor::::get(sibling_para_id) < FixedU128::from_float(1.72)); 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 79c8abceeb04..af9fc4475cf9 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -261,7 +261,6 @@ pub fn teleports_for_native_asset_works< },),) ); - // check balances assert_eq!( >::free_balance(&target_account), diff --git a/substrate/frame/support/procedural/src/pallet/expand/warnings.rs b/substrate/frame/support/procedural/src/pallet/expand/warnings.rs index 6ce2097c2684..030e3ddaf323 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/warnings.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/warnings.rs @@ -33,9 +33,7 @@ pub(crate) fn weight_witness_warning( if dev_mode { return } - let CallWeightDef::Immediate(w) = &method.weight else { - return - }; + let CallWeightDef::Immediate(w) = &method.weight else { return }; let partial_warning = Warning::new_deprecated("UncheckedWeightWitness") .old("not check weight witness data") @@ -66,9 +64,7 @@ pub(crate) fn weight_constant_warning( if dev_mode { return } - let syn::Expr::Lit(lit) = weight else { - return - }; + let syn::Expr::Lit(lit) = weight else { return }; let warning = Warning::new_deprecated("ConstantWeight") .index(warnings.len()) From 4ab90f7ffc993aeb21eb5a749bb81547703cd901 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 23 Oct 2023 12:43:50 +0300 Subject: [PATCH 36/98] pallet-xcm: split asset transfer tests to own file --- .../{tests.rs => tests/assets_transfer.rs} | 941 +---------------- polkadot/xcm/pallet-xcm/src/tests/mod.rs | 951 ++++++++++++++++++ 2 files changed, 962 insertions(+), 930 deletions(-) rename polkadot/xcm/pallet-xcm/src/{tests.rs => tests/assets_transfer.rs} (72%) create mode 100644 polkadot/xcm/pallet-xcm/src/tests/mod.rs diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs similarity index 72% rename from polkadot/xcm/pallet-xcm/src/tests.rs rename to polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index 3fb4922635f6..586fa1671b95 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -14,341 +14,21 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +#![cfg(test)] + use crate::{ - mock::*, AssetTraps, CurrentMigration, Error, LatestVersionedMultiLocation, Queries, - QueryStatus, VersionDiscoveryQueue, VersionMigrationStage, VersionNotifiers, - VersionNotifyTargets, + mock::*, + tests::{ALICE, BOB, FEE_AMOUNT, INITIAL_BALANCE, SEND_AMOUNT}, }; use frame_support::{ - assert_noop, assert_ok, - traits::{tokens::fungibles::Inspect, Currency, Hooks}, + assert_ok, + traits::{tokens::fungibles::Inspect, Currency}, weights::Weight, }; use polkadot_parachain_primitives::primitives::Id as ParaId; -use sp_runtime::{ - traits::{AccountIdConversion, BlakeTwo256, Hash}, - DispatchError, ModuleError, -}; -use xcm::{latest::QueryResponseInfo, prelude::*}; -use xcm_builder::AllowKnownQueryResponses; -use xcm_executor::{ - traits::{ConvertLocation, Properties, QueryHandler, QueryResponseStatus, ShouldExecute}, - XcmExecutor, -}; - -const ALICE: AccountId = AccountId::new([0u8; 32]); -const BOB: AccountId = AccountId::new([1u8; 32]); -const INITIAL_BALANCE: u128 = 100; -const SEND_AMOUNT: u128 = 10; -const FEE_AMOUNT: u128 = 2; - -#[test] -fn report_outcome_notify_works() { - let balances = vec![ - (ALICE, INITIAL_BALANCE), - (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), - ]; - let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); - let mut message = - Xcm(vec![TransferAsset { assets: (Here, SEND_AMOUNT).into(), beneficiary: sender }]); - let call = pallet_test_notifier::Call::notification_received { - query_id: 0, - response: Default::default(), - }; - let notify = RuntimeCall::TestNotifier(call); - new_test_ext_with_balances(balances).execute_with(|| { - XcmPallet::report_outcome_notify( - &mut message, - Parachain(OTHER_PARA_ID).into_location(), - notify, - 100, - ) - .unwrap(); - assert_eq!( - message, - Xcm(vec![ - SetAppendix(Xcm(vec![ReportError(QueryResponseInfo { - destination: Parent.into(), - query_id: 0, - max_weight: Weight::from_parts(1_000_000, 1_000_000), - })])), - TransferAsset { assets: (Here, SEND_AMOUNT).into(), beneficiary: sender }, - ]) - ); - let querier: MultiLocation = Here.into(); - let status = QueryStatus::Pending { - responder: MultiLocation::from(Parachain(OTHER_PARA_ID)).into(), - maybe_notify: Some((5, 2)), - timeout: 100, - maybe_match_querier: Some(querier.into()), - }; - assert_eq!(crate::Queries::::iter().collect::>(), vec![(0, status)]); - - let message = Xcm(vec![QueryResponse { - query_id: 0, - response: Response::ExecutionResult(None), - max_weight: Weight::from_parts(1_000_000, 1_000_000), - querier: Some(querier), - }]); - let hash = fake_message_hash(&message); - let r = XcmExecutor::::execute_xcm( - Parachain(OTHER_PARA_ID), - message, - hash, - Weight::from_parts(1_000_000_000, 1_000_000_000), - ); - assert_eq!(r, Outcome::Complete(Weight::from_parts(1_000, 1_000))); - assert_eq!( - last_events(2), - vec![ - RuntimeEvent::TestNotifier(pallet_test_notifier::Event::ResponseReceived( - Parachain(OTHER_PARA_ID).into(), - 0, - Response::ExecutionResult(None), - )), - RuntimeEvent::XcmPallet(crate::Event::Notified { - query_id: 0, - pallet_index: 5, - call_index: 2 - }), - ] - ); - assert_eq!(crate::Queries::::iter().collect::>(), vec![]); - }); -} - -#[test] -fn report_outcome_works() { - let balances = vec![ - (ALICE, INITIAL_BALANCE), - (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), - ]; - let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); - let mut message = - Xcm(vec![TransferAsset { assets: (Here, SEND_AMOUNT).into(), beneficiary: sender }]); - new_test_ext_with_balances(balances).execute_with(|| { - XcmPallet::report_outcome(&mut message, Parachain(OTHER_PARA_ID).into_location(), 100) - .unwrap(); - assert_eq!( - message, - Xcm(vec![ - SetAppendix(Xcm(vec![ReportError(QueryResponseInfo { - destination: Parent.into(), - query_id: 0, - max_weight: Weight::zero(), - })])), - TransferAsset { assets: (Here, SEND_AMOUNT).into(), beneficiary: sender }, - ]) - ); - let querier: MultiLocation = Here.into(); - let status = QueryStatus::Pending { - responder: MultiLocation::from(Parachain(OTHER_PARA_ID)).into(), - maybe_notify: None, - timeout: 100, - maybe_match_querier: Some(querier.into()), - }; - assert_eq!(crate::Queries::::iter().collect::>(), vec![(0, status)]); - - let message = Xcm(vec![QueryResponse { - query_id: 0, - response: Response::ExecutionResult(None), - max_weight: Weight::zero(), - querier: Some(querier), - }]); - let hash = fake_message_hash(&message); - let r = XcmExecutor::::execute_xcm( - Parachain(OTHER_PARA_ID), - message, - hash, - Weight::from_parts(1_000_000_000, 1_000_000_000), - ); - assert_eq!(r, Outcome::Complete(Weight::from_parts(1_000, 1_000))); - assert_eq!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::ResponseReady { - query_id: 0, - response: Response::ExecutionResult(None), - }) - ); - - let response = - QueryResponseStatus::Ready { response: Response::ExecutionResult(None), at: 1 }; - assert_eq!(XcmPallet::take_response(0), response); - }); -} - -#[test] -fn custom_querier_works() { - let balances = vec![ - (ALICE, INITIAL_BALANCE), - (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), - ]; - new_test_ext_with_balances(balances).execute_with(|| { - let querier: MultiLocation = - (Parent, AccountId32 { network: None, id: ALICE.into() }).into(); - - let r = TestNotifier::prepare_new_query(RuntimeOrigin::signed(ALICE), querier); - assert_eq!(r, Ok(())); - let status = QueryStatus::Pending { - responder: MultiLocation::from(AccountId32 { network: None, id: ALICE.into() }).into(), - maybe_notify: None, - timeout: 100, - maybe_match_querier: Some(querier.into()), - }; - assert_eq!(crate::Queries::::iter().collect::>(), vec![(0, status)]); - - // Supplying no querier when one is expected will fail - let message = Xcm(vec![QueryResponse { - query_id: 0, - response: Response::ExecutionResult(None), - max_weight: Weight::zero(), - querier: None, - }]); - let hash = fake_message_hash(&message); - let r = XcmExecutor::::execute_xcm_in_credit( - AccountId32 { network: None, id: ALICE.into() }, - message, - hash, - Weight::from_parts(1_000_000_000, 1_000_000_000), - Weight::from_parts(1_000, 1_000), - ); - assert_eq!(r, Outcome::Complete(Weight::from_parts(1_000, 1_000))); - assert_eq!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::InvalidQuerier { - origin: AccountId32 { network: None, id: ALICE.into() }.into(), - query_id: 0, - expected_querier: querier, - maybe_actual_querier: None, - }), - ); - - // Supplying the wrong querier will also fail - let message = Xcm(vec![QueryResponse { - query_id: 0, - response: Response::ExecutionResult(None), - max_weight: Weight::zero(), - querier: Some(MultiLocation::here()), - }]); - let hash = fake_message_hash(&message); - let r = XcmExecutor::::execute_xcm_in_credit( - AccountId32 { network: None, id: ALICE.into() }, - message, - hash, - Weight::from_parts(1_000_000_000, 1_000_000_000), - Weight::from_parts(1_000, 1_000), - ); - assert_eq!(r, Outcome::Complete(Weight::from_parts(1_000, 1_000))); - assert_eq!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::InvalidQuerier { - origin: AccountId32 { network: None, id: ALICE.into() }.into(), - query_id: 0, - expected_querier: querier, - maybe_actual_querier: Some(MultiLocation::here()), - }), - ); - - // Multiple failures should not have changed the query state - let message = Xcm(vec![QueryResponse { - query_id: 0, - response: Response::ExecutionResult(None), - max_weight: Weight::zero(), - querier: Some(querier), - }]); - let hash = fake_message_hash(&message); - let r = XcmExecutor::::execute_xcm( - AccountId32 { network: None, id: ALICE.into() }, - message, - hash, - Weight::from_parts(1_000_000_000, 1_000_000_000), - ); - assert_eq!(r, Outcome::Complete(Weight::from_parts(1_000, 1_000))); - assert_eq!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::ResponseReady { - query_id: 0, - response: Response::ExecutionResult(None), - }) - ); - - let response = - QueryResponseStatus::Ready { response: Response::ExecutionResult(None), at: 1 }; - assert_eq!(XcmPallet::take_response(0), response); - }); -} - -/// Test sending an `XCM` message (`XCM::ReserveAssetDeposit`) -/// -/// Asserts that the expected message is sent and the event is emitted -#[test] -fn send_works() { - let balances = vec![ - (ALICE, INITIAL_BALANCE), - (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), - ]; - new_test_ext_with_balances(balances).execute_with(|| { - let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); - let message = Xcm(vec![ - ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), - ClearOrigin, - buy_execution((Parent, SEND_AMOUNT)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: sender }, - ]); - - let versioned_dest = Box::new(RelayLocation::get().into()); - let versioned_message = Box::new(VersionedXcm::from(message.clone())); - assert_ok!(XcmPallet::send( - RuntimeOrigin::signed(ALICE), - versioned_dest, - versioned_message - )); - let sent_message = Xcm(Some(DescendOrigin(sender.try_into().unwrap())) - .into_iter() - .chain(message.0.clone().into_iter()) - .collect()); - let id = fake_message_hash(&sent_message); - assert_eq!(sent_xcm(), vec![(Here.into(), sent_message)]); - assert_eq!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Sent { - origin: sender, - destination: RelayLocation::get(), - message, - message_id: id, - }) - ); - }); -} - -/// Test that sending an `XCM` message fails when the `XcmRouter` blocks the -/// matching message format -/// -/// Asserts that `send` fails with `Error::SendFailure` -#[test] -fn send_fails_when_xcm_router_blocks() { - let balances = vec![ - (ALICE, INITIAL_BALANCE), - (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), - ]; - new_test_ext_with_balances(balances).execute_with(|| { - let sender: MultiLocation = - Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - let message = Xcm(vec![ - ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), - buy_execution((Parent, SEND_AMOUNT)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: sender }, - ]); - assert_noop!( - XcmPallet::send( - RuntimeOrigin::signed(ALICE), - Box::new(MultiLocation::ancestor(8).into()), - Box::new(VersionedXcm::from(message.clone())), - ), - crate::Error::::SendFailure - ); - }); -} +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( @@ -517,10 +197,10 @@ fn reserve_transfer_assets_with_paid_router_works() { // - remote reserve // - teleported // -// Bringing unique scenarios total to 3*4 = 12. So, following reserve-transfer tests try to cover +// Bringing unique scenarios total to 3*4 = 12. So, following reserve-transfer testz try to cover // the happy-case for each of these 12 scenarios. // -// TODO: also add negative tests for testing various error conditions. +// TODO: also add negative testz for testing various error conditions. fn set_up_foreign_asset( reserve_para_id: u32, @@ -2194,602 +1874,3 @@ fn reserve_transfer_assets_with_teleportable_asset_fails() { assert_eq!(Assets::active_issuance(usdt_id_multilocation), usdt_initial_local_amount); }); } - -/// Test local execution of XCM -/// -/// Asserts that the sender's balance is decreased and the beneficiary's balance -/// is increased. Verifies the expected event is emitted. -#[test] -fn execute_withdraw_to_deposit_works() { - let balances = vec![ - (ALICE, INITIAL_BALANCE), - (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), - ]; - new_test_ext_with_balances(balances).execute_with(|| { - let weight = BaseXcmWeight::get() * 3; - let dest: MultiLocation = Junction::AccountId32 { network: None, id: BOB.into() }.into(); - assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); - assert_ok!(XcmPallet::execute( - RuntimeOrigin::signed(ALICE), - Box::new(VersionedXcm::from(Xcm(vec![ - WithdrawAsset((Here, SEND_AMOUNT).into()), - buy_execution((Here, SEND_AMOUNT)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, - ]))), - weight - )); - assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); - assert_eq!(Balances::total_balance(&BOB), SEND_AMOUNT); - assert_eq!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) - ); - }); -} - -/// Test drop/claim assets. -#[test] -fn trapped_assets_can_be_claimed() { - let balances = vec![(ALICE, INITIAL_BALANCE), (BOB, INITIAL_BALANCE)]; - new_test_ext_with_balances(balances).execute_with(|| { - let weight = BaseXcmWeight::get() * 6; - let dest: MultiLocation = Junction::AccountId32 { network: None, id: BOB.into() }.into(); - - assert_ok!(XcmPallet::execute( - RuntimeOrigin::signed(ALICE), - Box::new(VersionedXcm::from(Xcm(vec![ - WithdrawAsset((Here, SEND_AMOUNT).into()), - buy_execution((Here, SEND_AMOUNT)), - // Don't propagated the error into the result. - SetErrorHandler(Xcm(vec![ClearError])), - // This will make an error. - Trap(0), - // This would succeed, but we never get to it. - DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, - ]))), - weight - )); - let source: MultiLocation = - Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - let trapped = AssetTraps::::iter().collect::>(); - let vma = VersionedMultiAssets::from(MultiAssets::from((Here, SEND_AMOUNT))); - let hash = BlakeTwo256::hash_of(&(source, vma.clone())); - assert_eq!( - last_events(2), - vec![ - RuntimeEvent::XcmPallet(crate::Event::AssetsTrapped { - hash, - origin: source, - assets: vma - }), - RuntimeEvent::XcmPallet(crate::Event::Attempted { - outcome: Outcome::Complete(BaseXcmWeight::get() * 5) - }), - ] - ); - assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); - assert_eq!(Balances::total_balance(&BOB), INITIAL_BALANCE); - - let expected = vec![(hash, 1u32)]; - assert_eq!(trapped, expected); - - let weight = BaseXcmWeight::get() * 3; - assert_ok!(XcmPallet::execute( - RuntimeOrigin::signed(ALICE), - Box::new(VersionedXcm::from(Xcm(vec![ - ClaimAsset { assets: (Here, SEND_AMOUNT).into(), ticket: Here.into() }, - buy_execution((Here, SEND_AMOUNT)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, - ]))), - weight - )); - - assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); - assert_eq!(Balances::total_balance(&BOB), INITIAL_BALANCE + SEND_AMOUNT); - assert_eq!(AssetTraps::::iter().collect::>(), vec![]); - - let weight = BaseXcmWeight::get() * 3; - assert_ok!(XcmPallet::execute( - RuntimeOrigin::signed(ALICE), - Box::new(VersionedXcm::from(Xcm(vec![ - ClaimAsset { assets: (Here, SEND_AMOUNT).into(), ticket: Here.into() }, - buy_execution((Here, SEND_AMOUNT)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, - ]))), - weight - )); - let outcome = Outcome::Incomplete(BaseXcmWeight::get(), XcmError::UnknownClaim); - assert_eq!(last_event(), RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome })); - }); -} - -#[test] -fn fake_latest_versioned_multilocation_works() { - use codec::Encode; - let remote: MultiLocation = Parachain(1000).into(); - let versioned_remote = LatestVersionedMultiLocation(&remote); - assert_eq!(versioned_remote.encode(), remote.into_versioned().encode()); -} - -#[test] -fn basic_subscription_works() { - new_test_ext_with_balances(vec![]).execute_with(|| { - let remote: MultiLocation = Parachain(1000).into(); - assert_ok!(XcmPallet::force_subscribe_version_notify( - RuntimeOrigin::root(), - Box::new(remote.into()), - )); - - assert_eq!( - Queries::::iter().collect::>(), - vec![(0, QueryStatus::VersionNotifier { origin: remote.into(), is_active: false })] - ); - assert_eq!( - VersionNotifiers::::iter().collect::>(), - vec![(XCM_VERSION, remote.into(), 0)] - ); - - assert_eq!( - take_sent_xcm(), - vec![( - remote, - Xcm(vec![SubscribeVersion { query_id: 0, max_response_weight: Weight::zero() }]), - ),] - ); - - let weight = BaseXcmWeight::get(); - let mut message = Xcm::<()>(vec![ - // Remote supports XCM v2 - QueryResponse { - query_id: 0, - max_weight: Weight::zero(), - response: Response::Version(1), - querier: None, - }, - ]); - assert_ok!(AllowKnownQueryResponses::::should_execute( - &remote, - message.inner_mut(), - weight, - &mut Properties { weight_credit: Weight::zero(), message_id: None }, - )); - }); -} - -#[test] -fn subscriptions_increment_id() { - new_test_ext_with_balances(vec![]).execute_with(|| { - let remote: MultiLocation = Parachain(1000).into(); - assert_ok!(XcmPallet::force_subscribe_version_notify( - RuntimeOrigin::root(), - Box::new(remote.into()), - )); - - let remote2: MultiLocation = Parachain(1001).into(); - assert_ok!(XcmPallet::force_subscribe_version_notify( - RuntimeOrigin::root(), - Box::new(remote2.into()), - )); - - assert_eq!( - take_sent_xcm(), - vec![ - ( - remote, - Xcm(vec![SubscribeVersion { - query_id: 0, - max_response_weight: Weight::zero() - }]), - ), - ( - remote2, - Xcm(vec![SubscribeVersion { - query_id: 1, - max_response_weight: Weight::zero() - }]), - ), - ] - ); - }); -} - -#[test] -fn double_subscription_fails() { - new_test_ext_with_balances(vec![]).execute_with(|| { - let remote: MultiLocation = Parachain(1000).into(); - assert_ok!(XcmPallet::force_subscribe_version_notify( - RuntimeOrigin::root(), - Box::new(remote.into()), - )); - assert_noop!( - XcmPallet::force_subscribe_version_notify( - RuntimeOrigin::root(), - Box::new(remote.into()) - ), - Error::::AlreadySubscribed, - ); - }) -} - -#[test] -fn unsubscribe_works() { - new_test_ext_with_balances(vec![]).execute_with(|| { - let remote: MultiLocation = Parachain(1000).into(); - assert_ok!(XcmPallet::force_subscribe_version_notify( - RuntimeOrigin::root(), - Box::new(remote.into()), - )); - assert_ok!(XcmPallet::force_unsubscribe_version_notify( - RuntimeOrigin::root(), - Box::new(remote.into()) - )); - assert_noop!( - XcmPallet::force_unsubscribe_version_notify( - RuntimeOrigin::root(), - Box::new(remote.into()) - ), - Error::::NoSubscription, - ); - - assert_eq!( - take_sent_xcm(), - vec![ - ( - remote, - Xcm(vec![SubscribeVersion { - query_id: 0, - max_response_weight: Weight::zero() - }]), - ), - (remote, Xcm(vec![UnsubscribeVersion]),), - ] - ); - }); -} - -/// Parachain 1000 is asking us for a version subscription. -#[test] -fn subscription_side_works() { - new_test_ext_with_balances(vec![]).execute_with(|| { - AdvertisedXcmVersion::set(1); - - let remote: MultiLocation = Parachain(1000).into(); - let weight = BaseXcmWeight::get(); - let message = - Xcm(vec![SubscribeVersion { query_id: 0, max_response_weight: Weight::zero() }]); - let hash = fake_message_hash(&message); - let r = XcmExecutor::::execute_xcm(remote, message, hash, weight); - assert_eq!(r, Outcome::Complete(weight)); - - let instr = QueryResponse { - query_id: 0, - max_weight: Weight::zero(), - response: Response::Version(1), - querier: None, - }; - assert_eq!(take_sent_xcm(), vec![(remote, Xcm(vec![instr]))]); - - // A runtime upgrade which doesn't alter the version sends no notifications. - CurrentMigration::::put(VersionMigrationStage::default()); - XcmPallet::on_initialize(1); - assert_eq!(take_sent_xcm(), vec![]); - - // New version. - AdvertisedXcmVersion::set(2); - - // A runtime upgrade which alters the version does send notifications. - CurrentMigration::::put(VersionMigrationStage::default()); - XcmPallet::on_initialize(2); - let instr = QueryResponse { - query_id: 0, - max_weight: Weight::zero(), - response: Response::Version(2), - querier: None, - }; - assert_eq!(take_sent_xcm(), vec![(remote, Xcm(vec![instr]))]); - }); -} - -#[test] -fn subscription_side_upgrades_work_with_notify() { - new_test_ext_with_balances(vec![]).execute_with(|| { - AdvertisedXcmVersion::set(1); - - // An entry from a previous runtime with v2 XCM. - let v2_location = VersionedMultiLocation::V2(xcm::v2::Junction::Parachain(1001).into()); - VersionNotifyTargets::::insert(1, v2_location, (70, Weight::zero(), 2)); - let v3_location = Parachain(1003).into_versioned(); - VersionNotifyTargets::::insert(3, v3_location, (72, Weight::zero(), 2)); - - // New version. - AdvertisedXcmVersion::set(3); - - // A runtime upgrade which alters the version does send notifications. - CurrentMigration::::put(VersionMigrationStage::default()); - XcmPallet::on_initialize(1); - - let instr1 = QueryResponse { - query_id: 70, - max_weight: Weight::zero(), - response: Response::Version(3), - querier: None, - }; - let instr3 = QueryResponse { - query_id: 72, - max_weight: Weight::zero(), - response: Response::Version(3), - querier: None, - }; - let mut sent = take_sent_xcm(); - sent.sort_by_key(|k| match (k.1).0[0] { - QueryResponse { query_id: q, .. } => q, - _ => 0, - }); - assert_eq!( - sent, - vec![ - (Parachain(1001).into(), Xcm(vec![instr1])), - (Parachain(1003).into(), Xcm(vec![instr3])), - ] - ); - - let mut contents = VersionNotifyTargets::::iter().collect::>(); - contents.sort_by_key(|k| k.2 .0); - assert_eq!( - contents, - vec![ - (XCM_VERSION, Parachain(1001).into_versioned(), (70, Weight::zero(), 3)), - (XCM_VERSION, Parachain(1003).into_versioned(), (72, Weight::zero(), 3)), - ] - ); - }); -} - -#[test] -fn subscription_side_upgrades_work_without_notify() { - new_test_ext_with_balances(vec![]).execute_with(|| { - // An entry from a previous runtime with v2 XCM. - let v2_location = VersionedMultiLocation::V2(xcm::v2::Junction::Parachain(1001).into()); - VersionNotifyTargets::::insert(1, v2_location, (70, Weight::zero(), 2)); - let v3_location = Parachain(1003).into_versioned(); - VersionNotifyTargets::::insert(3, v3_location, (72, Weight::zero(), 2)); - - // A runtime upgrade which alters the version does send notifications. - CurrentMigration::::put(VersionMigrationStage::default()); - XcmPallet::on_initialize(1); - - let mut contents = VersionNotifyTargets::::iter().collect::>(); - contents.sort_by_key(|k| k.2 .0); - assert_eq!( - contents, - vec![ - (XCM_VERSION, Parachain(1001).into_versioned(), (70, Weight::zero(), 3)), - (XCM_VERSION, Parachain(1003).into_versioned(), (72, Weight::zero(), 3)), - ] - ); - }); -} - -#[test] -fn subscriber_side_subscription_works() { - new_test_ext_with_balances(vec![]).execute_with(|| { - let remote: MultiLocation = Parachain(1000).into(); - assert_ok!(XcmPallet::force_subscribe_version_notify( - RuntimeOrigin::root(), - Box::new(remote.into()), - )); - take_sent_xcm(); - - // Assume subscription target is working ok. - - let weight = BaseXcmWeight::get(); - let message = Xcm(vec![ - // Remote supports XCM v2 - QueryResponse { - query_id: 0, - max_weight: Weight::zero(), - response: Response::Version(1), - querier: None, - }, - ]); - let hash = fake_message_hash(&message); - let r = XcmExecutor::::execute_xcm(remote, message, hash, weight); - assert_eq!(r, Outcome::Complete(weight)); - assert_eq!(take_sent_xcm(), vec![]); - - // This message cannot be sent to a v2 remote. - let v2_msg = xcm::v2::Xcm::<()>(vec![xcm::v2::Instruction::Trap(0)]); - assert_eq!(XcmPallet::wrap_version(&remote, v2_msg.clone()), Err(())); - - let message = Xcm(vec![ - // Remote upgraded to XCM v2 - QueryResponse { - query_id: 0, - max_weight: Weight::zero(), - response: Response::Version(2), - querier: None, - }, - ]); - let hash = fake_message_hash(&message); - let r = XcmExecutor::::execute_xcm(remote, message, hash, weight); - assert_eq!(r, Outcome::Complete(weight)); - - // This message can now be sent to remote as it's v2. - assert_eq!( - XcmPallet::wrap_version(&remote, v2_msg.clone()), - Ok(VersionedXcm::from(v2_msg)) - ); - }); -} - -/// We should auto-subscribe when we don't know the remote's version. -#[test] -fn auto_subscription_works() { - new_test_ext_with_balances(vec![]).execute_with(|| { - let remote_v2: MultiLocation = Parachain(1000).into(); - let remote_v3: MultiLocation = Parachain(1001).into(); - - assert_ok!(XcmPallet::force_default_xcm_version(RuntimeOrigin::root(), Some(2))); - - // Wrapping a version for a destination we don't know elicits a subscription. - let msg_v2 = xcm::v2::Xcm::<()>(vec![xcm::v2::Instruction::Trap(0)]); - let msg_v3 = xcm::v3::Xcm::<()>(vec![xcm::v3::Instruction::ClearTopic]); - assert_eq!( - XcmPallet::wrap_version(&remote_v2, msg_v2.clone()), - Ok(VersionedXcm::from(msg_v2.clone())), - ); - assert_eq!(XcmPallet::wrap_version(&remote_v2, msg_v3.clone()), Err(())); - - let expected = vec![(remote_v2.into(), 2)]; - assert_eq!(VersionDiscoveryQueue::::get().into_inner(), expected); - - assert_eq!( - XcmPallet::wrap_version(&remote_v3, msg_v2.clone()), - Ok(VersionedXcm::from(msg_v2.clone())), - ); - assert_eq!(XcmPallet::wrap_version(&remote_v3, msg_v3.clone()), Err(())); - - let expected = vec![(remote_v2.into(), 2), (remote_v3.into(), 2)]; - assert_eq!(VersionDiscoveryQueue::::get().into_inner(), expected); - - XcmPallet::on_initialize(1); - assert_eq!( - take_sent_xcm(), - vec![( - remote_v3, - Xcm(vec![SubscribeVersion { query_id: 0, max_response_weight: Weight::zero() }]), - )] - ); - - // Assume remote_v3 is working ok and XCM version 3. - - let weight = BaseXcmWeight::get(); - let message = Xcm(vec![ - // Remote supports XCM v3 - QueryResponse { - query_id: 0, - max_weight: Weight::zero(), - response: Response::Version(3), - querier: None, - }, - ]); - let hash = fake_message_hash(&message); - let r = XcmExecutor::::execute_xcm(remote_v3, message, hash, weight); - assert_eq!(r, Outcome::Complete(weight)); - - // V2 messages can be sent to remote_v3 under XCM v3. - assert_eq!( - XcmPallet::wrap_version(&remote_v3, msg_v2.clone()), - Ok(VersionedXcm::from(msg_v2.clone()).into_version(3).unwrap()), - ); - // This message can now be sent to remote_v3 as it's v3. - assert_eq!( - XcmPallet::wrap_version(&remote_v3, msg_v3.clone()), - Ok(VersionedXcm::from(msg_v3.clone())) - ); - - XcmPallet::on_initialize(2); - assert_eq!( - take_sent_xcm(), - vec![( - remote_v2, - Xcm(vec![SubscribeVersion { query_id: 1, max_response_weight: Weight::zero() }]), - )] - ); - - // Assume remote_v2 is working ok and XCM version 2. - - let weight = BaseXcmWeight::get(); - let message = Xcm(vec![ - // Remote supports XCM v2 - QueryResponse { - query_id: 1, - max_weight: Weight::zero(), - response: Response::Version(2), - querier: None, - }, - ]); - let hash = fake_message_hash(&message); - let r = XcmExecutor::::execute_xcm(remote_v2, message, hash, weight); - assert_eq!(r, Outcome::Complete(weight)); - - // v3 messages cannot be sent to remote_v2... - assert_eq!( - XcmPallet::wrap_version(&remote_v2, msg_v2.clone()), - Ok(VersionedXcm::V2(msg_v2)) - ); - assert_eq!(XcmPallet::wrap_version(&remote_v2, msg_v3.clone()), Err(())); - }) -} - -#[test] -fn subscription_side_upgrades_work_with_multistage_notify() { - new_test_ext_with_balances(vec![]).execute_with(|| { - AdvertisedXcmVersion::set(1); - - // An entry from a previous runtime with v0 XCM. - let v2_location = VersionedMultiLocation::V2(xcm::v2::Junction::Parachain(1001).into()); - VersionNotifyTargets::::insert(1, v2_location, (70, Weight::zero(), 1)); - let v2_location = VersionedMultiLocation::V2(xcm::v2::Junction::Parachain(1002).into()); - VersionNotifyTargets::::insert(2, v2_location, (71, Weight::zero(), 1)); - let v3_location = Parachain(1003).into_versioned(); - VersionNotifyTargets::::insert(3, v3_location, (72, Weight::zero(), 1)); - - // New version. - AdvertisedXcmVersion::set(3); - - // A runtime upgrade which alters the version does send notifications. - CurrentMigration::::put(VersionMigrationStage::default()); - let mut maybe_migration = CurrentMigration::::take(); - let mut counter = 0; - while let Some(migration) = maybe_migration.take() { - counter += 1; - let (_, m) = XcmPallet::check_xcm_version_change(migration, Weight::zero()); - maybe_migration = m; - } - assert_eq!(counter, 4); - - let instr1 = QueryResponse { - query_id: 70, - max_weight: Weight::zero(), - response: Response::Version(3), - querier: None, - }; - let instr2 = QueryResponse { - query_id: 71, - max_weight: Weight::zero(), - response: Response::Version(3), - querier: None, - }; - let instr3 = QueryResponse { - query_id: 72, - max_weight: Weight::zero(), - response: Response::Version(3), - querier: None, - }; - let mut sent = take_sent_xcm(); - sent.sort_by_key(|k| match (k.1).0[0] { - QueryResponse { query_id: q, .. } => q, - _ => 0, - }); - assert_eq!( - sent, - vec![ - (Parachain(1001).into(), Xcm(vec![instr1])), - (Parachain(1002).into(), Xcm(vec![instr2])), - (Parachain(1003).into(), Xcm(vec![instr3])), - ] - ); - - let mut contents = VersionNotifyTargets::::iter().collect::>(); - contents.sort_by_key(|k| k.2 .0); - assert_eq!( - contents, - vec![ - (XCM_VERSION, Parachain(1001).into_versioned(), (70, Weight::zero(), 3)), - (XCM_VERSION, Parachain(1002).into_versioned(), (71, Weight::zero(), 3)), - (XCM_VERSION, Parachain(1003).into_versioned(), (72, Weight::zero(), 3)), - ] - ); - }); -} diff --git a/polkadot/xcm/pallet-xcm/src/tests/mod.rs b/polkadot/xcm/pallet-xcm/src/tests/mod.rs new file mode 100644 index 000000000000..72814e507f2a --- /dev/null +++ b/polkadot/xcm/pallet-xcm/src/tests/mod.rs @@ -0,0 +1,951 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +#![cfg(test)] + +mod assets_transfer; + +use crate::{ + mock::*, AssetTraps, CurrentMigration, Error, LatestVersionedMultiLocation, Queries, + QueryStatus, VersionDiscoveryQueue, VersionMigrationStage, VersionNotifiers, + VersionNotifyTargets, +}; +use frame_support::{ + assert_noop, assert_ok, + traits::{Currency, Hooks}, + weights::Weight, +}; +use polkadot_parachain_primitives::primitives::Id as ParaId; +use sp_runtime::traits::{AccountIdConversion, BlakeTwo256, Hash}; +use xcm::{latest::QueryResponseInfo, prelude::*}; +use xcm_builder::AllowKnownQueryResponses; +use xcm_executor::{ + traits::{Properties, QueryHandler, QueryResponseStatus, ShouldExecute}, + XcmExecutor, +}; + +const ALICE: AccountId = AccountId::new([0u8; 32]); +const BOB: AccountId = AccountId::new([1u8; 32]); +const INITIAL_BALANCE: u128 = 100; +const SEND_AMOUNT: u128 = 10; +const FEE_AMOUNT: u128 = 2; + +#[test] +fn report_outcome_notify_works() { + let balances = vec![ + (ALICE, INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), + ]; + let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); + let mut message = + Xcm(vec![TransferAsset { assets: (Here, SEND_AMOUNT).into(), beneficiary: sender }]); + let call = pallet_test_notifier::Call::notification_received { + query_id: 0, + response: Default::default(), + }; + let notify = RuntimeCall::TestNotifier(call); + new_test_ext_with_balances(balances).execute_with(|| { + XcmPallet::report_outcome_notify( + &mut message, + Parachain(OTHER_PARA_ID).into_location(), + notify, + 100, + ) + .unwrap(); + assert_eq!( + message, + Xcm(vec![ + SetAppendix(Xcm(vec![ReportError(QueryResponseInfo { + destination: Parent.into(), + query_id: 0, + max_weight: Weight::from_parts(1_000_000, 1_000_000), + })])), + TransferAsset { assets: (Here, SEND_AMOUNT).into(), beneficiary: sender }, + ]) + ); + let querier: MultiLocation = Here.into(); + let status = QueryStatus::Pending { + responder: MultiLocation::from(Parachain(OTHER_PARA_ID)).into(), + maybe_notify: Some((5, 2)), + timeout: 100, + maybe_match_querier: Some(querier.into()), + }; + assert_eq!(crate::Queries::::iter().collect::>(), vec![(0, status)]); + + let message = Xcm(vec![QueryResponse { + query_id: 0, + response: Response::ExecutionResult(None), + max_weight: Weight::from_parts(1_000_000, 1_000_000), + querier: Some(querier), + }]); + let hash = fake_message_hash(&message); + let r = XcmExecutor::::execute_xcm( + Parachain(OTHER_PARA_ID), + message, + hash, + Weight::from_parts(1_000_000_000, 1_000_000_000), + ); + assert_eq!(r, Outcome::Complete(Weight::from_parts(1_000, 1_000))); + assert_eq!( + last_events(2), + vec![ + RuntimeEvent::TestNotifier(pallet_test_notifier::Event::ResponseReceived( + Parachain(OTHER_PARA_ID).into(), + 0, + Response::ExecutionResult(None), + )), + RuntimeEvent::XcmPallet(crate::Event::Notified { + query_id: 0, + pallet_index: 5, + call_index: 2 + }), + ] + ); + assert_eq!(crate::Queries::::iter().collect::>(), vec![]); + }); +} + +#[test] +fn report_outcome_works() { + let balances = vec![ + (ALICE, INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), + ]; + let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); + let mut message = + Xcm(vec![TransferAsset { assets: (Here, SEND_AMOUNT).into(), beneficiary: sender }]); + new_test_ext_with_balances(balances).execute_with(|| { + XcmPallet::report_outcome(&mut message, Parachain(OTHER_PARA_ID).into_location(), 100) + .unwrap(); + assert_eq!( + message, + Xcm(vec![ + SetAppendix(Xcm(vec![ReportError(QueryResponseInfo { + destination: Parent.into(), + query_id: 0, + max_weight: Weight::zero(), + })])), + TransferAsset { assets: (Here, SEND_AMOUNT).into(), beneficiary: sender }, + ]) + ); + let querier: MultiLocation = Here.into(); + let status = QueryStatus::Pending { + responder: MultiLocation::from(Parachain(OTHER_PARA_ID)).into(), + maybe_notify: None, + timeout: 100, + maybe_match_querier: Some(querier.into()), + }; + assert_eq!(crate::Queries::::iter().collect::>(), vec![(0, status)]); + + let message = Xcm(vec![QueryResponse { + query_id: 0, + response: Response::ExecutionResult(None), + max_weight: Weight::zero(), + querier: Some(querier), + }]); + let hash = fake_message_hash(&message); + let r = XcmExecutor::::execute_xcm( + Parachain(OTHER_PARA_ID), + message, + hash, + Weight::from_parts(1_000_000_000, 1_000_000_000), + ); + assert_eq!(r, Outcome::Complete(Weight::from_parts(1_000, 1_000))); + assert_eq!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::ResponseReady { + query_id: 0, + response: Response::ExecutionResult(None), + }) + ); + + let response = + QueryResponseStatus::Ready { response: Response::ExecutionResult(None), at: 1 }; + assert_eq!(XcmPallet::take_response(0), response); + }); +} + +#[test] +fn custom_querier_works() { + let balances = vec![ + (ALICE, INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), + ]; + new_test_ext_with_balances(balances).execute_with(|| { + let querier: MultiLocation = + (Parent, AccountId32 { network: None, id: ALICE.into() }).into(); + + let r = TestNotifier::prepare_new_query(RuntimeOrigin::signed(ALICE), querier); + assert_eq!(r, Ok(())); + let status = QueryStatus::Pending { + responder: MultiLocation::from(AccountId32 { network: None, id: ALICE.into() }).into(), + maybe_notify: None, + timeout: 100, + maybe_match_querier: Some(querier.into()), + }; + assert_eq!(crate::Queries::::iter().collect::>(), vec![(0, status)]); + + // Supplying no querier when one is expected will fail + let message = Xcm(vec![QueryResponse { + query_id: 0, + response: Response::ExecutionResult(None), + max_weight: Weight::zero(), + querier: None, + }]); + let hash = fake_message_hash(&message); + let r = XcmExecutor::::execute_xcm_in_credit( + AccountId32 { network: None, id: ALICE.into() }, + message, + hash, + Weight::from_parts(1_000_000_000, 1_000_000_000), + Weight::from_parts(1_000, 1_000), + ); + assert_eq!(r, Outcome::Complete(Weight::from_parts(1_000, 1_000))); + assert_eq!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::InvalidQuerier { + origin: AccountId32 { network: None, id: ALICE.into() }.into(), + query_id: 0, + expected_querier: querier, + maybe_actual_querier: None, + }), + ); + + // Supplying the wrong querier will also fail + let message = Xcm(vec![QueryResponse { + query_id: 0, + response: Response::ExecutionResult(None), + max_weight: Weight::zero(), + querier: Some(MultiLocation::here()), + }]); + let hash = fake_message_hash(&message); + let r = XcmExecutor::::execute_xcm_in_credit( + AccountId32 { network: None, id: ALICE.into() }, + message, + hash, + Weight::from_parts(1_000_000_000, 1_000_000_000), + Weight::from_parts(1_000, 1_000), + ); + assert_eq!(r, Outcome::Complete(Weight::from_parts(1_000, 1_000))); + assert_eq!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::InvalidQuerier { + origin: AccountId32 { network: None, id: ALICE.into() }.into(), + query_id: 0, + expected_querier: querier, + maybe_actual_querier: Some(MultiLocation::here()), + }), + ); + + // Multiple failures should not have changed the query state + let message = Xcm(vec![QueryResponse { + query_id: 0, + response: Response::ExecutionResult(None), + max_weight: Weight::zero(), + querier: Some(querier), + }]); + let hash = fake_message_hash(&message); + let r = XcmExecutor::::execute_xcm( + AccountId32 { network: None, id: ALICE.into() }, + message, + hash, + Weight::from_parts(1_000_000_000, 1_000_000_000), + ); + assert_eq!(r, Outcome::Complete(Weight::from_parts(1_000, 1_000))); + assert_eq!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::ResponseReady { + query_id: 0, + response: Response::ExecutionResult(None), + }) + ); + + let response = + QueryResponseStatus::Ready { response: Response::ExecutionResult(None), at: 1 }; + assert_eq!(XcmPallet::take_response(0), response); + }); +} + +/// Test sending an `XCM` message (`XCM::ReserveAssetDeposit`) +/// +/// Asserts that the expected message is sent and the event is emitted +#[test] +fn send_works() { + let balances = vec![ + (ALICE, INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), + ]; + new_test_ext_with_balances(balances).execute_with(|| { + let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); + let message = Xcm(vec![ + ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), + ClearOrigin, + buy_execution((Parent, SEND_AMOUNT)), + DepositAsset { assets: AllCounted(1).into(), beneficiary: sender }, + ]); + + let versioned_dest = Box::new(RelayLocation::get().into()); + let versioned_message = Box::new(VersionedXcm::from(message.clone())); + assert_ok!(XcmPallet::send( + RuntimeOrigin::signed(ALICE), + versioned_dest, + versioned_message + )); + let sent_message = Xcm(Some(DescendOrigin(sender.try_into().unwrap())) + .into_iter() + .chain(message.0.clone().into_iter()) + .collect()); + let id = fake_message_hash(&sent_message); + assert_eq!(sent_xcm(), vec![(Here.into(), sent_message)]); + assert_eq!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::Sent { + origin: sender, + destination: RelayLocation::get(), + message, + message_id: id, + }) + ); + }); +} + +/// Test that sending an `XCM` message fails when the `XcmRouter` blocks the +/// matching message format +/// +/// Asserts that `send` fails with `Error::SendFailure` +#[test] +fn send_fails_when_xcm_router_blocks() { + let balances = vec![ + (ALICE, INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), + ]; + new_test_ext_with_balances(balances).execute_with(|| { + let sender: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let message = Xcm(vec![ + ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), + buy_execution((Parent, SEND_AMOUNT)), + DepositAsset { assets: AllCounted(1).into(), beneficiary: sender }, + ]); + assert_noop!( + XcmPallet::send( + RuntimeOrigin::signed(ALICE), + Box::new(MultiLocation::ancestor(8).into()), + Box::new(VersionedXcm::from(message.clone())), + ), + crate::Error::::SendFailure + ); + }); +} + +/// Test local execution of XCM +/// +/// Asserts that the sender's balance is decreased and the beneficiary's balance +/// is increased. Verifies the expected event is emitted. +#[test] +fn execute_withdraw_to_deposit_works() { + let balances = vec![ + (ALICE, INITIAL_BALANCE), + (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), + ]; + new_test_ext_with_balances(balances).execute_with(|| { + let weight = BaseXcmWeight::get() * 3; + let dest: MultiLocation = Junction::AccountId32 { network: None, id: BOB.into() }.into(); + assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); + assert_ok!(XcmPallet::execute( + RuntimeOrigin::signed(ALICE), + Box::new(VersionedXcm::from(Xcm(vec![ + WithdrawAsset((Here, SEND_AMOUNT).into()), + buy_execution((Here, SEND_AMOUNT)), + DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, + ]))), + weight + )); + assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); + assert_eq!(Balances::total_balance(&BOB), SEND_AMOUNT); + assert_eq!( + last_event(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) + ); + }); +} + +/// Test drop/claim assets. +#[test] +fn trapped_assets_can_be_claimed() { + let balances = vec![(ALICE, INITIAL_BALANCE), (BOB, INITIAL_BALANCE)]; + new_test_ext_with_balances(balances).execute_with(|| { + let weight = BaseXcmWeight::get() * 6; + let dest: MultiLocation = Junction::AccountId32 { network: None, id: BOB.into() }.into(); + + assert_ok!(XcmPallet::execute( + RuntimeOrigin::signed(ALICE), + Box::new(VersionedXcm::from(Xcm(vec![ + WithdrawAsset((Here, SEND_AMOUNT).into()), + buy_execution((Here, SEND_AMOUNT)), + // Don't propagated the error into the result. + SetErrorHandler(Xcm(vec![ClearError])), + // This will make an error. + Trap(0), + // This would succeed, but we never get to it. + DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, + ]))), + weight + )); + let source: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let trapped = AssetTraps::::iter().collect::>(); + let vma = VersionedMultiAssets::from(MultiAssets::from((Here, SEND_AMOUNT))); + let hash = BlakeTwo256::hash_of(&(source, vma.clone())); + assert_eq!( + last_events(2), + vec![ + RuntimeEvent::XcmPallet(crate::Event::AssetsTrapped { + hash, + origin: source, + assets: vma + }), + RuntimeEvent::XcmPallet(crate::Event::Attempted { + outcome: Outcome::Complete(BaseXcmWeight::get() * 5) + }), + ] + ); + assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); + assert_eq!(Balances::total_balance(&BOB), INITIAL_BALANCE); + + let expected = vec![(hash, 1u32)]; + assert_eq!(trapped, expected); + + let weight = BaseXcmWeight::get() * 3; + assert_ok!(XcmPallet::execute( + RuntimeOrigin::signed(ALICE), + Box::new(VersionedXcm::from(Xcm(vec![ + ClaimAsset { assets: (Here, SEND_AMOUNT).into(), ticket: Here.into() }, + buy_execution((Here, SEND_AMOUNT)), + DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, + ]))), + weight + )); + + assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); + assert_eq!(Balances::total_balance(&BOB), INITIAL_BALANCE + SEND_AMOUNT); + assert_eq!(AssetTraps::::iter().collect::>(), vec![]); + + let weight = BaseXcmWeight::get() * 3; + assert_ok!(XcmPallet::execute( + RuntimeOrigin::signed(ALICE), + Box::new(VersionedXcm::from(Xcm(vec![ + ClaimAsset { assets: (Here, SEND_AMOUNT).into(), ticket: Here.into() }, + buy_execution((Here, SEND_AMOUNT)), + DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, + ]))), + weight + )); + let outcome = Outcome::Incomplete(BaseXcmWeight::get(), XcmError::UnknownClaim); + assert_eq!(last_event(), RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome })); + }); +} + +#[test] +fn fake_latest_versioned_multilocation_works() { + use codec::Encode; + let remote: MultiLocation = Parachain(1000).into(); + let versioned_remote = LatestVersionedMultiLocation(&remote); + assert_eq!(versioned_remote.encode(), remote.into_versioned().encode()); +} + +#[test] +fn basic_subscription_works() { + new_test_ext_with_balances(vec![]).execute_with(|| { + let remote: MultiLocation = Parachain(1000).into(); + assert_ok!(XcmPallet::force_subscribe_version_notify( + RuntimeOrigin::root(), + Box::new(remote.into()), + )); + + assert_eq!( + Queries::::iter().collect::>(), + vec![(0, QueryStatus::VersionNotifier { origin: remote.into(), is_active: false })] + ); + assert_eq!( + VersionNotifiers::::iter().collect::>(), + vec![(XCM_VERSION, remote.into(), 0)] + ); + + assert_eq!( + take_sent_xcm(), + vec![( + remote, + Xcm(vec![SubscribeVersion { query_id: 0, max_response_weight: Weight::zero() }]), + ),] + ); + + let weight = BaseXcmWeight::get(); + let mut message = Xcm::<()>(vec![ + // Remote supports XCM v2 + QueryResponse { + query_id: 0, + max_weight: Weight::zero(), + response: Response::Version(1), + querier: None, + }, + ]); + assert_ok!(AllowKnownQueryResponses::::should_execute( + &remote, + message.inner_mut(), + weight, + &mut Properties { weight_credit: Weight::zero(), message_id: None }, + )); + }); +} + +#[test] +fn subscriptions_increment_id() { + new_test_ext_with_balances(vec![]).execute_with(|| { + let remote: MultiLocation = Parachain(1000).into(); + assert_ok!(XcmPallet::force_subscribe_version_notify( + RuntimeOrigin::root(), + Box::new(remote.into()), + )); + + let remote2: MultiLocation = Parachain(1001).into(); + assert_ok!(XcmPallet::force_subscribe_version_notify( + RuntimeOrigin::root(), + Box::new(remote2.into()), + )); + + assert_eq!( + take_sent_xcm(), + vec![ + ( + remote, + Xcm(vec![SubscribeVersion { + query_id: 0, + max_response_weight: Weight::zero() + }]), + ), + ( + remote2, + Xcm(vec![SubscribeVersion { + query_id: 1, + max_response_weight: Weight::zero() + }]), + ), + ] + ); + }); +} + +#[test] +fn double_subscription_fails() { + new_test_ext_with_balances(vec![]).execute_with(|| { + let remote: MultiLocation = Parachain(1000).into(); + assert_ok!(XcmPallet::force_subscribe_version_notify( + RuntimeOrigin::root(), + Box::new(remote.into()), + )); + assert_noop!( + XcmPallet::force_subscribe_version_notify( + RuntimeOrigin::root(), + Box::new(remote.into()) + ), + Error::::AlreadySubscribed, + ); + }) +} + +#[test] +fn unsubscribe_works() { + new_test_ext_with_balances(vec![]).execute_with(|| { + let remote: MultiLocation = Parachain(1000).into(); + assert_ok!(XcmPallet::force_subscribe_version_notify( + RuntimeOrigin::root(), + Box::new(remote.into()), + )); + assert_ok!(XcmPallet::force_unsubscribe_version_notify( + RuntimeOrigin::root(), + Box::new(remote.into()) + )); + assert_noop!( + XcmPallet::force_unsubscribe_version_notify( + RuntimeOrigin::root(), + Box::new(remote.into()) + ), + Error::::NoSubscription, + ); + + assert_eq!( + take_sent_xcm(), + vec![ + ( + remote, + Xcm(vec![SubscribeVersion { + query_id: 0, + max_response_weight: Weight::zero() + }]), + ), + (remote, Xcm(vec![UnsubscribeVersion]),), + ] + ); + }); +} + +/// Parachain 1000 is asking us for a version subscription. +#[test] +fn subscription_side_works() { + new_test_ext_with_balances(vec![]).execute_with(|| { + AdvertisedXcmVersion::set(1); + + let remote: MultiLocation = Parachain(1000).into(); + let weight = BaseXcmWeight::get(); + let message = + Xcm(vec![SubscribeVersion { query_id: 0, max_response_weight: Weight::zero() }]); + let hash = fake_message_hash(&message); + let r = XcmExecutor::::execute_xcm(remote, message, hash, weight); + assert_eq!(r, Outcome::Complete(weight)); + + let instr = QueryResponse { + query_id: 0, + max_weight: Weight::zero(), + response: Response::Version(1), + querier: None, + }; + assert_eq!(take_sent_xcm(), vec![(remote, Xcm(vec![instr]))]); + + // A runtime upgrade which doesn't alter the version sends no notifications. + CurrentMigration::::put(VersionMigrationStage::default()); + XcmPallet::on_initialize(1); + assert_eq!(take_sent_xcm(), vec![]); + + // New version. + AdvertisedXcmVersion::set(2); + + // A runtime upgrade which alters the version does send notifications. + CurrentMigration::::put(VersionMigrationStage::default()); + XcmPallet::on_initialize(2); + let instr = QueryResponse { + query_id: 0, + max_weight: Weight::zero(), + response: Response::Version(2), + querier: None, + }; + assert_eq!(take_sent_xcm(), vec![(remote, Xcm(vec![instr]))]); + }); +} + +#[test] +fn subscription_side_upgrades_work_with_notify() { + new_test_ext_with_balances(vec![]).execute_with(|| { + AdvertisedXcmVersion::set(1); + + // An entry from a previous runtime with v2 XCM. + let v2_location = VersionedMultiLocation::V2(xcm::v2::Junction::Parachain(1001).into()); + VersionNotifyTargets::::insert(1, v2_location, (70, Weight::zero(), 2)); + let v3_location = Parachain(1003).into_versioned(); + VersionNotifyTargets::::insert(3, v3_location, (72, Weight::zero(), 2)); + + // New version. + AdvertisedXcmVersion::set(3); + + // A runtime upgrade which alters the version does send notifications. + CurrentMigration::::put(VersionMigrationStage::default()); + XcmPallet::on_initialize(1); + + let instr1 = QueryResponse { + query_id: 70, + max_weight: Weight::zero(), + response: Response::Version(3), + querier: None, + }; + let instr3 = QueryResponse { + query_id: 72, + max_weight: Weight::zero(), + response: Response::Version(3), + querier: None, + }; + let mut sent = take_sent_xcm(); + sent.sort_by_key(|k| match (k.1).0[0] { + QueryResponse { query_id: q, .. } => q, + _ => 0, + }); + assert_eq!( + sent, + vec![ + (Parachain(1001).into(), Xcm(vec![instr1])), + (Parachain(1003).into(), Xcm(vec![instr3])), + ] + ); + + let mut contents = VersionNotifyTargets::::iter().collect::>(); + contents.sort_by_key(|k| k.2 .0); + assert_eq!( + contents, + vec![ + (XCM_VERSION, Parachain(1001).into_versioned(), (70, Weight::zero(), 3)), + (XCM_VERSION, Parachain(1003).into_versioned(), (72, Weight::zero(), 3)), + ] + ); + }); +} + +#[test] +fn subscription_side_upgrades_work_without_notify() { + new_test_ext_with_balances(vec![]).execute_with(|| { + // An entry from a previous runtime with v2 XCM. + let v2_location = VersionedMultiLocation::V2(xcm::v2::Junction::Parachain(1001).into()); + VersionNotifyTargets::::insert(1, v2_location, (70, Weight::zero(), 2)); + let v3_location = Parachain(1003).into_versioned(); + VersionNotifyTargets::::insert(3, v3_location, (72, Weight::zero(), 2)); + + // A runtime upgrade which alters the version does send notifications. + CurrentMigration::::put(VersionMigrationStage::default()); + XcmPallet::on_initialize(1); + + let mut contents = VersionNotifyTargets::::iter().collect::>(); + contents.sort_by_key(|k| k.2 .0); + assert_eq!( + contents, + vec![ + (XCM_VERSION, Parachain(1001).into_versioned(), (70, Weight::zero(), 3)), + (XCM_VERSION, Parachain(1003).into_versioned(), (72, Weight::zero(), 3)), + ] + ); + }); +} + +#[test] +fn subscriber_side_subscription_works() { + new_test_ext_with_balances(vec![]).execute_with(|| { + let remote: MultiLocation = Parachain(1000).into(); + assert_ok!(XcmPallet::force_subscribe_version_notify( + RuntimeOrigin::root(), + Box::new(remote.into()), + )); + take_sent_xcm(); + + // Assume subscription target is working ok. + + let weight = BaseXcmWeight::get(); + let message = Xcm(vec![ + // Remote supports XCM v2 + QueryResponse { + query_id: 0, + max_weight: Weight::zero(), + response: Response::Version(1), + querier: None, + }, + ]); + let hash = fake_message_hash(&message); + let r = XcmExecutor::::execute_xcm(remote, message, hash, weight); + assert_eq!(r, Outcome::Complete(weight)); + assert_eq!(take_sent_xcm(), vec![]); + + // This message cannot be sent to a v2 remote. + let v2_msg = xcm::v2::Xcm::<()>(vec![xcm::v2::Instruction::Trap(0)]); + assert_eq!(XcmPallet::wrap_version(&remote, v2_msg.clone()), Err(())); + + let message = Xcm(vec![ + // Remote upgraded to XCM v2 + QueryResponse { + query_id: 0, + max_weight: Weight::zero(), + response: Response::Version(2), + querier: None, + }, + ]); + let hash = fake_message_hash(&message); + let r = XcmExecutor::::execute_xcm(remote, message, hash, weight); + assert_eq!(r, Outcome::Complete(weight)); + + // This message can now be sent to remote as it's v2. + assert_eq!( + XcmPallet::wrap_version(&remote, v2_msg.clone()), + Ok(VersionedXcm::from(v2_msg)) + ); + }); +} + +/// We should auto-subscribe when we don't know the remote's version. +#[test] +fn auto_subscription_works() { + new_test_ext_with_balances(vec![]).execute_with(|| { + let remote_v2: MultiLocation = Parachain(1000).into(); + let remote_v3: MultiLocation = Parachain(1001).into(); + + assert_ok!(XcmPallet::force_default_xcm_version(RuntimeOrigin::root(), Some(2))); + + // Wrapping a version for a destination we don't know elicits a subscription. + let msg_v2 = xcm::v2::Xcm::<()>(vec![xcm::v2::Instruction::Trap(0)]); + let msg_v3 = xcm::v3::Xcm::<()>(vec![xcm::v3::Instruction::ClearTopic]); + assert_eq!( + XcmPallet::wrap_version(&remote_v2, msg_v2.clone()), + Ok(VersionedXcm::from(msg_v2.clone())), + ); + assert_eq!(XcmPallet::wrap_version(&remote_v2, msg_v3.clone()), Err(())); + + let expected = vec![(remote_v2.into(), 2)]; + assert_eq!(VersionDiscoveryQueue::::get().into_inner(), expected); + + assert_eq!( + XcmPallet::wrap_version(&remote_v3, msg_v2.clone()), + Ok(VersionedXcm::from(msg_v2.clone())), + ); + assert_eq!(XcmPallet::wrap_version(&remote_v3, msg_v3.clone()), Err(())); + + let expected = vec![(remote_v2.into(), 2), (remote_v3.into(), 2)]; + assert_eq!(VersionDiscoveryQueue::::get().into_inner(), expected); + + XcmPallet::on_initialize(1); + assert_eq!( + take_sent_xcm(), + vec![( + remote_v3, + Xcm(vec![SubscribeVersion { query_id: 0, max_response_weight: Weight::zero() }]), + )] + ); + + // Assume remote_v3 is working ok and XCM version 3. + + let weight = BaseXcmWeight::get(); + let message = Xcm(vec![ + // Remote supports XCM v3 + QueryResponse { + query_id: 0, + max_weight: Weight::zero(), + response: Response::Version(3), + querier: None, + }, + ]); + let hash = fake_message_hash(&message); + let r = XcmExecutor::::execute_xcm(remote_v3, message, hash, weight); + assert_eq!(r, Outcome::Complete(weight)); + + // V2 messages can be sent to remote_v3 under XCM v3. + assert_eq!( + XcmPallet::wrap_version(&remote_v3, msg_v2.clone()), + Ok(VersionedXcm::from(msg_v2.clone()).into_version(3).unwrap()), + ); + // This message can now be sent to remote_v3 as it's v3. + assert_eq!( + XcmPallet::wrap_version(&remote_v3, msg_v3.clone()), + Ok(VersionedXcm::from(msg_v3.clone())) + ); + + XcmPallet::on_initialize(2); + assert_eq!( + take_sent_xcm(), + vec![( + remote_v2, + Xcm(vec![SubscribeVersion { query_id: 1, max_response_weight: Weight::zero() }]), + )] + ); + + // Assume remote_v2 is working ok and XCM version 2. + + let weight = BaseXcmWeight::get(); + let message = Xcm(vec![ + // Remote supports XCM v2 + QueryResponse { + query_id: 1, + max_weight: Weight::zero(), + response: Response::Version(2), + querier: None, + }, + ]); + let hash = fake_message_hash(&message); + let r = XcmExecutor::::execute_xcm(remote_v2, message, hash, weight); + assert_eq!(r, Outcome::Complete(weight)); + + // v3 messages cannot be sent to remote_v2... + assert_eq!( + XcmPallet::wrap_version(&remote_v2, msg_v2.clone()), + Ok(VersionedXcm::V2(msg_v2)) + ); + assert_eq!(XcmPallet::wrap_version(&remote_v2, msg_v3.clone()), Err(())); + }) +} + +#[test] +fn subscription_side_upgrades_work_with_multistage_notify() { + new_test_ext_with_balances(vec![]).execute_with(|| { + AdvertisedXcmVersion::set(1); + + // An entry from a previous runtime with v0 XCM. + let v2_location = VersionedMultiLocation::V2(xcm::v2::Junction::Parachain(1001).into()); + VersionNotifyTargets::::insert(1, v2_location, (70, Weight::zero(), 1)); + let v2_location = VersionedMultiLocation::V2(xcm::v2::Junction::Parachain(1002).into()); + VersionNotifyTargets::::insert(2, v2_location, (71, Weight::zero(), 1)); + let v3_location = Parachain(1003).into_versioned(); + VersionNotifyTargets::::insert(3, v3_location, (72, Weight::zero(), 1)); + + // New version. + AdvertisedXcmVersion::set(3); + + // A runtime upgrade which alters the version does send notifications. + CurrentMigration::::put(VersionMigrationStage::default()); + let mut maybe_migration = CurrentMigration::::take(); + let mut counter = 0; + while let Some(migration) = maybe_migration.take() { + counter += 1; + let (_, m) = XcmPallet::check_xcm_version_change(migration, Weight::zero()); + maybe_migration = m; + } + assert_eq!(counter, 4); + + let instr1 = QueryResponse { + query_id: 70, + max_weight: Weight::zero(), + response: Response::Version(3), + querier: None, + }; + let instr2 = QueryResponse { + query_id: 71, + max_weight: Weight::zero(), + response: Response::Version(3), + querier: None, + }; + let instr3 = QueryResponse { + query_id: 72, + max_weight: Weight::zero(), + response: Response::Version(3), + querier: None, + }; + let mut sent = take_sent_xcm(); + sent.sort_by_key(|k| match (k.1).0[0] { + QueryResponse { query_id: q, .. } => q, + _ => 0, + }); + assert_eq!( + sent, + vec![ + (Parachain(1001).into(), Xcm(vec![instr1])), + (Parachain(1002).into(), Xcm(vec![instr2])), + (Parachain(1003).into(), Xcm(vec![instr3])), + ] + ); + + let mut contents = VersionNotifyTargets::::iter().collect::>(); + contents.sort_by_key(|k| k.2 .0); + assert_eq!( + contents, + vec![ + (XCM_VERSION, Parachain(1001).into_versioned(), (70, Weight::zero(), 3)), + (XCM_VERSION, Parachain(1002).into_versioned(), (71, Weight::zero(), 3)), + (XCM_VERSION, Parachain(1003).into_versioned(), (72, Weight::zero(), 3)), + ] + ); + }); +} From 30709948c6d28615a1ea90e599fbc1843dc5a049 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 23 Oct 2023 12:56:17 +0300 Subject: [PATCH 37/98] address review comments --- polkadot/xcm/pallet-xcm/src/lib.rs | 23 ++++++++++++++----- polkadot/xcm/pallet-xcm/src/mock.rs | 21 ++++++----------- .../pallet-xcm/src/tests/assets_transfer.rs | 10 ++++---- .../xcm-executor/src/traits/asset_transfer.rs | 9 ++------ 4 files changed, 31 insertions(+), 32 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 75ec7b041fed..bba33c0efca9 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -444,8 +444,10 @@ pub mod pallet { NoSubscription, /// The location is invalid since it already has a subscription from us. AlreadySubscribed, - /// Invalid asset for the operation. - InvalidAsset(AssetTransferError), + /// Invalid non-concrete asset. + InvalidAssetNotConcrete, + /// Invalid asset, reserve chain could not be determined for it. + InvalidAssetUnknownReserve, /// The owner does not own (all) of the asset that they wish to do the operation on. LowBalance, /// The asset owner has too many locks on the asset. @@ -472,6 +474,15 @@ pub mod pallet { } } + impl From for Error { + fn from(e: AssetTransferError) -> Self { + match e { + AssetTransferError::NotConcrete => Error::::InvalidAssetNotConcrete, + AssetTransferError::UnknownReserve => Error::::InvalidAssetUnknownReserve, + } + } + } + /// The status of a query. #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub enum QueryStatus { @@ -1225,7 +1236,7 @@ impl Pallet { } let transfer_type = ::determine_for(&asset, dest) - .map_err(Error::::InvalidAsset)?; + .map_err(Error::::from)?; // Ensure asset is not teleportable to `dest`. ensure!(transfer_type != TransferType::Teleport, Error::::Filtered); if let Some(reserve) = reserve.as_ref() { @@ -1265,7 +1276,7 @@ impl Pallet { let mut fees = assets.swap_remove(fee_asset_item as usize); let fees_transfer_type = ::determine_for(&fees, &dest) - .map_err(Error::::InvalidAsset)?; + .map_err(Error::::from)?; let assets_transfer_type = if assets.is_empty() { // Single asset to transfer (one used for fees where transfer type is determined above). ensure!(fees_transfer_type != TransferType::Teleport, Error::::Filtered); @@ -1309,7 +1320,7 @@ impl Pallet { beneficiary, vec![fees.clone()], ::determine_for(&fees, &assets_reserve) - .map_err(Error::::InvalidAsset)?, + .map_err(Error::::from)?, fees.clone(), quarter_weight_limit.clone(), )?; @@ -1372,7 +1383,7 @@ impl Pallet { for asset in assets.iter() { let transfer_type = ::determine_for(asset, &dest) - .map_err(Error::::InvalidAsset)?; + .map_err(Error::::from)?; ensure!(matches!(transfer_type, TransferType::Teleport), Error::::Filtered); } let fees = assets.get(fee_asset_item as usize).ok_or(Error::::Empty)?.clone(); diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index b678d33251ec..7b74322e44ca 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -18,7 +18,7 @@ use codec::Encode; use frame_support::{ construct_runtime, match_types, parameter_types, traits::{ - AsEnsureOriginWithArg, ConstU128, ConstU32, Contains, Everything, EverythingBut, Nothing, + AsEnsureOriginWithArg, ConstU128, ConstU32, Equals, Everything, EverythingBut, Nothing, }, weights::Weight, }; @@ -34,17 +34,17 @@ use xcm::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, Case, ChildParachainAsNative, ChildParachainConvertsVia, - ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible, - FixedWeightBounds, FungiblesAdapter, IsConcrete, MatchedConvertedConcreteId, NoChecking, - SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, XcmFeesToAccount, + ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, DescribeAllTerminal, + DescribeFamily, FixedRateOfFungible, FixedWeightBounds, FungiblesAdapter, HashedDescription, + IsConcrete, MatchedConvertedConcreteId, NoChecking, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, XcmFeesToAccount, }; use xcm_executor::{ traits::{Identity, JustTry}, XcmExecutor, }; -use crate::{self as pallet_xcm, Get, TestWeightInfo}; +use crate::{self as pallet_xcm, TestWeightInfo}; pub type AccountId = AccountId32; pub type Balance = u128; @@ -381,16 +381,9 @@ parameter_types! { pub type SovereignAccountOf = ( ChildParachainConvertsVia, AccountId32Aliases, - SiblingParachainConvertsVia, + HashedDescription>, ); -pub struct Equals(PhantomData); -impl> Contains for Equals { - fn contains(t: &MultiLocation) -> bool { - t == &Location::get() - } -} - pub type ForeignAssetsConvertedConcreteId = MatchedConvertedConcreteId< MultiLocation, Balance, diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index 586fa1671b95..bc04fcac837b 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -190,7 +190,7 @@ fn reserve_transfer_assets_with_paid_router_works() { // - local reserve // - destination reserve // - remote reserve -// - fee assests: +// - fee assets: // - reserve-transferred with reserve: // - local reserve // - destination reserve @@ -653,8 +653,8 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_works /// | /// | 1. execute `InitiateReserveWithdraw(fees)` /// | \--> sends `WithdrawAsset(fees), ClearOrigin, BuyExecution(fees), DepositAsset` -/// | 2. execute `TransferReserveAsset(assts)` -/// | \-> sends `ReserveAssetDeposited(assts), ClearOrigin, BuyExecution(fees), DepositAsset` +/// | 2. execute `TransferReserveAsset(assets)` +/// | \-> sends `ReserveAssetDeposited(assets), ClearOrigin, BuyExecution(fees), DepositAsset` /// \------------------------------------------> /// ``` #[test] @@ -1426,8 +1426,8 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work /// | /// | 1. execute `InitiateTeleport(fees)` /// | \--> sends `ReceiveTeleportedAsset(fees), .., DepositAsset(fees)` -/// | 2. execute `TransferReserveAsset(assts)` -/// | \-> sends `ReserveAssetDeposited(assts), ClearOrigin, BuyExecution(fees), DepositAsset` +/// | 2. execute `TransferReserveAsset(assets)` +/// | \-> sends `ReserveAssetDeposited(assets), ClearOrigin, BuyExecution(fees), DepositAsset` /// \------------------------------------------> /// ``` #[test] diff --git a/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs b/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs index 7d6609a24226..566b65739224 100644 --- a/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs +++ b/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use frame_support::traits::{ContainsPair, PalletError}; +use frame_support::traits::ContainsPair; use scale_info::TypeInfo; use sp_runtime::codec::{Decode, Encode}; use xcm::prelude::*; @@ -28,12 +28,7 @@ pub enum Error { UnknownReserve, } -impl PalletError for Error { - const MAX_ENCODED_SIZE: usize = 1; -} - -/// Specify which type of asset transfer is required for a particular `(origin, asset, dest)` -/// combination. +/// Specify which type of asset transfer is required for a particular `(asset, dest)` combination. #[derive(Copy, Clone, PartialEq, Debug)] pub enum TransferType { /// should teleport `asset` to `dest` From f045c737b3d8d3d34e9ebc5e0b5f41546134e951 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 23 Oct 2023 16:56:45 +0300 Subject: [PATCH 38/98] pallet-xcm: disallow combining remote reserves with other xfer types --- .../test-utils/src/test_cases_over_bridge.rs | 1 - polkadot/xcm/pallet-xcm/src/lib.rs | 130 ++-- .../pallet-xcm/src/tests/assets_transfer.rs | 673 +++--------------- 3 files changed, 169 insertions(+), 635 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs index 9852453d283b..a4f59b563485 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs @@ -183,7 +183,6 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< )); // check alice account decreased by balance_to_transfer - // TODO:check-parameter: change and assert in tests when (https://github.com/paritytech/polkadot-sdk/pull/1234) merged assert_eq!( >::free_balance(&alice_account), alice_account_init_balance - balance_to_transfer.into() diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index bba33c0efca9..257c46746ad2 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -448,6 +448,8 @@ pub mod pallet { InvalidAssetNotConcrete, /// Invalid asset, reserve chain could not be determined for it. InvalidAssetUnknownReserve, + /// Invalid asset, do not support remote asset reserves with different fees reserves. + InvalidAssetUnsupportedReserve, /// The owner does not own (all) of the asset that they wish to do the operation on. LowBalance, /// The asset owner has too many locks on the asset. @@ -1257,7 +1259,7 @@ impl Pallet { beneficiary: Box, assets: Box, fee_asset_item: u32, - mut weight_limit: WeightLimit, + weight_limit: WeightLimit, ) -> DispatchResult { let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; let dest = (*dest).try_into().map_err(|()| Error::::BadVersion)?; @@ -1273,7 +1275,7 @@ impl Pallet { if fee_asset_item as usize >= assets.len() { return Err(Error::::Empty.into()) } - let mut fees = assets.swap_remove(fee_asset_item as usize); + let fees = assets.swap_remove(fee_asset_item as usize); let fees_transfer_type = ::determine_for(&fees, &dest) .map_err(Error::::from)?; @@ -1286,68 +1288,43 @@ impl Pallet { Self::validate_assets_and_find_reserve(&assets, &dest)? }; - // Disallow (for now) different _remote_ reserves for assets and fees. - match (&fees_transfer_type, &assets_transfer_type) { - (TransferType::RemoteReserve(a), TransferType::RemoteReserve(b)) if a != b => - return Err(Error::::TooManyReserves.into()), - _ => (), - }; - + let jit_withdraw_fee_on_dest; if fees_transfer_type == assets_transfer_type { // Same reserve location (fees not teleportable), we can batch together fees and assets // in same reserve-based-transfer. assets.push(fees.clone()); + // no need to jit withdraw fee, fees batched with assets will be available in holding + jit_withdraw_fee_on_dest = false; } else { - // Different transfer types: we have to do separate transfers for fees and assets. - // This code block handles transferring the assets *used for fees*. - - // Use only half the weight limit for fees transfer, then other half for assets + // 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. - weight_limit = Self::halve_weight_limit(&weight_limit); - - // When assets reserve is remote chain, we need to "prefund" fees to be able to - // BuyExecution on both chains. Split fees, and deposit half at assets-reserve chain - // and half at destination. - if let TransferType::RemoteReserve(assets_reserve) = assets_transfer_type { - // Halve amount of fees, each half will be sent to one chain. - Self::halve_fees(&mut fees)?; - // Halve weight limit again to be used for the two fees transfers. - let quarter_weight_limit = Self::halve_weight_limit(&weight_limit); - // Send half the `fees` to `beneficiary` on assets-reserve chain. - Self::build_and_execute_xcm_transfer_type( - origin_location, - assets_reserve, - beneficiary, - vec![fees.clone()], - ::determine_for(&fees, &assets_reserve) - .map_err(Error::::from)?, - fees.clone(), - quarter_weight_limit.clone(), - )?; - // Send the other half of the `fees` to `beneficiary` on dest chain. - Self::build_and_execute_xcm_transfer_type( - origin_location, - dest, - beneficiary, - vec![fees.clone()], - fees_transfer_type, - fees.clone(), - quarter_weight_limit, - )?; - } else { - // execute fees transfer - have to do it separately than assets because of the - // different transfer type (different XCM program required) - Self::build_and_execute_xcm_transfer_type( - origin_location, - dest, - beneficiary, - vec![fees.clone()], - fees_transfer_type, - fees.clone(), - weight_limit.clone(), - )?; - } - } + if let TransferType::RemoteReserve(_) = assets_transfer_type {} + // Disallow (for now) different _remote_ reserves for assets and fees. + match (&fees_transfer_type, &assets_transfer_type) { + (TransferType::RemoteReserve(_), _) | (_, TransferType::RemoteReserve(_)) => + return Err(Error::::InvalidAssetUnsupportedReserve.into()), + _ => (), + }; + + // execute fees transfer - do it in a separate asset transfer call to keep code logic + // simple: first send over fees, then assets with `jit_withdraw=true` + Self::build_and_execute_xcm_transfer_type( + origin_location, + dest, + beneficiary, + vec![fees.clone()], + fees_transfer_type, + fees.clone(), + false, + weight_limit.clone(), + )?; + // fees are deposited to beneficiary in call above, when transferring rest of assets, + // jit withdraw fee on destination + jit_withdraw_fee_on_dest = true; + }; // Fees have been prefunded/transferred (or batched together with assets to be transferred // here), now do reserve-transfer assets. @@ -1358,6 +1335,7 @@ impl Pallet { assets, assets_transfer_type, fees, + jit_withdraw_fee_on_dest, weight_limit, ) } @@ -1395,6 +1373,7 @@ impl Pallet { assets, TransferType::Teleport, fees, + false, weight_limit, ) } @@ -1406,16 +1385,24 @@ impl Pallet { assets: Vec, transfer_type: TransferType, fees: MultiAsset, + jit_withdraw_fee_on_dest: bool, weight_limit: WeightLimit, ) -> DispatchResult { let mut message = match transfer_type { - TransferType::LocalReserve => - Self::local_reserve_transfer_message(dest, beneficiary, assets, fees, weight_limit), + TransferType::LocalReserve => Self::local_reserve_transfer_message( + dest, + beneficiary, + assets, + fees, + jit_withdraw_fee_on_dest, + weight_limit, + ), TransferType::DestinationReserve => Self::destination_reserve_transfer_message( dest, beneficiary, assets, fees, + jit_withdraw_fee_on_dest, weight_limit, ), TransferType::RemoteReserve(reserve) => Self::remote_reserve_transfer_message( @@ -1442,12 +1429,14 @@ impl Pallet { beneficiary: MultiLocation, assets: Vec, mut fees: MultiAsset, + jit_withdraw_fee_on_dest: bool, weight_limit: WeightLimit, ) -> Result::RuntimeCall>, Error> { let context = T::UniversalLocation::get(); fees.reanchor(&dest, context).map_err(|_| Error::::CannotReanchor)?; let max_assets = assets.len() as u32; let xcm_on_dest = Xcm(vec![ + SetFeesMode { jit_withdraw: jit_withdraw_fee_on_dest }, BuyExecution { fees, weight_limit }, DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, ]); @@ -1462,12 +1451,14 @@ impl Pallet { beneficiary: MultiLocation, assets: Vec, mut fees: MultiAsset, + jit_withdraw_fee_on_dest: bool, weight_limit: WeightLimit, ) -> Result::RuntimeCall>, Error> { let context = T::UniversalLocation::get(); fees.reanchor(&dest, context).map_err(|_| Error::::CannotReanchor)?; let max_assets = assets.len() as u32; let xcm_on_dest = Xcm(vec![ + SetFeesMode { jit_withdraw: jit_withdraw_fee_on_dest }, BuyExecution { fees, weight_limit }, DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, ]); @@ -1875,25 +1866,6 @@ impl Pallet { Self::deposit_event(Event::FeesPaid { paying: location, fees: assets }); Ok(()) } - - /// Return `WeightLimit` with half the given weight `limit`. - fn halve_weight_limit(limit: &WeightLimit) -> WeightLimit { - match limit { - Unlimited => Unlimited, - Limited(w) => Limited(w.saturating_div(2)), - } - } - - /// Halve `fees` fungible amount. - pub(crate) fn halve_fees(fees: &mut MultiAsset) -> Result<(), Error> { - match &mut fees.fun { - Fungible(amount) => { - *amount = amount.saturating_div(2); - Ok(()) - }, - NonFungible(_) => Err(Error::::FeesNotMet), - } - } } pub struct LockTicket { diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index bc04fcac837b..2e90b6efccbf 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -171,13 +171,12 @@ fn reserve_transfer_assets_with_paid_router_works() { Xcm(vec![ ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), ClearOrigin, + SetFeesMode { jit_withdraw: false }, buy_execution((Parent, SEND_AMOUNT)), DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, ]), )] ); - let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); - let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); assert_eq!( last_event(), RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) @@ -291,6 +290,7 @@ fn do_test_and_verify_reserve_transfer_assets_local_ar_local_fr( Xcm(vec![ ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), ClearOrigin, + SetFeesMode { jit_withdraw: false }, buy_limited_execution((Parent, SEND_AMOUNT), expected_weight_limit), DepositAsset { assets: AllCounted(1).into(), @@ -299,8 +299,6 @@ fn do_test_and_verify_reserve_transfer_assets_local_ar_local_fr( ]), )] ); - let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); - let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); assert_eq!( last_event(), RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) @@ -462,6 +460,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ Xcm(vec![ ReserveAssetDeposited((Parent, FEE_AMOUNT).into()), ClearOrigin, + SetFeesMode { jit_withdraw: false }, buy_limited_execution((Parent, FEE_AMOUNT), Unlimited), DepositAsset { assets: AllCounted(1).into(), beneficiary }, ]) @@ -474,171 +473,77 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ Xcm(vec![ WithdrawAsset(expected_asset.into()), ClearOrigin, + SetFeesMode { jit_withdraw: true }, buy_limited_execution(expected_fee, Unlimited), DepositAsset { assets: AllCounted(1).into(), beneficiary }, ]) ) ] ); - let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); - let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); }); } /// Test `reserve_transfer_assets` with remote asset reserve and local fee reserve. /// /// Transferring foreign asset (reserve on `FOREIGN_ASSET_RESERVE_PARA_ID`) to `OTHER_PARA_ID`. -/// Using native (local reserve) as fee. -/// -/// ```nocompile -/// | chain `A` | chain `C` | chain `B` -/// | Here (source) | FOREIGN_ASSET_RESERVE_PARA_ID | OTHER_PARA_ID (destination) -/// | `fees` reserve | `assets` reserve | no trust -/// | -/// | 1. `A` executes `TransferReserveAsset(fees)` dest `C` -/// | \----------> `C` executes `WithdrawAsset(fees), .., DepositAsset(fees)` -/// | -/// | 2. `A` executes `TransferReserveAsset(fees)` dest `B` -/// | \-------------------------------------------------> `B` executes: -/// | `WithdrawAsset(fees), .., DepositAsset(fees)` -/// | -/// | 3. `A` executes `InitiateReserveWithdraw(assets)` dest `C` -/// | -----------------> `C` executes `DepositReserveAsset(assets)` dest `B` -/// | --------------------------> `DepositAsset(assets)` -/// | all of which at step 3. being paid with fees prefunded in steps 1 & 2 -/// ``` +/// Using native (local reserve) as fee should be disallowed. #[test] -fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_works() { +fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_disallowed() { let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - let expected_beneficiary_on_reserve = beneficiary; new_test_ext_with_balances(balances).execute_with(|| { // create non-sufficient foreign asset BLA (0 total issuance) let foreign_initial_amount = 142; - let (reserve_location, reserve_sovereign_account, foreign_asset_id_multilocation) = - set_up_foreign_asset( - FOREIGN_ASSET_RESERVE_PARA_ID, - Some(FOREIGN_ASSET_INNER_JUNCTION), - foreign_initial_amount, - false, - ); + let (_, _, foreign_asset_id_multilocation) = set_up_foreign_asset( + FOREIGN_ASSET_RESERVE_PARA_ID, + Some(FOREIGN_ASSET_INNER_JUNCTION), + foreign_initial_amount, + false, + ); // transfer destination is OTHER_PARA_ID (foreign asset needs to go through its reserve // chain) let dest = RelayLocation::get().pushed_with_interior(Parachain(OTHER_PARA_ID)).unwrap(); - let dest_sovereign_account = SovereignAccountOf::convert_location(&dest).unwrap(); - let (assets, fee_index, fee_asset, xfer_asset) = into_multiassets_checked( + let (assets, fee_index, _, _) = into_multiassets_checked( // native asset for fee - local reserve (MultiLocation::here(), FEE_AMOUNT).into(), // foreign asset to transfer - remote reserve (foreign_asset_id_multilocation, SEND_AMOUNT).into(), ); - // reanchor according to test-case - let context = UniversalLocation::get(); - let expected_dest_on_reserve = dest.reanchored(&reserve_location, context).unwrap(); - let mut expected_fee_on_reserve = - fee_asset.clone().reanchored(&reserve_location, context).unwrap(); - let expected_asset_on_reserve = - xfer_asset.clone().reanchored(&reserve_location, context).unwrap(); - let mut expected_fee = fee_asset.reanchored(&dest, context).unwrap(); - - // fees are split between the asset-reserve chain and the destination chain - crate::Pallet::::halve_fees(&mut expected_fee_on_reserve).unwrap(); - crate::Pallet::::halve_fees(&mut expected_fee).unwrap(); - // balances checks before assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_initial_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); - // do the transfer - assert_ok!(XcmPallet::limited_reserve_transfer_assets( + // try the transfer + let result = XcmPallet::limited_reserve_transfer_assets( RuntimeOrigin::signed(ALICE), Box::new(dest.into()), Box::new(beneficiary.into()), Box::new(assets.into()), fee_index as u32, Unlimited, - )); - assert!(matches!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) - )); - - // Alice transferred BLA + ); assert_eq!( - Assets::balance(foreign_asset_id_multilocation, ALICE), - foreign_initial_amount - SEND_AMOUNT + result, + Err(DispatchError::Module(ModuleError { + index: 4, + error: [15, 0, 0, 0], + message: Some("InvalidAssetUnsupportedReserve") + })) ); + + // Alice transferred nothing + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_initial_amount); // Alice spent native asset for fees - assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - FEE_AMOUNT); - // Half the fee went to reserve chain - assert_eq!(Balances::free_balance(reserve_sovereign_account.clone()), FEE_AMOUNT / 2); - // Other half went to dest chain - assert_eq!(Balances::free_balance(dest_sovereign_account.clone()), FEE_AMOUNT / 2); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // Verify total and active issuance of foreign BLA asset have decreased (burned on // reserve-withdraw) - let expected_issuance = foreign_initial_amount - SEND_AMOUNT; + let expected_issuance = foreign_initial_amount; assert_eq!(Assets::total_issuance(foreign_asset_id_multilocation), expected_issuance); assert_eq!(Assets::active_issuance(foreign_asset_id_multilocation), expected_issuance); - - // Verify sent XCM program - assert_eq!( - sent_xcm(), - vec![ - ( - // first message is to prefund fees on `reserve` - reserve_location, - // fees are being sent through local-reserve transfer because fee reserve is - // local chain - Xcm(vec![ - ReserveAssetDeposited(expected_fee_on_reserve.clone().into()), - ClearOrigin, - buy_limited_execution(expected_fee_on_reserve.clone(), Unlimited), - DepositAsset { - assets: AllCounted(1).into(), - beneficiary: expected_beneficiary_on_reserve - }, - ]) - ), - ( - // second message is to prefund fees on `dest` - dest, - // fees are being sent through local-reserve transfer because fee reserve - // is local chain - Xcm(vec![ - ReserveAssetDeposited(expected_fee.clone().into()), - ClearOrigin, - buy_limited_execution(expected_fee.clone(), Unlimited), - DepositAsset { assets: AllCounted(1).into(), beneficiary }, - ]) - ), - ( - // third message is to transfer/deposit foreign assets on `dest` by going - // through `reserve` while paying using prefunded (teleported above) fees - reserve_location, - Xcm(vec![ - WithdrawAsset(expected_asset_on_reserve.into()), - ClearOrigin, - buy_limited_execution(expected_fee_on_reserve, Unlimited), - DepositReserveAsset { - assets: Wild(AllCounted(1)), - // final destination is `dest` as seen by `reserve` - dest: expected_dest_on_reserve, - // message sent onward to final `dest` to deposit/prefund fees - xcm: Xcm(vec![ - buy_limited_execution(expected_fee, Unlimited), - DepositAsset { assets: AllCounted(1).into(), beneficiary } - ]) - } - ]) - ) - ] - ); - let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); - let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); }); } @@ -733,6 +638,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ Xcm(vec![ WithdrawAsset(expected_fee.clone().into()), ClearOrigin, + SetFeesMode { jit_withdraw: false }, buy_limited_execution(expected_fee.clone(), Unlimited), DepositAsset { assets: AllCounted(1).into(), beneficiary }, ]) @@ -746,14 +652,13 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ Xcm(vec![ ReserveAssetDeposited(expected_asset.into()), ClearOrigin, + SetFeesMode { jit_withdraw: true }, buy_limited_execution(expected_fee, Unlimited), DepositAsset { assets: AllCounted(1).into(), beneficiary }, ]) ) ] ); - let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); - let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); }); } @@ -836,46 +741,22 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re Xcm(vec![ WithdrawAsset(expected_assets.clone()), ClearOrigin, + SetFeesMode { jit_withdraw: false }, buy_limited_execution(expected_assets.get(0).unwrap().clone(), Unlimited), DepositAsset { assets: AllCounted(1).into(), beneficiary }, ]), )] ); - let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); - let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); }); } -/// Test `reserve_transfer_assets` with remote asset reserve and destination fee reserve. +/// Test `reserve_transfer_assets` with remote asset reserve and destination fee reserve is +/// disallowed. /// /// Transferring foreign asset (reserve on `FOREIGN_ASSET_RESERVE_PARA_ID`) to /// `USDC_RESERVE_PARA_ID`. Using USDC (destination reserve) as fee. -/// -/// ```nocompile -/// | chain `A` | chain `C` | chain `B` -/// | Here (source) | FOREIGN_ASSET_RESERVE_PARA_ID | USDC_RESERVE_PARA_ID (destination) -/// | | `assets` reserve | `fees` reserve -/// -/// 1. `A` executes `InitiateReserveWithdraw(fees)` dest `B` -/// ---------------------------------------------------> `B` executes: -/// `WithdrawAsset(fees), ClearOrigin` -/// `BuyExecution(fees)` -/// `DepositReserveAsset(fees)` dest `C` -/// `C` executes `DepositAsset(fees)` <---------------------------- -/// -/// 2. `A` executes `InitiateReserveWithdraw(fees)` dest `B` -/// ---------------------------------------------------> `B` executes: -/// `WithdrawAsset(fees), .., DepositAsset(fees)` -/// -/// 3. `A` executes `InitiateReserveWithdraw(assets)` dest `C` -/// --------------> `C` executes `DepositReserveAsset(assets)` dest `B` -/// ----------------------------> `B` executes: -/// WithdrawAsset(assets), .., DepositAsset(assets)` -/// -/// all of which at step 3. being paid with fees prefunded in steps 1 & 2 -/// ``` #[test] -fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve_works() { +fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve_disallowed() { let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); @@ -891,7 +772,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve // create non-sufficient foreign asset BLA (0 total issuance) let foreign_initial_amount = 142; - let (reserve_location, _, foreign_asset_id_multilocation) = set_up_foreign_asset( + let (_, _, foreign_asset_id_multilocation) = set_up_foreign_asset( FOREIGN_ASSET_RESERVE_PARA_ID, Some(FOREIGN_ASSET_INNER_JUNCTION), foreign_initial_amount, @@ -902,277 +783,117 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve // reserve chain) let dest = usdc_chain; - let (assets, fee_index, fee_asset, xfer_asset) = into_multiassets_checked( + let (assets, fee_index, _, _) = into_multiassets_checked( // USDC for fees (is sufficient on local chain too) - destination reserve (usdc_id_multilocation, FEE_AMOUNT).into(), // foreign asset to transfer (not used for fees) - remote reserve (foreign_asset_id_multilocation, SEND_AMOUNT).into(), ); - // reanchor according to test-case - let context = UniversalLocation::get(); - let expected_dest_on_reserve = dest.reanchored(&reserve_location, context).unwrap(); - let expected_reserve_on_dest = reserve_location.reanchored(&dest, context).unwrap(); - let mut expected_fee_on_reserve = - fee_asset.clone().reanchored(&reserve_location, context).unwrap(); - let expected_asset_on_reserve = - xfer_asset.clone().reanchored(&reserve_location, context).unwrap(); - let mut expected_fee = fee_asset.reanchored(&dest, context).unwrap(); - - // fees are split between the asset-reserve chain and the destination chain - crate::Pallet::::halve_fees(&mut expected_fee_on_reserve).unwrap(); - crate::Pallet::::halve_fees(&mut expected_fee).unwrap(); - // balances checks before assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_initial_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // do the transfer - assert_ok!(XcmPallet::limited_reserve_transfer_assets( + let result = XcmPallet::limited_reserve_transfer_assets( RuntimeOrigin::signed(ALICE), Box::new(dest.into()), Box::new(beneficiary.into()), Box::new(assets.into()), fee_index as u32, Unlimited, - )); - assert!(matches!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) - )); - - // Alice native asset untouched - assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); - // Alice spent USDC for fees - assert_eq!( - Assets::balance(usdc_id_multilocation, ALICE), - usdc_initial_local_amount - FEE_AMOUNT ); - // Alice transferred BLA assert_eq!( - Assets::balance(foreign_asset_id_multilocation, ALICE), - foreign_initial_amount - SEND_AMOUNT + result, + Err(DispatchError::Module(ModuleError { + index: 4, + error: [15, 0, 0, 0], + message: Some("InvalidAssetUnsupportedReserve") + })) ); - // Verify total and active issuance of USDC have decreased (burned on reserve-withdraw) - let expected_usdc_issuance = usdc_initial_local_amount - FEE_AMOUNT; + + // Alice native asset untouched + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_initial_amount); + let expected_usdc_issuance = usdc_initial_local_amount; assert_eq!(Assets::total_issuance(usdc_id_multilocation), expected_usdc_issuance); assert_eq!(Assets::active_issuance(usdc_id_multilocation), expected_usdc_issuance); - // Verify total and active issuance of foreign BLA asset have decreased (burned on - // reserve-withdraw) - let expected_bla_issuance = foreign_initial_amount - SEND_AMOUNT; + let expected_bla_issuance = foreign_initial_amount; assert_eq!(Assets::total_issuance(foreign_asset_id_multilocation), expected_bla_issuance); assert_eq!(Assets::active_issuance(foreign_asset_id_multilocation), expected_bla_issuance); - - // Verify sent XCM program - assert_eq!( - sent_xcm(), - vec![ - ( - // first message is to prefund fees on `reserve`, but we need to go through - // `fee_reserve == dest` to get them there - dest, - // fees are reserve-withdrawn on `dest` chain then reserve-deposited to - // `asset_reserve` chain - Xcm(vec![ - WithdrawAsset(expected_fee.clone().into()), - ClearOrigin, - buy_limited_execution(expected_fee.clone(), Unlimited), - DepositReserveAsset { - assets: Wild(AllCounted(1)), - // final fees destination is `asset_reserve` as seen by `dest` - dest: expected_reserve_on_dest, - // message sent onward to final `dest` to deposit/prefund fees - xcm: Xcm(vec![ - buy_limited_execution(expected_fee_on_reserve.clone(), Unlimited), - DepositAsset { assets: AllCounted(1).into(), beneficiary } - ]) - } - ]) - ), - ( - // second message is to prefund fees on `dest` - dest, - // fees are reserve-withdrawn on destination chain - Xcm(vec![ - WithdrawAsset(expected_fee.clone().into()), - ClearOrigin, - buy_limited_execution(expected_fee.clone(), Unlimited), - DepositAsset { assets: AllCounted(1).into(), beneficiary }, - ]) - ), - ( - // third message is to transfer/deposit foreign assets on `dest` by going - // through `reserve` while paying using prefunded (teleported above) fees - reserve_location, - Xcm(vec![ - WithdrawAsset(expected_asset_on_reserve.into()), - ClearOrigin, - buy_limited_execution(expected_fee_on_reserve, Unlimited), - DepositReserveAsset { - assets: Wild(AllCounted(1)), - // final destination is `dest` as seen by `reserve` - dest: expected_dest_on_reserve, - // message sent onward to final `dest` to deposit/prefund fees - xcm: Xcm(vec![ - buy_limited_execution(expected_fee, Unlimited), - DepositAsset { assets: AllCounted(1).into(), beneficiary } - ]) - } - ]) - ) - ] - ); - let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); - let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); }); } -/// Test `reserve_transfer_assets` with local asset reserve and remote fee reserve. +/// Test `reserve_transfer_assets` with local asset reserve and remote fee reserve is disallowed. /// /// Transferring native asset (local reserve) to `OTHER_PARA_ID` (no teleport trust). Using foreign /// asset (`USDC_RESERVE_PARA_ID` remote reserve) for fees. -/// -/// ```nocompile -/// | chain `A` | chain `C` | chain `B` -/// | Here (source) | USDC_RESERVE_PARA_ID | OTHER_PARA_ID (destination) -/// | `assets` reserve | `fees` reserve | -/// | -/// | 1. `A` executes `InitiateReserveWithdraw(fees)` dest `C` -/// | -----------------> `C` executes `DepositReserveAsset(fees)` dest `B` -/// | --------------------------> `DepositAsset(fees)` -/// | 2. `A` executes `TransferReserveAsset(assets)` dest `B` -/// | --------------------------------------------------> `ReserveAssetDeposited(assets)` -/// ``` #[test] -fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_works() { +fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_disallowed() { let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { // create sufficient foreign asset USDC (0 total issuance) let usdc_initial_local_amount = 142; - let (fee_reserve_location, usdc_chain_sovereign_account, usdc_id_multilocation) = - set_up_foreign_asset( - USDC_RESERVE_PARA_ID, - Some(USDC_INNER_JUNCTION), - usdc_initial_local_amount, - true, - ); + let (_, usdc_chain_sovereign_account, usdc_id_multilocation) = set_up_foreign_asset( + USDC_RESERVE_PARA_ID, + Some(USDC_INNER_JUNCTION), + usdc_initial_local_amount, + true, + ); // transfer destination is some other parachain != fee reserve location (no teleport trust) let dest = RelayLocation::get().pushed_with_interior(Parachain(OTHER_PARA_ID)).unwrap(); let dest_sovereign_account = SovereignAccountOf::convert_location(&dest).unwrap(); - let (assets, fee_index, fee_asset, xfer_asset) = into_multiassets_checked( + let (assets, fee_index, _, _) = into_multiassets_checked( // USDC for fees (is sufficient on local chain too) - remote reserve (usdc_id_multilocation, FEE_AMOUNT).into(), // native asset to transfer (not used for fees) - local reserve (MultiLocation::here(), SEND_AMOUNT).into(), ); - // reanchor according to test-case - let context = UniversalLocation::get(); - let expected_dest_on_reserve = dest.reanchored(&fee_reserve_location, context).unwrap(); - let expected_fee_on_reserve = - fee_asset.clone().reanchored(&fee_reserve_location, context).unwrap(); - let expected_fee = fee_asset.reanchored(&dest, context).unwrap(); - let expected_asset = xfer_asset.reanchored(&dest, context).unwrap(); - // balances checks before assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // do the transfer - assert_ok!(XcmPallet::limited_reserve_transfer_assets( + let result = XcmPallet::limited_reserve_transfer_assets( RuntimeOrigin::signed(ALICE), Box::new(dest.into()), Box::new(beneficiary.into()), Box::new(assets.into()), fee_index as u32, Unlimited, - )); - assert!(matches!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) - )); - // Alice spent (fees) amount + ); assert_eq!( - Assets::balance(usdc_id_multilocation, ALICE), - usdc_initial_local_amount - FEE_AMOUNT + result, + Err(DispatchError::Module(ModuleError { + index: 4, + error: [15, 0, 0, 0], + message: Some("InvalidAssetUnsupportedReserve") + })) ); - // Alice used native asset for transfer - assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); + assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // Sovereign account of reserve parachain is unchanged assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), 0); assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); - // Sovereign account of destination parachain holds `SEND_AMOUNT` in local reserve - assert_eq!(Balances::free_balance(dest_sovereign_account), SEND_AMOUNT); - // Verify total and active issuance of USDC have decreased (burned on reserve-withdraw) - let expected_usdc_issuance = usdc_initial_local_amount - FEE_AMOUNT; + assert_eq!(Balances::free_balance(dest_sovereign_account), 0); + let expected_usdc_issuance = usdc_initial_local_amount; assert_eq!(Assets::total_issuance(usdc_id_multilocation), expected_usdc_issuance); assert_eq!(Assets::active_issuance(usdc_id_multilocation), expected_usdc_issuance); - - // Verify sent XCM program - assert_eq!( - sent_xcm(), - vec![ - ( - // first message is to prefund (USDC) fees on `dest` (by going through - // fee remote (USDC) reserve) - fee_reserve_location, - Xcm(vec![ - WithdrawAsset(expected_fee_on_reserve.clone().into()), - ClearOrigin, - buy_limited_execution(expected_fee_on_reserve, Unlimited), - DepositReserveAsset { - assets: Wild(AllCounted(1)), - // final destination is `dest` as seen by `reserve` - dest: expected_dest_on_reserve, - // message sent onward to final `dest` to deposit/prefund fees - xcm: Xcm(vec![ - buy_limited_execution(expected_fee.clone(), Unlimited), - DepositAsset { assets: AllCounted(1).into(), beneficiary } - ]) - } - ]) - ), - ( - // second message is to transfer/deposit (native) asset on `dest` while paying - // using prefunded (transferred above) fees/USDC - dest, - // transfer is through local-reserve transfer because `assets` (native asset) - // have local reserve - Xcm(vec![ - ReserveAssetDeposited(expected_asset.into()), - ClearOrigin, - buy_limited_execution(expected_fee, Unlimited), - DepositAsset { assets: AllCounted(1).into(), beneficiary }, - ]) - ) - ] - ); - let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); - let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); }); } -/// Test `reserve_transfer_assets` with destination asset reserve and remote fee reserve. +/// Test `reserve_transfer_assets` with destination asset reserve and remote fee reserve is +/// disallowed. /// /// Transferring native asset (local reserve) to `OTHER_PARA_ID` (no teleport trust). Using foreign /// asset (`USDC_RESERVE_PARA_ID` remote reserve) for fees. -/// -/// ```nocompile -/// | chain `A` | chain `C` | chain `B` -/// | Here (source) | USDC_RESERVE_PARA_ID | FOREIGN_ASSET_RESERVE_PARA_ID (destination) -/// | | `fees` reserve | `assets` reserve -/// | -/// | 1. `A` executes `InitiateReserveWithdraw(fees)` dest `C` -/// | -----------------> `C` executes `DepositReserveAsset(fees)` dest `B` -/// | --------------------------> `DepositAsset(fees)` -/// | 2. `A` executes `InitiateReserveWithdraw(assets)` dest `B` -/// | --------------------------------------------------> `DepositAsset(assets)` -/// ``` #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve_works() { let balances = vec![(ALICE, INITIAL_BALANCE)]; @@ -1181,13 +902,12 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve new_test_ext_with_balances(balances).execute_with(|| { // create sufficient foreign asset USDC (0 total issuance) let usdc_initial_local_amount = 42; - let (fee_reserve_location, usdc_chain_sovereign_account, usdc_id_multilocation) = - set_up_foreign_asset( - USDC_RESERVE_PARA_ID, - Some(USDC_INNER_JUNCTION), - usdc_initial_local_amount, - true, - ); + let (_, usdc_chain_sovereign_account, usdc_id_multilocation) = set_up_foreign_asset( + USDC_RESERVE_PARA_ID, + Some(USDC_INNER_JUNCTION), + usdc_initial_local_amount, + true, + ); // create non-sufficient foreign asset BLA (0 total issuance) let foreign_initial_amount = 142; @@ -1203,106 +923,48 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve let dest = reserve_location; let dest_sovereign_account = foreign_sovereign_account; - let (assets, fee_index, fee_asset, xfer_asset) = into_multiassets_checked( + let (assets, fee_index, _, _) = into_multiassets_checked( // USDC for fees (is sufficient on local chain too) - remote reserve (usdc_id_multilocation, FEE_AMOUNT).into(), // foreign asset to transfer (not used for fees) - destination reserve (foreign_asset_id_multilocation, SEND_AMOUNT).into(), ); - // reanchor according to test-case - let context = UniversalLocation::get(); - let expected_dest_on_reserve = dest.reanchored(&fee_reserve_location, context).unwrap(); - let expected_fee_on_reserve = - fee_asset.clone().reanchored(&fee_reserve_location, context).unwrap(); - let expected_fee = fee_asset.reanchored(&dest, context).unwrap(); - let expected_asset = xfer_asset.reanchored(&dest, context).unwrap(); - // balances checks before assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // do the transfer - assert_ok!(XcmPallet::limited_reserve_transfer_assets( + let result = XcmPallet::limited_reserve_transfer_assets( RuntimeOrigin::signed(ALICE), Box::new(dest.into()), Box::new(beneficiary.into()), Box::new(assets.into()), fee_index as u32, Unlimited, - )); - assert!(matches!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) - )); - // Alice native asset untouched - assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); - // Alice spent USDC for fees - assert_eq!( - Assets::balance(usdc_id_multilocation, ALICE), - usdc_initial_local_amount - FEE_AMOUNT ); - // Alice transferred BLA assert_eq!( - Assets::balance(foreign_asset_id_multilocation, ALICE), - foreign_initial_amount - SEND_AMOUNT + result, + Err(DispatchError::Module(ModuleError { + index: 4, + error: [15, 0, 0, 0], + message: Some("InvalidAssetUnsupportedReserve") + })) ); - // Verify balances of USDC reserve parachain + // Alice native asset untouched + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_initial_amount); assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), 0); assert_eq!(Assets::balance(usdc_id_multilocation, usdc_chain_sovereign_account), 0); - // Verify balances of transferred-asset reserve parachain assert_eq!(Balances::free_balance(dest_sovereign_account.clone()), 0); assert_eq!(Assets::balance(foreign_asset_id_multilocation, dest_sovereign_account), 0); - // Verify total and active issuance of USDC have decreased (burned on reserve-withdraw) - let expected_usdc_issuance = usdc_initial_local_amount - FEE_AMOUNT; + let expected_usdc_issuance = usdc_initial_local_amount; assert_eq!(Assets::total_issuance(usdc_id_multilocation), expected_usdc_issuance); assert_eq!(Assets::active_issuance(usdc_id_multilocation), expected_usdc_issuance); - // Verify total and active issuance of foreign BLA asset have decreased (burned on - // reserve-withdraw) - let expected_bla_issuance = foreign_initial_amount - SEND_AMOUNT; + let expected_bla_issuance = foreign_initial_amount; assert_eq!(Assets::total_issuance(foreign_asset_id_multilocation), expected_bla_issuance); assert_eq!(Assets::active_issuance(foreign_asset_id_multilocation), expected_bla_issuance); - - // Verify sent XCM program - assert_eq!( - sent_xcm(), - vec![ - ( - // first message is to prefund (USDC) fees on `dest` (by going through - // fee remote (USDC) reserve) - fee_reserve_location, - Xcm(vec![ - WithdrawAsset(expected_fee_on_reserve.clone().into()), - ClearOrigin, - buy_limited_execution(expected_fee_on_reserve, Unlimited), - DepositReserveAsset { - assets: Wild(AllCounted(1)), - // final destination is `dest` as seen by `reserve` - dest: expected_dest_on_reserve, - // message sent onward to final `dest` to deposit/prefund fees - xcm: Xcm(vec![ - buy_limited_execution(expected_fee.clone(), Unlimited), - DepositAsset { assets: AllCounted(1).into(), beneficiary } - ]) - } - ]) - ), - ( - // second message is to transfer/deposit foreign assets on `dest` while paying - // using prefunded (transferred above) fees (USDC) - // (dest is reserve location for `expected_asset`) - dest, - Xcm(vec![ - WithdrawAsset(expected_asset.into()), - ClearOrigin, - buy_limited_execution(expected_fee, Unlimited), - DepositAsset { assets: AllCounted(1).into(), beneficiary }, - ]) - ) - ] - ); - let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); - let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); }); } @@ -1410,8 +1072,6 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work ]) )], ); - let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); - let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); }); } @@ -1512,14 +1172,13 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { Xcm(vec![ ReserveAssetDeposited(expected_asset.into()), ClearOrigin, + SetFeesMode { jit_withdraw: true }, buy_limited_execution(expected_fee, Unlimited), DepositAsset { assets: AllCounted(1).into(), beneficiary }, ]) ) ] ); - let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); - let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); }); } @@ -1644,45 +1303,25 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_wor Xcm(vec![ WithdrawAsset(expected_asset.into()), ClearOrigin, + SetFeesMode { jit_withdraw: true }, buy_limited_execution(expected_fee, Unlimited), DepositAsset { assets: AllCounted(1).into(), beneficiary }, ]) ) ] ); - let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); - let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); }); } -/// Test `reserve_transfer_assets` with remote asset reserve and teleported fee. +/// Test `reserve_transfer_assets` with remote asset reserve and teleported fee is disallowed. /// -/// Transferring foreign asset (reserve on `FOREIGN_ASSET_RESERVE_PARA_ID`) to `USDT_PARA_ID`. Using -/// teleport-trusted USDT for fees. -/// -/// ```nocompile -/// | chain `A` | chain `C` | chain `B` -/// | Here (source) | FOREIGN_ASSET_RESERVE_PARA_ID | USDT_PARA_ID (destination) -/// | | `assets` reserve | `fees` (USDT) teleport-trust -/// | -/// | 1. `A` executes `InitiateTeleport(fees)` dest `C` -/// | \----------> `C` executes `ReceiveTeleportedAsset(fees), .., DepositAsset(fees)` -/// | -/// | 2. `A` executes `InitiateTeleport(fees)` dest `B` -/// | \-------------------------------------------------> `B` executes: -/// | `ReceiveTeleportedAsset(fees), .., DepositAsset(fees)` -/// | -/// | 3. `A` executes `InitiateReserveWithdraw(assets)` dest `C` -/// | -----------------> `C` executes `DepositReserveAsset(assets)` dest `B` -/// | --------------------------> `DepositAsset(assets)` -/// | all of which at step 3. being paid with fees prefunded in steps 1 & 2 -/// ``` +/// Transferring foreign asset (reserve on `FOREIGN_ASSET_RESERVE_PARA_ID`) to `USDT_PARA_ID`. +/// Using teleport-trusted USDT for fees. #[test] fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_works() { let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - let expected_beneficiary_on_reserve = beneficiary; new_test_ext_with_balances(balances).execute_with(|| { // create sufficient foreign asset USDT (0 total issuance) let usdt_initial_local_amount = 42; @@ -1691,135 +1330,58 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_works() // create non-sufficient foreign asset BLA (0 total issuance) let foreign_initial_amount = 142; - let (reserve_location, reserve_sovereign_account, foreign_asset_id_multilocation) = - set_up_foreign_asset( - FOREIGN_ASSET_RESERVE_PARA_ID, - Some(FOREIGN_ASSET_INNER_JUNCTION), - foreign_initial_amount, - false, - ); + let (_, reserve_sovereign_account, foreign_asset_id_multilocation) = set_up_foreign_asset( + FOREIGN_ASSET_RESERVE_PARA_ID, + Some(FOREIGN_ASSET_INNER_JUNCTION), + foreign_initial_amount, + false, + ); // transfer destination is USDT chain (foreign asset needs to go through its reserve chain) let dest = usdt_chain; - let (assets, fee_index, fee_asset, xfer_asset) = into_multiassets_checked( + let (assets, fee_index, _, _) = into_multiassets_checked( // USDT for fees (is sufficient on local chain too) - teleported (usdt_id_multilocation, FEE_AMOUNT).into(), // foreign asset to transfer (not used for fees) - remote reserve (foreign_asset_id_multilocation, SEND_AMOUNT).into(), ); - // reanchor according to test-case - let context = UniversalLocation::get(); - let expected_dest_on_reserve = dest.reanchored(&reserve_location, context).unwrap(); - let mut expected_fee_on_reserve = - fee_asset.clone().reanchored(&reserve_location, context).unwrap(); - let expected_asset_on_reserve = - xfer_asset.clone().reanchored(&reserve_location, context).unwrap(); - let mut expected_fee = fee_asset.reanchored(&dest, context).unwrap(); - - // fees are split between the asset-reserve chain and the destination chain - crate::Pallet::::halve_fees(&mut expected_fee_on_reserve).unwrap(); - crate::Pallet::::halve_fees(&mut expected_fee).unwrap(); - // balances checks before assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // do the transfer - assert_ok!(XcmPallet::limited_reserve_transfer_assets( + let result = XcmPallet::limited_reserve_transfer_assets( RuntimeOrigin::signed(ALICE), Box::new(dest.into()), Box::new(beneficiary.into()), Box::new(assets.into()), fee_index as u32, Unlimited, - )); - assert!(matches!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) - )); - // Alice native asset untouched - assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); - // Alice spent USDT for fees - assert_eq!( - Assets::balance(usdt_id_multilocation, ALICE), - usdt_initial_local_amount - FEE_AMOUNT ); - // Alice transferred BLA assert_eq!( - Assets::balance(foreign_asset_id_multilocation, ALICE), - foreign_initial_amount - SEND_AMOUNT + result, + Err(DispatchError::Module(ModuleError { + index: 4, + error: [15, 0, 0, 0], + message: Some("InvalidAssetUnsupportedReserve") + })) ); - // Verify balances of USDT reserve parachain + // Alice native asset untouched + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_initial_amount); assert_eq!(Balances::free_balance(usdt_chain_sovereign_account.clone()), 0); assert_eq!(Assets::balance(usdt_id_multilocation, usdt_chain_sovereign_account), 0); - // Verify balances of transferred-asset reserve parachain assert_eq!(Balances::free_balance(reserve_sovereign_account.clone()), 0); assert_eq!(Assets::balance(foreign_asset_id_multilocation, reserve_sovereign_account), 0); - // Verify total and active issuance of USDT have decreased (teleported) - let expected_usdt_issuance = usdt_initial_local_amount - FEE_AMOUNT; + let expected_usdt_issuance = usdt_initial_local_amount; assert_eq!(Assets::total_issuance(usdt_id_multilocation), expected_usdt_issuance); assert_eq!(Assets::active_issuance(usdt_id_multilocation), expected_usdt_issuance); - // Verify total and active issuance of foreign BLA asset have decreased (burned on - // reserve-withdraw) - let expected_bla_issuance = foreign_initial_amount - SEND_AMOUNT; + let expected_bla_issuance = foreign_initial_amount; assert_eq!(Assets::total_issuance(foreign_asset_id_multilocation), expected_bla_issuance); assert_eq!(Assets::active_issuance(foreign_asset_id_multilocation), expected_bla_issuance); - - // Verify sent XCM program - assert_eq!( - sent_xcm(), - vec![ - ( - // first message is to prefund fees on `reserve` - reserve_location, - // fees are teleported to reserve chain - Xcm(vec![ - ReceiveTeleportedAsset(expected_fee_on_reserve.clone().into()), - ClearOrigin, - buy_limited_execution(expected_fee_on_reserve.clone(), Unlimited), - DepositAsset { - assets: AllCounted(1).into(), - beneficiary: expected_beneficiary_on_reserve - }, - ]) - ), - ( - // second message is to prefund fees on `dest` - dest, - // fees are teleported to destination chain - Xcm(vec![ - ReceiveTeleportedAsset(expected_fee.clone().into()), - ClearOrigin, - buy_limited_execution(expected_fee.clone(), Unlimited), - DepositAsset { assets: AllCounted(1).into(), beneficiary }, - ]) - ), - ( - // third message is to transfer/deposit foreign assets on `dest` by going - // through `reserve` while paying using prefunded (teleported above) fees - reserve_location, - Xcm(vec![ - WithdrawAsset(expected_asset_on_reserve.into()), - ClearOrigin, - buy_limited_execution(expected_fee_on_reserve, Unlimited), - DepositReserveAsset { - assets: Wild(AllCounted(1)), - // final destination is `dest` as seen by `reserve` - dest: expected_dest_on_reserve, - // message sent onward to final `dest` to deposit/prefund fees - xcm: Xcm(vec![ - buy_limited_execution(expected_fee, Unlimited), - DepositAsset { assets: AllCounted(1).into(), beneficiary } - ]) - } - ]) - ) - ] - ); - let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); - let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); }); } @@ -1831,6 +1393,7 @@ fn reserve_transfer_assets_with_teleportable_asset_fails() { let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + new_test_ext_with_balances(balances).execute_with(|| { // create sufficient foreign asset USDT (0 total issuance) let usdt_initial_local_amount = 42; From d1a9709e5f8a45d1fdedab6734ed659dd05ee722 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 23 Oct 2023 18:07:50 +0300 Subject: [PATCH 39/98] xcm-barriers: allow SetFeesMode in BuyExecution barrier and fix tests --- .../assets/test-utils/src/test_cases.rs | 21 +++++----- .../test-utils/src/test_cases_over_bridge.rs | 40 +++++++++++-------- polkadot/xcm/xcm-builder/src/barriers.rs | 2 + 3 files changed, 36 insertions(+), 27 deletions(-) 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 af9fc4475cf9..2a32989aae9a 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -1463,7 +1463,8 @@ pub fn reserve_transfer_native_asset_to_non_teleport_para_works< ); // drip ED to account - let alice_account_init_balance = existential_deposit + balance_to_transfer.into(); + let alice_account_init_balance = + existential_deposit.saturating_mul(2.into()) + balance_to_transfer.into(); let _ = >::deposit_creating( &alice_account, alice_account_init_balance, @@ -1503,6 +1504,15 @@ pub fn reserve_transfer_native_asset_to_non_teleport_para_works< weight_limit, )); + // check events + // check pallet_xcm attempted + RuntimeHelper::::assert_pallet_xcm_event_outcome( + &unwrap_pallet_xcm_event, + |outcome| { + assert_ok!(outcome.ensure_complete()); + }, + ); + // check alice account decreased by balance_to_transfer // TODO:check-parameter: change and assert in tests when (https://github.com/paritytech/polkadot/pull/7005) merged assert_eq!( @@ -1517,15 +1527,6 @@ pub fn reserve_transfer_native_asset_to_non_teleport_para_works< existential_deposit + balance_to_transfer.into() ); - // check events - // check pallet_xcm attempted - RuntimeHelper::::assert_pallet_xcm_event_outcome( - &unwrap_pallet_xcm_event, - |outcome| { - assert_ok!(outcome.ensure_complete()); - }, - ); - // check that xcm was sent let xcm_sent_message_hash = >::events() .into_iter() diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs index a4f59b563485..2d4039357660 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs @@ -30,7 +30,7 @@ use parachains_runtimes_test_utils::{ mock_open_hrmp_channel, AccountIdOf, BalanceOf, CollatorSessionKeys, ExtBuilder, RuntimeHelper, ValidatorIdOf, XcmReceivedFrom, }; -use sp_runtime::traits::StaticLookup; +use sp_runtime::{traits::StaticLookup, Saturating}; use xcm::{latest::prelude::*, VersionedMultiAssets}; use xcm_builder::{CreateMatcher, MatchXcm}; use xcm_executor::{traits::ConvertLocation, XcmExecutor}; @@ -127,7 +127,8 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< ); // drip ED to account - let alice_account_init_balance = existential_deposit + balance_to_transfer.into(); + let alice_account_init_balance = + existential_deposit.saturating_mul(2.into()) + balance_to_transfer.into(); let _ = >::deposit_creating( &alice_account, alice_account_init_balance, @@ -168,7 +169,7 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< // Make sure sender has enough funds for paying delivery fees // TODO: Get this fee via weighing the corresponding message - let delivery_fees = 1324039894; + let delivery_fees = 1324173226; >::mint_into(&alice_account, delivery_fees.into()) .unwrap(); @@ -182,19 +183,6 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< weight_limit, )); - // check alice account decreased by balance_to_transfer - assert_eq!( - >::free_balance(&alice_account), - alice_account_init_balance - balance_to_transfer.into() - ); - - // check reserve account - // check reserve account increased by balance_to_transfer - assert_eq!( - >::free_balance(&reserve_account), - existential_deposit + balance_to_transfer.into() - ); - // check events // check pallet_xcm attempted RuntimeHelper::::assert_pallet_xcm_event_outcome( @@ -219,7 +207,6 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< local_bridge_hub_para_id.into(), ) .unwrap(); - assert_eq!( xcm_sent_message_hash, Some(xcm_sent.using_encoded(sp_io::hashing::blake2_256)) @@ -274,6 +261,19 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< _ => Err(ProcessMessageError::BadFormat), }) .expect("contains ExportMessage"); + + // check alice account decreased by balance_to_transfer + assert_eq!( + >::free_balance(&alice_account), + alice_account_init_balance - balance_to_transfer.into() + ); + + // check reserve account + // check reserve account increased by balance_to_transfer + assert_eq!( + >::free_balance(&reserve_account), + existential_deposit + balance_to_transfer.into() + ); }) } @@ -415,6 +415,7 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< fun: Fungible(transfered_foreign_asset_id_amount), }])), ClearOrigin, + SetFeesMode { jit_withdraw: false }, BuyExecution { fees: MultiAsset { id: Concrete(foreign_asset_id_multilocation), @@ -516,6 +517,11 @@ fn assert_matches_pallet_xcm_reserve_transfer_assets_instructions( _ => Err(ProcessMessageError::BadFormat), }) .expect("expected instruction ClearOrigin") + .match_next_inst(|instr| match instr { + SetFeesMode { .. } => Ok(()), + _ => Err(ProcessMessageError::BadFormat), + }) + .expect("expected instruction SetFeesMode") .match_next_inst(|instr| match instr { BuyExecution { .. } => Ok(()), _ => Err(ProcessMessageError::BadFormat), diff --git a/polkadot/xcm/xcm-builder/src/barriers.rs b/polkadot/xcm/xcm-builder/src/barriers.rs index 3b13cab2c1ea..50098791b443 100644 --- a/polkadot/xcm/xcm-builder/src/barriers.rs +++ b/polkadot/xcm/xcm-builder/src/barriers.rs @@ -88,6 +88,8 @@ impl> ShouldExecute for AllowTopLevelPaidExecutionFro _ => Err(ProcessMessageError::BadFormat), })? .skip_inst_while(|inst| matches!(inst, ClearOrigin))? + // allow setting fees mode to jit or not for use in following `BuyExecution` + .skip_inst_while(|inst| matches!(inst, SetFeesMode { .. }))? .match_next_inst(|inst| match inst { BuyExecution { weight_limit: Limited(ref mut weight), .. } if weight.all_gte(max_weight) => From 50d844f5d049d7de9a86a0ec9abdcf092c0119fc Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 24 Oct 2023 16:23:19 +0300 Subject: [PATCH 40/98] verify assets and beneficiary in over-bridge test --- .../runtimes/assets/test-utils/src/lib.rs | 16 +++- .../test-utils/src/test_cases_over_bridge.rs | 87 ++++++++----------- 2 files changed, 47 insertions(+), 56 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs b/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs index 82482599fd4d..019287cd1bf8 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs @@ -19,15 +19,17 @@ pub mod test_cases; pub mod test_cases_over_bridge; pub mod xcm_helpers; + use frame_support::traits::ProcessMessageError; pub use parachains_runtimes_test_utils::*; +use std::fmt::Debug; use xcm::latest::prelude::*; use xcm_builder::{CreateMatcher, MatchXcm}; /// Helper function to verify `xcm` contains all relevant instructions expected on destination /// chain as part of a reserve-asset-transfer. -pub(crate) fn assert_matches_reserve_asset_deposited_instructions( +pub(crate) fn assert_matches_reserve_asset_deposited_instructions( xcm: &mut Xcm, expected_reserve_assets_deposited: &MultiAssets, expected_beneficiary: &MultiLocation, @@ -38,9 +40,10 @@ pub(crate) fn assert_matches_reserve_asset_deposited_instructions( .skip_inst_while(|inst| !matches!(inst, ReserveAssetDeposited(..))) .expect("no instruction ReserveAssetDeposited?") .match_next_inst(|instr| match instr { - ReserveAssetDeposited(reserve_assets) - if reserve_assets == expected_reserve_assets_deposited => - Ok(()), + ReserveAssetDeposited(reserve_assets) => { + assert_eq!(reserve_assets, expected_reserve_assets_deposited); + Ok(()) + }, _ => Err(ProcessMessageError::BadFormat), }) .expect("expected instruction ReserveAssetDeposited") @@ -49,6 +52,11 @@ pub(crate) fn assert_matches_reserve_asset_deposited_instructions( _ => Err(ProcessMessageError::BadFormat), }) .expect("expected instruction ClearOrigin") + .match_next_inst(|instr| match instr { + SetFeesMode { .. } => Ok(()), + _ => Err(ProcessMessageError::BadFormat), + }) + .expect("expected instruction SetFeesMode") .match_next_inst(|instr| match instr { BuyExecution { .. } => Ok(()), _ => Err(ProcessMessageError::BadFormat), diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs index 2d4039357660..1eed91a64a4a 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs @@ -16,6 +16,7 @@ //! Module contains predefined test-case scenarios for `Runtime` with various assets transferred //! over a bridge. +use crate::assert_matches_reserve_asset_deposited_instructions; use codec::Encode; use cumulus_primitives_core::XcmpMessageSource; use frame_support::{ @@ -173,12 +174,24 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< >::mint_into(&alice_account, delivery_fees.into()) .unwrap(); + let assets_to_transfer = MultiAssets::from(asset_to_transfer); + let mut expected_assets = assets_to_transfer.clone(); + expected_assets + .reanchor(&target_location_from_different_consensus, Here.into()) + .unwrap(); + // FIXME: remove this hardcode here when fixing reanchor over bridge + expected_assets = MultiAssets::from(MultiAsset { + id: Concrete(MultiLocation { parents: 2, interior: X1(GlobalConsensus(Rococo)) }), + fun: Fungible(1000000000000), + }); + + let expected_beneficiary = target_destination_account; // do pallet_xcm call reserve transfer assert_ok!(>::limited_reserve_transfer_assets( RuntimeHelper::::origin_of(alice_account.clone()), Box::new(target_location_from_different_consensus.into_versioned()), Box::new(target_destination_account.into_versioned()), - Box::new(VersionedMultiAssets::from(MultiAssets::from(asset_to_transfer))), + Box::new(VersionedMultiAssets::from(assets_to_transfer)), 0, weight_limit, )); @@ -255,7 +268,11 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< .split_global() .expect("split works"); assert_eq!(destination, &target_location_junctions_without_global_consensus); - assert_matches_pallet_xcm_reserve_transfer_assets_instructions(inner_xcm); + assert_matches_reserve_asset_deposited_instructions( + inner_xcm, + &expected_assets, + &expected_beneficiary, + ); Ok(()) }, _ => Err(ProcessMessageError::BadFormat), @@ -405,15 +422,21 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< 0.into() ); + let expected_assets = MultiAssets::from(vec![MultiAsset { + id: Concrete(foreign_asset_id_multilocation), + fun: Fungible(transfered_foreign_asset_id_amount), + }]); + let expected_beneficiary = MultiLocation { + parents: 0, + interior: X1(AccountId32 { network: None, id: target_account.clone().into() }), + }; + // Call received XCM execution let xcm = Xcm(vec![ DescendOrigin(bridge_instance), UniversalOrigin(universal_origin), DescendOrigin(descend_origin), - ReserveAssetDeposited(MultiAssets::from(vec![MultiAsset { - id: Concrete(foreign_asset_id_multilocation), - fun: Fungible(transfered_foreign_asset_id_amount), - }])), + ReserveAssetDeposited(expected_assets.clone()), ClearOrigin, SetFeesMode { jit_withdraw: false }, BuyExecution { @@ -423,22 +446,17 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< }, weight_limit: Unlimited, }, - DepositAsset { - assets: Wild(AllCounted(1)), - beneficiary: MultiLocation { - parents: 0, - interior: X1(AccountId32 { - network: None, - id: target_account.clone().into(), - }), - }, - }, + DepositAsset { assets: Wild(AllCounted(1)), beneficiary: expected_beneficiary }, SetTopic([ 220, 188, 144, 32, 213, 83, 111, 175, 44, 210, 111, 19, 90, 165, 191, 112, 140, 247, 192, 124, 42, 17, 153, 141, 114, 34, 189, 20, 83, 69, 237, 173, ]), ]); - assert_matches_pallet_xcm_reserve_transfer_assets_instructions(&mut xcm.clone()); + assert_matches_reserve_asset_deposited_instructions( + &mut xcm.clone(), + &expected_assets, + &expected_beneficiary, + ); let hash = xcm.using_encoded(sp_io::hashing::blake2_256); @@ -499,41 +517,6 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< }) } -fn assert_matches_pallet_xcm_reserve_transfer_assets_instructions( - xcm: &mut Xcm, -) { - let _ = xcm - .0 - .matcher() - .skip_inst_while(|inst| !matches!(inst, ReserveAssetDeposited(..))) - .expect("no instruction ReserveAssetDeposited?") - .match_next_inst(|instr| match instr { - ReserveAssetDeposited(..) => Ok(()), - _ => Err(ProcessMessageError::BadFormat), - }) - .expect("expected instruction ReserveAssetDeposited") - .match_next_inst(|instr| match instr { - ClearOrigin => Ok(()), - _ => Err(ProcessMessageError::BadFormat), - }) - .expect("expected instruction ClearOrigin") - .match_next_inst(|instr| match instr { - SetFeesMode { .. } => Ok(()), - _ => Err(ProcessMessageError::BadFormat), - }) - .expect("expected instruction SetFeesMode") - .match_next_inst(|instr| match instr { - BuyExecution { .. } => Ok(()), - _ => Err(ProcessMessageError::BadFormat), - }) - .expect("expected instruction BuyExecution") - .match_next_inst(|instr| match instr { - DepositAsset { .. } => Ok(()), - _ => Err(ProcessMessageError::BadFormat), - }) - .expect("expected instruction DepositAsset"); -} - pub fn report_bridge_status_from_xcm_bridge_router_works< Runtime, AllPalletsWithoutSystem, From 0bf64e687eb3c987be74c25af2cc391758f9d60b Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 24 Oct 2023 16:43:28 +0300 Subject: [PATCH 41/98] fix AHs tests --- .../runtimes/assets/test-utils/src/test_cases.rs | 13 +++++++++---- .../assets/test-utils/src/test_cases_over_bridge.rs | 10 +++------- 2 files changed, 12 insertions(+), 11 deletions(-) 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 2a32989aae9a..9d15eea49f2d 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -169,7 +169,7 @@ pub fn teleports_for_native_asset_works< id: sp_runtime::AccountId32::new([3; 32]).into(), }) .unwrap(); - dest_beneficiary.reanchor(&dest, Here.into()).unwrap(); + dest_beneficiary.reanchor(&dest, XcmConfig::UniversalLocation::get()).unwrap(); let target_account_balance_before_teleport = >::free_balance(&target_account); @@ -234,7 +234,7 @@ pub fn teleports_for_native_asset_works< id: sp_runtime::AccountId32::new([3; 32]).into(), }) .unwrap(); - dest_beneficiary.reanchor(&dest, Here.into()).unwrap(); + dest_beneficiary.reanchor(&dest, XcmConfig::UniversalLocation::get()).unwrap(); let target_account_balance_before_teleport = >::free_balance(&target_account); @@ -543,7 +543,7 @@ pub fn teleports_for_foreign_assets_works< id: sp_runtime::AccountId32::new([3; 32]).into(), }) .unwrap(); - dest_beneficiary.reanchor(&dest, Here.into()).unwrap(); + dest_beneficiary.reanchor(&dest, XcmConfig::UniversalLocation::get()).unwrap(); let target_account_balance_before_teleport = >::balance( @@ -1448,7 +1448,7 @@ pub fn reserve_transfer_native_asset_to_non_teleport_para_works< id: sp_runtime::AccountId32::new([3; 32]).into(), }) .unwrap(); - dest_beneficiary.reanchor(&dest, Here.into()).unwrap(); + dest_beneficiary.reanchor(&dest, XcmConfig::UniversalLocation::get()).unwrap(); let reserve_account = LocationToAccountId::convert_location(&dest) .expect("Sovereign account for reserves"); @@ -1494,6 +1494,11 @@ pub fn reserve_transfer_native_asset_to_non_teleport_para_works< id: Concrete(native_asset), }; + // TODO: Get this fee via weighing the corresponding message + let delivery_fees = 31010000000; + >::mint_into(&alice_account, delivery_fees.into()) + .unwrap(); + // pallet_xcm call reserve transfer assert_ok!(>::limited_reserve_transfer_assets( RuntimeHelper::::origin_of(alice_account.clone()), diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs index 1eed91a64a4a..547d4dfcec7c 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs @@ -22,7 +22,7 @@ use cumulus_primitives_core::XcmpMessageSource; use frame_support::{ assert_ok, traits::{ - fungible::Mutate, Currency, OnFinalize, OnInitialize, OriginTrait, ProcessMessageError, + fungible::Mutate, Currency, Get, OnFinalize, OnInitialize, OriginTrait, ProcessMessageError, }, }; use frame_system::pallet_prelude::BlockNumberFor; @@ -176,14 +176,10 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< let assets_to_transfer = MultiAssets::from(asset_to_transfer); let mut expected_assets = assets_to_transfer.clone(); + let context = XcmConfig::UniversalLocation::get(); expected_assets - .reanchor(&target_location_from_different_consensus, Here.into()) + .reanchor(&target_location_from_different_consensus, context) .unwrap(); - // FIXME: remove this hardcode here when fixing reanchor over bridge - expected_assets = MultiAssets::from(MultiAsset { - id: Concrete(MultiLocation { parents: 2, interior: X1(GlobalConsensus(Rococo)) }), - fun: Fungible(1000000000000), - }); let expected_beneficiary = target_destination_account; // do pallet_xcm call reserve transfer From c71196166e422a6d12e0d00ffd40ba859482b29e Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 24 Oct 2023 16:58:24 +0300 Subject: [PATCH 42/98] AHs: fix emulated tests --- .../src/tests/reserve_transfer.rs | 2 +- .../asset-hub-rococo/src/tests/teleport.rs | 12 ++--- .../src/tests/reserve_transfer.rs | 10 ++-- .../asset-hub-westend/src/tests/teleport.rs | 12 ++--- .../emulated/common/src/macros.rs | 2 +- .../assets/test-utils/src/test_cases.rs | 4 +- .../assets/test-utils/src/xcm_helpers.rs | 50 ++++++++++++++++--- 7 files changed, 62 insertions(+), 30 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index 073c93ec254a..0a55a609ecce 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -176,7 +176,7 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { let sender_balance_after = test.sender.balance; let delivery_fees = AssetHubRococo::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::reserve_transfer_localreserve_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/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs index 4b2ea0e160cb..e74e97dc3391 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs @@ -174,7 +174,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) }); @@ -221,7 +221,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) }); @@ -262,7 +262,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) }); @@ -295,7 +295,7 @@ fn 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) }); @@ -342,7 +342,7 @@ fn 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) }); @@ -380,7 +380,7 @@ fn teleport_native_assets_from_system_para_to_relay_fails() { test.assert(); 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) }); diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs index c7a25dde78d3..bc18daf35eb7 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -175,13 +175,9 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { let sender_balance_after = test.sender.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, - ) + xcm_helpers::reserve_transfer_localreserve_assets_delivery_fees::< + ::XcmSender, + >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs index 4fe0062dafcd..7423f6f60eb1 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs @@ -176,7 +176,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) }); @@ -223,7 +223,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) }); @@ -264,7 +264,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) }); @@ -297,7 +297,7 @@ fn 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) }); @@ -341,7 +341,7 @@ fn teleport_native_assets_back_from_system_para_to_relay_works() { test.assert(); 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) }); @@ -382,7 +382,7 @@ fn teleport_native_assets_from_system_para_to_relay_fails() { test.assert(); 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) }); diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs index a65b2057afda..52780a5c4a75 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs @@ -90,7 +90,7 @@ macro_rules! test_parachain_is_trusted_teleporter { let para_receiver_balance_after = <$receiver_para as $crate::Chain>::account_data_of(receiver.clone()).free; let delivery_fees = <$sender_para>::execute_with(|| { - asset_test_utils::xcm_helpers::transfer_assets_delivery_fees::< + 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/runtimes/assets/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs index 9d15eea49f2d..31f235db0edb 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -181,7 +181,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, native_asset_to_teleport_away.into()).into(), 0, Unlimited, @@ -560,7 +560,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_multilocation, 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 0aebe38fef53..ca92c469df80 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. -/// 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( +/// Returns the delivery fees amount for pallet xcm's `teleport_assets` extrinsic. +/// Because it returns only a `u128`, it assumes delivery fees are only paid in one asset and that +/// asset is known. +pub fn teleport_assets_delivery_fees( assets: MultiAssets, fee_asset_item: u32, weight_limit: WeightLimit, @@ -33,6 +32,25 @@ pub fn transfer_assets_delivery_fees( get_fungible_delivery_fees::(destination, message) } +/// Returns the delivery fees amount for pallet xcm's `reserve_transfer_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 reserve_transfer_localreserve_assets_delivery_fees( + assets: MultiAssets, + fee_asset_item: u32, + weight_limit: WeightLimit, + beneficiary: MultiLocation, + destination: MultiLocation, +) -> u128 { + let message = reserve_transfer_localreserve_assets_dummy_message( + assets, + fee_asset_item, + weight_limit, + beneficiary, + ); + get_fungible_delivery_fees::(destination, message) +} + /// Returns the delivery fees amount for a query response as a result of the execution /// of a `ExpectError` instruction with no error. pub fn query_response_delivery_fees(querier: MultiLocation) -> u128 { @@ -76,7 +94,6 @@ pub fn pay_over_xcm_delivery_fees( /// Approximates the actual message sent by the teleport extrinsic. /// The assets are not reanchored and the topic is a dummy one. /// However, it should have the same encoded size, which is what matters for delivery fees. -/// Also has same encoded size as the one created by the reserve transfer assets extrinsic. fn teleport_assets_dummy_message( assets: MultiAssets, fee_asset_item: u32, @@ -84,8 +101,27 @@ fn teleport_assets_dummy_message( beneficiary: MultiLocation, ) -> Xcm<()> { Xcm(vec![ - ReceiveTeleportedAsset(assets.clone()), // Same encoded size as `ReserveAssetDeposited` + ReceiveTeleportedAsset(assets.clone()), + ClearOrigin, + BuyExecution { fees: assets.get(fee_asset_item as usize).unwrap().clone(), weight_limit }, + DepositAsset { assets: Wild(AllCounted(assets.len() as u32)), beneficiary }, + SetTopic([0u8; 32]), // Dummy topic + ]) +} + +/// Approximates the actual message sent by the reserve-transfer of local reserve asset extrinsic. +/// The assets are not reanchored and the topic is a dummy one. +/// However, it should have the same encoded size, which is what matters for delivery fees. +fn reserve_transfer_localreserve_assets_dummy_message( + assets: MultiAssets, + fee_asset_item: u32, + weight_limit: WeightLimit, + beneficiary: MultiLocation, +) -> Xcm<()> { + Xcm(vec![ + ReserveAssetDeposited(assets.clone()), ClearOrigin, + SetFeesMode { jit_withdraw: false }, BuyExecution { fees: assets.get(fee_asset_item as usize).unwrap().clone(), weight_limit }, DepositAsset { assets: Wild(AllCounted(assets.len() as u32)), beneficiary }, SetTopic([0u8; 32]), // Dummy topic From 67929a54ea86b32bcba7b9ef44843a179c42156d Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 24 Oct 2023 18:32:28 +0300 Subject: [PATCH 43/98] AHs: include delivery-fee checking in tests --- .../assets/asset-hub-rococo/tests/tests.rs | 29 +++++++++++ .../runtimes/assets/test-utils/src/lib.rs | 15 ++++++ .../assets/test-utils/src/test_cases.rs | 51 ++++++++++--------- 3 files changed, 71 insertions(+), 24 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs index 2fffd63316bf..49fae83d5091 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -810,6 +810,35 @@ mod asset_hub_rococo_tests { actual ); } + + #[test] + fn reserve_transfer_native_asset_to_non_teleport_para_works() { + asset_test_utils::test_cases::reserve_transfer_native_asset_to_non_teleport_para_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + ParachainSystem, + XcmpQueue, + LocationToAccountId, + >( + collator_session_keys(), + ExistentialDeposit::get(), + AccountId::from(ALICE), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event), + _ => None, + } + }), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), + _ => None, + } + }), + WeightLimit::Unlimited, + ); + } } mod asset_hub_wococo_tests { diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs b/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs index 019287cd1bf8..2a1e72dc002f 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs @@ -27,6 +27,21 @@ use std::fmt::Debug; use xcm::latest::prelude::*; use xcm_builder::{CreateMatcher, MatchXcm}; +/// Given a message, a sender, and a destination, it returns the delivery fees +fn get_fungible_delivery_fees(destination: MultiLocation, message: Xcm<()>) -> u128 { + let Ok((_, delivery_fees)) = validate_send::(destination, message) else { + unreachable!("message can be sent; qed") + }; + if let Some(delivery_fee) = delivery_fees.inner().first() { + let Fungible(delivery_fee_amount) = delivery_fee.fun else { + unreachable!("asset is fungible; qed"); + }; + delivery_fee_amount + } else { + 0 + } +} + /// Helper function to verify `xcm` contains all relevant instructions expected on destination /// chain as part of a reserve-asset-transfer. pub(crate) fn assert_matches_reserve_asset_deposited_instructions( 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 31f235db0edb..2fab95832fe4 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -16,7 +16,7 @@ //! Module contains predefined test-case scenarios for `Runtime` with various assets. use super::xcm_helpers; -use crate::assert_matches_reserve_asset_deposited_instructions; +use crate::{assert_matches_reserve_asset_deposited_instructions, get_fungible_delivery_fees}; use codec::Encode; use cumulus_primitives_core::XcmpMessageSource; use frame_support::{ @@ -1462,9 +1462,14 @@ pub fn reserve_transfer_native_asset_to_non_teleport_para_works< &alice, ); - // drip ED to account - let alice_account_init_balance = - existential_deposit.saturating_mul(2.into()) + balance_to_transfer.into(); + // we calculate exact delivery fees _after_ sending the message by weighing the sent + // xcm, and this delivery fee varies for different runtimes, so just add enough buffer, + // then verify the arithmetics check out on final balance. + let delivery_fees_buffer = 40_000_000_000u128; + // drip 2xED + transfer_amount + delivery_fees_buffer to Alice account + let alice_account_init_balance = existential_deposit.saturating_mul(2.into()) + + balance_to_transfer.into() + + delivery_fees_buffer.into(); let _ = >::deposit_creating( &alice_account, alice_account_init_balance, @@ -1494,15 +1499,10 @@ pub fn reserve_transfer_native_asset_to_non_teleport_para_works< id: Concrete(native_asset), }; - // TODO: Get this fee via weighing the corresponding message - let delivery_fees = 31010000000; - >::mint_into(&alice_account, delivery_fees.into()) - .unwrap(); - // pallet_xcm call reserve transfer assert_ok!(>::limited_reserve_transfer_assets( RuntimeHelper::::origin_of(alice_account.clone()), - Box::new(dest.into_versioned()), + Box::new(dest.clone().into_versioned()), Box::new(dest_beneficiary.into_versioned()), Box::new(VersionedMultiAssets::from(MultiAssets::from(asset_to_transfer))), 0, @@ -1518,20 +1518,6 @@ pub fn reserve_transfer_native_asset_to_non_teleport_para_works< }, ); - // check alice account decreased by balance_to_transfer - // TODO:check-parameter: change and assert in tests when (https://github.com/paritytech/polkadot/pull/7005) merged - assert_eq!( - >::free_balance(&alice_account), - alice_account_init_balance - balance_to_transfer.into() - ); - - // check reserve account - // check reserve account increased by balance_to_transfer - assert_eq!( - >::free_balance(&reserve_account), - existential_deposit + balance_to_transfer.into() - ); - // check that xcm was sent let xcm_sent_message_hash = >::events() .into_iter() @@ -1548,6 +1534,10 @@ pub fn reserve_transfer_native_asset_to_non_teleport_para_works< ) .unwrap(); + let delivery_fees = get_fungible_delivery_fees::< + ::XcmSender, + >(dest, Xcm::try_from(xcm_sent.clone()).unwrap()); + assert_eq!( xcm_sent_message_hash, Some(xcm_sent.using_encoded(sp_io::hashing::blake2_256)) @@ -1566,5 +1556,18 @@ pub fn reserve_transfer_native_asset_to_non_teleport_para_works< &reserve_assets_deposited, &dest_beneficiary, ); + + // check alice account decreased by balance_to_transfer ( + delivery_fees) + assert_eq!( + >::free_balance(&alice_account), + alice_account_init_balance - balance_to_transfer.into() - delivery_fees.into() + ); + + // check reserve account + // check reserve account increased by balance_to_transfer + assert_eq!( + >::free_balance(&reserve_account), + existential_deposit + balance_to_transfer.into() + ); }) } From dd46f23d2f6d7c1ede65a01b1a44c8fdf30b2624 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 24 Oct 2023 18:38:36 +0300 Subject: [PATCH 44/98] fix runtime-benchmarks for AHRococo --- .../assets/asset-hub-rococo/src/xcm_config.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index ae4a275d43ac..e76417ba309a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -653,6 +653,16 @@ pub type XcmRouter = WithUniqueTopic<( #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parent.into()); + // Relay/native token can be teleported between AH and Relay. + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + Parent.into(), + )); + // We can reserve transfer some local token to Relay. + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Here.into()) }.into(), + Parent.into(), + )); } impl pallet_xcm::Config for Runtime { @@ -691,11 +701,15 @@ impl pallet_xcm::Config for Runtime { type SovereignAccountOf = LocationToAccountId; type MaxLockers = ConstU32<8>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + #[cfg(feature = "runtime-benchmarks")] + type TeleportableAssets = TeleportableAssets; + #[cfg(feature = "runtime-benchmarks")] + type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { From e8cbcb954782db95a918a8c8bbb6d0682b5c29bd Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 24 Oct 2023 18:51:39 +0300 Subject: [PATCH 45/98] fix clippy --- cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 2fab95832fe4..97f68269c81a 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -1502,7 +1502,7 @@ pub fn reserve_transfer_native_asset_to_non_teleport_para_works< // pallet_xcm call reserve transfer assert_ok!(>::limited_reserve_transfer_assets( RuntimeHelper::::origin_of(alice_account.clone()), - Box::new(dest.clone().into_versioned()), + Box::new(dest.into_versioned()), Box::new(dest_beneficiary.into_versioned()), Box::new(VersionedMultiAssets::from(MultiAssets::from(asset_to_transfer))), 0, From d725103702fc8f76405b507185f7b1ae7d9bfece Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 25 Oct 2023 13:39:49 +0300 Subject: [PATCH 46/98] withdraw fees before buyexecution - still broken because of executor appended ClearOrigin --- polkadot/xcm/pallet-xcm/src/lib.rs | 58 +++++++++++-------- .../pallet-xcm/src/tests/assets_transfer.rs | 21 +++---- 2 files changed, 41 insertions(+), 38 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 257c46746ad2..3b066f3df83a 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1288,21 +1288,20 @@ impl Pallet { Self::validate_assets_and_find_reserve(&assets, &dest)? }; - let jit_withdraw_fee_on_dest; + let explicit_withdraw_fee_on_dest; if fees_transfer_type == assets_transfer_type { // Same reserve location (fees not teleportable), we can batch together fees and assets // in same reserve-based-transfer. assets.push(fees.clone()); - // no need to jit withdraw fee, fees batched with assets will be available in holding - jit_withdraw_fee_on_dest = false; + // no need to withdraw fee on dest, fees batched with assets will be available in + // holding + explicit_withdraw_fee_on_dest = false; } 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. - if let TransferType::RemoteReserve(_) = assets_transfer_type {} - // Disallow (for now) different _remote_ reserves for assets and fees. match (&fees_transfer_type, &assets_transfer_type) { (TransferType::RemoteReserve(_), _) | (_, TransferType::RemoteReserve(_)) => return Err(Error::::InvalidAssetUnsupportedReserve.into()), @@ -1322,8 +1321,8 @@ impl Pallet { weight_limit.clone(), )?; // fees are deposited to beneficiary in call above, when transferring rest of assets, - // jit withdraw fee on destination - jit_withdraw_fee_on_dest = true; + // withdraw fee to holding on destination so it can be used for `BuyExecution` + explicit_withdraw_fee_on_dest = true; }; // Fees have been prefunded/transferred (or batched together with assets to be transferred @@ -1335,7 +1334,7 @@ impl Pallet { assets, assets_transfer_type, fees, - jit_withdraw_fee_on_dest, + explicit_withdraw_fee_on_dest, weight_limit, ) } @@ -1385,7 +1384,7 @@ impl Pallet { assets: Vec, transfer_type: TransferType, fees: MultiAsset, - jit_withdraw_fee_on_dest: bool, + explicit_withdraw_fee_on_dest: bool, weight_limit: WeightLimit, ) -> DispatchResult { let mut message = match transfer_type { @@ -1394,7 +1393,7 @@ impl Pallet { beneficiary, assets, fees, - jit_withdraw_fee_on_dest, + explicit_withdraw_fee_on_dest, weight_limit, ), TransferType::DestinationReserve => Self::destination_reserve_transfer_message( @@ -1402,7 +1401,7 @@ impl Pallet { beneficiary, assets, fees, - jit_withdraw_fee_on_dest, + explicit_withdraw_fee_on_dest, weight_limit, ), TransferType::RemoteReserve(reserve) => Self::remote_reserve_transfer_message( @@ -1429,17 +1428,21 @@ impl Pallet { beneficiary: MultiLocation, assets: Vec, mut fees: MultiAsset, - jit_withdraw_fee_on_dest: bool, + explicit_withdraw_fee_on_dest: bool, weight_limit: WeightLimit, ) -> Result::RuntimeCall>, Error> { let context = T::UniversalLocation::get(); fees.reanchor(&dest, context).map_err(|_| Error::::CannotReanchor)?; - let max_assets = assets.len() as u32; - let xcm_on_dest = Xcm(vec![ - SetFeesMode { jit_withdraw: jit_withdraw_fee_on_dest }, - BuyExecution { fees, weight_limit }, - DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, - ]); + let mut max_assets = assets.len() as u32; + let mut xcm_on_dest = Vec::with_capacity(3); + if explicit_withdraw_fee_on_dest { + // also deposit `fees` which are not included in `assets` + max_assets += 1; + xcm_on_dest.push(WithdrawAsset(fees.clone().into())); + }; + xcm_on_dest.push(BuyExecution { fees, weight_limit }); + xcm_on_dest.push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }); + let xcm_on_dest = Xcm(xcm_on_dest); Ok(Xcm(vec![ SetFeesMode { jit_withdraw: true }, TransferReserveAsset { assets: assets.into(), dest, xcm: xcm_on_dest }, @@ -1451,17 +1454,22 @@ impl Pallet { beneficiary: MultiLocation, assets: Vec, mut fees: MultiAsset, - jit_withdraw_fee_on_dest: bool, + explicit_withdraw_fee_on_dest: bool, weight_limit: WeightLimit, ) -> Result::RuntimeCall>, Error> { let context = T::UniversalLocation::get(); fees.reanchor(&dest, context).map_err(|_| Error::::CannotReanchor)?; - let max_assets = assets.len() as u32; - let xcm_on_dest = Xcm(vec![ - SetFeesMode { jit_withdraw: jit_withdraw_fee_on_dest }, - BuyExecution { fees, weight_limit }, - DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, - ]); + let mut max_assets = assets.len() as u32; + + let mut xcm_on_dest = Vec::with_capacity(3); + if explicit_withdraw_fee_on_dest { + // also deposit `fees` which are not included in `assets` + max_assets += 1; + xcm_on_dest.push(WithdrawAsset(fees.clone().into())); + }; + xcm_on_dest.push(BuyExecution { fees, weight_limit }); + xcm_on_dest.push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }); + let xcm_on_dest = Xcm(xcm_on_dest); Ok(Xcm(vec![ WithdrawAsset(assets.into()), InitiateReserveWithdraw { diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index 2e90b6efccbf..44e41d641447 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -171,7 +171,6 @@ fn reserve_transfer_assets_with_paid_router_works() { Xcm(vec![ ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), ClearOrigin, - SetFeesMode { jit_withdraw: false }, buy_execution((Parent, SEND_AMOUNT)), DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, ]), @@ -290,7 +289,6 @@ fn do_test_and_verify_reserve_transfer_assets_local_ar_local_fr( Xcm(vec![ ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), ClearOrigin, - SetFeesMode { jit_withdraw: false }, buy_limited_execution((Parent, SEND_AMOUNT), expected_weight_limit), DepositAsset { assets: AllCounted(1).into(), @@ -460,7 +458,6 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ Xcm(vec![ ReserveAssetDeposited((Parent, FEE_AMOUNT).into()), ClearOrigin, - SetFeesMode { jit_withdraw: false }, buy_limited_execution((Parent, FEE_AMOUNT), Unlimited), DepositAsset { assets: AllCounted(1).into(), beneficiary }, ]) @@ -473,9 +470,9 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ Xcm(vec![ WithdrawAsset(expected_asset.into()), ClearOrigin, - SetFeesMode { jit_withdraw: true }, + WithdrawAsset(expected_fee.clone().into()), buy_limited_execution(expected_fee, Unlimited), - DepositAsset { assets: AllCounted(1).into(), beneficiary }, + DepositAsset { assets: AllCounted(2).into(), beneficiary }, ]) ) ] @@ -638,7 +635,6 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ Xcm(vec![ WithdrawAsset(expected_fee.clone().into()), ClearOrigin, - SetFeesMode { jit_withdraw: false }, buy_limited_execution(expected_fee.clone(), Unlimited), DepositAsset { assets: AllCounted(1).into(), beneficiary }, ]) @@ -652,9 +648,9 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ Xcm(vec![ ReserveAssetDeposited(expected_asset.into()), ClearOrigin, - SetFeesMode { jit_withdraw: true }, + WithdrawAsset(expected_fee.clone().into()), buy_limited_execution(expected_fee, Unlimited), - DepositAsset { assets: AllCounted(1).into(), beneficiary }, + DepositAsset { assets: AllCounted(2).into(), beneficiary }, ]) ) ] @@ -741,7 +737,6 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re Xcm(vec![ WithdrawAsset(expected_assets.clone()), ClearOrigin, - SetFeesMode { jit_withdraw: false }, buy_limited_execution(expected_assets.get(0).unwrap().clone(), Unlimited), DepositAsset { assets: AllCounted(1).into(), beneficiary }, ]), @@ -1172,9 +1167,9 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { Xcm(vec![ ReserveAssetDeposited(expected_asset.into()), ClearOrigin, - SetFeesMode { jit_withdraw: true }, + WithdrawAsset(expected_fee.clone().into()), buy_limited_execution(expected_fee, Unlimited), - DepositAsset { assets: AllCounted(1).into(), beneficiary }, + DepositAsset { assets: AllCounted(2).into(), beneficiary }, ]) ) ] @@ -1303,9 +1298,9 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_wor Xcm(vec![ WithdrawAsset(expected_asset.into()), ClearOrigin, - SetFeesMode { jit_withdraw: true }, + WithdrawAsset(expected_fee.clone().into()), buy_limited_execution(expected_fee, Unlimited), - DepositAsset { assets: AllCounted(1).into(), beneficiary }, + DepositAsset { assets: AllCounted(2).into(), beneficiary }, ]) ) ] From 3d97f19e679735daa6e5c2c9b27960e624270b81 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 25 Oct 2023 14:19:31 +0300 Subject: [PATCH 47/98] pallet-xcm: uses single custom XCM to send both fees and assets --- polkadot/xcm/pallet-xcm/src/lib.rs | 346 ++++++++++++++++++++--------- 1 file changed, 246 insertions(+), 100 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 3b066f3df83a..f2d5779019ed 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1288,41 +1288,32 @@ impl Pallet { Self::validate_assets_and_find_reserve(&assets, &dest)? }; - let explicit_withdraw_fee_on_dest; + let prefund_fees_messages: Option<(Xcm<::RuntimeCall>, Xcm<()>)>; if fees_transfer_type == assets_transfer_type { // Same reserve location (fees not teleportable), we can batch together fees and assets // in same reserve-based-transfer. assets.push(fees.clone()); - // no need to withdraw fee on dest, fees batched with assets will be available in - // holding - explicit_withdraw_fee_on_dest = false; + // no need for custom prefund messages, fees are batched with assets + prefund_fees_messages = None; } 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. - match (&fees_transfer_type, &assets_transfer_type) { - (TransferType::RemoteReserve(_), _) | (_, TransferType::RemoteReserve(_)) => + if let TransferType::RemoteReserve(_) = assets_transfer_type { + return Err(Error::::InvalidAssetUnsupportedReserve.into()) + } + // build fees transfer instructions to be added to assets transfers XCM programs + prefund_fees_messages = Some(match fees_transfer_type { + TransferType::LocalReserve => + Self::prefund_local_reserve_fees_messages(dest, fees.clone())?, + TransferType::DestinationReserve => + Self::prefund_destination_reserve_fees_messages(dest, fees.clone())?, + TransferType::Teleport => Self::prefund_teleport_fees_messages(dest, fees.clone())?, + TransferType::RemoteReserve(_) => return Err(Error::::InvalidAssetUnsupportedReserve.into()), - _ => (), - }; - - // execute fees transfer - do it in a separate asset transfer call to keep code logic - // simple: first send over fees, then assets with `jit_withdraw=true` - Self::build_and_execute_xcm_transfer_type( - origin_location, - dest, - beneficiary, - vec![fees.clone()], - fees_transfer_type, - fees.clone(), - false, - weight_limit.clone(), - )?; - // fees are deposited to beneficiary in call above, when transferring rest of assets, - // withdraw fee to holding on destination so it can be used for `BuyExecution` - explicit_withdraw_fee_on_dest = true; + }); }; // Fees have been prefunded/transferred (or batched together with assets to be transferred @@ -1334,7 +1325,7 @@ impl Pallet { assets, assets_transfer_type, fees, - explicit_withdraw_fee_on_dest, + prefund_fees_messages, weight_limit, ) } @@ -1372,114 +1363,242 @@ impl Pallet { assets, TransferType::Teleport, fees, - false, + None, weight_limit, ) } fn build_and_execute_xcm_transfer_type( - origin: impl Into, + origin: MultiLocation, dest: MultiLocation, beneficiary: MultiLocation, assets: Vec, transfer_type: TransferType, fees: MultiAsset, - explicit_withdraw_fee_on_dest: bool, + prefund_fees_messages: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, weight_limit: WeightLimit, ) -> DispatchResult { - let mut message = match transfer_type { - TransferType::LocalReserve => Self::local_reserve_transfer_message( - dest, - beneficiary, - assets, - fees, - explicit_withdraw_fee_on_dest, - weight_limit, - ), - TransferType::DestinationReserve => Self::destination_reserve_transfer_message( - dest, - beneficiary, - assets, - fees, - explicit_withdraw_fee_on_dest, - weight_limit, - ), - TransferType::RemoteReserve(reserve) => Self::remote_reserve_transfer_message( - reserve, - dest, - beneficiary, - assets, - fees, - weight_limit, + let (mut local_xcm, remote_xcm) = match transfer_type { + TransferType::LocalReserve => { + let (local, remote) = Self::local_reserve_transfer_messages( + dest, + beneficiary, + assets, + fees, + prefund_fees_messages, + weight_limit, + )?; + (local, Some(remote)) + }, + TransferType::DestinationReserve => { + let (local, remote) = Self::destination_reserve_transfer_messages( + dest, + beneficiary, + assets, + fees, + prefund_fees_messages, + weight_limit, + )?; + (local, Some(remote)) + }, + TransferType::RemoteReserve(reserve) => ( + Self::remote_reserve_transfer_message( + reserve, + dest, + beneficiary, + assets, + fees, + weight_limit, + )?, + None, ), TransferType::Teleport => - Self::teleport_asset_message(dest, beneficiary, assets, fees, weight_limit), - }?; + (Self::teleport_asset_message(dest, beneficiary, assets, fees, weight_limit)?, None), + }; let weight = - T::Weigher::weight(&mut message).map_err(|()| Error::::UnweighableMessage)?; - let hash = message.using_encoded(sp_io::hashing::blake2_256); - let outcome = T::XcmExecutor::execute_xcm_in_credit(origin, message, hash, weight, weight); - Self::deposit_event(Event::Attempted { outcome }); + T::Weigher::weight(&mut local_xcm).map_err(|()| Error::::UnweighableMessage)?; + let hash = local_xcm.using_encoded(sp_io::hashing::blake2_256); + let outcome = + T::XcmExecutor::execute_xcm_in_credit(origin, local_xcm, hash, weight, weight); + Self::deposit_event(Event::Attempted { outcome: outcome.clone() }); + if let Some(remote_xcm) = remote_xcm { + outcome.ensure_complete().map_err(|_| Error::::FeesNotMet)?; + let interior: Junctions = origin.try_into().map_err(|_| Error::::InvalidOrigin)?; + let message_id = + Self::send_xcm(interior, dest, remote_xcm.clone()).map_err(Error::::from)?; + let e = Event::Sent { origin, destination: dest, message: remote_xcm, message_id }; + Self::deposit_event(e); + } Ok(()) } - fn local_reserve_transfer_message( + fn prefund_local_reserve_fees_messages( + dest: MultiLocation, + fees: MultiAsset, + ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { + let context = T::UniversalLocation::get(); + let reanchored_fees = fees + .clone() + .reanchored(&dest, context) + .map_err(|_| Error::::CannotReanchor)?; + + let local_execute_xcm = Xcm(vec![ + // move `fees` to `dest`s local sovereign account + TransferAsset { assets: fees.into(), beneficiary: dest }, + ]); + let xcm_on_dest = Xcm(vec![ + // let (dest) chain know `fees` are in its SA on reserve + ReserveAssetDeposited(reanchored_fees.into()), + ]); + Ok((local_execute_xcm, xcm_on_dest)) + } + + fn local_reserve_transfer_messages( dest: MultiLocation, beneficiary: MultiLocation, assets: Vec, - mut fees: MultiAsset, - explicit_withdraw_fee_on_dest: bool, + fees: MultiAsset, + prefund_fees_messages: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, weight_limit: WeightLimit, - ) -> Result::RuntimeCall>, Error> { + ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { + // max assets is `assets` ( + potentially separately handled fee) + let max_assets = + assets.len() as u32 + prefund_fees_messages.as_ref().map(|_| 1).unwrap_or(0); + let assets: MultiAssets = assets.into(); let context = T::UniversalLocation::get(); - fees.reanchor(&dest, context).map_err(|_| Error::::CannotReanchor)?; - let mut max_assets = assets.len() as u32; - let mut xcm_on_dest = Vec::with_capacity(3); - if explicit_withdraw_fee_on_dest { - // also deposit `fees` which are not included in `assets` - max_assets += 1; - xcm_on_dest.push(WithdrawAsset(fees.clone().into())); - }; - xcm_on_dest.push(BuyExecution { fees, weight_limit }); - xcm_on_dest.push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }); - let xcm_on_dest = Xcm(xcm_on_dest); - Ok(Xcm(vec![ - SetFeesMode { jit_withdraw: true }, - TransferReserveAsset { assets: assets.into(), dest, xcm: xcm_on_dest }, - ])) + let reanchored_fees = + fees.reanchored(&dest, context).map_err(|_| Error::::CannotReanchor)?; + let mut reanchored_assets = assets.clone(); + reanchored_assets + .reanchor(&dest, context) + .map_err(|_| Error::::CannotReanchor)?; + + let (prefund_local_xcm, prefund_remote_xcm) = prefund_fees_messages + .map(|(local, remote)| (local.into_inner(), remote.into_inner())) + .unwrap_or_default(); + + let local_execute_xcm = Xcm( + // JIT withdraw fees for local execution + [SetFeesMode { jit_withdraw: true }] + .into_iter() + // run any necessary local prefund fees instructions + .chain(prefund_local_xcm.into_iter()) + // move `assets` to `dest`s local sovereign account + .chain([TransferAsset { assets, beneficiary: dest }].into_iter()) + .collect(), + ); + let xcm_on_dest = Xcm( + // run any necessary remote prefund fees instructions + prefund_remote_xcm + .into_iter() + .chain( + [ + // let (dest) chain know assets are in its SA on reserve + ReserveAssetDeposited(reanchored_assets), + // following instructions are not exec'ed on behalf of origin chain anymore + ClearOrigin, + // buy exec using `fees` in holding deposited in top instruction here + BuyExecution { fees: reanchored_fees, weight_limit }, + // deposit all assets in holding to `beneficiary` account(s) + DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, + ] + .into_iter(), + ) + .collect(), + ); + Ok((local_execute_xcm, xcm_on_dest)) } - fn destination_reserve_transfer_message( + fn prefund_destination_reserve_fees_messages( + dest: MultiLocation, + fees: MultiAsset, + ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { + let context = T::UniversalLocation::get(); + let reanchored_fees = fees + .clone() + .reanchored(&dest, context) + .map_err(|_| Error::::CannotReanchor)?; + let fees: MultiAssets = fees.into(); + + let local_execute_xcm = Xcm(vec![ + // withdraw reserve-based fees (derivatives) + WithdrawAsset(fees.clone()), + // burn derivatives + BurnAsset(fees), + ]); + let xcm_on_dest = Xcm(vec![ + // withdraw `fees` from origin chain's sovereign account + WithdrawAsset(reanchored_fees.into()), + ]); + Ok((local_execute_xcm, xcm_on_dest)) + } + + fn destination_reserve_transfer_messages( dest: MultiLocation, beneficiary: MultiLocation, assets: Vec, - mut fees: MultiAsset, - explicit_withdraw_fee_on_dest: bool, + fees: MultiAsset, + prefund_fees_messages: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, weight_limit: WeightLimit, - ) -> Result::RuntimeCall>, Error> { + ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { + // max assets is `assets` ( + potentially separately handled fee) + let max_assets = + assets.len() as u32 + prefund_fees_messages.as_ref().map(|_| 1).unwrap_or(0); + let assets: MultiAssets = assets.into(); let context = T::UniversalLocation::get(); - fees.reanchor(&dest, context).map_err(|_| Error::::CannotReanchor)?; - let mut max_assets = assets.len() as u32; + let reanchored_fees = + fees.reanchored(&dest, context).map_err(|_| Error::::CannotReanchor)?; + let mut reanchored_assets = assets.clone(); + reanchored_assets + .reanchor(&dest, context) + .map_err(|_| Error::::CannotReanchor)?; - let mut xcm_on_dest = Vec::with_capacity(3); - if explicit_withdraw_fee_on_dest { - // also deposit `fees` which are not included in `assets` - max_assets += 1; - xcm_on_dest.push(WithdrawAsset(fees.clone().into())); - }; - xcm_on_dest.push(BuyExecution { fees, weight_limit }); - xcm_on_dest.push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }); - let xcm_on_dest = Xcm(xcm_on_dest); - Ok(Xcm(vec![ - WithdrawAsset(assets.into()), - InitiateReserveWithdraw { - assets: Wild(AllCounted(max_assets)), - reserve: dest, - xcm: xcm_on_dest, - }, - ])) + let (prefund_local_xcm, prefund_remote_xcm) = prefund_fees_messages + .map(|(local, remote)| (local.into_inner(), remote.into_inner())) + // default is empty vec, so no prefund instructions required + .unwrap_or_default(); + + let local_execute_xcm = Xcm( + // JIT withdraw fees for local execution + [SetFeesMode { jit_withdraw: true }] + .into_iter() + // run any necessary local prefund fees instructions + .chain(prefund_local_xcm.into_iter()) + // move `assets` to `dest`s local sovereign account + .chain( + [ + // withdraw reserve-based assets + WithdrawAsset(assets.clone()), + // burn reserve-based assets + BurnAsset(assets), + ] + .into_iter(), + ) + .collect(), + ); + let xcm_on_dest = Xcm( + // run any necessary remote prefund fees instructions + prefund_remote_xcm + .into_iter() + .chain( + [ + // withdraw `assets` from origin chain's sovereign account + WithdrawAsset(reanchored_assets), + // following instructions are not exec'ed on behalf of origin chain anymore + ClearOrigin, + // buy exec using `fees` in holding deposited in top instruction here + BuyExecution { fees: reanchored_fees, weight_limit }, + // deposit all assets in holding to `beneficiary` account(s) + DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, + ] + .into_iter(), + ) + .collect(), + ); + Ok((local_execute_xcm, xcm_on_dest)) } + // function assumes fees and assets have the same remote reserve fn remote_reserve_transfer_message( reserve: MultiLocation, dest: MultiLocation, @@ -1519,6 +1638,33 @@ impl Pallet { ])) } + fn prefund_teleport_fees_messages( + dest: MultiLocation, + fees: MultiAsset, + ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { + let context = T::UniversalLocation::get(); + let reanchored_fees = fees + .clone() + .reanchored(&dest, context) + .map_err(|_| Error::::CannotReanchor)?; + let fees: MultiAssets = fees.into(); + + // FIXME: this should also handle `checking_account` in `XcmExecutor::AssetTransactor` but + // we can't access it here rignt now. + + let local_execute_xcm = Xcm(vec![ + // withdraw fees + WithdrawAsset(fees.clone()), + // burn fees + BurnAsset(fees), + ]); + let xcm_on_dest = Xcm(vec![ + // (dest) chain receive teleported assets burned on origin chain + ReceiveTeleportedAsset(reanchored_fees.into()), + ]); + Ok((local_execute_xcm, xcm_on_dest)) + } + fn teleport_asset_message( dest: MultiLocation, beneficiary: MultiLocation, From ac3773eddc7b4a8b8a5ed56d039f8cab614541d5 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 25 Oct 2023 14:22:06 +0300 Subject: [PATCH 48/98] pallet-xcm: handle teleport checking account when custom burn+teleport --- polkadot/xcm/pallet-xcm/src/lib.rs | 26 ++++++++++++++++--- polkadot/xcm/xcm-executor/src/lib.rs | 1 + .../xcm-executor/src/traits/asset_transfer.rs | 4 +++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index f2d5779019ed..9fd233e37507 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -53,7 +53,7 @@ pub use pallet::*; use xcm_executor::{ traits::{ CheckSuspension, ClaimAssets, ConvertLocation, DropAssets, MatchesFungible, OnResponse, - QueryHandler, QueryResponseStatus, VersionChangeNotifier, WeightBounds, + QueryHandler, QueryResponseStatus, TransactAsset, VersionChangeNotifier, WeightBounds, }, Assets, }; @@ -429,6 +429,8 @@ pub mod pallet { DestinationNotInvertible, /// The assets to be sent are empty. Empty, + /// Could not check-out the assets for teleportation to the destination chain. + CannotCheckOutTeleport, /// Could not re-anchor the assets to declare the fees for the destination chain. CannotReanchor, /// Too many assets have been attempted for transfer. @@ -1647,11 +1649,27 @@ impl Pallet { .clone() .reanchored(&dest, context) .map_err(|_| Error::::CannotReanchor)?; - let fees: MultiAssets = fees.into(); - // FIXME: this should also handle `checking_account` in `XcmExecutor::AssetTransactor` but - // we can't access it here rignt now. + // XcmContext irrelevant in teleports checks + let dummy_context = + XcmContext { origin: None, message_id: Default::default(), topic: None }; + // We should check that the asset can actually be teleported out (for this to + // be in error, there would need to be an accounting violation by ourselves, + // so it's unlikely, but we don't want to allow that kind of bug to leak into + // a trusted chain. + ::AssetTransactor::can_check_out( + &dest, + &fees, + &dummy_context, + ) + .map_err(|_| Error::::CannotCheckOutTeleport)?; + ::AssetTransactor::check_out( + &dest, + &fees, + &dummy_context, + ); + let fees: MultiAssets = fees.into(); let local_execute_xcm = Xcm(vec![ // withdraw fees WithdrawAsset(fees.clone()), diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index d9a1123e00c2..b8e4c53c9889 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -258,6 +258,7 @@ impl ExecuteXcm for XcmExecutor AssetTransferSupport for XcmExecutor { type IsReserve = Config::IsReserve; type IsTeleporter = Config::IsTeleporter; + type AssetTransactor = Config::AssetTransactor; } #[derive(Debug)] diff --git a/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs b/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs index 566b65739224..77b326052dcc 100644 --- a/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs +++ b/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +use crate::traits::TransactAsset; use frame_support::traits::ContainsPair; use scale_info::TypeInfo; use sp_runtime::codec::{Decode, Encode}; @@ -52,6 +53,9 @@ pub trait AssetTransferSupport { /// to be used for assets matching this filter. type IsTeleporter: ContainsPair; + /// How to withdraw and deposit an asset. + type AssetTransactor: TransactAsset; + /// Determine transfer type to be used for transferring `asset` from local chain to `dest`. fn determine_for(asset: &MultiAsset, dest: &MultiLocation) -> Result { if Self::IsTeleporter::contains(asset, dest) { From cb6f53a6fdec12b10d06d543707eab469bd5f490 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 25 Oct 2023 15:50:04 +0300 Subject: [PATCH 49/98] fixes plus tests --- polkadot/xcm/pallet-xcm/src/lib.rs | 27 +-- polkadot/xcm/pallet-xcm/src/mock.rs | 14 +- .../pallet-xcm/src/tests/assets_transfer.rs | 161 +++++++++--------- 3 files changed, 103 insertions(+), 99 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 9fd233e37507..f97b6135d484 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -429,8 +429,6 @@ pub mod pallet { DestinationNotInvertible, /// The assets to be sent are empty. Empty, - /// Could not check-out the assets for teleportation to the destination chain. - CannotCheckOutTeleport, /// Could not re-anchor the assets to declare the fees for the destination chain. CannotReanchor, /// Too many assets have been attempted for transfer. @@ -446,12 +444,8 @@ pub mod pallet { NoSubscription, /// The location is invalid since it already has a subscription from us. AlreadySubscribed, - /// Invalid non-concrete asset. - InvalidAssetNotConcrete, - /// Invalid asset, reserve chain could not be determined for it. - InvalidAssetUnknownReserve, - /// Invalid asset, do not support remote asset reserves with different fees reserves. - InvalidAssetUnsupportedReserve, + /// Could not check-out the assets for teleportation to the destination chain. + CannotCheckOutTeleport, /// The owner does not own (all) of the asset that they wish to do the operation on. LowBalance, /// The asset owner has too many locks on the asset. @@ -464,6 +458,12 @@ pub mod pallet { LockNotFound, /// The unlock operation cannot succeed because there are still consumers of the lock. InUse, + /// Invalid non-concrete asset. + InvalidAssetNotConcrete, + /// Invalid asset, reserve chain could not be determined for it. + InvalidAssetUnknownReserve, + /// Invalid asset, do not support remote asset reserves with different fees reserves. + InvalidAssetUnsupportedReserve, /// Too many assets with different reserve locations have been attempted for transfer. TooManyReserves, } @@ -1425,9 +1425,14 @@ impl Pallet { Self::deposit_event(Event::Attempted { outcome: outcome.clone() }); if let Some(remote_xcm) = remote_xcm { outcome.ensure_complete().map_err(|_| Error::::FeesNotMet)?; - let interior: Junctions = origin.try_into().map_err(|_| Error::::InvalidOrigin)?; - let message_id = - Self::send_xcm(interior, dest, remote_xcm.clone()).map_err(Error::::from)?; + + let (ticket, price) = validate_send::(dest, remote_xcm.clone()) + .map_err(Error::::from)?; + if origin != Here.into_location() { + Self::charge_fees(origin, price).map_err(|_| Error::::FeesNotMet)?; + } + let message_id = T::XcmRouter::deliver(ticket).map_err(Error::::from)?; + let e = Event::Sent { origin, destination: dest, message: remote_xcm, message_id }; Self::deposit_event(e); } diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 7b74322e44ca..8fc980d04b80 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -186,13 +186,13 @@ impl SendXcm for TestSendXcmErrX8 { type Ticket = (MultiLocation, Xcm<()>); fn validate( dest: &mut Option, - msg: &mut Option>, + _: &mut Option>, ) -> SendResult<(MultiLocation, Xcm<()>)> { - let (dest, msg) = (dest.take().unwrap(), msg.take().unwrap()); - if dest.len() == 8 { + if dest.as_ref().unwrap().len() == 8 { + dest.take(); Err(SendError::Transport("Destination location full")) } else { - Ok(((dest, msg), MultiAssets::new())) + Err(SendError::NotApplicable) } } fn deliver(pair: (MultiLocation, Xcm<()>)) -> Result { @@ -439,10 +439,12 @@ pub type Barrier = ( AllowSubscriptionsFrom, ); +pub type XcmRouter = (TestPaidForPara3000SendXcm, TestSendXcmErrX8, TestSendXcm); + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; - type XcmSender = (TestPaidForPara3000SendXcm, TestSendXcm); + type XcmSender = XcmRouter; type AssetTransactor = AssetTransactors; type OriginConverter = LocalOriginConverter; type IsReserve = (Case, Case); @@ -494,7 +496,7 @@ parameter_types! { impl pallet_xcm::Config for Test { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; - type XcmRouter = (TestSendXcmErrX8, TestPaidForPara3000SendXcm, TestSendXcm); + type XcmRouter = XcmRouter; type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; type XcmExecuteFilter = Everything; type XcmExecutor = XcmExecutor; diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index 44e41d641447..2f85fac7f840 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -145,27 +145,26 @@ fn reserve_transfer_assets_with_paid_router_works() { Box::new((Here, SEND_AMOUNT).into()), 0, )); - // check event - assert_eq!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) - ); // XCM_FEES_NOT_WAIVED_USER_ACCOUNT spent amount assert_eq!( Balances::free_balance(user_account), INITIAL_BALANCE - SEND_AMOUNT - xcm_router_fee_amount ); + // Destination account (parachain account) has amount let para_acc: AccountId = ParaId::from(paid_para_id).into_account_truncating(); assert_eq!(Balances::free_balance(para_acc), INITIAL_BALANCE + SEND_AMOUNT); + // XcmFeesTargetAccount where should lend xcm_router_fee_amount assert_eq!( Balances::free_balance(XcmFeesTargetAccount::get()), INITIAL_BALANCE + xcm_router_fee_amount ); + + let sent_xcm = sent_xcm(); assert_eq!( - sent_xcm(), + sent_xcm, vec![( Parachain(paid_para_id).into(), Xcm(vec![ @@ -176,10 +175,34 @@ fn reserve_transfer_assets_with_paid_router_works() { ]), )] ); + let inner_message = sent_xcm.into_iter().next().unwrap().1; + let mut last_events = last_events(5).into_iter(); assert_eq!( - last_event(), + last_events.next().unwrap(), RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) ); + // balances events + last_events.next().unwrap(); + last_events.next().unwrap(); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::FeesPaid { + paying: dest, + fees: Para3000PaymentMultiAssets::get(), + }) + ); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Sent { + origin: dest, + destination: Parachain(paid_para_id).into(), + message: inner_message, + message_id: [ + 55, 64, 13, 96, 90, 32, 133, 17, 152, 138, 167, 156, 159, 194, 154, 181, 130, + 98, 75, 249, 162, 253, 58, 246, 44, 117, 152, 11, 57, 102, 238, 131 + ], + }) + ); }); } @@ -248,8 +271,7 @@ fn into_multiassets_checked( (assets, fee_index, fee_asset, transfer_asset) } -/// Helper function to test `reserve_transfer_assets` with local asset reserve and local fee -/// reserve. +/// Test `limited_reserve_transfer_assets` with local asset reserve and local fee reserve. /// /// Transferring native asset (local reserve) to some `OTHER_PARA_ID` (no teleport trust). /// Using native asset for fees as well. @@ -263,27 +285,39 @@ fn into_multiassets_checked( /// | \--> sends `ReserveAssetDeposited(both), ClearOrigin, BuyExecution(fees), DepositAsset` /// \------------------------------------------> /// ``` -fn do_test_and_verify_reserve_transfer_assets_local_ar_local_fr( - expected_beneficiary: MultiLocation, - call: Call, - expected_weight_limit: WeightLimit, -) { +#[test] +fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserve_works() { let balances = vec![ (ALICE, INITIAL_BALANCE), (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; + + let beneficiary: MultiLocation = + Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let weight_limit = WeightLimit::Limited(Weight::from_parts(5000, 5000)); + let expected_weight_limit = weight_limit.clone(); + let expected_beneficiary = beneficiary; + new_test_ext_with_balances(balances).execute_with(|| { let weight = BaseXcmWeight::get() * 2; assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); // call extrinsic - call(); + assert_ok!(XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(Parachain(OTHER_PARA_ID).into()), + Box::new(beneficiary.into()), + Box::new((Here, SEND_AMOUNT).into()), + 0, + weight_limit, + )); // Alice spent amount assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); // Destination account (parachain account) has amount let para_acc: AccountId = ParaId::from(OTHER_PARA_ID).into_account_truncating(); assert_eq!(Balances::free_balance(para_acc), INITIAL_BALANCE + SEND_AMOUNT); + let sent_xcm = sent_xcm(); assert_eq!( - sent_xcm(), + sent_xcm, vec![( Parachain(OTHER_PARA_ID).into(), Xcm(vec![ @@ -297,71 +331,34 @@ fn do_test_and_verify_reserve_transfer_assets_local_ar_local_fr( ]), )] ); + let inner_message = sent_xcm.into_iter().next().unwrap().1; + let mut last_events = last_events(3).into_iter(); assert_eq!( - last_event(), + last_events.next().unwrap(), RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) ); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::FeesPaid { + paying: expected_beneficiary, + fees: MultiAssets::new(), + }) + ); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Sent { + origin: expected_beneficiary, + destination: Parachain(OTHER_PARA_ID).into(), + message: inner_message, + message_id: [ + 53, 1, 255, 66, 147, 147, 39, 116, 107, 79, 145, 26, 237, 73, 0, 165, 70, 43, + 122, 224, 230, 68, 62, 15, 200, 250, 105, 14, 100, 65, 100, 204 + ], + }) + ); }); } -/// Test `reserve_transfer_assets` with local asset reserve and local fee reserve. -/// -/// Transferring native asset (local reserve) to some `OTHER_PARA_ID` (no teleport trust). -/// Using native asset for fees as well. -/// -/// ```nocompile -/// Here (source) OTHER_PARA_ID (destination) -/// | `assets` reserve -/// | `fees` reserve -/// | -/// | 1. execute `TransferReserveAsset(assets_and_fees_batched_together)` -/// | \--> sends `ReserveAssetDeposited(both), ClearOrigin, BuyExecution(fees), DepositAsset` -/// \------------------------------------------> -/// ``` -#[test] -fn reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserve_works() { - let beneficiary: MultiLocation = - Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - do_test_and_verify_reserve_transfer_assets_local_ar_local_fr( - beneficiary, - || { - assert_ok!(XcmPallet::reserve_transfer_assets( - RuntimeOrigin::signed(ALICE), - Box::new(Parachain(OTHER_PARA_ID).into()), - Box::new(beneficiary.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - )); - }, - Unlimited, - ); -} - -/// Test `limited_reserve_transfer_assets` with local asset reserve and local fee reserve. -/// -/// Same as test above but with limited weight. -#[test] -fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserve_works() { - let beneficiary: MultiLocation = - Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - let weight_limit = WeightLimit::Limited(Weight::from_parts(5000, 5000)); - let expected_weight_limit = weight_limit.clone(); - do_test_and_verify_reserve_transfer_assets_local_ar_local_fr( - beneficiary, - || { - assert_ok!(XcmPallet::limited_reserve_transfer_assets( - RuntimeOrigin::signed(ALICE), - Box::new(Parachain(OTHER_PARA_ID).into()), - Box::new(beneficiary.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - weight_limit, - )); - }, - expected_weight_limit, - ); -} - /// Test `reserve_transfer_assets` with destination asset reserve and local fee reserve. /// /// Transferring foreign asset (`FOREIGN_ASSET_RESERVE_PARA_ID` reserve) to @@ -527,7 +524,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_disal result, Err(DispatchError::Module(ModuleError { index: 4, - error: [15, 0, 0, 0], + error: [22, 0, 0, 0], message: Some("InvalidAssetUnsupportedReserve") })) ); @@ -803,7 +800,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve result, Err(DispatchError::Module(ModuleError { index: 4, - error: [15, 0, 0, 0], + error: [22, 0, 0, 0], message: Some("InvalidAssetUnsupportedReserve") })) ); @@ -868,7 +865,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_disal result, Err(DispatchError::Module(ModuleError { index: 4, - error: [15, 0, 0, 0], + error: [22, 0, 0, 0], message: Some("InvalidAssetUnsupportedReserve") })) ); @@ -890,7 +887,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_disal /// Transferring native asset (local reserve) to `OTHER_PARA_ID` (no teleport trust). Using foreign /// asset (`USDC_RESERVE_PARA_ID` remote reserve) for fees. #[test] -fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve_works() { +fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve_disallowed() { let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); @@ -942,7 +939,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve result, Err(DispatchError::Module(ModuleError { index: 4, - error: [15, 0, 0, 0], + error: [22, 0, 0, 0], message: Some("InvalidAssetUnsupportedReserve") })) ); @@ -1313,7 +1310,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_wor /// Transferring foreign asset (reserve on `FOREIGN_ASSET_RESERVE_PARA_ID`) to `USDT_PARA_ID`. /// Using teleport-trusted USDT for fees. #[test] -fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_works() { +fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_disallowed() { let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); @@ -1359,7 +1356,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_works() result, Err(DispatchError::Module(ModuleError { index: 4, - error: [15, 0, 0, 0], + error: [22, 0, 0, 0], message: Some("InvalidAssetUnsupportedReserve") })) ); From 560d78814291a2738f1ecb3893e7e527983d90f9 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 25 Oct 2023 16:20:59 +0300 Subject: [PATCH 50/98] fix pallet-xcm tests --- .../pallet-xcm/src/tests/assets_transfer.rs | 299 ++++++++---------- 1 file changed, 137 insertions(+), 162 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index 2f85fac7f840..d3df75708213 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -162,11 +162,11 @@ fn reserve_transfer_assets_with_paid_router_works() { INITIAL_BALANCE + xcm_router_fee_amount ); - let sent_xcm = sent_xcm(); + let dest_para: MultiLocation = Parachain(paid_para_id).into(); assert_eq!( - sent_xcm, + sent_xcm(), vec![( - Parachain(paid_para_id).into(), + dest_para, Xcm(vec![ ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), ClearOrigin, @@ -175,7 +175,6 @@ fn reserve_transfer_assets_with_paid_router_works() { ]), )] ); - let inner_message = sent_xcm.into_iter().next().unwrap().1; let mut last_events = last_events(5).into_iter(); assert_eq!( last_events.next().unwrap(), @@ -191,38 +190,13 @@ fn reserve_transfer_assets_with_paid_router_works() { fees: Para3000PaymentMultiAssets::get(), }) ); - assert_eq!( + assert!(matches!( last_events.next().unwrap(), - RuntimeEvent::XcmPallet(crate::Event::Sent { - origin: dest, - destination: Parachain(paid_para_id).into(), - message: inner_message, - message_id: [ - 55, 64, 13, 96, 90, 32, 133, 17, 152, 138, 167, 156, 159, 194, 154, 181, 130, - 98, 75, 249, 162, 253, 58, 246, 44, 117, 152, 11, 57, 102, 238, 131 - ], - }) - ); + RuntimeEvent::XcmPallet(crate::Event::Sent { .. }) + )); }); } -// For reserve-based transfers, we want to support: -// - non-fee assets reserve: -// - local reserve -// - destination reserve -// - remote reserve -// - fee assets: -// - reserve-transferred with reserve: -// - local reserve -// - destination reserve -// - remote reserve -// - teleported -// -// Bringing unique scenarios total to 3*4 = 12. So, following reserve-transfer testz try to cover -// the happy-case for each of these 12 scenarios. -// -// TODO: also add negative testz for testing various error conditions. - fn set_up_foreign_asset( reserve_para_id: u32, inner_junction: Option, @@ -297,6 +271,7 @@ fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserv let weight_limit = WeightLimit::Limited(Weight::from_parts(5000, 5000)); let expected_weight_limit = weight_limit.clone(); let expected_beneficiary = beneficiary; + let dest: MultiLocation = Parachain(OTHER_PARA_ID).into(); new_test_ext_with_balances(balances).execute_with(|| { let weight = BaseXcmWeight::get() * 2; @@ -304,7 +279,7 @@ fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserv // call extrinsic assert_ok!(XcmPallet::limited_reserve_transfer_assets( RuntimeOrigin::signed(ALICE), - Box::new(Parachain(OTHER_PARA_ID).into()), + Box::new(dest.into()), Box::new(beneficiary.into()), Box::new((Here, SEND_AMOUNT).into()), 0, @@ -315,11 +290,10 @@ fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserv // Destination account (parachain account) has amount let para_acc: AccountId = ParaId::from(OTHER_PARA_ID).into_account_truncating(); assert_eq!(Balances::free_balance(para_acc), INITIAL_BALANCE + SEND_AMOUNT); - let sent_xcm = sent_xcm(); assert_eq!( - sent_xcm, + sent_xcm(), vec![( - Parachain(OTHER_PARA_ID).into(), + dest, Xcm(vec![ ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), ClearOrigin, @@ -331,7 +305,6 @@ fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserv ]), )] ); - let inner_message = sent_xcm.into_iter().next().unwrap().1; let mut last_events = last_events(3).into_iter(); assert_eq!( last_events.next().unwrap(), @@ -344,18 +317,10 @@ fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserv fees: MultiAssets::new(), }) ); - assert_eq!( + assert!(matches!( last_events.next().unwrap(), - RuntimeEvent::XcmPallet(crate::Event::Sent { - origin: expected_beneficiary, - destination: Parachain(OTHER_PARA_ID).into(), - message: inner_message, - message_id: [ - 53, 1, 255, 66, 147, 147, 39, 116, 107, 79, 145, 26, 237, 73, 0, 165, 70, 43, - 122, 224, 230, 68, 62, 15, 200, 250, 105, 14, 100, 65, 100, 204 - ], - }) - ); + RuntimeEvent::XcmPallet(crate::Event::Sent { .. }) + )); }); } @@ -380,6 +345,7 @@ fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserv /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_works() { + let weight = BaseXcmWeight::get() * 4; let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); @@ -422,10 +388,12 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ fee_index as u32, Unlimited, )); - assert!(matches!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) - )); + + let mut last_events = last_events(3).into_iter(); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) + ); // Alice spent (transferred) amount assert_eq!( @@ -446,34 +414,30 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ // Verify sent XCM program assert_eq!( sent_xcm(), - vec![ - ( - // first message is to prefund fees on `dest` - dest, - // fees are being sent through local-reserve transfer because fee reserve is - // local chain - Xcm(vec![ - ReserveAssetDeposited((Parent, FEE_AMOUNT).into()), - ClearOrigin, - buy_limited_execution((Parent, FEE_AMOUNT), Unlimited), - DepositAsset { assets: AllCounted(1).into(), beneficiary }, - ]) - ), - ( - // second message is to transfer/deposit foreign assets on `dest` while paying - // using prefunded (transferred above) fees - // (dest is reserve location for `expected_asset`) - dest, - Xcm(vec![ - WithdrawAsset(expected_asset.into()), - ClearOrigin, - WithdrawAsset(expected_fee.clone().into()), - buy_limited_execution(expected_fee, Unlimited), - DepositAsset { assets: AllCounted(2).into(), beneficiary }, - ]) - ) - ] + vec![( + dest, + // `fees` are being sent through local-reserve transfer because fee reserve is + // local chain; `assets` are burned on source and withdrawn from SA here + Xcm(vec![ + ReserveAssetDeposited((Parent, FEE_AMOUNT).into()), + WithdrawAsset(expected_asset.into()), + ClearOrigin, + buy_limited_execution(expected_fee, Unlimited), + DepositAsset { assets: AllCounted(2).into(), beneficiary }, + ]) + )] ); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::FeesPaid { + paying: beneficiary, + fees: MultiAssets::new(), + }) + ); + assert!(matches!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Sent { .. }) + )); }); } @@ -600,9 +564,22 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ fee_index as u32, Unlimited, )); + let weight = BaseXcmWeight::get() * 4; + let mut last_events = last_events(3).into_iter(); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) + ); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::FeesPaid { + paying: beneficiary, + fees: MultiAssets::new(), + }) + ); assert!(matches!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Sent { .. }) )); // Alice spent (fees) amount @@ -623,34 +600,20 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ // Verify sent XCM program assert_eq!( sent_xcm(), - vec![ - ( - // first message is to prefund fees on `dest` - dest, + vec![( + dest, + Xcm(vec![ // fees are being sent through destination-reserve transfer because fee reserve // is destination chain - Xcm(vec![ - WithdrawAsset(expected_fee.clone().into()), - ClearOrigin, - buy_limited_execution(expected_fee.clone(), Unlimited), - DepositAsset { assets: AllCounted(1).into(), beneficiary }, - ]) - ), - ( - // second message is to transfer/deposit (native) asset on `dest` while paying - // using prefunded (transferred above) fees - dest, + WithdrawAsset(expected_fee.clone().into()), // transfer is through local-reserve transfer because `assets` (native asset) // have local reserve - Xcm(vec![ - ReserveAssetDeposited(expected_asset.into()), - ClearOrigin, - WithdrawAsset(expected_fee.clone().into()), - buy_limited_execution(expected_fee, Unlimited), - DepositAsset { assets: AllCounted(2).into(), beneficiary }, - ]) - ) - ] + ReserveAssetDeposited(expected_asset.into()), + ClearOrigin, + buy_limited_execution(expected_fee, Unlimited), + DepositAsset { assets: AllCounted(2).into(), beneficiary }, + ]) + )] ); }); } @@ -705,9 +668,23 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re fee_index, Unlimited, )); + + let weight = BaseXcmWeight::get() * 3; + let mut last_events = last_events(3).into_iter(); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) + ); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::FeesPaid { + paying: beneficiary, + fees: MultiAssets::new(), + }) + ); assert!(matches!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Sent { .. }) )); // Alice spent (transferred) amount @@ -1121,9 +1098,22 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { fee_index as u32, Unlimited, )); + let weight = BaseXcmWeight::get() * 4; + let mut last_events = last_events(3).into_iter(); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) + ); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::FeesPaid { + paying: beneficiary, + fees: MultiAssets::new(), + }) + ); assert!(matches!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Sent { .. }) )); // Alice spent (fees) amount assert_eq!( @@ -1143,33 +1133,19 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { // Verify sent XCM program assert_eq!( sent_xcm(), - vec![ - ( - // first message is to prefund fees on `dest` - dest, + vec![( + dest, + Xcm(vec![ // fees are teleported to destination chain - Xcm(vec![ - ReceiveTeleportedAsset(expected_fee.clone().into()), - ClearOrigin, - buy_limited_execution(expected_fee.clone(), Unlimited), - DepositAsset { assets: AllCounted(1).into(), beneficiary }, - ]) - ), - ( - // second message is to transfer/deposit (native) asset on `dest` while paying - // using prefunded (transferred above) fees - dest, - // transfer is through local-reserve transfer because `assets` (native asset) - // have local reserve - Xcm(vec![ - ReserveAssetDeposited(expected_asset.into()), - ClearOrigin, - WithdrawAsset(expected_fee.clone().into()), - buy_limited_execution(expected_fee, Unlimited), - DepositAsset { assets: AllCounted(2).into(), beneficiary }, - ]) - ) - ] + ReceiveTeleportedAsset(expected_fee.clone().into()), + // transfer is through local-reserve transfer because `assets` (native + // asset) have local reserve + ReserveAssetDeposited(expected_asset.into()), + ClearOrigin, + buy_limited_execution(expected_fee, Unlimited), + DepositAsset { assets: AllCounted(2).into(), beneficiary }, + ]) + )] ); }); } @@ -1240,9 +1216,22 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_wor fee_index as u32, Unlimited, )); + let weight = BaseXcmWeight::get() * 5; + let mut last_events = last_events(3).into_iter(); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) + ); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::FeesPaid { + paying: beneficiary, + fees: MultiAssets::new(), + }) + ); assert!(matches!( - last_event(), - RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Sent { .. }) )); // Alice native asset untouched assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); @@ -1275,32 +1264,18 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_wor // Verify sent XCM program assert_eq!( sent_xcm(), - vec![ - ( - // first message is to prefund fees on `dest` - dest, + vec![( + dest, + Xcm(vec![ // fees are teleported to destination chain - Xcm(vec![ - ReceiveTeleportedAsset(expected_fee.clone().into()), - ClearOrigin, - buy_limited_execution(expected_fee.clone(), Unlimited), - DepositAsset { assets: AllCounted(1).into(), beneficiary }, - ]) - ), - ( - // second message is to transfer/deposit foreign assets on `dest` while paying - // using prefunded (transferred above) fees (USDT) - // (dest is reserve location for `expected_asset`) - dest, - Xcm(vec![ - WithdrawAsset(expected_asset.into()), - ClearOrigin, - WithdrawAsset(expected_fee.clone().into()), - buy_limited_execution(expected_fee, Unlimited), - DepositAsset { assets: AllCounted(2).into(), beneficiary }, - ]) - ) - ] + ReceiveTeleportedAsset(expected_fee.clone().into()), + // assets are withdrawn from origin's local SA + WithdrawAsset(expected_asset.into()), + ClearOrigin, + buy_limited_execution(expected_fee, Unlimited), + DepositAsset { assets: AllCounted(2).into(), beneficiary }, + ]) + )] ); }); } From 3bc2d73d3af3f9d1f40d158c60ef627b04bb7d12 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 25 Oct 2023 17:07:00 +0300 Subject: [PATCH 51/98] fix AHs tests --- .../src/tests/reserve_transfer.rs | 2 +- .../asset-hub-rococo/src/tests/teleport.rs | 12 ++--- .../src/tests/reserve_transfer.rs | 10 ++-- .../asset-hub-westend/src/tests/teleport.rs | 12 ++--- .../emulated/common/src/macros.rs | 2 +- .../runtimes/assets/test-utils/src/lib.rs | 5 -- .../assets/test-utils/src/test_cases.rs | 4 +- .../test-utils/src/test_cases_over_bridge.rs | 3 +- .../assets/test-utils/src/xcm_helpers.rs | 50 +++---------------- 9 files changed, 31 insertions(+), 69 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index 0a55a609ecce..073c93ec254a 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -176,7 +176,7 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { let sender_balance_after = test.sender.balance; let delivery_fees = AssetHubRococo::execute_with(|| { - xcm_helpers::reserve_transfer_localreserve_assets_delivery_fees::< + xcm_helpers::transfer_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/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs index e74e97dc3391..4b2ea0e160cb 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs @@ -174,7 +174,7 @@ fn limited_teleport_native_assets_from_relay_to_system_para_works() { test.assert(); let delivery_fees = Rococo::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< + xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -221,7 +221,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::teleport_assets_delivery_fees::< + xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -262,7 +262,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::teleport_assets_delivery_fees::< + xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -295,7 +295,7 @@ fn teleport_native_assets_from_relay_to_system_para_works() { test.assert(); let delivery_fees = Rococo::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< + xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -342,7 +342,7 @@ fn 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::teleport_assets_delivery_fees::< + xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -380,7 +380,7 @@ fn teleport_native_assets_from_system_para_to_relay_fails() { test.assert(); let delivery_fees = AssetHubRococo::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< + xcm_helpers::transfer_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/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs index bc18daf35eb7..c7a25dde78d3 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -175,9 +175,13 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { let sender_balance_after = test.sender.balance; let delivery_fees = AssetHubWestend::execute_with(|| { - xcm_helpers::reserve_transfer_localreserve_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + xcm_helpers::transfer_assets_delivery_fees::<::XcmSender>( + test.args.assets.clone(), + 0, + test.args.weight_limit, + test.args.beneficiary, + test.args.dest, + ) }); assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs index 7423f6f60eb1..4fe0062dafcd 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs @@ -176,7 +176,7 @@ fn limited_teleport_native_assets_from_relay_to_system_para_works() { test.assert(); let delivery_fees = Westend::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< + xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -223,7 +223,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::teleport_assets_delivery_fees::< + xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -264,7 +264,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::teleport_assets_delivery_fees::< + xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -297,7 +297,7 @@ fn teleport_native_assets_from_relay_to_system_para_works() { test.assert(); let delivery_fees = Westend::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< + xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -341,7 +341,7 @@ fn teleport_native_assets_back_from_system_para_to_relay_works() { test.assert(); let delivery_fees = AssetHubWestend::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< + xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -382,7 +382,7 @@ fn teleport_native_assets_from_system_para_to_relay_fails() { test.assert(); let delivery_fees = AssetHubWestend::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< + xcm_helpers::transfer_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/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs index 52780a5c4a75..a65b2057afda 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs @@ -90,7 +90,7 @@ macro_rules! test_parachain_is_trusted_teleporter { let para_receiver_balance_after = <$receiver_para as $crate::Chain>::account_data_of(receiver.clone()).free; let delivery_fees = <$sender_para>::execute_with(|| { - asset_test_utils::xcm_helpers::teleport_assets_delivery_fees::< + asset_test_utils::xcm_helpers::transfer_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/runtimes/assets/test-utils/src/lib.rs b/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs index 2a1e72dc002f..872ad06ddd5b 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs @@ -67,11 +67,6 @@ pub(crate) fn assert_matches_reserve_asset_deposited_instructions Err(ProcessMessageError::BadFormat), }) .expect("expected instruction ClearOrigin") - .match_next_inst(|instr| match instr { - SetFeesMode { .. } => Ok(()), - _ => Err(ProcessMessageError::BadFormat), - }) - .expect("expected instruction SetFeesMode") .match_next_inst(|instr| match instr { BuyExecution { .. } => Ok(()), _ => Err(ProcessMessageError::BadFormat), 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 97f68269c81a..2900ec6f308b 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -181,7 +181,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::teleport_assets_delivery_fees::( + xcm_helpers::transfer_assets_delivery_fees::( (native_asset_id, native_asset_to_teleport_away.into()).into(), 0, Unlimited, @@ -560,7 +560,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::teleport_assets_delivery_fees::( + xcm_helpers::transfer_assets_delivery_fees::( (foreign_asset_id_multilocation, asset_to_teleport_away).into(), 0, Unlimited, diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs index 547d4dfcec7c..16ad63532ab2 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs @@ -170,7 +170,7 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< // Make sure sender has enough funds for paying delivery fees // TODO: Get this fee via weighing the corresponding message - let delivery_fees = 1324173226; + let delivery_fees = 1324039894; >::mint_into(&alice_account, delivery_fees.into()) .unwrap(); @@ -434,7 +434,6 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< DescendOrigin(descend_origin), ReserveAssetDeposited(expected_assets.clone()), ClearOrigin, - SetFeesMode { jit_withdraw: false }, BuyExecution { fees: MultiAsset { id: Concrete(foreign_asset_id_multilocation), 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 ca92c469df80..0aebe38fef53 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/xcm_helpers.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/xcm_helpers.rs @@ -18,10 +18,11 @@ use xcm::latest::prelude::*; -/// Returns the delivery fees amount for pallet xcm's `teleport_assets` extrinsic. -/// Because it returns only a `u128`, it assumes delivery fees are only paid in one asset and that -/// asset is known. -pub fn teleport_assets_delivery_fees( +/// Returns the delivery fees amount for pallet xcm's `teleport_assets` and +/// `reserve_transfer_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( assets: MultiAssets, fee_asset_item: u32, weight_limit: WeightLimit, @@ -32,25 +33,6 @@ pub fn teleport_assets_delivery_fees( get_fungible_delivery_fees::(destination, message) } -/// Returns the delivery fees amount for pallet xcm's `reserve_transfer_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 reserve_transfer_localreserve_assets_delivery_fees( - assets: MultiAssets, - fee_asset_item: u32, - weight_limit: WeightLimit, - beneficiary: MultiLocation, - destination: MultiLocation, -) -> u128 { - let message = reserve_transfer_localreserve_assets_dummy_message( - assets, - fee_asset_item, - weight_limit, - beneficiary, - ); - get_fungible_delivery_fees::(destination, message) -} - /// Returns the delivery fees amount for a query response as a result of the execution /// of a `ExpectError` instruction with no error. pub fn query_response_delivery_fees(querier: MultiLocation) -> u128 { @@ -94,6 +76,7 @@ pub fn pay_over_xcm_delivery_fees( /// Approximates the actual message sent by the teleport extrinsic. /// The assets are not reanchored and the topic is a dummy one. /// However, it should have the same encoded size, which is what matters for delivery fees. +/// Also has same encoded size as the one created by the reserve transfer assets extrinsic. fn teleport_assets_dummy_message( assets: MultiAssets, fee_asset_item: u32, @@ -101,27 +84,8 @@ fn teleport_assets_dummy_message( beneficiary: MultiLocation, ) -> Xcm<()> { Xcm(vec![ - ReceiveTeleportedAsset(assets.clone()), - ClearOrigin, - BuyExecution { fees: assets.get(fee_asset_item as usize).unwrap().clone(), weight_limit }, - DepositAsset { assets: Wild(AllCounted(assets.len() as u32)), beneficiary }, - SetTopic([0u8; 32]), // Dummy topic - ]) -} - -/// Approximates the actual message sent by the reserve-transfer of local reserve asset extrinsic. -/// The assets are not reanchored and the topic is a dummy one. -/// However, it should have the same encoded size, which is what matters for delivery fees. -fn reserve_transfer_localreserve_assets_dummy_message( - assets: MultiAssets, - fee_asset_item: u32, - weight_limit: WeightLimit, - beneficiary: MultiLocation, -) -> Xcm<()> { - Xcm(vec![ - ReserveAssetDeposited(assets.clone()), + ReceiveTeleportedAsset(assets.clone()), // Same encoded size as `ReserveAssetDeposited` ClearOrigin, - SetFeesMode { jit_withdraw: false }, BuyExecution { fees: assets.get(fee_asset_item as usize).unwrap().clone(), weight_limit }, DepositAsset { assets: Wild(AllCounted(assets.len() as u32)), beneficiary }, SetTopic([0u8; 32]), // Dummy topic From bd60203a1a1ac1384d150c8cf20cbc200aa47dac Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 26 Oct 2023 18:12:41 +0300 Subject: [PATCH 52/98] remove unused SetFeesMode instruction --- polkadot/xcm/pallet-xcm/src/lib.rs | 12 ++++-------- .../xcm/pallet-xcm/src/tests/assets_transfer.rs | 14 +++++++------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index f97b6135d484..8d9bc7373c6c 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1485,11 +1485,9 @@ impl Pallet { .unwrap_or_default(); let local_execute_xcm = Xcm( - // JIT withdraw fees for local execution - [SetFeesMode { jit_withdraw: true }] + // run any necessary local prefund fees instructions + prefund_local_xcm .into_iter() - // run any necessary local prefund fees instructions - .chain(prefund_local_xcm.into_iter()) // move `assets` to `dest`s local sovereign account .chain([TransferAsset { assets, beneficiary: dest }].into_iter()) .collect(), @@ -1566,11 +1564,9 @@ impl Pallet { .unwrap_or_default(); let local_execute_xcm = Xcm( - // JIT withdraw fees for local execution - [SetFeesMode { jit_withdraw: true }] + // run any necessary local prefund fees instructions + prefund_local_xcm .into_iter() - // run any necessary local prefund fees instructions - .chain(prefund_local_xcm.into_iter()) // move `assets` to `dest`s local sovereign account .chain( [ diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index d3df75708213..7a9b7be8dff2 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -134,7 +134,7 @@ fn reserve_transfer_assets_with_paid_router_works() { ]; new_test_ext_with_balances(balances).execute_with(|| { let xcm_router_fee_amount = Para3000PaymentAmount::get(); - let weight = BaseXcmWeight::get() * 2; + let weight = BaseXcmWeight::get(); let dest: MultiLocation = Junction::AccountId32 { network: None, id: user_account.clone().into() }.into(); assert_eq!(Balances::total_balance(&user_account), INITIAL_BALANCE); @@ -274,7 +274,7 @@ fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserv let dest: MultiLocation = Parachain(OTHER_PARA_ID).into(); new_test_ext_with_balances(balances).execute_with(|| { - let weight = BaseXcmWeight::get() * 2; + let weight = BaseXcmWeight::get(); assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); // call extrinsic assert_ok!(XcmPallet::limited_reserve_transfer_assets( @@ -345,7 +345,7 @@ fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserv /// is increased. Verifies the correct message is sent and event is emitted. #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_works() { - let weight = BaseXcmWeight::get() * 4; + let weight = BaseXcmWeight::get() * 3; let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); @@ -564,7 +564,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ fee_index as u32, Unlimited, )); - let weight = BaseXcmWeight::get() * 4; + let weight = BaseXcmWeight::get() * 3; let mut last_events = last_events(3).into_iter(); assert_eq!( last_events.next().unwrap(), @@ -669,7 +669,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re Unlimited, )); - let weight = BaseXcmWeight::get() * 3; + let weight = BaseXcmWeight::get() * 2; let mut last_events = last_events(3).into_iter(); assert_eq!( last_events.next().unwrap(), @@ -1098,7 +1098,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { fee_index as u32, Unlimited, )); - let weight = BaseXcmWeight::get() * 4; + let weight = BaseXcmWeight::get() * 3; let mut last_events = last_events(3).into_iter(); assert_eq!( last_events.next().unwrap(), @@ -1216,7 +1216,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_wor fee_index as u32, Unlimited, )); - let weight = BaseXcmWeight::get() * 5; + let weight = BaseXcmWeight::get() * 4; let mut last_events = last_events(3).into_iter(); assert_eq!( last_events.next().unwrap(), From 371ac2d798f74a42510e58682a22879235e839c8 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 26 Oct 2023 18:20:11 +0300 Subject: [PATCH 53/98] pallet-xcm: fix broken reserve_transfer_assets benchmark --- polkadot/xcm/pallet-xcm/Cargo.toml | 7 +- polkadot/xcm/pallet-xcm/src/benchmarking.rs | 86 +++++++++++++++++++-- polkadot/xcm/pallet-xcm/src/mock.rs | 8 +- 3 files changed, 88 insertions(+), 13 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index eedf3041cb37..67c54f8d9bc4 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -13,7 +13,6 @@ scale-info = { version = "2.10.0", default-features = false, features = ["derive serde = { version = "1.0.188", optional = true, features = ["derive"] } log = { version = "0.4.17", default-features = false } -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } frame-support = { path = "../../../substrate/frame/support", default-features = false} frame-system = { path = "../../../substrate/frame/system", default-features = false} sp-core = { path = "../../../substrate/primitives/core", default-features = false} @@ -24,8 +23,11 @@ sp-std = { path = "../../../substrate/primitives/std", default-features = false} xcm = { package = "staging-xcm", path = "..", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false } +# marked optional, used in benchmarking +frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } +pallet-assets = { path = "../../../substrate/frame/assets", default-features = false, optional = true } + [dev-dependencies] -pallet-assets = { path = "../../../substrate/frame/assets" } pallet-balances = { path = "../../../substrate/frame/balances" } polkadot-runtime-parachains = { path = "../../runtime/parachains" } polkadot-parachain-primitives = { path = "../../parachain" } @@ -40,6 +42,7 @@ std = [ "frame-support/std", "frame-system/std", "log/std", + "pallet-assets/std", "scale-info/std", "serde", "sp-core/std", diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs index f567691b5092..4f61d34feeca 100644 --- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs @@ -16,15 +16,58 @@ use super::*; use bounded_collections::{ConstU32, WeakBoundedVec}; -use frame_benchmarking::{benchmarks, BenchmarkError, BenchmarkResult}; -use frame_support::weights::Weight; +use frame_benchmarking::{benchmarks, whitelisted_caller, BenchmarkError, BenchmarkResult}; +use frame_support::{assert_ok, traits::Currency, weights::Weight}; use frame_system::RawOrigin; +use pallet_assets::Pallet as AssetsPallet; +use sp_runtime::traits::StaticLookup; use sp_std::prelude::*; use xcm::{latest::prelude::*, v2}; type RuntimeOrigin = ::RuntimeOrigin; +fn create_default_asset( + asset_id: T::AssetIdParameter, + is_sufficient: bool, + caller: T::AccountId, +) { + let beneficiary = T::Lookup::unlookup(caller); + let root = frame_system::RawOrigin::Root.into(); + assert_ok!(AssetsPallet::::force_create( + root, + asset_id, + beneficiary, + is_sufficient, + 1u32.into(), + )); +} + +fn create_default_minted_asset( + asset_id: T::AssetIdParameter, + is_sufficient: bool, + amount: T::Balance, + caller: T::AccountId, +) { + create_default_asset::(asset_id, is_sufficient, caller.clone()); + if !is_sufficient { + T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); + } + let beneficiary = T::Lookup::unlookup(caller.clone()); + assert_ok!(AssetsPallet::::mint( + frame_system::RawOrigin::Signed(caller).into(), + asset_id, + beneficiary, + amount, + )); +} + benchmarks! { + where_clause { + where + T: pallet_assets::Config, + ::AssetIdParameter: From, + ::Balance: From + Into, + } send { let send_origin = T::SendXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; @@ -62,9 +105,23 @@ benchmarks! { let (assets, destination) = T::ReserveTransferableAssets::get().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), )?; - let send_origin = - T::ExecuteXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone()) + let caller: T::AccountId = whitelisted_caller(); + for asset in assets.inner() { + let amount = match &asset.fun { + Fungible(amount) => *amount, + _ => return Err(BenchmarkError::Stop("AssetNotFungible")), + }; + let id = match &asset.id { + Concrete(location) => *location, + _ => return Err(BenchmarkError::Stop("AssetNotFungible")), + }; + let asset_id: T::AssetIdParameter = id.into(); + create_default_minted_asset::(asset_id.clone(), true, amount.into(), caller.clone()); + // verify initial balance + assert_eq!(AssetsPallet::::balance(asset_id.into(), caller.clone()), amount.into()); + } + let send_origin = RawOrigin::Signed(caller.clone()); + let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone().into()) .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; if !T::XcmReserveTransferFilter::contains(&(origin_location, assets.clone().into_inner())) { return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) @@ -74,8 +131,23 @@ benchmarks! { let versioned_dest: VersionedMultiLocation = destination.into(); let versioned_beneficiary: VersionedMultiLocation = AccountId32 { network: None, id: recipient.into() }.into(); - let versioned_assets: VersionedMultiAssets = assets.into(); - }: _>(send_origin, Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0) + let versioned_assets: VersionedMultiAssets = assets.clone().into(); + }: _>(send_origin.into(), Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0) + verify { + for asset in assets.inner() { + let amount = match &asset.fun { + Fungible(amount) => *amount, + _ => return Err(BenchmarkError::Stop("AssetNotFungible")), + }; + let id = match &asset.id { + Concrete(location) => *location, + _ => return Err(BenchmarkError::Stop("AssetNotFungible")), + }; + let asset_id: T::AssetIdParameter = id.into(); + // verify balance after transfer + assert_eq!(AssetsPallet::::balance(asset_id.into(), caller.clone()), 0.into()); + } + } execute { let execute_origin = diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 984b359617f2..43974545ec45 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -35,9 +35,9 @@ use xcm_builder::{ AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, Case, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, DescribeAllTerminal, - DescribeFamily, FixedRateOfFungible, FixedWeightBounds, FungiblesAdapter, HashedDescription, - IsConcrete, MatchedConvertedConcreteId, NoChecking, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, XcmFeesToAccount, + FixedRateOfFungible, FixedWeightBounds, FungiblesAdapter, HashedDescription, IsConcrete, + MatchedConvertedConcreteId, NoChecking, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, XcmFeesToAccount, }; use xcm_executor::{ traits::{Identity, JustTry}, @@ -382,7 +382,7 @@ parameter_types! { pub type SovereignAccountOf = ( ChildParachainConvertsVia, AccountId32Aliases, - HashedDescription>, + HashedDescription, ); pub type ForeignAssetsConvertedConcreteId = MatchedConvertedConcreteId< From 9b58ff0e877f3ec7214183da7cf31d9b5b6625b8 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 27 Oct 2023 12:33:08 +0300 Subject: [PATCH 54/98] try add pallet-assets for benchmarking to rococo --- Cargo.lock | 1 + polkadot/runtime/rococo/Cargo.toml | 4 ++++ polkadot/runtime/rococo/src/lib.rs | 36 ++++++++++++++++++++++++++---- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 843083beb9ae..fd94c08a3a79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14221,6 +14221,7 @@ dependencies = [ "hex-literal", "log", "pallet-asset-rate", + "pallet-assets", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 6d0dee3e4343..337bb4142047 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -90,6 +90,7 @@ pallet-xcm-benchmarks = { path = "../../xcm/pallet-xcm-benchmarks", default-feat frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } frame-try-runtime = { path = "../../../substrate/frame/try-runtime", default-features = false, optional = true } frame-system-benchmarking = { path = "../../../substrate/frame/system/benchmarking", default-features = false, optional = true } +pallet-assets = { path = "../../../substrate/frame/assets", default-features = false, optional = true } hex-literal = { version = "0.4.1" } runtime-common = { package = "polkadot-runtime-common", path = "../common", default-features = false } @@ -134,6 +135,7 @@ std = [ "log/std", "offchain-primitives/std", "pallet-asset-rate/std", + "pallet-assets/std", "pallet-authority-discovery/std", "pallet-authorship/std", "pallet-babe/std", @@ -211,6 +213,7 @@ runtime-benchmarks = [ "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-asset-rate/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", "pallet-babe/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-bounties/runtime-benchmarks", @@ -263,6 +266,7 @@ try-runtime = [ "frame-try-runtime", "frame-try-runtime/try-runtime", "pallet-asset-rate/try-runtime", + "pallet-assets/try-runtime", "pallet-authority-discovery/try-runtime", "pallet-authorship/try-runtime", "pallet-babe/try-runtime", diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index e6ad061ce069..439e010f50ff 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -67,14 +67,14 @@ use frame_support::{ genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ - fungible::HoldConsideration, EitherOf, EitherOfDiverse, Everything, InstanceFilter, - KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, ProcessMessageError, - StorageMapShim, WithdrawReasons, + fungible::HoldConsideration, AsEnsureOriginWithArg, EitherOf, EitherOfDiverse, Everything, + InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, + ProcessMessageError, StorageMapShim, WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter}, PalletId, }; -use frame_system::EnsureRoot; +use frame_system::{EnsureRoot, EnsureSigned}; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; use pallet_identity::simple::IdentityInfo; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; @@ -302,6 +302,30 @@ impl pallet_balances::Config for Runtime { type MaxHolds = ConstU32<2>; } +// only used in benchmarks +#[cfg(feature = "runtime-benchmarks")] +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = MultiLocationForAssetId; + type AssetIdParameter = MultiLocationForAssetId; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = EnsureRoot; + type AssetDeposit = ConstU128<1>; + type AssetAccountDeposit = ConstU128<10>; + type MetadataDepositBase = ConstU128<1>; + type MetadataDepositPerByte = ConstU128<1>; + type ApprovalDeposit = ConstU128<1>; + type StringLimit = ConstU32<50>; + type Freezer = (); + type WeightInfo = (); + type CallbackHandle = (); + type Extra = (); + type RemoveItemsLimit = ConstU32<5>; + type BenchmarkHelper = (); +} + parameter_types! { pub const TransactionByteFee: Balance = 10 * MILLICENTS; /// This value increases the priority of `Operational` transactions by adding @@ -1359,6 +1383,10 @@ construct_runtime! { // Pallet for sending XCM. XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event, Origin, Config} = 99, + // Assets pallet only used in benchmarks. + #[cfg(feature = "runtime-benchmarks")] + Assets: pallet_assets::{Pallet, Call, Storage, Config, Event} = 100, + ParasSudoWrapper: paras_sudo_wrapper::{Pallet, Call} = 250, AssignedSlots: assigned_slots::{Pallet, Call, Storage, Event, Config} = 251, From 942977e64fb9918e6c383a22e60ac565818c2dff Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 27 Oct 2023 13:06:36 +0300 Subject: [PATCH 55/98] Revert "try add pallet-assets for benchmarking to rococo" This reverts commit c82330b614df352a0e25a8f18dbd43bc356aed4b. --- Cargo.lock | 1 - polkadot/runtime/rococo/Cargo.toml | 4 ---- polkadot/runtime/rococo/src/lib.rs | 36 ++++-------------------------- 3 files changed, 4 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fd94c08a3a79..843083beb9ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14221,7 +14221,6 @@ dependencies = [ "hex-literal", "log", "pallet-asset-rate", - "pallet-assets", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 337bb4142047..6d0dee3e4343 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -90,7 +90,6 @@ pallet-xcm-benchmarks = { path = "../../xcm/pallet-xcm-benchmarks", default-feat frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } frame-try-runtime = { path = "../../../substrate/frame/try-runtime", default-features = false, optional = true } frame-system-benchmarking = { path = "../../../substrate/frame/system/benchmarking", default-features = false, optional = true } -pallet-assets = { path = "../../../substrate/frame/assets", default-features = false, optional = true } hex-literal = { version = "0.4.1" } runtime-common = { package = "polkadot-runtime-common", path = "../common", default-features = false } @@ -135,7 +134,6 @@ std = [ "log/std", "offchain-primitives/std", "pallet-asset-rate/std", - "pallet-assets/std", "pallet-authority-discovery/std", "pallet-authorship/std", "pallet-babe/std", @@ -213,7 +211,6 @@ runtime-benchmarks = [ "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-asset-rate/runtime-benchmarks", - "pallet-assets/runtime-benchmarks", "pallet-babe/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-bounties/runtime-benchmarks", @@ -266,7 +263,6 @@ try-runtime = [ "frame-try-runtime", "frame-try-runtime/try-runtime", "pallet-asset-rate/try-runtime", - "pallet-assets/try-runtime", "pallet-authority-discovery/try-runtime", "pallet-authorship/try-runtime", "pallet-babe/try-runtime", diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 439e010f50ff..e6ad061ce069 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -67,14 +67,14 @@ use frame_support::{ genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ - fungible::HoldConsideration, AsEnsureOriginWithArg, EitherOf, EitherOfDiverse, Everything, - InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, - ProcessMessageError, StorageMapShim, WithdrawReasons, + fungible::HoldConsideration, EitherOf, EitherOfDiverse, Everything, InstanceFilter, + KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, ProcessMessageError, + StorageMapShim, WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter}, PalletId, }; -use frame_system::{EnsureRoot, EnsureSigned}; +use frame_system::EnsureRoot; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; use pallet_identity::simple::IdentityInfo; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; @@ -302,30 +302,6 @@ impl pallet_balances::Config for Runtime { type MaxHolds = ConstU32<2>; } -// only used in benchmarks -#[cfg(feature = "runtime-benchmarks")] -impl pallet_assets::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Balance = Balance; - type AssetId = MultiLocationForAssetId; - type AssetIdParameter = MultiLocationForAssetId; - type Currency = Balances; - type CreateOrigin = AsEnsureOriginWithArg>; - type ForceOrigin = EnsureRoot; - type AssetDeposit = ConstU128<1>; - type AssetAccountDeposit = ConstU128<10>; - type MetadataDepositBase = ConstU128<1>; - type MetadataDepositPerByte = ConstU128<1>; - type ApprovalDeposit = ConstU128<1>; - type StringLimit = ConstU32<50>; - type Freezer = (); - type WeightInfo = (); - type CallbackHandle = (); - type Extra = (); - type RemoveItemsLimit = ConstU32<5>; - type BenchmarkHelper = (); -} - parameter_types! { pub const TransactionByteFee: Balance = 10 * MILLICENTS; /// This value increases the priority of `Operational` transactions by adding @@ -1383,10 +1359,6 @@ construct_runtime! { // Pallet for sending XCM. XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event, Origin, Config} = 99, - // Assets pallet only used in benchmarks. - #[cfg(feature = "runtime-benchmarks")] - Assets: pallet_assets::{Pallet, Call, Storage, Config, Event} = 100, - ParasSudoWrapper: paras_sudo_wrapper::{Pallet, Call} = 250, AssignedSlots: assigned_slots::{Pallet, Call, Storage, Event, Config} = 251, From 3b9965b2b6b99d44fef881dfe638f4e07d1f04ef Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 27 Oct 2023 13:07:20 +0300 Subject: [PATCH 56/98] pallet-xcm benchmarking: most chains do not have pallet-assets, use pallet-balances instead --- polkadot/xcm/pallet-xcm/Cargo.toml | 6 +- polkadot/xcm/pallet-xcm/src/benchmarking.rs | 95 ++++++--------------- polkadot/xcm/pallet-xcm/src/mock.rs | 7 +- 3 files changed, 36 insertions(+), 72 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index 67c54f8d9bc4..2005fc0375ef 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -25,10 +25,10 @@ xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", def # marked optional, used in benchmarking frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } -pallet-assets = { path = "../../../substrate/frame/assets", default-features = false, optional = true } +pallet-balances = { path = "../../../substrate/frame/balances", default-features = false, optional = true } [dev-dependencies] -pallet-balances = { path = "../../../substrate/frame/balances" } +pallet-assets = { path = "../../../substrate/frame/assets" } polkadot-runtime-parachains = { path = "../../runtime/parachains" } polkadot-parachain-primitives = { path = "../../parachain" } xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder" } @@ -42,7 +42,7 @@ std = [ "frame-support/std", "frame-system/std", "log/std", - "pallet-assets/std", + "pallet-balances/std", "scale-info/std", "serde", "sp-core/std", diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs index 4f61d34feeca..c44307f9891d 100644 --- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs @@ -17,56 +17,21 @@ use super::*; use bounded_collections::{ConstU32, WeakBoundedVec}; use frame_benchmarking::{benchmarks, whitelisted_caller, BenchmarkError, BenchmarkResult}; -use frame_support::{assert_ok, traits::Currency, weights::Weight}; +use frame_support::{traits::Currency, weights::Weight}; use frame_system::RawOrigin; -use pallet_assets::Pallet as AssetsPallet; -use sp_runtime::traits::StaticLookup; use sp_std::prelude::*; use xcm::{latest::prelude::*, v2}; type RuntimeOrigin = ::RuntimeOrigin; -fn create_default_asset( - asset_id: T::AssetIdParameter, - is_sufficient: bool, - caller: T::AccountId, -) { - let beneficiary = T::Lookup::unlookup(caller); - let root = frame_system::RawOrigin::Root.into(); - assert_ok!(AssetsPallet::::force_create( - root, - asset_id, - beneficiary, - is_sufficient, - 1u32.into(), - )); -} - -fn create_default_minted_asset( - asset_id: T::AssetIdParameter, - is_sufficient: bool, - amount: T::Balance, - caller: T::AccountId, -) { - create_default_asset::(asset_id, is_sufficient, caller.clone()); - if !is_sufficient { - T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); - } - let beneficiary = T::Lookup::unlookup(caller.clone()); - assert_ok!(AssetsPallet::::mint( - frame_system::RawOrigin::Signed(caller).into(), - asset_id, - beneficiary, - amount, - )); -} +// existential deposit multiplier +const ED_MULTIPLIER: u32 = 10; benchmarks! { where_clause { where - T: pallet_assets::Config, - ::AssetIdParameter: From, - ::Balance: From + Into, + T: pallet_balances::Config, + ::Balance: From + Into, } send { let send_origin = @@ -105,21 +70,28 @@ benchmarks! { let (assets, destination) = T::ReserveTransferableAssets::get().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), )?; - let caller: T::AccountId = whitelisted_caller(); - for asset in assets.inner() { - let amount = match &asset.fun { - Fungible(amount) => *amount, - _ => return Err(BenchmarkError::Stop("AssetNotFungible")), - }; - let id = match &asset.id { - Concrete(location) => *location, - _ => return Err(BenchmarkError::Stop("AssetNotFungible")), - }; - let asset_id: T::AssetIdParameter = id.into(); - create_default_minted_asset::(asset_id.clone(), true, amount.into(), caller.clone()); - // verify initial balance - assert_eq!(AssetsPallet::::balance(asset_id.into(), caller.clone()), amount.into()); + + // most chains deploying `pallet-xcm` don't have `pallet-assets` so we're + // stuck with using native token and `pallet-balances`. + if assets.len() != 1 { + return Err(BenchmarkError::Stop("Generic benchmark supports only single native asset")) } + let asset = assets.inner().clone().pop().unwrap(); + let transferred_amount = match &asset.fun { + Fungible(amount) => *amount, + _ => return Err(BenchmarkError::Stop("Benchmark asset not fungible")), + }.into(); + + let existential_deposit = T::ExistentialDeposit::get(); + let caller = whitelisted_caller(); + + // Give some multiple of the existential deposit + let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into()); + assert!(balance >= transferred_amount); + let _ = as Currency<_>>::make_free_balance_be(&caller, balance); + // verify initial balance + assert_eq!(pallet_balances::Pallet::::free_balance(&caller), balance); + let send_origin = RawOrigin::Signed(caller.clone()); let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone().into()) .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; @@ -134,19 +106,8 @@ benchmarks! { let versioned_assets: VersionedMultiAssets = assets.clone().into(); }: _>(send_origin.into(), Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0) verify { - for asset in assets.inner() { - let amount = match &asset.fun { - Fungible(amount) => *amount, - _ => return Err(BenchmarkError::Stop("AssetNotFungible")), - }; - let id = match &asset.id { - Concrete(location) => *location, - _ => return Err(BenchmarkError::Stop("AssetNotFungible")), - }; - let asset_id: T::AssetIdParameter = id.into(); - // verify balance after transfer - assert_eq!(AssetsPallet::::balance(asset_id.into(), caller.clone()), 0.into()); - } + // verify balance after transfer + assert_eq!(pallet_balances::Pallet::::free_balance(&caller), balance - transferred_amount); } execute { diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 43974545ec45..7afa9f581f44 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -489,8 +489,11 @@ parameter_types! { UsdtTeleportLocation::get(), )); pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - vec![ForeignAsset::get()].into(), - ForeignReserveLocation::get(), + MultiAsset { + fun: Fungible(10), + id: Concrete(Here.into_location()), + }.into(), + Parachain(OTHER_PARA_ID).into(), )); } From adcd6889b33ac7597bf9aa3ec9e22fec94294589 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 27 Oct 2023 14:38:10 +0300 Subject: [PATCH 57/98] pallet-xcm: fix teleport_assets benchmark --- polkadot/runtime/rococo/src/xcm_config.rs | 4 +-- polkadot/xcm/pallet-xcm/src/benchmarking.rs | 39 +++++++++++++++++---- polkadot/xcm/pallet-xcm/src/mock.rs | 31 ++++++++++++---- 3 files changed, 58 insertions(+), 16 deletions(-) diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index 65661b3e9334..da0aabfbaea5 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -212,12 +212,12 @@ parameter_types! { pub ReachableDest: Option = Some(Parachain(ASSET_HUB_ID).into()); // Relay/native token can be teleported to/from AH. pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Here.into()) }.into(), + MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Here.into()) }.into(), AssetHub::get(), )); // We can reserve transfer native token to some random parachain. pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Here.into()) }.into(), + MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Here.into()) }.into(), Parachain(4321).into(), )); } diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs index c44307f9891d..b0a37db6a783 100644 --- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs @@ -51,9 +51,30 @@ benchmarks! { let (assets, destination) = T::TeleportableAssets::get().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), )?; - let send_origin = - T::ExecuteXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone()) + + // most chains deploying `pallet-xcm` don't have `pallet-assets` so we're + // stuck with using native token and `pallet-balances`. + if assets.len() != 1 { + return Err(BenchmarkError::Stop("Generic benchmark supports only single native asset")) + } + let asset = assets.inner().clone().pop().unwrap(); + let transferred_amount = match &asset.fun { + Fungible(amount) => *amount, + _ => return Err(BenchmarkError::Stop("Benchmark asset not fungible")), + }.into(); + + let existential_deposit = T::ExistentialDeposit::get(); + let caller = whitelisted_caller(); + + // Give some multiple of the existential deposit + let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into()); + assert!(balance >= transferred_amount); + let _ = as Currency<_>>::make_free_balance_be(&caller, balance); + // verify initial balance + assert_eq!(pallet_balances::Pallet::::free_balance(&caller), balance); + + let send_origin = RawOrigin::Signed(caller.clone()); + let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone().into()) .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; if !T::XcmTeleportFilter::contains(&(origin_location, assets.clone().into_inner())) { return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) @@ -64,7 +85,11 @@ benchmarks! { let versioned_beneficiary: VersionedMultiLocation = AccountId32 { network: None, id: recipient.into() }.into(); let versioned_assets: VersionedMultiAssets = assets.into(); - }: _>(send_origin, Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0) + }: _>(send_origin.into(), Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0) + verify { + // verify balance after transfer, decreased by transferred amount (+ maybe XCM delivery fees) + assert!(pallet_balances::Pallet::::free_balance(&caller) <= balance - transferred_amount); + } reserve_transfer_assets { let (assets, destination) = T::ReserveTransferableAssets::get().ok_or( @@ -103,11 +128,11 @@ benchmarks! { let versioned_dest: VersionedMultiLocation = destination.into(); let versioned_beneficiary: VersionedMultiLocation = AccountId32 { network: None, id: recipient.into() }.into(); - let versioned_assets: VersionedMultiAssets = assets.clone().into(); + let versioned_assets: VersionedMultiAssets = assets.into(); }: _>(send_origin.into(), Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0) verify { - // verify balance after transfer - assert_eq!(pallet_balances::Pallet::::free_balance(&caller), balance - transferred_amount); + // verify balance after transfer, decreased by transferred amount (+ maybe XCM delivery fees) + assert!(pallet_balances::Pallet::::free_balance(&caller) <= balance - transferred_amount); } execute { diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 7afa9f581f44..e421d46f206b 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -320,6 +320,9 @@ impl pallet_assets::Config for Test { type BenchmarkHelper = XcmBenchmarkHelper; } +// This child parachain is a system parachain trusted to teleport native token. +pub const SOME_SYSTEM_PARA: u32 = 1001; + // This child parachain acts as trusted reserve for its assets in tests. // USDT allowed to teleport to/from here. pub const FOREIGN_ASSET_RESERVE_PARA_ID: u32 = 2001; @@ -340,6 +343,14 @@ pub const OTHER_PARA_ID: u32 = 2009; parameter_types! { pub const RelayLocation: MultiLocation = Here.into_location(); + pub const NativeAsset: MultiAsset = MultiAsset { + fun: Fungible(10), + id: Concrete(Here.into_location()), + }; + pub const SystemParachainLocation: MultiLocation = MultiLocation { + parents: 0, + interior: X1(Parachain(SOME_SYSTEM_PARA)) + }; pub const ForeignReserveLocation: MultiLocation = MultiLocation { parents: 0, interior: X1(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID)) @@ -417,10 +428,11 @@ parameter_types! { pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000); pub CurrencyPerSecondPerByte: (AssetId, u128, u128) = (Concrete(RelayLocation::get()), 1, 1); pub TrustedLocal: (MultiAssetFilter, MultiLocation) = (All.into(), Here.into()); - pub TrustedUsdt: (MultiAssetFilter, MultiLocation) = (vec![Usdt::get()].into(), UsdtTeleportLocation::get()); - pub TeleportUsdtToForeign: (MultiAssetFilter, MultiLocation) = (vec![Usdt::get()].into(), ForeignReserveLocation::get()); - pub TrustedForeign: (MultiAssetFilter, MultiLocation) = (vec![ForeignAsset::get()].into(), ForeignReserveLocation::get()); - pub TrustedUsdc: (MultiAssetFilter, MultiLocation) = (vec![Usdc::get()].into(), UsdcReserveLocation::get()); + pub TrustedSystemPara: (MultiAssetFilter, MultiLocation) = (NativeAsset::get().into(), SystemParachainLocation::get()); + pub TrustedUsdt: (MultiAssetFilter, MultiLocation) = (Usdt::get().into(), UsdtTeleportLocation::get()); + pub TeleportUsdtToForeign: (MultiAssetFilter, MultiLocation) = (Usdt::get().into(), ForeignReserveLocation::get()); + pub TrustedForeign: (MultiAssetFilter, MultiLocation) = (ForeignAsset::get().into(), ForeignReserveLocation::get()); + pub TrustedUsdc: (MultiAssetFilter, MultiLocation) = (Usdc::get().into(), UsdcReserveLocation::get()); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; pub XcmFeesTargetAccount: AccountId = AccountId::new([167u8; 32]); @@ -449,7 +461,12 @@ impl xcm_executor::Config for XcmConfig { type AssetTransactor = AssetTransactors; type OriginConverter = LocalOriginConverter; type IsReserve = (Case, Case); - type IsTeleporter = (Case, Case, Case); + type IsTeleporter = ( + Case, + Case, + Case, + Case, + ); type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = FixedWeightBounds; @@ -485,8 +502,8 @@ parameter_types! { parameter_types! { pub ReachableDest: Option = Some(Parachain(1000).into()); pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - vec![Usdt::get()].into(), - UsdtTeleportLocation::get(), + NativeAsset::get().into(), + SystemParachainLocation::get(), )); pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( MultiAsset { From eca0c3ef19cb4e5bb6651eeee069705009675f0c Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 27 Oct 2023 14:54:18 +0300 Subject: [PATCH 58/98] fix runtimes benchmarks for pallet-xcm --- cumulus/parachain-template/runtime/src/xcm_config.rs | 7 ++----- .../assets/asset-hub-kusama/src/xcm_config.rs | 8 ++++---- .../assets/asset-hub-polkadot/src/xcm_config.rs | 8 ++++---- .../assets/asset-hub-rococo/src/xcm_config.rs | 8 ++++---- .../assets/asset-hub-westend/src/xcm_config.rs | 8 ++++---- .../bridge-hubs/bridge-hub-kusama/src/xcm_config.rs | 2 +- .../bridge-hub-polkadot/src/xcm_config.rs | 2 +- .../bridge-hubs/bridge-hub-rococo/src/xcm_config.rs | 2 +- .../collectives-polkadot/src/xcm_config.rs | 2 +- .../contracts/contracts-rococo/src/xcm_config.rs | 9 +++------ .../runtimes/testing/penpal/src/xcm_config.rs | 2 +- .../runtimes/testing/rococo-parachain/src/lib.rs | 12 ++---------- polkadot/runtime/rococo/src/xcm_config.rs | 2 +- polkadot/runtime/westend/src/xcm_config.rs | 6 +++--- 14 files changed, 32 insertions(+), 46 deletions(-) diff --git a/cumulus/parachain-template/runtime/src/xcm_config.rs b/cumulus/parachain-template/runtime/src/xcm_config.rs index 0b82dba25f28..9f7de9895fae 100644 --- a/cumulus/parachain-template/runtime/src/xcm_config.rs +++ b/cumulus/parachain-template/runtime/src/xcm_config.rs @@ -155,11 +155,8 @@ parameter_types! { pub ReachableDest: Option = Some(Parent.into()); // Teleports are disabled pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = None; - // We can reserve transfer relay/native token between us and Relay. - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), - Parent.into(), - )); + // Reserve transfers are disabled. + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; } impl pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs index 5cd821fe9aa8..ea28ec91832a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs @@ -557,13 +557,13 @@ parameter_types! { pub ReachableDest: Option = Some(Parent.into()); // Relay/native token can be teleported between AH and Relay. pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), Parent.into(), )); - // We can reserve transfer some local token to Relay. + // We can reserve transfer native token to some random parachain. pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Here.into()) }.into(), - Parent.into(), + MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), + Parachain(43211234).into(), )); } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs index d23e209adcef..71dc71f477e1 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs @@ -481,13 +481,13 @@ parameter_types! { pub ReachableDest: Option = Some(Parent.into()); // Relay/native token can be teleported between AH and Relay. pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), Parent.into(), )); - // We can reserve transfer some local token to Relay. + // We can reserve transfer native token to some random parachain. pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Here.into()) }.into(), - Parent.into(), + MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), + Parachain(43211234).into(), )); } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 8127dbfb87f7..441589aa8641 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -660,13 +660,13 @@ parameter_types! { pub ReachableDest: Option = Some(Parent.into()); // Relay/native token can be teleported between AH and Relay. pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), Parent.into(), )); - // We can reserve transfer some local token to Relay. + // We can reserve transfer native token to some random parachain. pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Here.into()) }.into(), - Parent.into(), + MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), + Parachain(43211234).into(), )); } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index 08d27d7de573..dc4e4372816d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs @@ -590,13 +590,13 @@ parameter_types! { pub ReachableDest: Option = Some(Parent.into()); // Relay/native token can be teleported between AH and Relay. pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), Parent.into(), )); - // We can reserve transfer some local token to Relay. + // We can reserve transfer native token to some random parachain. pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Here.into()) }.into(), - Parent.into(), + MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), + Parachain(43211234).into(), )); } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs index 99b00c641e27..e65f346137bf 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs @@ -246,7 +246,7 @@ parameter_types! { pub ReachableDest: Option = Some(Parent.into()); // Relay/native token can be teleported between BH and Relay. pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), Parent.into(), )); // Reserve transfers are disabled on BH. diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs index c4827268362c..1a3d4a938a97 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs @@ -250,7 +250,7 @@ parameter_types! { pub ReachableDest: Option = Some(Parent.into()); // Relay/native token can be teleported between BH and Relay. pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), Parent.into(), )); // Reserve transfers are disabled on BH. diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index 03909a68f7dc..6646e5edf94f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs @@ -319,7 +319,7 @@ parameter_types! { pub ReachableDest: Option = Some(Parent.into()); // Relay/native token can be teleported between BH and Relay. pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), Parent.into(), )); // Reserve transfers are disabled on BH. diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs index b6496ddc5056..1f673a1ee29b 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs @@ -298,7 +298,7 @@ parameter_types! { pub ReachableDest: Option = Some(Parent.into()); // Relay/native token can be teleported between BH and Relay. pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), Parent.into(), )); // Reserve transfers are disabled on Collectives. diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs index d02bcff4150c..fc55fc6a4cb4 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -228,14 +228,11 @@ parameter_types! { pub ReachableDest: Option = Some(Parent.into()); // Relay/native token can be teleported to Relay. pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), Parent.into(), )); - // Act as reserve for native token when sending to random parachain. - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), - Parachain(4321).into(), - )); + // Reserve transfers are disabled on Contracts. + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; } impl pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index 289f920253b6..a17f8e5b99ac 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -317,7 +317,7 @@ parameter_types! { pub ReachableDest: Option = Some(Parent.into()); // Relay/native token can be teleported to Relay. pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), + MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), Parent.into(), )); // Disable reserve transfers benchmarks for penpal. diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 78cefad66372..84181b1da31d 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -470,16 +470,8 @@ pub type XcmRouter = WithUniqueTopic<( #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parent.into()); - // Relay/native token can be teleported to/from Relay. - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Parent.into()) }.into(), - Parent.into(), - )); - // We can reserve transfer some AH local token to/from AH. - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(SystemAssetHubLocation::get()) }.into(), - SystemAssetHubLocation::get(), - )); + pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = None; + pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; } impl pallet_xcm::Config for Runtime { diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index da0aabfbaea5..24333aea9d91 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -218,7 +218,7 @@ parameter_types! { // We can reserve transfer native token to some random parachain. pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Here.into()) }.into(), - Parachain(4321).into(), + Parachain(43211234).into(), )); } diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index fe61725bd6d8..9e90b5640fb9 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -124,13 +124,13 @@ parameter_types! { pub ReachableDest: Option = Some(Parachain(ASSET_HUB_ID).into()); // Relay/native token can be teleported to/from AH. pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Here.into()) }.into(), + MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Here.into()) }.into(), AssetHub::get(), )); // We can reserve transfer native token to some random parachain. pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Here.into()) }.into(), - Parachain(4321).into(), + MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Here.into()) }.into(), + Parachain(43211234).into(), )); } From b648df2ba4b31e2bf45b2e1da2596de2ff6bee1a Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 27 Oct 2023 16:07:37 +0300 Subject: [PATCH 59/98] AHs simplify test_cases_over_bridge --- .../test-utils/src/test_cases_over_bridge.rs | 87 +++++-------------- 1 file changed, 21 insertions(+), 66 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs index 9d8ca0e0042a..2cb304d22388 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs @@ -16,7 +16,7 @@ //! Module contains predefined test-case scenarios for `Runtime` with various assets transferred //! over a bridge. -use crate::assert_matches_reserve_asset_deposited_instructions; +use crate::{assert_matches_reserve_asset_deposited_instructions, get_fungible_delivery_fees}; use codec::Encode; use cumulus_primitives_core::XcmpMessageSource; use frame_support::{ @@ -32,10 +32,7 @@ use parachains_runtimes_test_utils::{ use sp_runtime::{traits::StaticLookup, Saturating}; use xcm::{latest::prelude::*, VersionedMultiAssets}; use xcm_builder::{CreateMatcher, MatchXcm}; -use xcm_executor::{ - traits::{ConvertLocation, TransactAsset}, - XcmExecutor, -}; +use xcm_executor::{traits::ConvertLocation, XcmExecutor}; pub struct TestBridgingConfig { pub bridged_network: NetworkId, @@ -129,9 +126,13 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< &alice, ); - // drip ED to account + // we calculate exact delivery fees _after_ sending the message by weighing the sent + // xcm, and this delivery fee varies for different runtimes, so just add enough buffer, + // then verify the arithmetics check out on final balance. + let delivery_fees_buffer = 40_000_000_000u128; + // drip ED + transfer_amount + delivery_fees_buffer to Alice account let alice_account_init_balance = - existential_deposit.saturating_mul(2.into()) + balance_to_transfer.into(); + existential_deposit + balance_to_transfer.into() + delivery_fees_buffer.into(); let _ = >::deposit_creating( &alice_account, alice_account_init_balance, @@ -184,56 +185,6 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< let expected_beneficiary = target_destination_account; - // Make sure sender has enough funds for paying delivery fees - let handling_delivery_fees = { - // Probable XCM with `ReserveAssetDeposited`. - let mut expected_reserve_asset_deposited_message = Xcm(vec![ - ReserveAssetDeposited(MultiAssets::from(expected_assets.clone())), - ClearOrigin, - BuyExecution { - fees: MultiAsset { - id: Concrete(Default::default()), - fun: Fungible(balance_to_transfer), - }, - weight_limit: Unlimited, - }, - DepositAsset { assets: Wild(AllCounted(1)), beneficiary: expected_beneficiary }, - SetTopic([ - 220, 188, 144, 32, 213, 83, 111, 175, 44, 210, 111, 19, 90, 165, 191, 112, - 140, 247, 192, 124, 42, 17, 153, 141, 114, 34, 189, 20, 83, 69, 237, 173, - ]), - ]); - assert_matches_reserve_asset_deposited_instructions( - &mut expected_reserve_asset_deposited_message, - &expected_assets, - &expected_beneficiary, - ); - - // Call `SendXcm::validate` to get delivery fees. - let (_, delivery_fees): (_, MultiAssets) = XcmConfig::XcmSender::validate( - &mut Some(target_location_from_different_consensus), - &mut Some(expected_reserve_asset_deposited_message), - ) - .expect("validate passes"); - // Drip delivery fee to Alice account. - let mut delivery_fees_added = false; - for delivery_fee in delivery_fees.inner() { - assert_ok!(::deposit_asset( - &delivery_fee, - &MultiLocation { - parents: 0, - interior: X1(AccountId32 { - network: None, - id: alice_account.clone().into(), - }), - }, - None, - )); - delivery_fees_added = true; - } - delivery_fees_added - }; - // do pallet_xcm call reserve transfer assert_ok!(>::limited_reserve_transfer_assets( RuntimeHelper::::origin_of(alice_account.clone()), @@ -276,6 +227,7 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< // check sent XCM ExportMessage to BridgeHub + let mut delivery_fees = 0; // 1. check paid or unpaid if let Some(expected_fee_asset_id) = maybe_paid_export_message { xcm_sent @@ -316,6 +268,10 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< .split_global() .expect("split works"); assert_eq!(destination, &target_location_junctions_without_global_consensus); + // Call `SendXcm::validate` to get delivery fees. + delivery_fees = get_fungible_delivery_fees::< + ::XcmSender, + >(target_location_from_different_consensus, inner_xcm.clone()); assert_matches_reserve_asset_deposited_instructions( inner_xcm, &expected_assets, @@ -331,8 +287,8 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< assert_eq!( >::free_balance(&alice_account), alice_account_init_balance - .saturating_sub(existential_deposit) .saturating_sub(balance_to_transfer.into()) + .saturating_sub(delivery_fees.into()) ); // check reserve account increased by balance_to_transfer @@ -342,14 +298,13 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< ); // check dedicated account increased by delivery fees (if configured) - if handling_delivery_fees { - if let Some(delivery_fees_account) = delivery_fees_account { - let delivery_fees_account_balance_after = - >::free_balance(&delivery_fees_account); - assert!( - delivery_fees_account_balance_after > delivery_fees_account_balance_before - ); - } + if let Some(delivery_fees_account) = delivery_fees_account { + let delivery_fees_account_balance_after = + >::free_balance(&delivery_fees_account); + assert!( + delivery_fees_account_balance_after - delivery_fees.into() >= + delivery_fees_account_balance_before + ); } }) } From da7d8ff110fe9ee1aca3df47e438c42dc232165e Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 27 Oct 2023 18:04:18 +0300 Subject: [PATCH 60/98] runtimes: add dedicated benchmarking config for pallet-xcm --- .../runtime/src/xcm_config.rs | 15 ---- .../assets/asset-hub-kusama/src/lib.rs | 36 +++++++++- .../assets/asset-hub-kusama/src/xcm_config.rs | 21 ------ .../assets/asset-hub-polkadot/src/lib.rs | 36 +++++++++- .../asset-hub-polkadot/src/xcm_config.rs | 21 ------ .../assets/asset-hub-rococo/src/lib.rs | 36 +++++++++- .../assets/asset-hub-rococo/src/xcm_config.rs | 21 ------ .../assets/asset-hub-westend/src/lib.rs | 36 +++++++++- .../asset-hub-westend/src/xcm_config.rs | 21 ------ .../bridge-hubs/bridge-hub-kusama/src/lib.rs | 26 ++++++- .../bridge-hub-kusama/src/xcm_config.rs | 18 ----- .../bridge-hub-polkadot/src/lib.rs | 26 ++++++- .../bridge-hub-polkadot/src/xcm_config.rs | 18 ----- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 26 ++++++- .../bridge-hub-rococo/src/xcm_config.rs | 18 ----- .../collectives-polkadot/src/lib.rs | 26 ++++++- .../collectives-polkadot/src/xcm_config.rs | 18 ----- .../contracts/contracts-rococo/src/lib.rs | 27 +++++++- .../contracts-rococo/src/xcm_config.rs | 18 ----- .../runtimes/testing/penpal/src/xcm_config.rs | 18 ----- .../testing/rococo-parachain/src/lib.rs | 13 ---- polkadot/runtime/rococo/src/lib.rs | 32 ++++++++- polkadot/runtime/rococo/src/xcm_config.rs | 21 ------ .../runtime/test-runtime/src/xcm_config.rs | 13 ---- polkadot/runtime/westend/src/lib.rs | 31 ++++++++- polkadot/runtime/westend/src/xcm_config.rs | 21 ------ polkadot/xcm/pallet-xcm/src/benchmarking.rs | 69 ++++++++++++++----- polkadot/xcm/pallet-xcm/src/lib.rs | 22 +----- polkadot/xcm/pallet-xcm/src/mock.rs | 40 +++++------ .../xcm/xcm-builder/src/tests/pay/mock.rs | 13 ---- polkadot/xcm/xcm-builder/tests/mock/mod.rs | 13 ---- .../xcm-simulator/example/src/parachain.rs | 13 ---- .../xcm-simulator/example/src/relay_chain.rs | 13 ---- .../xcm/xcm-simulator/fuzzer/src/parachain.rs | 13 ---- .../xcm-simulator/fuzzer/src/relay_chain.rs | 13 ---- 35 files changed, 397 insertions(+), 425 deletions(-) diff --git a/cumulus/parachain-template/runtime/src/xcm_config.rs b/cumulus/parachain-template/runtime/src/xcm_config.rs index 9f7de9895fae..752137c96f18 100644 --- a/cumulus/parachain-template/runtime/src/xcm_config.rs +++ b/cumulus/parachain-template/runtime/src/xcm_config.rs @@ -150,15 +150,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); - // Teleports are disabled - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = None; - // Reserve transfers are disabled. - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = EnsureXcmOrigin; @@ -187,12 +178,6 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs index bc17fcada23f..f83ed416f327 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs @@ -929,7 +929,7 @@ mod benches { [pallet_collator_selection, CollatorSelection] [cumulus_pallet_xcmp_queue, XcmpQueue] // XCM - [pallet_xcm, PolkadotXcm] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -1167,6 +1167,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -1210,6 +1211,39 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // Relay/native token can be teleported between AH and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }.into(), + Parent.into(), + )) + } + + fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // AH can reserve transfer native token to some random parachain. + let random_para_id = 43211234; + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( + random_para_id.into() + ); + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }.into(), + Parachain(random_para_id).into(), + )) + } + } + use xcm::latest::prelude::*; use xcm_config::{KsmLocation, MaxAssetsIntoHolding}; use pallet_xcm_benchmarks::asset_instance_from; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs index ea28ec91832a..176a6d023178 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs @@ -552,21 +552,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); - // Relay/native token can be teleported between AH and Relay. - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), - Parent.into(), - )); - // We can reserve transfer native token to some random parachain. - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), - Parachain(43211234).into(), - )); -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; // We want to disallow users sending (arbitrary) XCMs from this chain. @@ -599,12 +584,6 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs index 7033e1c2dcac..d2f318ab11e7 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs @@ -833,7 +833,7 @@ mod benches { [pallet_collator_selection, CollatorSelection] [cumulus_pallet_xcmp_queue, XcmpQueue] // XCM - [pallet_xcm, PolkadotXcm] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -1047,6 +1047,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -1089,6 +1090,39 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // Relay/native token can be teleported between AH and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }.into(), + Parent.into(), + )) + } + + fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // AH can reserve transfer native token to some random parachain. + let random_para_id = 43211234; + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( + random_para_id.into() + ); + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }.into(), + Parachain(random_para_id).into(), + )) + } + } + use xcm::latest::prelude::*; use xcm_config::{DotLocation, MaxAssetsIntoHolding}; use pallet_xcm_benchmarks::asset_instance_from; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs index 71dc71f477e1..3910e68bf206 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs @@ -476,21 +476,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); - // Relay/native token can be teleported between AH and Relay. - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), - Parent.into(), - )); - // We can reserve transfer native token to some random parachain. - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), - Parachain(43211234).into(), - )); -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; // We want to disallow users sending (arbitrary) XCMs from this chain. @@ -523,12 +508,6 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 1ce504d6704f..44fa05b9924e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -1008,7 +1008,7 @@ mod benches { [pallet_xcm_bridge_hub_router, ToWococo] [pallet_xcm_bridge_hub_router, ToRococo] // XCM - [pallet_xcm, PolkadotXcm] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -1246,6 +1246,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; use pallet_xcm_bridge_hub_router::benchmarking::Pallet as XcmBridgeHubRouterBench; // This is defined once again in dispatch_benchmark, because list_benchmarks! @@ -1298,6 +1299,39 @@ impl_runtime_apis! { Config as XcmBridgeHubRouterConfig, }; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // Relay/native token can be teleported between AH and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }.into(), + Parent.into(), + )) + } + + fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // AH can reserve transfer native token to some random parachain. + let random_para_id = 43211234; + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( + random_para_id.into() + ); + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }.into(), + Parachain(random_para_id).into(), + )) + } + } + impl XcmBridgeHubRouterConfig for Runtime { fn make_congested() { cumulus_pallet_xcmp_queue::bridging::suspend_channel_for_benchmarks::( diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 441589aa8641..6aebaf9be6d2 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -655,21 +655,6 @@ pub type XcmRouter = WithUniqueTopic<( ToRococoXcmRouter, )>; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); - // Relay/native token can be teleported between AH and Relay. - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), - Parent.into(), - )); - // We can reserve transfer native token to some random parachain. - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), - Parachain(43211234).into(), - )); -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; // We want to disallow users sending (arbitrary) XCMs from this chain. @@ -709,12 +694,6 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 30d384222422..af7e41f81236 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -947,7 +947,7 @@ mod benches { [pallet_collator_selection, CollatorSelection] [cumulus_pallet_xcmp_queue, XcmpQueue] // XCM - [pallet_xcm, PolkadotXcm] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -1231,6 +1231,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -1274,6 +1275,39 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // Relay/native token can be teleported between AH and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }.into(), + Parent.into(), + )) + } + + fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // AH can reserve transfer native token to some random parachain. + let random_para_id = 43211234; + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( + random_para_id.into() + ); + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }.into(), + Parachain(random_para_id).into(), + )) + } + } + use xcm::latest::prelude::*; use xcm_config::{MaxAssetsIntoHolding, WestendLocation}; use pallet_xcm_benchmarks::asset_instance_from; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index dc4e4372816d..373d6dc3b588 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs @@ -585,21 +585,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); - // Relay/native token can be teleported between AH and Relay. - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), - Parent.into(), - )); - // We can reserve transfer native token to some random parachain. - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), - Parachain(43211234).into(), - )); -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = EnsureXcmOrigin; @@ -628,12 +613,6 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs index 9fdf8380bc3a..7ff1e1cdb356 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs @@ -456,7 +456,7 @@ mod benches { [pallet_collator_selection, CollatorSelection] [cumulus_pallet_xcmp_queue, XcmpQueue] // XCM - [pallet_xcm, PolkadotXcm] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -636,6 +636,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -671,6 +672,29 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // Relay/native token can be teleported between BH and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }.into(), + Parent.into(), + )) + } + + fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // Reserve transfers are disabled on BH. + None + } + } + use xcm::latest::prelude::*; use xcm_config::KsmRelayLocation; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs index e65f346137bf..218da1a9bb61 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs @@ -241,18 +241,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); - // Relay/native token can be teleported between BH and Relay. - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), - Parent.into(), - )); - // Reserve transfers are disabled on BH. - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; // We want to disallow users sending (arbitrary) XCMs from this chain. @@ -284,12 +272,6 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs index 6ce1df992957..39238689d458 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs @@ -456,7 +456,7 @@ mod benches { [pallet_collator_selection, CollatorSelection] [cumulus_pallet_xcmp_queue, XcmpQueue] // XCM - [pallet_xcm, PolkadotXcm] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -636,6 +636,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -671,6 +672,29 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // Relay/native token can be teleported between BH and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }.into(), + Parent.into(), + )) + } + + fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // Reserve transfers are disabled on BH. + None + } + } + use xcm::latest::prelude::*; use xcm_config::DotRelayLocation; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs index 1a3d4a938a97..727990d85f49 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs @@ -245,18 +245,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); - // Relay/native token can be teleported between BH and Relay. - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), - Parent.into(), - )); - // Reserve transfers are disabled on BH. - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; // We want to disallow users sending (arbitrary) XCMs from this chain. @@ -288,12 +276,6 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 326acc812a27..77f6d8cdd1ea 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -535,7 +535,7 @@ mod benches { [pallet_collator_selection, CollatorSelection] [cumulus_pallet_xcmp_queue, XcmpQueue] // XCM - [pallet_xcm, PolkadotXcm] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -816,6 +816,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -860,6 +861,29 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // Relay/native token can be teleported between BH and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }.into(), + Parent.into(), + )) + } + + fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // Reserve transfers are disabled on BH. + None + } + } + use xcm::latest::prelude::*; use xcm_config::TokenLocation; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index 6646e5edf94f..01624c574344 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs @@ -314,18 +314,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); - // Relay/native token can be teleported between BH and Relay. - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), - Parent.into(), - )); - // Reserve transfers are disabled on BH. - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type XcmRouter = XcmRouter; @@ -356,12 +344,6 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs index edfbfa851fe3..258ecd54f901 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs @@ -719,7 +719,7 @@ mod benches { [cumulus_pallet_xcmp_queue, XcmpQueue] [pallet_alliance, Alliance] [pallet_collective, AllianceMotion] - [pallet_xcm, PolkadotXcm] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] [pallet_preimage, Preimage] [pallet_scheduler, Scheduler] [pallet_referenda, FellowshipReferenda] @@ -907,6 +907,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -936,6 +937,29 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // Relay/native token can be teleported between Collectives and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }.into(), + Parent.into(), + )) + } + + fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // Reserve transfers are disabled on Collectives. + None + } + } + let whitelist: Vec = vec![ // Block Number hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs index 1f673a1ee29b..cab853741ded 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs @@ -293,18 +293,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); - // Relay/native token can be teleported between BH and Relay. - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), - Parent.into(), - )); - // Reserve transfers are disabled on Collectives. - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; -} - /// Type to convert the Fellows origin to a Plurality `MultiLocation` value. pub type FellowsToPlurality = OriginToPluralityVoice; @@ -335,12 +323,6 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 71733d48e815..4353d209fe21 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -405,7 +405,7 @@ mod benches { [pallet_timestamp, Timestamp] [pallet_collator_selection, CollatorSelection] [pallet_contracts, Contracts] - [pallet_xcm, PolkadotXcm] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] ); } @@ -650,6 +650,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -679,6 +680,30 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use xcm::latest::prelude::*; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // Relay/native token can be teleported between Contracts-System-Para and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }.into(), + Parent.into(), + )) + } + + fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // Reserve transfers are disabled on Contracts-System-Para. + None + } + } + let whitelist: Vec = vec![ // Block Number hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs index fc55fc6a4cb4..ef52ac002412 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -223,18 +223,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); - // Relay/native token can be teleported to Relay. - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), - Parent.into(), - )); - // Reserve transfers are disabled on Contracts. - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; // We want to disallow users sending (arbitrary) XCMs from this chain. @@ -264,12 +252,6 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index a17f8e5b99ac..542d07fbed95 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -312,18 +312,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); - // Relay/native token can be teleported to Relay. - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), - Parent.into(), - )); - // Disable reserve transfers benchmarks for penpal. - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = EnsureXcmOrigin; @@ -352,12 +340,6 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 84181b1da31d..01fcd4d3c1d5 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -467,13 +467,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = None; - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = EnsureXcmOrigin; @@ -498,12 +491,6 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index e6ad061ce069..6171576d30c0 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -1572,7 +1572,7 @@ mod benches { [pallet_asset_rate, AssetRate] [pallet_whitelist, Whitelist] // XCM - [pallet_xcm, XcmPallet] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] [pallet_xcm_benchmarks::fungible, pallet_xcm_benchmarks::fungible::Pallet::] [pallet_xcm_benchmarks::generic, pallet_xcm_benchmarks::generic::Pallet::] ); @@ -2048,6 +2048,8 @@ sp_api::impl_runtime_apis! { use frame_system_benchmarking::Pallet as SystemBench; use frame_benchmarking::baseline::Pallet as Baseline; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -2065,6 +2067,7 @@ sp_api::impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; use frame_system_benchmarking::Pallet as SystemBench; use frame_benchmarking::baseline::Pallet as Baseline; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; use sp_storage::TrackedStorageKey; use xcm::latest::prelude::*; use xcm_config::{ @@ -2081,6 +2084,33 @@ sp_api::impl_runtime_apis! { impl frame_system_benchmarking::Config for Runtime {} impl frame_benchmarking::baseline::Config for Runtime {} + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(crate::xcm_config::AssetHub::get()) + } + + fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // Relay/native token can be teleported to/from AH. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Here.into()) + }.into(), + crate::xcm_config::AssetHub::get(), + )) + } + + fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // Relay can reserve transfer native token to some random parachain. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Here.into()) + }.into(), + Parachain(43211234).into(), + )) + } + } impl pallet_xcm_benchmarks::Config for Runtime { type XcmConfig = XcmConfig; type AccountIdConverter = LocationConverter; diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index 24333aea9d91..54828e0b8a60 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -207,21 +207,6 @@ parameter_types! { pub const FellowsBodyId: BodyId = BodyId::Technical; } -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parachain(ASSET_HUB_ID).into()); - // Relay/native token can be teleported to/from AH. - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Here.into()) }.into(), - AssetHub::get(), - )); - // We can reserve transfer native token to some random parachain. - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Here.into()) }.into(), - Parachain(43211234).into(), - )); -} - /// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior /// location of this chain. pub type LocalOriginToLocation = ( @@ -276,10 +261,4 @@ impl pallet_xcm::Config for Runtime { type RemoteLockConsumerIdentifier = (); type WeightInfo = crate::weights::pallet_xcm::WeightInfo; type AdminOrigin = EnsureRoot; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } diff --git a/polkadot/runtime/test-runtime/src/xcm_config.rs b/polkadot/runtime/test-runtime/src/xcm_config.rs index aa9e29795fcb..ae4faecf7001 100644 --- a/polkadot/runtime/test-runtime/src/xcm_config.rs +++ b/polkadot/runtime/test-runtime/src/xcm_config.rs @@ -127,13 +127,6 @@ impl xcm_executor::Config for XcmConfig { type Aliasers = Nothing; } -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(xcm::latest::Junctions::Here.into()); - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = None; - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; -} - impl pallet_xcm::Config for crate::Runtime { // The config types here are entirely configurable, since the only one that is sorely needed // is `XcmExecutor`, which will be used in unit tests located in xcm-executor. @@ -160,10 +153,4 @@ impl pallet_xcm::Config for crate::Runtime { type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; type AdminOrigin = EnsureRoot; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 9ee4f3cf23e5..79145855d71a 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1616,7 +1616,7 @@ mod benches { [pallet_whitelist, Whitelist] [pallet_asset_rate, AssetRate] // XCM - [pallet_xcm, XcmPallet] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -2131,6 +2131,7 @@ sp_api::impl_runtime_apis! { use pallet_session_benchmarking::Pallet as SessionBench; use pallet_offences_benchmarking::Pallet as OffencesBench; use pallet_election_provider_support_benchmarking::Pallet as ElectionProviderBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; use frame_system_benchmarking::Pallet as SystemBench; use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; @@ -2158,12 +2159,40 @@ sp_api::impl_runtime_apis! { use pallet_session_benchmarking::Pallet as SessionBench; use pallet_offences_benchmarking::Pallet as OffencesBench; use pallet_election_provider_support_benchmarking::Pallet as ElectionProviderBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; use frame_system_benchmarking::Pallet as SystemBench; use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; impl pallet_session_benchmarking::Config for Runtime {} impl pallet_offences_benchmarking::Config for Runtime {} impl pallet_election_provider_support_benchmarking::Config for Runtime {} + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(crate::xcm_config::AssetHub::get()) + } + + fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // Relay/native token can be teleported to/from AH. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Here.into()) + }.into(), + crate::xcm_config::AssetHub::get(), + )) + } + + fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + // Relay can reserve transfer native token to some random parachain. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Here.into()) + }.into(), + crate::Junction::Parachain(43211234).into(), + )) + } + } impl frame_system_benchmarking::Config for Runtime {} impl pallet_nomination_pools_benchmarking::Config for Runtime {} impl runtime_parachains::disputes::slashing::benchmarking::Config for Runtime {} diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index 9e90b5640fb9..470f1252b191 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -119,21 +119,6 @@ parameter_types! { pub const MaxAssetsIntoHolding: u32 = 64; } -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parachain(ASSET_HUB_ID).into()); - // Relay/native token can be teleported to/from AH. - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Here.into()) }.into(), - AssetHub::get(), - )); - // We can reserve transfer native token to some random parachain. - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { fun: Fungible(crate::EXISTENTIAL_DEPOSIT), id: Concrete(Here.into()) }.into(), - Parachain(43211234).into(), - )); -} - pub type TrustedTeleporters = ( xcm_builder::Case, xcm_builder::Case, @@ -273,10 +258,4 @@ impl pallet_xcm::Config for Runtime { type RemoteLockConsumerIdentifier = (); type WeightInfo = crate::weights::pallet_xcm::WeightInfo; type AdminOrigin = EnsureRoot; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs index b0a37db6a783..ab2941b10de3 100644 --- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs @@ -25,7 +25,40 @@ use xcm::{latest::prelude::*, v2}; type RuntimeOrigin = ::RuntimeOrigin; // existential deposit multiplier -const ED_MULTIPLIER: u32 = 10; +const ED_MULTIPLIER: u32 = 100; + +/// Pallet we're benchmarking here. +pub struct Pallet(crate::Pallet); + +/// Trait that must be implemented by runtime to be able to benchmark pallet properly. +pub trait Config: crate::Config { + /// A `MultiLocation` that can be reached via `XcmRouter`. Used only in benchmarks. + /// + /// If `None`, the benchmarks that depend on a reachable destination will be skipped. + fn reachable_dest() -> Option { + None + } + + /// A `(MultiAssets, MultiLocation)` pair representing assets and the destination they can + /// be teleported to. Used only in benchmarks. + /// + /// Implementation should also make sure `dest` is reachable/connected. + /// + /// If `None`, the benchmarks that depend on this will be skipped. + fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + None + } + + /// A `(MultiAssets, MultiLocation)` pair representing assets and the destination they can + /// be reserve-transferred to. Used only in benchmarks. + /// + /// Implementation should also make sure `dest` is reachable/connected. + /// + /// If `None`, the benchmarks that depend on this will be skipped. + fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + None + } +} benchmarks! { where_clause { @@ -40,7 +73,7 @@ benchmarks! { return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) } let msg = Xcm(vec![ClearOrigin]); - let versioned_dest: VersionedMultiLocation = T::ReachableDest::get().ok_or( + let versioned_dest: VersionedMultiLocation = T::reachable_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), )? .into(); @@ -48,7 +81,7 @@ benchmarks! { }: _>(send_origin, Box::new(versioned_dest), Box::new(versioned_msg)) teleport_assets { - let (assets, destination) = T::TeleportableAssets::get().ok_or( + let (assets, destination) = T::teleportable_assets_and_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), )?; @@ -92,7 +125,7 @@ benchmarks! { } reserve_transfer_assets { - let (assets, destination) = T::ReserveTransferableAssets::get().ok_or( + let (assets, destination) = T::reserve_transferable_assets_and_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), )?; @@ -148,7 +181,7 @@ benchmarks! { }: _>(execute_origin, Box::new(versioned_msg), Weight::zero()) force_xcm_version { - let loc = T::ReachableDest::get().ok_or( + let loc = T::reachable_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), )?; let xcm_version = 2; @@ -157,18 +190,18 @@ benchmarks! { force_default_xcm_version {}: _(RawOrigin::Root, Some(2)) force_subscribe_version_notify { - let versioned_loc: VersionedMultiLocation = T::ReachableDest::get().ok_or( + let versioned_loc: VersionedMultiLocation = T::reachable_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), )? .into(); }: _(RawOrigin::Root, Box::new(versioned_loc)) force_unsubscribe_version_notify { - let loc = T::ReachableDest::get().ok_or( + let loc = T::reachable_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), )?; let versioned_loc: VersionedMultiLocation = loc.into(); - let _ = Pallet::::request_version_notify(loc); + let _ = crate::Pallet::::request_version_notify(loc); }: _(RawOrigin::Root, Box::new(versioned_loc)) force_suspension {}: _(RawOrigin::Root, true) @@ -178,7 +211,7 @@ benchmarks! { let loc = VersionedMultiLocation::from(MultiLocation::from(Parent)); SupportedVersion::::insert(old_version, loc, old_version); }: { - Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateSupportedVersion, Weight::zero()); + crate::Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateSupportedVersion, Weight::zero()); } migrate_version_notifiers { @@ -186,22 +219,22 @@ benchmarks! { let loc = VersionedMultiLocation::from(MultiLocation::from(Parent)); VersionNotifiers::::insert(old_version, loc, 0); }: { - Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateVersionNotifiers, Weight::zero()); + crate::Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateVersionNotifiers, Weight::zero()); } already_notified_target { - let loc = T::ReachableDest::get().ok_or( + let loc = T::reachable_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(T::DbWeight::get().reads(1))), )?; let loc = VersionedMultiLocation::from(loc); let current_version = T::AdvertisedXcmVersion::get(); VersionNotifyTargets::::insert(current_version, loc, (0, Weight::zero(), current_version)); }: { - Pallet::::check_xcm_version_change(VersionMigrationStage::NotifyCurrentTargets(None), Weight::zero()); + crate::Pallet::::check_xcm_version_change(VersionMigrationStage::NotifyCurrentTargets(None), Weight::zero()); } notify_current_targets { - let loc = T::ReachableDest::get().ok_or( + let loc = T::reachable_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(T::DbWeight::get().reads_writes(1, 3))), )?; let loc = VersionedMultiLocation::from(loc); @@ -209,7 +242,7 @@ benchmarks! { let old_version = current_version - 1; VersionNotifyTargets::::insert(current_version, loc, (0, Weight::zero(), old_version)); }: { - Pallet::::check_xcm_version_change(VersionMigrationStage::NotifyCurrentTargets(None), Weight::zero()); + crate::Pallet::::check_xcm_version_change(VersionMigrationStage::NotifyCurrentTargets(None), Weight::zero()); } notify_target_migration_fail { @@ -223,7 +256,7 @@ benchmarks! { let current_version = T::AdvertisedXcmVersion::get(); VersionNotifyTargets::::insert(current_version, bad_loc, (0, Weight::zero(), current_version)); }: { - Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero()); + crate::Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero()); } migrate_version_notify_targets { @@ -232,18 +265,18 @@ benchmarks! { let loc = VersionedMultiLocation::from(MultiLocation::from(Parent)); VersionNotifyTargets::::insert(old_version, loc, (0, Weight::zero(), current_version)); }: { - Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero()); + crate::Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero()); } migrate_and_notify_old_targets { - let loc = T::ReachableDest::get().ok_or( + let loc = T::reachable_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(T::DbWeight::get().reads_writes(1, 3))), )?; let loc = VersionedMultiLocation::from(loc); let old_version = T::AdvertisedXcmVersion::get() - 1; VersionNotifyTargets::::insert(old_version, loc, (0, Weight::zero(), old_version)); }: { - Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero()); + crate::Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero()); } impl_benchmark_test_suite!( diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 8d9bc7373c6c..186dd2d51197 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -19,7 +19,7 @@ #![cfg_attr(not(feature = "std"), no_std)] #[cfg(feature = "runtime-benchmarks")] -mod benchmarking; +pub mod benchmarking; #[cfg(test)] mod mock; #[cfg(test)] @@ -261,26 +261,6 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; - - /// A `MultiLocation` that can be reached via `XcmRouter`. Used only in benchmarks. - /// - /// If `None`, the benchmarks that depend on a reachable destination will be skipped. - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest: Get>; - - /// A `(MultiAssets, MultiLocation)` pair representing assets and the destination they can - /// be teleported to. Used only in benchmarks. - /// - /// If `None`, the benchmarks that depend on `TeleportableAssets` will be skipped. - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets: Get>; - - /// A `(MultiAssets, MultiLocation)` pair representing assets and the destination they can - /// be reserve-transferred to. Used only in benchmarks. - /// - /// If `None`, the benchmarks that depend on `ReserveTransferableAssets` will be skipped. - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets: Get>; } #[pallet::event] diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index e421d46f206b..b88734b9abfb 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -498,22 +498,6 @@ parameter_types! { pub static AdvertisedXcmVersion: pallet_xcm::XcmVersion = 3; } -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parachain(1000).into()); - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - NativeAsset::get().into(), - SystemParachainLocation::get(), - )); - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = Some(( - MultiAsset { - fun: Fungible(10), - id: Concrete(Here.into_location()), - }.into(), - Parachain(OTHER_PARA_ID).into(), - )); -} - impl pallet_xcm::Config for Test { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; @@ -538,12 +522,6 @@ impl pallet_xcm::Config for Test { type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } impl origin::Config for Test {} @@ -554,6 +532,24 @@ impl pallet_test_notifier::Config for Test { type RuntimeCall = RuntimeCall; } +#[cfg(feature = "runtime-benchmarks")] +impl super::benchmarking::Config for Test { + fn reachable_dest() -> Option { + Some(Parachain(1000).into()) + } + + fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + Some((NativeAsset::get().into(), SystemParachainLocation::get())) + } + + fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + Some(( + MultiAsset { fun: Fungible(10), id: Concrete(Here.into_location()) }.into(), + Parachain(OTHER_PARA_ID).into(), + )) + } +} + pub(crate) fn last_event() -> RuntimeEvent { System::events().pop().expect("RuntimeEvent expected").event } diff --git a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs index b4c2d9ae3dc7..78b9284c689f 100644 --- a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs @@ -246,13 +246,6 @@ type SovereignAccountOf = ( HashedDescription>, ); -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parachain(1000).into()); - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = None; - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; -} - impl pallet_xcm::Config for Test { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = EnsureXcmOrigin; @@ -277,12 +270,6 @@ impl pallet_xcm::Config for Test { type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; type AdminOrigin = EnsureRoot; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } pub const UNITS: Balance = 1_000_000_000_000; diff --git a/polkadot/xcm/xcm-builder/tests/mock/mod.rs b/polkadot/xcm/xcm-builder/tests/mock/mod.rs index c9c57d8bf7ad..4f183c7a15b6 100644 --- a/polkadot/xcm/xcm-builder/tests/mock/mod.rs +++ b/polkadot/xcm/xcm-builder/tests/mock/mod.rs @@ -210,13 +210,6 @@ impl xcm_executor::Config for XcmConfig { pub type LocalOriginToLocation = SignedToAccountId32; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Here.into()); - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = None; - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type UniversalLocation = UniversalLocation; @@ -242,12 +235,6 @@ impl pallet_xcm::Config for Runtime { type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; type AdminOrigin = EnsureRoot; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } impl origin::Config for Runtime {} diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain.rs b/polkadot/xcm/xcm-simulator/example/src/parachain.rs index 0e1e3fd8f89f..9f0411970ce7 100644 --- a/polkadot/xcm/xcm-simulator/example/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/example/src/parachain.rs @@ -399,13 +399,6 @@ impl mock_msg_queue::Config for Runtime { pub type LocalOriginToLocation = SignedToAccountId32; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = None; - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; -} - pub struct TrustedLockerCase(PhantomData); impl> ContainsPair for TrustedLockerCase @@ -446,12 +439,6 @@ impl pallet_xcm::Config for Runtime { type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; type AdminOrigin = EnsureRoot; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } type Block = frame_system::mocking::MockBlock; diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs index f68e94df1fa0..bdd7ff6d3eaf 100644 --- a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs @@ -199,13 +199,6 @@ impl Config for XcmConfig { pub type LocalOriginToLocation = SignedToAccountId32; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parachain(1).into()); - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = None; - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; @@ -231,12 +224,6 @@ impl pallet_xcm::Config for Runtime { type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; type AdminOrigin = EnsureRoot; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } parameter_types! { diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs index f47476dcb615..41234837aca0 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs @@ -313,13 +313,6 @@ impl mock_msg_queue::Config for Runtime { pub type LocalOriginToLocation = SignedToAccountId32; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = None; - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = EnsureXcmOrigin; @@ -344,12 +337,6 @@ impl pallet_xcm::Config for Runtime { type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; type AdminOrigin = EnsureRoot; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } type Block = frame_system::mocking::MockBlock; diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs index 2a843acf62c1..c9a57db970a7 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs @@ -163,13 +163,6 @@ impl Config for XcmConfig { pub type LocalOriginToLocation = SignedToAccountId32; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parachain(1).into()); - pub TeleportableAssets: Option<(MultiAssets, MultiLocation)> = None; - pub ReserveTransferableAssets: Option<(MultiAssets, MultiLocation)> = None; -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; @@ -195,12 +188,6 @@ impl pallet_xcm::Config for Runtime { type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; type AdminOrigin = EnsureRoot; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - #[cfg(feature = "runtime-benchmarks")] - type TeleportableAssets = TeleportableAssets; - #[cfg(feature = "runtime-benchmarks")] - type ReserveTransferableAssets = ReserveTransferableAssets; } parameter_types! { From 8d85faa3e65c2eb29533d43ae8795e4c991df7b7 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Sat, 28 Oct 2023 11:49:51 +0300 Subject: [PATCH 61/98] AHs benchmarks: fix transfer to sibling parachain --- cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs | 2 +- .../parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs | 2 +- cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs | 2 +- cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs index f83ed416f327..25d5712f4dfb 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs @@ -1239,7 +1239,7 @@ impl_runtime_apis! { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), - Parachain(random_para_id).into(), + ParentThen(Parachain(random_para_id).into()).into(), )) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs index d2f318ab11e7..dd111355c02b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs @@ -1118,7 +1118,7 @@ impl_runtime_apis! { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), - Parachain(random_para_id).into(), + ParentThen(Parachain(random_para_id).into()).into(), )) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 44fa05b9924e..1f54c3ca997b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -1327,7 +1327,7 @@ impl_runtime_apis! { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), - Parachain(random_para_id).into(), + ParentThen(Parachain(random_para_id).into()).into(), )) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index af7e41f81236..cc04db22785b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -1303,7 +1303,7 @@ impl_runtime_apis! { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) }.into(), - Parachain(random_para_id).into(), + ParentThen(Parachain(random_para_id).into()).into(), )) } } From 37552fd5ca94bfb72ff09e6c1a5045a039b6371d Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 30 Oct 2023 13:24:22 +0200 Subject: [PATCH 62/98] Update polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs Co-authored-by: Francisco Aguirre --- polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs b/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs index 77b326052dcc..a35c6555c96c 100644 --- a/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs +++ b/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs @@ -74,7 +74,8 @@ pub trait AssetTransferSupport { if asset_location == MultiLocation::here() || Self::IsTeleporter::contains(asset, &asset_location) { - // if local asset, or remote location that allows local teleports => local reserve + // if the asset is local, then it's a local reserve + // it's also a local reserve if the asset's location is not `here` but it's a location where it can be teleported to `here` => local reserve Ok(TransferType::LocalReserve) } else if Self::IsReserve::contains(asset, &asset_location) { // remote location that is recognized as reserve location for asset From 6714d39146e80c8d8559e12b8af57fef1ef4f38f Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 30 Oct 2023 13:25:55 +0200 Subject: [PATCH 63/98] Update polkadot/xcm/pallet-xcm/src/lib.rs Co-authored-by: Francisco Aguirre --- polkadot/xcm/pallet-xcm/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 186dd2d51197..fcd51fd7b0f2 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1484,7 +1484,7 @@ impl Pallet { ClearOrigin, // buy exec using `fees` in holding deposited in top instruction here BuyExecution { fees: reanchored_fees, weight_limit }, - // deposit all assets in holding to `beneficiary` account(s) + // deposit all assets in holding to `beneficiary` location DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, ] .into_iter(), From 7a61129cb91a05d7aacb4f378151aa6c303a15e6 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 30 Oct 2023 13:31:38 +0200 Subject: [PATCH 64/98] fmt --- polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs b/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs index a35c6555c96c..980554f2dce2 100644 --- a/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs +++ b/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs @@ -75,7 +75,8 @@ pub trait AssetTransferSupport { Self::IsTeleporter::contains(asset, &asset_location) { // if the asset is local, then it's a local reserve - // it's also a local reserve if the asset's location is not `here` but it's a location where it can be teleported to `here` => local reserve + // it's also a local reserve if the asset's location is not `here` but it's a location + // where it can be teleported to `here` => local reserve Ok(TransferType::LocalReserve) } else if Self::IsReserve::contains(asset, &asset_location) { // remote location that is recognized as reserve location for asset From 0f76530bfb21ad30452f6c60a33637a72a9bbd08 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 31 Oct 2023 16:20:31 +0200 Subject: [PATCH 65/98] Update polkadot/xcm/xcm-builder/src/barriers.rs Co-authored-by: Branislav Kontur --- polkadot/xcm/xcm-builder/src/barriers.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/polkadot/xcm/xcm-builder/src/barriers.rs b/polkadot/xcm/xcm-builder/src/barriers.rs index 50098791b443..3b13cab2c1ea 100644 --- a/polkadot/xcm/xcm-builder/src/barriers.rs +++ b/polkadot/xcm/xcm-builder/src/barriers.rs @@ -88,8 +88,6 @@ impl> ShouldExecute for AllowTopLevelPaidExecutionFro _ => Err(ProcessMessageError::BadFormat), })? .skip_inst_while(|inst| matches!(inst, ClearOrigin))? - // allow setting fees mode to jit or not for use in following `BuyExecution` - .skip_inst_while(|inst| matches!(inst, SetFeesMode { .. }))? .match_next_inst(|inst| match inst { BuyExecution { weight_limit: Limited(ref mut weight), .. } if weight.all_gte(max_weight) => From 9d3f2dda31bd3e75044e8a5932f2c6c1eafa142b Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 31 Oct 2023 16:21:08 +0200 Subject: [PATCH 66/98] Update polkadot/xcm/pallet-xcm/src/lib.rs Co-authored-by: Branislav Kontur --- polkadot/xcm/pallet-xcm/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index fcd51fd7b0f2..0d146dff9e44 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1219,7 +1219,7 @@ impl Pallet { ensure!(!x.is_zero(), Error::::Empty); } let transfer_type = - ::determine_for(&asset, dest) + T::XcmExecutor::determine_for(&asset, dest) .map_err(Error::::from)?; // Ensure asset is not teleportable to `dest`. ensure!(transfer_type != TransferType::Teleport, Error::::Filtered); From 9feb4b0103819eaac668cafde11b4840ecba0c7f Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 31 Oct 2023 16:21:23 +0200 Subject: [PATCH 67/98] Update polkadot/xcm/pallet-xcm/src/lib.rs Co-authored-by: Branislav Kontur --- polkadot/xcm/pallet-xcm/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 0d146dff9e44..f57a4720282b 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1259,7 +1259,7 @@ impl Pallet { } let fees = assets.swap_remove(fee_asset_item as usize); let fees_transfer_type = - ::determine_for(&fees, &dest) + T::XcmExecutor::determine_for(&fees, &dest) .map_err(Error::::from)?; let assets_transfer_type = if assets.is_empty() { // Single asset to transfer (one used for fees where transfer type is determined above). From 0a38b70d17fe5fb059e847381280769624372073 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 31 Oct 2023 16:21:39 +0200 Subject: [PATCH 68/98] Update polkadot/xcm/pallet-xcm/src/lib.rs Co-authored-by: Branislav Kontur --- polkadot/xcm/pallet-xcm/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index f57a4720282b..3cc2d600d62c 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1332,7 +1332,7 @@ impl Pallet { let (origin_location, assets) = value; for asset in assets.iter() { let transfer_type = - ::determine_for(asset, &dest) + T::XcmExecutor::determine_for(asset, &dest) .map_err(Error::::from)?; ensure!(matches!(transfer_type, TransferType::Teleport), Error::::Filtered); } From 02447d00d928b27bd94022fa87eac09ec1978af2 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 31 Oct 2023 16:22:56 +0200 Subject: [PATCH 69/98] fmt --- polkadot/xcm/pallet-xcm/src/lib.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 3cc2d600d62c..3af0a48b2440 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1219,8 +1219,7 @@ impl Pallet { ensure!(!x.is_zero(), Error::::Empty); } let transfer_type = - T::XcmExecutor::determine_for(&asset, dest) - .map_err(Error::::from)?; + T::XcmExecutor::determine_for(&asset, dest).map_err(Error::::from)?; // Ensure asset is not teleportable to `dest`. ensure!(transfer_type != TransferType::Teleport, Error::::Filtered); if let Some(reserve) = reserve.as_ref() { @@ -1259,8 +1258,7 @@ impl Pallet { } let fees = assets.swap_remove(fee_asset_item as usize); let fees_transfer_type = - T::XcmExecutor::determine_for(&fees, &dest) - .map_err(Error::::from)?; + T::XcmExecutor::determine_for(&fees, &dest).map_err(Error::::from)?; let assets_transfer_type = if assets.is_empty() { // Single asset to transfer (one used for fees where transfer type is determined above). ensure!(fees_transfer_type != TransferType::Teleport, Error::::Filtered); @@ -1332,8 +1330,7 @@ impl Pallet { let (origin_location, assets) = value; for asset in assets.iter() { let transfer_type = - T::XcmExecutor::determine_for(asset, &dest) - .map_err(Error::::from)?; + T::XcmExecutor::determine_for(asset, &dest).map_err(Error::::from)?; ensure!(matches!(transfer_type, TransferType::Teleport), Error::::Filtered); } let fees = assets.get(fee_asset_item as usize).ok_or(Error::::Empty)?.clone(); From b67cb0f8ab13b20aba82c19d4b08ae84f9f71efc Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 1 Nov 2023 09:43:54 +0200 Subject: [PATCH 70/98] xcm-emulator: configure penpal for asset transfers and enhance existing tests --- .../src/tests/reserve_transfer.rs | 7 ++- .../asset-hub-rococo/src/tests/teleport.rs | 2 +- .../asset-hub-westend/src/tests/teleport.rs | 2 +- .../emulated/common/src/constants.rs | 15 +++-- .../runtimes/testing/penpal/src/xcm_config.rs | 56 ++++++------------- 5 files changed, 33 insertions(+), 49 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index a1b604fad02c..903c01ee921c 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -166,6 +166,7 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { let mut test = SystemParaToParaTest::new(test_args); let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; test.set_assertion::(system_para_to_para_assertions); // TODO: Add assertion for Penpal runtime. Right now message is failing with @@ -174,6 +175,7 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { 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::< @@ -181,9 +183,10 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { >(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); - // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve - // transfers + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); } /// Limited Reserve Transfers of a local asset from System Parachain to Parachain should work diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs index 0d2ca6852470..297ee83d7535 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs @@ -51,7 +51,7 @@ fn relay_dest_assertions(t: SystemParaToRelayTest) { assert_expected_events!( Rococo, vec![ - // Amount is witdrawn from Relay Chain's `CheckAccount` + // Amount is withdrawn from Relay Chain's `CheckAccount` RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { who: *who == ::XcmPallet::check_account(), amount: *amount == t.args.amount, diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs index 4fe0062dafcd..aca41322c3cf 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs @@ -53,7 +53,7 @@ fn relay_dest_assertions(t: SystemParaToRelayTest) { assert_expected_events!( Westend, vec![ - // Amount is witdrawn from Relay Chain's `CheckAccount` + // Amount is withdrawn from Relay Chain's `CheckAccount` RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { who: *who == ::XcmPallet::check_account(), amount: *amount == t.args.amount, diff --git a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs index 93abae753b94..6b2824bd09f2 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs @@ -386,6 +386,7 @@ pub mod asset_hub_westend { use super::*; pub const PARA_ID: u32 = 1000; pub const ED: Balance = parachains_common::westend::currency::EXISTENTIAL_DEPOSIT; + const ENDOWMENT: u128 = ED * 4096; pub fn genesis() -> Storage { let genesis_config = asset_hub_westend_runtime::RuntimeGenesisConfig { @@ -399,7 +400,7 @@ pub mod asset_hub_westend { balances: accounts::init_balances() .iter() .cloned() - .map(|k| (k, ED * 4096)) + .map(|k| (k, ENDOWMENT)) .collect(), }, parachain_info: asset_hub_westend_runtime::ParachainInfoConfig { @@ -442,6 +443,7 @@ pub mod asset_hub_rococo { use super::*; pub const PARA_ID: u32 = 1000; pub const ED: Balance = parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT; + const ENDOWMENT: u128 = ED * 4096 * 4096; pub fn genesis() -> Storage { let genesis_config = asset_hub_rococo_runtime::RuntimeGenesisConfig { @@ -455,7 +457,7 @@ pub mod asset_hub_rococo { balances: accounts::init_balances() .iter() .cloned() - .map(|k| (k, ED * 4096 * 4096)) + .map(|k| (k, ENDOWMENT)) .collect(), }, parachain_info: asset_hub_rococo_runtime::ParachainInfoConfig { @@ -498,6 +500,7 @@ pub mod asset_hub_wococo { use super::*; pub const PARA_ID: u32 = 1000; pub const ED: Balance = parachains_common::wococo::currency::EXISTENTIAL_DEPOSIT; + const ENDOWMENT: u128 = ED * 4096; pub fn genesis() -> Storage { let genesis_config = asset_hub_rococo_runtime::RuntimeGenesisConfig { @@ -511,7 +514,7 @@ pub mod asset_hub_wococo { balances: accounts::init_balances() .iter() .cloned() - .map(|k| (k, ED * 4096)) + .map(|k| (k, ENDOWMENT)) .collect(), }, parachain_info: asset_hub_rococo_runtime::ParachainInfoConfig { @@ -556,6 +559,7 @@ pub mod penpal { pub const PARA_ID_A: u32 = 2000; pub const PARA_ID_B: u32 = 2001; pub const ED: Balance = penpal_runtime::EXISTENTIAL_DEPOSIT; + const ENDOWMENT: u128 = ED * 4096; pub fn genesis(para_id: u32) -> Storage { let genesis_config = penpal_runtime::RuntimeGenesisConfig { @@ -569,7 +573,7 @@ pub mod penpal { balances: accounts::init_balances() .iter() .cloned() - .map(|k| (k, ED * 4096)) + .map(|k| (k, ENDOWMENT)) .collect(), }, parachain_info: penpal_runtime::ParachainInfoConfig { @@ -616,6 +620,7 @@ pub mod bridge_hub_rococo { use super::*; pub const PARA_ID: u32 = 1013; pub const ED: Balance = parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT; + const ENDOWMENT: u128 = ED * 4096; pub fn genesis() -> Storage { let genesis_config = bridge_hub_rococo_runtime::RuntimeGenesisConfig { @@ -629,7 +634,7 @@ pub mod bridge_hub_rococo { balances: accounts::init_balances() .iter() .cloned() - .map(|k| (k, ED * 4096)) + .map(|k| (k, ENDOWMENT)) .collect(), }, parachain_info: bridge_hub_rococo_runtime::ParachainInfoConfig { diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index 542d07fbed95..7dde53452d35 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -182,7 +182,7 @@ pub type Barrier = TrailingSetTopicAsId< /// Type alias to conveniently refer to `frame_system`'s `Config::AccountId`. pub type AccountIdOf = ::AccountId; -/// Asset filter that allows all assets from a certain location. +/// Asset filter that allows all assets from a certain location matching asset id. pub struct AssetsFrom(PhantomData); impl> ContainsPair for AssetsFrom { fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool { @@ -193,6 +193,17 @@ impl> ContainsPair for AssetsFr } } +/// Asset filter that allows native/relay asset if coming from a certain location. +pub struct NativeAssetFrom(PhantomData); +impl> ContainsPair for NativeAssetFrom { + fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool { + let loc = T::get(); + &loc == origin && + matches!(asset, MultiAsset { id: AssetId::Concrete(asset_loc), fun: Fungible(_a) } + if *asset_loc == MultiLocation::from(Parent)) + } +} + /// Allow checking in assets that have issuance > 0. pub struct NonZeroIssuance(PhantomData<(AccountId, Assets)>); impl Contains<>::AssetId> @@ -221,43 +232,6 @@ where } } -pub trait Reserve { - /// Returns assets reserve location. - fn reserve(&self) -> Option; -} - -// Takes the chain part of a MultiAsset -impl Reserve for MultiAsset { - fn reserve(&self) -> Option { - if let AssetId::Concrete(location) = self.id { - let first_interior = location.first_interior(); - let parents = location.parent_count(); - match (parents, first_interior) { - (0, Some(Parachain(id))) => Some(MultiLocation::new(0, X1(Parachain(*id)))), - (1, Some(Parachain(id))) => Some(MultiLocation::new(1, X1(Parachain(*id)))), - (1, _) => Some(MultiLocation::parent()), - _ => None, - } - } else { - None - } - } -} - -/// A `FilterAssetLocation` implementation. Filters multi native assets whose -/// reserve is same with `origin`. -pub struct MultiNativeAsset; -impl ContainsPair for MultiNativeAsset { - fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool { - if let Some(ref reserve) = asset.reserve() { - if reserve == origin { - return true - } - } - false - } -} - parameter_types! { /// The location that this chain recognizes as the Relay network's Asset Hub. pub SystemAssetHubLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(1000))); @@ -268,7 +242,8 @@ parameter_types! { pub CheckingAccount: AccountId = PolkadotXcm::check_account(); } -pub type Reserves = (NativeAsset, AssetsFrom); +pub type Reserves = + (NativeAsset, AssetsFrom, NativeAssetFrom); pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { @@ -277,7 +252,8 @@ impl xcm_executor::Config for XcmConfig { // How to withdraw and deposit an asset. type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; - type IsReserve = MultiNativeAsset; // TODO: maybe needed to be replaced by Reserves + type IsReserve = Reserves; + // no teleport trust established with other chains type IsTeleporter = NativeAsset; type UniversalLocation = UniversalLocation; type Barrier = Barrier; From ec87ce6d97c85c5c50a9205bbc7d2a30689f1a07 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 1 Nov 2023 11:00:16 +0200 Subject: [PATCH 71/98] xcm-emulator: add relay to penpal native transfer test --- Cargo.lock | 3 + .../assets/asset-hub-rococo/Cargo.toml | 2 + .../assets/asset-hub-rococo/src/lib.rs | 20 ++-- .../src/tests/reserve_transfer.rs | 109 +++++++++++++++++- .../asset-hub-rococo/src/tests/teleport.rs | 8 +- .../assets/asset-hub-westend/Cargo.toml | 1 + .../src/tests/reserve_transfer.rs | 29 +++-- 7 files changed, 147 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6af9c3efdf56..0c35615ddaa4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -879,6 +879,8 @@ dependencies = [ "assert_matches", "asset-hub-rococo-runtime", "asset-test-utils", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-xcmp-queue", "frame-support", "frame-system", "integration-tests-common", @@ -985,6 +987,7 @@ dependencies = [ "asset-test-utils", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", + "cumulus-pallet-xcmp-queue", "frame-support", "frame-system", "integration-tests-common", diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml index db58d8d33039..5b8ad06d63bd 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml @@ -32,6 +32,8 @@ rococo-runtime = { path = "../../../../../../polkadot/runtime/rococo", default-f asset-test-utils = { path = "../../../../runtimes/assets/test-utils", default-features = false } parachains-common = { path = "../../../../common" } asset-hub-rococo-runtime = { path = "../../../../runtimes/assets/asset-hub-rococo" } +cumulus-pallet-dmp-queue = { path = "../../../../../pallets/dmp-queue", default-features = false} +cumulus-pallet-xcmp-queue = { path = "../../../../../pallets/xcmp-queue", default-features = false} # Local xcm-emulator = { path = "../../../../../xcm/xcm-emulator", default-features = false} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs index 42f54bdf49df..686d9e3f0d36 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs @@ -49,18 +49,20 @@ pub const ASSET_MIN_BALANCE: u128 = 1000; pub const ASSETS_PALLET_ID: u8 = 50; pub type RelayToSystemParaTest = Test; +pub type RelayToParaTest = Test; pub type SystemParaToRelayTest = Test; pub type SystemParaToParaTest = Test; +pub type ParaToSystemParaTest = Test; -/// Returns a `TestArgs` instance to de used for the Relay Chain accross integraton tests -pub fn relay_test_args(amount: Balance) -> TestArgs { +/// Returns a `TestArgs` instance to de used for the Relay Chain across integration tests +pub fn relay_test_args( + dest: MultiLocation, + beneficiary_id: AccountId32, + amount: Balance, +) -> TestArgs { TestArgs { - dest: Rococo::child_location_of(AssetHubRococo::para_id()), - beneficiary: AccountId32Junction { - network: None, - id: AssetHubRococoReceiver::get().into(), - } - .into(), + dest, + beneficiary: AccountId32Junction { network: None, id: beneficiary_id.into() }.into(), amount, assets: (Here, amount).into(), asset_id: None, @@ -69,7 +71,7 @@ pub fn relay_test_args(amount: Balance) -> TestArgs { } } -/// Returns a `TestArgs` instance to de used for the System Parachain accross integraton tests +/// Returns a `TestArgs` instance to de used for the System Parachain across integration tests pub fn system_para_test_args( dest: MultiLocation, beneficiary_id: AccountId32, diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index 903c01ee921c..08873a9ce548 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -15,8 +15,45 @@ use crate::*; use asset_hub_rococo_runtime::xcm_config::XcmConfig as AssetHubRococoXcmConfig; +use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig; -fn system_para_to_para_assertions(t: SystemParaToParaTest) { +fn relay_to_para_sender_assertions(t: RelayToParaTest) { + type RuntimeEvent = ::RuntimeEvent; + + Rococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799))); + + assert_expected_events!( + Rococo, + vec![ + // 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 == Rococo::sovereign_account_id_of( + t.args.dest + ), + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn relay_to_para_receiver_assertions(_: Test) { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + PenpalRococoA, + vec![ + RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::DmpQueue(cumulus_pallet_dmp_queue::Event::ExecutedDownward { + outcome: Outcome::Complete(_), + .. + }) => {}, + ] + ); +} + +fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( @@ -27,7 +64,7 @@ fn system_para_to_para_assertions(t: SystemParaToParaTest) { assert_expected_events!( AssetHubRococo, vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereing account + // Amount to reserve transfer is transferred to Parachain's Sovereign account RuntimeEvent::Balances( pallet_balances::Event::Transfer { from, to, amount } ) => { @@ -41,6 +78,17 @@ fn system_para_to_para_assertions(t: SystemParaToParaTest) { ); } +fn system_para_to_para_receiver_assertions(_: Test) { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + PenpalRococoA, + vec![ + RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) => {}, + ] + ); +} + fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -52,7 +100,7 @@ fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { assert_expected_events!( AssetHubRococo, vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereing account + // Amount to reserve transfer is transferred to Parachain's Sovereign account RuntimeEvent::Assets( pallet_assets::Event::Transferred { asset_id, from, to, amount } ) => { @@ -67,6 +115,17 @@ fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { ); } +fn relay_to_para_limited_reserve_transfer_assets(t: RelayToParaTest) -> DispatchResult { + ::XcmPallet::limited_reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { ::PolkadotXcm::limited_reserve_transfer_assets( t.signed_origin, @@ -148,6 +207,45 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_relay_fails() { }); } +/// Limited Reserve Transfers of native asset from Relay to Parachain should work +#[test] +fn limited_reserve_transfer_native_asset_from_relay_to_para() { + // Init values for Relay + let destination = Rococo::child_location_of(PenpalRococoA::para_id()); + let beneficiary_id = PenpalRococoAReceiver::get(); + let amount_to_send: Balance = ROCOCO_ED * 1000; + + let test_args = TestContext { + sender: RococoSender::get(), + receiver: PenpalRococoAReceiver::get(), + args: relay_test_args(destination, beneficiary_id, amount_to_send), + }; + + let mut test = RelayToParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::(relay_to_para_sender_assertions); + test.set_assertion::(relay_to_para_receiver_assertions); + test.set_dispatchable::(relay_to_para_limited_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + 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) + }); + + // 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); +} + /// Limited Reserve Transfers of native asset from System Parachain to Parachain should work #[test] fn limited_reserve_transfer_native_asset_from_system_para_to_para() { @@ -168,9 +266,8 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { let sender_balance_before = test.sender.balance; let receiver_balance_before = test.receiver.balance; - test.set_assertion::(system_para_to_para_assertions); - // TODO: Add assertion for Penpal runtime. Right now message is failing with - // `UntrustedReserveLocation` + test.set_assertion::(system_para_to_para_sender_assertions); + test.set_assertion::(system_para_to_para_receiver_assertions); test.set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); test.assert(); diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs index 297ee83d7535..09f1e6c0a590 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs @@ -157,10 +157,12 @@ fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { fn limited_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: relay_test_args(amount_to_send), + args: relay_test_args(dest, beneficiary_id, amount_to_send), }; let mut test = RelayToSystemParaTest::new(test_args); @@ -278,10 +280,12 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { 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: relay_test_args(amount_to_send), + args: relay_test_args(dest, beneficiary_id, amount_to_send), }; let mut test = RelayToSystemParaTest::new(test_args); diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/Cargo.toml index 4b6b8874b6a4..87f3c1d4b513 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/Cargo.toml @@ -39,6 +39,7 @@ asset-hub-westend-runtime = { path = "../../../../runtimes/assets/asset-hub-west asset-test-utils = { path = "../../../../runtimes/assets/test-utils", default-features = false } cumulus-pallet-dmp-queue = { default-features = false, path = "../../../../../pallets/dmp-queue" } cumulus-pallet-parachain-system = { default-features = false, path = "../../../../../pallets/parachain-system" } +cumulus-pallet-xcmp-queue = { path = "../../../../../pallets/xcmp-queue", default-features = false} # Local xcm-emulator = { path = "../../../../../xcm/xcm-emulator", default-features = false} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs index c7a25dde78d3..518e117c1074 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -16,7 +16,7 @@ use crate::*; use asset_hub_westend_runtime::xcm_config::XcmConfig; -fn system_para_to_para_assertions(t: SystemParaToParaTest) { +fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; AssetHubWestend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( @@ -27,7 +27,7 @@ fn system_para_to_para_assertions(t: SystemParaToParaTest) { assert_expected_events!( AssetHubWestend, vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereing account + // Amount to reserve transfer is transferred to Parachain's Sovereign account RuntimeEvent::Balances( pallet_balances::Event::Transfer { from, to, amount } ) => { @@ -41,6 +41,17 @@ fn system_para_to_para_assertions(t: SystemParaToParaTest) { ); } +fn para_receiver_assertions(_: Test) { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + PenpalWestendA, + vec![ + RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) => {}, + ] + ); +} + fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -52,7 +63,7 @@ fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { assert_expected_events!( AssetHubWestend, vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereing account + // Amount to reserve transfer is transferred to Parachain's Sovereign account RuntimeEvent::Assets( pallet_assets::Event::Transferred { asset_id, from, to, amount } ) => { @@ -165,14 +176,15 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { let mut test = SystemParaToParaTest::new(test_args); let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; - test.set_assertion::(system_para_to_para_assertions); - // TODO: Add assertion for Penpal runtime. Right now message is failing with - // `UntrustedReserveLocation` + test.set_assertion::(system_para_to_para_sender_assertions); + test.set_assertion::(para_receiver_assertions); test.set_dispatchable::(system_para_to_para_limited_reserve_transfer_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>( @@ -184,9 +196,10 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { ) }); + // Sender's balance is reduced assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve - // transfers + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); } /// Limited Reserve Transfers of a local asset from System Parachain to Parachain should work From da3c12e89f5e21aaabe43b8be58c77e65d2a7b97 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 1 Nov 2023 13:47:04 +0200 Subject: [PATCH 72/98] xcm-emulator: add ah to penpal native asset transfer test --- Cargo.lock | 1 + .../assets/asset-hub-rococo/Cargo.toml | 1 + .../assets/asset-hub-rococo/src/lib.rs | 6 +- .../src/tests/reserve_transfer.rs | 113 +++++++++++++++++- .../asset-hub-rococo/src/tests/teleport.rs | 8 +- .../assets/asset-hub-westend/src/lib.rs | 4 +- .../bridges/bridge-hub-rococo/src/lib.rs | 2 +- .../emulated/common/src/lib.rs | 2 + 8 files changed, 123 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c35615ddaa4..066cc394bd82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -890,6 +890,7 @@ dependencies = [ "pallet-xcm", "parachains-common", "parity-scale-codec", + "penpal-runtime", "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-runtime-parachains", diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml index 5b8ad06d63bd..820429deae45 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml @@ -32,6 +32,7 @@ rococo-runtime = { path = "../../../../../../polkadot/runtime/rococo", default-f asset-test-utils = { path = "../../../../runtimes/assets/test-utils", default-features = false } parachains-common = { path = "../../../../common" } asset-hub-rococo-runtime = { path = "../../../../runtimes/assets/asset-hub-rococo" } +penpal-runtime = { path = "../../../../runtimes/testing/penpal" } cumulus-pallet-dmp-queue = { path = "../../../../../pallets/dmp-queue", default-features = false} cumulus-pallet-xcmp-queue = { path = "../../../../../pallets/xcmp-queue", default-features = false} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs index 686d9e3f0d36..6da7537e82f4 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs @@ -54,7 +54,7 @@ pub type SystemParaToRelayTest = Test; pub type SystemParaToParaTest = Test; pub type ParaToSystemParaTest = Test; -/// Returns a `TestArgs` instance to de used for the Relay Chain across integration tests +/// Returns a `TestArgs` instance to be used for the Relay Chain across integration tests pub fn relay_test_args( dest: MultiLocation, beneficiary_id: AccountId32, @@ -71,8 +71,8 @@ pub fn relay_test_args( } } -/// Returns a `TestArgs` instance to de used for the System Parachain across integration tests -pub fn system_para_test_args( +/// Returns a `TestArgs` instance to be used by parachains across integration tests +pub fn para_test_args( dest: MultiLocation, beneficiary_id: AccountId32, amount: Balance, diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index 08873a9ce548..14b2aae7a8e0 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -15,6 +15,7 @@ use crate::*; use asset_hub_rococo_runtime::xcm_config::XcmConfig as AssetHubRococoXcmConfig; +use penpal_runtime::xcm_config::XcmConfig as PenpalRococoXcmConfig; use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig; fn relay_to_para_sender_assertions(t: RelayToParaTest) { @@ -89,6 +90,51 @@ fn system_para_to_para_receiver_assertions(_: Test) { ); } +fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { + type RuntimeEvent = ::RuntimeEvent; + + PenpalRococoA::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( + 864_610_000, + 8_799, + ))); + + assert_expected_events!( + PenpalRococoA, + vec![ + // Amount to reserve transfer is transferred to Parachain's Sovereign account + RuntimeEvent::Balances( + pallet_balances::Event::Withdraw { who, amount } + ) => { + who: *who == t.sender.account_id, + amount: *amount == t.args.amount, + }, + ] + ); +} + +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(PenpalRococoA::para_id()), + ); + + assert_expected_events!( + AssetHubRococo, + vec![ + // Amount to reserve transfer is transferred to Parachain's Sovereign account + RuntimeEvent::Balances( + pallet_balances::Event::Withdraw { who, amount } + ) => { + who: *who == sov_penpal_on_ahr.clone().into(), + amount: *amount == t.args.amount, + }, + RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) => {}, + ] + ); +} + fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -137,6 +183,17 @@ fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) ) } +fn para_to_system_para_limited_reserve_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { + ::PolkadotXcm::limited_reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + /// Limited Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't /// work #[test] @@ -258,7 +315,7 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { let test_args = TestContext { sender: AssetHubRococoSender::get(), receiver: PenpalRococoAReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; let mut test = SystemParaToParaTest::new(test_args); @@ -286,6 +343,54 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { assert!(receiver_balance_after > receiver_balance_before); } +/// Limited Reserve Transfers of native asset from Parachain to System Parachain should work +#[test] +fn limited_reserve_transfer_native_asset_from_para_to_system_para() { + // Init values for Penpal Parachain + let destination = PenpalRococoA::sibling_location_of(AssetHubRococo::para_id()); + let beneficiary_id = AssetHubRococoReceiver::get(); + let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: PenpalRococoASender::get(), + receiver: AssetHubRococoReceiver::get(), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = ParaToSystemParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + // MultiLocation { parents: 1, interior: X1(Parachain(PenpalRococoA::para_id().into())) }; + let penpal_location_as_seen_by_ahr = + AssetHubRococo::sibling_location_of(PenpalRococoA::para_id()); + let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location_as_seen_by_ahr); + + // fund the Penpal's SA on AHR with the native tokens held in reserve + AssetHubRococo::fund_accounts(vec![(sov_penpal_on_ahr.into(), amount_to_send * 2)]); + + test.set_assertion::(para_to_system_para_sender_assertions); + test.set_assertion::(para_to_system_para_receiver_assertions); + test.set_dispatchable::(para_to_system_para_limited_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + let delivery_fees = PenpalRococoA::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); +} + /// Limited Reserve Transfers of a local asset from System Parachain to Parachain should work #[test] fn limited_reserve_transfer_asset_from_system_para_to_para() { @@ -307,13 +412,13 @@ fn limited_reserve_transfer_asset_from_system_para_to_para() { (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send) .into(); - let system_para_test_args = TestContext { + let para_test_args = TestContext { sender: AssetHubRococoSender::get(), receiver: PenpalRococoAReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; - let mut system_para_test = SystemParaToParaTest::new(system_para_test_args); + let mut system_para_test = SystemParaToParaTest::new(para_test_args); system_para_test.set_assertion::(system_para_to_para_assets_assertions); // TODO: Add assertions when Penpal is able to manage assets diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs index 09f1e6c0a590..217bac6865c8 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs @@ -206,7 +206,7 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { let test_args = TestContext { sender: AssetHubRococoSender::get(), receiver: RococoReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; let mut test = SystemParaToRelayTest::new(test_args); @@ -247,7 +247,7 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { let test_args = TestContext { sender: AssetHubRococoSender::get(), receiver: RococoReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; let mut test = SystemParaToRelayTest::new(test_args); @@ -329,7 +329,7 @@ fn teleport_native_assets_back_from_system_para_to_relay_works() { let test_args = TestContext { sender: AssetHubRococoSender::get(), receiver: RococoReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; let mut test = SystemParaToRelayTest::new(test_args); @@ -370,7 +370,7 @@ fn teleport_native_assets_from_system_para_to_relay_fails() { let test_args = TestContext { sender: AssetHubRococoSender::get(), receiver: RococoReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; let mut test = SystemParaToRelayTest::new(test_args); diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs index 2ade5f81d8a9..d3ad32f7c946 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs @@ -53,7 +53,7 @@ pub type RelayToSystemParaTest = Test; pub type SystemParaToRelayTest = Test; pub type SystemParaToParaTest = Test; -/// Returns a `TestArgs` instance to de used for the Relay Chain across integration tests +/// Returns a `TestArgs` instance to be used for the Relay Chain across integration tests pub fn relay_test_args(amount: Balance) -> TestArgs { TestArgs { dest: Westend::child_location_of(AssetHubWestend::para_id()), @@ -70,7 +70,7 @@ pub fn relay_test_args(amount: Balance) -> TestArgs { } } -/// Returns a `TestArgs` instance to de used for the System Parachain across integration tests +/// Returns a `TestArgs` instance to be used for the System Parachain across integration tests pub fn system_para_test_args( dest: MultiLocation, beneficiary_id: AccountId32, diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/lib.rs index ecf773765b3e..ab7043b37f8f 100644 --- a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/lib.rs @@ -46,7 +46,7 @@ pub type RelayToSystemParaTest = Test; pub type SystemParaToRelayTest = Test; pub type SystemParaToParaTest = Test; -/// Returns a `TestArgs` instance to de used for the Relay Chain across integration tests +/// Returns a `TestArgs` instance to be used for the Relay Chain across integration tests pub fn relay_test_args(amount: Balance) -> TestArgs { TestArgs { dest: Rococo::child_location_of(AssetHubRococo::para_id()), diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 8a8081c9fac3..1ec006f4510b 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -189,6 +189,7 @@ decl_test_parachains! { pallets = { PolkadotXcm: penpal_runtime::PolkadotXcm, Assets: penpal_runtime::Assets, + Balances: penpal_runtime::Balances, } }, pub struct PenpalRococoB { @@ -326,6 +327,7 @@ impl_accounts_helpers_for_parachain!(BridgeHubRococo); impl_assert_events_helpers_for_parachain!(BridgeHubRococo); // PenpalRococo implementations +impl_accounts_helpers_for_parachain!(PenpalRococoA); impl_assert_events_helpers_for_parachain!(PenpalRococoA); impl_assert_events_helpers_for_parachain!(PenpalRococoB); From ac9bf49411b9de4545ad4ef97d696a74bd536871 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 1 Nov 2023 17:43:00 +0200 Subject: [PATCH 73/98] xcm: MultiLocation::chain_location() takes nonmut reference --- polkadot/xcm/src/v3/multilocation.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/polkadot/xcm/src/v3/multilocation.rs b/polkadot/xcm/src/v3/multilocation.rs index f948340abcb5..a685c15c7d98 100644 --- a/polkadot/xcm/src/v3/multilocation.rs +++ b/polkadot/xcm/src/v3/multilocation.rs @@ -446,17 +446,18 @@ impl MultiLocation { } /// Return the MultiLocation subsection identifying the chain that `self` points to. - pub fn chain_location(mut self) -> MultiLocation { + pub fn chain_location(&self) -> MultiLocation { + let mut clone = self.clone(); // start popping junctions until we reach chain identifier - while let Some(j) = self.last() { + while let Some(j) = clone.last() { if matches!(j, Junction::Parachain(_) | Junction::GlobalConsensus(_)) { // return chain subsection - return self + return clone } else { - (self, _) = self.split_last_interior(); + (clone, _) = clone.split_last_interior(); } } - MultiLocation::new(self.parents, Junctions::Here) + MultiLocation::new(clone.parents, Junctions::Here) } } From e85e3390609ee69bda7316c03bbe0622042fda7a Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 1 Nov 2023 18:01:32 +0200 Subject: [PATCH 74/98] pallet-xcm: benchmarks: enforce single asset transfer at the api level --- .../assets/asset-hub-kusama/src/lib.rs | 8 ++--- .../assets/asset-hub-polkadot/src/lib.rs | 8 ++--- .../assets/asset-hub-rococo/src/lib.rs | 8 ++--- .../assets/asset-hub-westend/src/lib.rs | 8 ++--- .../bridge-hubs/bridge-hub-kusama/src/lib.rs | 6 ++-- .../bridge-hub-polkadot/src/lib.rs | 6 ++-- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 6 ++-- .../collectives-polkadot/src/lib.rs | 4 +-- .../contracts/contracts-rococo/src/lib.rs | 6 ++-- polkadot/runtime/rococo/src/lib.rs | 8 ++--- polkadot/runtime/westend/src/lib.rs | 11 +++---- polkadot/xcm/pallet-xcm/src/benchmarking.rs | 30 +++++++------------ polkadot/xcm/pallet-xcm/src/mock.rs | 8 ++--- 13 files changed, 52 insertions(+), 65 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs index 25d5712f4dfb..e5261cf06b63 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs @@ -1217,18 +1217,18 @@ impl_runtime_apis! { Some(Parent.into()) } - fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // Relay/native token can be teleported between AH and Relay. Some(( MultiAsset { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) - }.into(), + }, Parent.into(), )) } - fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // AH can reserve transfer native token to some random parachain. let random_para_id = 43211234; ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( @@ -1238,7 +1238,7 @@ impl_runtime_apis! { MultiAsset { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) - }.into(), + }, ParentThen(Parachain(random_para_id).into()).into(), )) } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs index dd111355c02b..99898c1a5b44 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs @@ -1096,18 +1096,18 @@ impl_runtime_apis! { Some(Parent.into()) } - fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // Relay/native token can be teleported between AH and Relay. Some(( MultiAsset { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) - }.into(), + }, Parent.into(), )) } - fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // AH can reserve transfer native token to some random parachain. let random_para_id = 43211234; ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( @@ -1117,7 +1117,7 @@ impl_runtime_apis! { MultiAsset { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) - }.into(), + }, ParentThen(Parachain(random_para_id).into()).into(), )) } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 1f54c3ca997b..06787c9e1e7e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -1305,18 +1305,18 @@ impl_runtime_apis! { Some(Parent.into()) } - fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // Relay/native token can be teleported between AH and Relay. Some(( MultiAsset { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) - }.into(), + }, Parent.into(), )) } - fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // AH can reserve transfer native token to some random parachain. let random_para_id = 43211234; ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( @@ -1326,7 +1326,7 @@ impl_runtime_apis! { MultiAsset { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) - }.into(), + }, ParentThen(Parachain(random_para_id).into()).into(), )) } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index cc04db22785b..e23b9b36e12d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -1281,18 +1281,18 @@ impl_runtime_apis! { Some(Parent.into()) } - fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // Relay/native token can be teleported between AH and Relay. Some(( MultiAsset { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) - }.into(), + }, Parent.into(), )) } - fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // AH can reserve transfer native token to some random parachain. let random_para_id = 43211234; ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( @@ -1302,7 +1302,7 @@ impl_runtime_apis! { MultiAsset { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) - }.into(), + }, ParentThen(Parachain(random_para_id).into()).into(), )) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs index 7ff1e1cdb356..ba4d373de3b0 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs @@ -678,18 +678,18 @@ impl_runtime_apis! { Some(Parent.into()) } - fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // Relay/native token can be teleported between BH and Relay. Some(( MultiAsset { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) - }.into(), + }, Parent.into(), )) } - fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // Reserve transfers are disabled on BH. None } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs index 39238689d458..18269d713c45 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs @@ -678,18 +678,18 @@ impl_runtime_apis! { Some(Parent.into()) } - fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // Relay/native token can be teleported between BH and Relay. Some(( MultiAsset { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) - }.into(), + }, Parent.into(), )) } - fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // Reserve transfers are disabled on BH. None } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 77f6d8cdd1ea..4914554227a9 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -867,18 +867,18 @@ impl_runtime_apis! { Some(Parent.into()) } - fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // Relay/native token can be teleported between BH and Relay. Some(( MultiAsset { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) - }.into(), + }, Parent.into(), )) } - fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // Reserve transfers are disabled on BH. None } diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs index 258ecd54f901..3fc2215c7658 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs @@ -943,7 +943,7 @@ impl_runtime_apis! { Some(Parent.into()) } - fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // Relay/native token can be teleported between Collectives and Relay. Some(( MultiAsset { @@ -954,7 +954,7 @@ impl_runtime_apis! { )) } - fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // Reserve transfers are disabled on Collectives. None } diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 4353d209fe21..958ee94b5ac1 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -687,18 +687,18 @@ impl_runtime_apis! { Some(Parent.into()) } - fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // Relay/native token can be teleported between Contracts-System-Para and Relay. Some(( MultiAsset { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Parent.into()) - }.into(), + }, Parent.into(), )) } - fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // Reserve transfers are disabled on Contracts-System-Para. None } diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 6171576d30c0..643cde530078 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -2089,24 +2089,24 @@ sp_api::impl_runtime_apis! { Some(crate::xcm_config::AssetHub::get()) } - fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // Relay/native token can be teleported to/from AH. Some(( MultiAsset { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Here.into()) - }.into(), + }, crate::xcm_config::AssetHub::get(), )) } - fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // Relay can reserve transfer native token to some random parachain. Some(( MultiAsset { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Here.into()) - }.into(), + }, Parachain(43211234).into(), )) } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 79145855d71a..47454dae0ad6 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -2171,24 +2171,21 @@ sp_api::impl_runtime_apis! { Some(crate::xcm_config::AssetHub::get()) } - fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // Relay/native token can be teleported to/from AH. Some(( - MultiAsset { - fun: Fungible(EXISTENTIAL_DEPOSIT), - id: Concrete(Here.into()) - }.into(), + MultiAsset { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Here.into()) }, crate::xcm_config::AssetHub::get(), )) } - fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { // Relay can reserve transfer native token to some random parachain. Some(( MultiAsset { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Here.into()) - }.into(), + }, crate::Junction::Parachain(43211234).into(), )) } diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs index ab2941b10de3..fb3929bfa8e3 100644 --- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs @@ -39,23 +39,23 @@ pub trait Config: crate::Config { None } - /// A `(MultiAssets, MultiLocation)` pair representing assets and the destination they can - /// be teleported to. Used only in benchmarks. + /// A `(MultiAsset, MultiLocation)` pair representing asset and the destination it can be + /// teleported to. Used only in benchmarks. /// /// Implementation should also make sure `dest` is reachable/connected. /// /// If `None`, the benchmarks that depend on this will be skipped. - fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { None } - /// A `(MultiAssets, MultiLocation)` pair representing assets and the destination they can - /// be reserve-transferred to. Used only in benchmarks. + /// A `(MultiAsset, MultiLocation)` pair representing asset and the destination it can be + /// reserve-transferred to. Used only in benchmarks. /// /// Implementation should also make sure `dest` is reachable/connected. /// /// If `None`, the benchmarks that depend on this will be skipped. - fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { None } } @@ -81,20 +81,15 @@ benchmarks! { }: _>(send_origin, Box::new(versioned_dest), Box::new(versioned_msg)) teleport_assets { - let (assets, destination) = T::teleportable_assets_and_dest().ok_or( + let (asset, destination) = T::teleportable_asset_and_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), )?; - // most chains deploying `pallet-xcm` don't have `pallet-assets` so we're - // stuck with using native token and `pallet-balances`. - if assets.len() != 1 { - return Err(BenchmarkError::Stop("Generic benchmark supports only single native asset")) - } - let asset = assets.inner().clone().pop().unwrap(); let transferred_amount = match &asset.fun { Fungible(amount) => *amount, _ => return Err(BenchmarkError::Stop("Benchmark asset not fungible")), }.into(); + let assets: MultiAssets = asset.into(); let existential_deposit = T::ExistentialDeposit::get(); let caller = whitelisted_caller(); @@ -125,20 +120,15 @@ benchmarks! { } reserve_transfer_assets { - let (assets, destination) = T::reserve_transferable_assets_and_dest().ok_or( + let (asset, destination) = T::reserve_transferable_asset_and_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), )?; - // most chains deploying `pallet-xcm` don't have `pallet-assets` so we're - // stuck with using native token and `pallet-balances`. - if assets.len() != 1 { - return Err(BenchmarkError::Stop("Generic benchmark supports only single native asset")) - } - let asset = assets.inner().clone().pop().unwrap(); let transferred_amount = match &asset.fun { Fungible(amount) => *amount, _ => return Err(BenchmarkError::Stop("Benchmark asset not fungible")), }.into(); + let assets: MultiAssets = asset.into(); let existential_deposit = T::ExistentialDeposit::get(); let caller = whitelisted_caller(); diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index b88734b9abfb..c018ef723fe4 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -538,13 +538,13 @@ impl super::benchmarking::Config for Test { Some(Parachain(1000).into()) } - fn teleportable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { - Some((NativeAsset::get().into(), SystemParachainLocation::get())) + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + Some((NativeAsset::get(), SystemParachainLocation::get())) } - fn reserve_transferable_assets_and_dest() -> Option<(MultiAssets, MultiLocation)> { + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { Some(( - MultiAsset { fun: Fungible(10), id: Concrete(Here.into_location()) }.into(), + MultiAsset { fun: Fungible(10), id: Concrete(Here.into_location()) }, Parachain(OTHER_PARA_ID).into(), )) } From 9f7538dc333ed18472cef0f6742cc354a07d73bf Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 1 Nov 2023 18:51:48 +0200 Subject: [PATCH 75/98] xcm-executor: rename AssetTransferSupport to XcmAssetTransfer --- polkadot/xcm/pallet-xcm/src/lib.rs | 8 ++++---- polkadot/xcm/xcm-executor/src/lib.rs | 4 ++-- polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs | 2 +- polkadot/xcm/xcm-executor/src/traits/mod.rs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 3af0a48b2440..a89baedb7f4c 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -42,7 +42,7 @@ use sp_runtime::{ use sp_std::{boxed::Box, marker::PhantomData, prelude::*, result::Result, vec}; use xcm::{latest::QueryResponseInfo, prelude::*}; use xcm_executor::traits::{ - AssetTransferError, AssetTransferSupport, ConvertOrigin, Properties, TransferType, + AssetTransferError, ConvertOrigin, Properties, TransferType, XcmAssetTransfers, }; use frame_support::{ @@ -208,7 +208,7 @@ pub mod pallet { type XcmExecuteFilter: Contains<(MultiLocation, Xcm<::RuntimeCall>)>; /// Something to execute an XCM message. - type XcmExecutor: ExecuteXcm<::RuntimeCall> + AssetTransferSupport; + type XcmExecutor: ExecuteXcm<::RuntimeCall> + XcmAssetTransfers; /// Our XCM filter which messages to be teleported using the dedicated extrinsic must pass. type XcmTeleportFilter: Contains<(MultiLocation, Vec)>; @@ -1635,13 +1635,13 @@ impl Pallet { // be in error, there would need to be an accounting violation by ourselves, // so it's unlikely, but we don't want to allow that kind of bug to leak into // a trusted chain. - ::AssetTransactor::can_check_out( + ::AssetTransactor::can_check_out( &dest, &fees, &dummy_context, ) .map_err(|_| Error::::CannotCheckOutTeleport)?; - ::AssetTransactor::check_out( + ::AssetTransactor::check_out( &dest, &fees, &dummy_context, diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index b8e4c53c9889..53a2620a37be 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -38,7 +38,7 @@ use traits::{ mod assets; pub use assets::Assets; mod config; -use crate::traits::AssetTransferSupport; +use crate::traits::XcmAssetTransfers; pub use config::Config; /// A struct to specify how fees are being paid. @@ -255,7 +255,7 @@ impl ExecuteXcm for XcmExecutor AssetTransferSupport for XcmExecutor { +impl XcmAssetTransfers for XcmExecutor { type IsReserve = Config::IsReserve; type IsTeleporter = Config::IsTeleporter; type AssetTransactor = Config::AssetTransactor; diff --git a/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs b/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs index 980554f2dce2..5fdc9b15e015 100644 --- a/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs +++ b/polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs @@ -44,7 +44,7 @@ pub enum TransferType { /// A trait for identifying asset transfer type based on `IsTeleporter` and `IsReserve` /// configurations. -pub trait AssetTransferSupport { +pub trait XcmAssetTransfers { /// Combinations of (Asset, Location) pairs which we trust as reserves. Meaning /// reserve-based-transfers are to be used for assets matching this filter. type IsReserve: ContainsPair; diff --git a/polkadot/xcm/xcm-executor/src/traits/mod.rs b/polkadot/xcm/xcm-executor/src/traits/mod.rs index 1723da0c3f40..71e75c77e939 100644 --- a/polkadot/xcm/xcm-executor/src/traits/mod.rs +++ b/polkadot/xcm/xcm-executor/src/traits/mod.rs @@ -25,7 +25,7 @@ pub use asset_exchange::AssetExchange; mod asset_lock; pub use asset_lock::{AssetLock, Enact, LockError}; mod asset_transfer; -pub use asset_transfer::{AssetTransferSupport, Error as AssetTransferError, TransferType}; +pub use asset_transfer::{Error as AssetTransferError, TransferType, XcmAssetTransfers}; mod export; pub use export::{export_xcm, validate_export, ExportXcm}; mod fee_manager; From 45279ccce23e3dbf3ee0dd0b04ddf7a1545ce3f2 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 1 Nov 2023 20:19:12 +0200 Subject: [PATCH 76/98] clippy --- polkadot/xcm/src/v3/multilocation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/xcm/src/v3/multilocation.rs b/polkadot/xcm/src/v3/multilocation.rs index a685c15c7d98..89e259844438 100644 --- a/polkadot/xcm/src/v3/multilocation.rs +++ b/polkadot/xcm/src/v3/multilocation.rs @@ -447,7 +447,7 @@ impl MultiLocation { /// Return the MultiLocation subsection identifying the chain that `self` points to. pub fn chain_location(&self) -> MultiLocation { - let mut clone = self.clone(); + let mut clone = *self; // start popping junctions until we reach chain identifier while let Some(j) = clone.last() { if matches!(j, Junction::Parachain(_) | Junction::GlobalConsensus(_)) { From 6ba36f8c863bc7492c35b880b428263a6f07c044 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 2 Nov 2023 10:16:39 +0200 Subject: [PATCH 77/98] AssetHub tests: account for Westend higher delivery fees --- .../runtimes/assets/test-utils/src/test_cases_over_bridge.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs index 2cb304d22388..5f2d7942e232 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs @@ -129,7 +129,7 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works< // we calculate exact delivery fees _after_ sending the message by weighing the sent // xcm, and this delivery fee varies for different runtimes, so just add enough buffer, // then verify the arithmetics check out on final balance. - let delivery_fees_buffer = 40_000_000_000u128; + let delivery_fees_buffer = 800_000_000_000u128; // drip ED + transfer_amount + delivery_fees_buffer to Alice account let alice_account_init_balance = existential_deposit + balance_to_transfer.into() + delivery_fees_buffer.into(); From 772852778f0b2d5ccbe3b0428dc8dd4ea24ed708 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 2 Nov 2023 10:33:31 +0200 Subject: [PATCH 78/98] fix merge damage --- .../runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs index babd579f0022..62c5bc8271f0 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -111,12 +111,6 @@ bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!( _ => None, } }), - Box::new(|runtime_event_encoded: Vec| { - match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { - Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), - _ => None, - } - }), bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID ); From a4089c8de3d5d36a7f0c7c8e3f9dc0a8ec779eb7 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 2 Nov 2023 11:29:49 +0100 Subject: [PATCH 79/98] Added withdraw reserve to scripts --- .../parachains/runtimes/bridge-hubs/README.md | 16 ++++++++++- cumulus/scripts/bridges_rococo_westend.sh | 28 ++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/README.md b/cumulus/parachains/runtimes/bridge-hubs/README.md index 9bd6557f350c..b2a14a0405d2 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/README.md +++ b/cumulus/parachains/runtimes/bridge-hubs/README.md @@ -270,7 +270,7 @@ cd ### Send messages - transfer asset over bridge (ROCs/WNDs) -Do (asset) transfers: +Do reserve-backed transfers: ``` cd @@ -291,6 +291,20 @@ cd - AssetHubWestend (see `foreignAssets.Issued`, `xcmpQueue.Success`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:9010#/explorer - BridgeHubRocococ (see `bridgeWestendMessages.MessagesDelivered`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8943#/explorer +Do reserve withdraw transfers: (when previous is finished) +``` +cd + +# wrappedWNDs from Rococo's Asset Hub to Westend's. +./cumulus/scripts/bridges_rococo_westend.sh withdraw-reserve-assets-from-asset-hub-rococo-local +``` +``` +cd + +# wrappedROCs from Westend's Asset Hub to Rococo's. +./cumulus/scripts/bridges_rococo_westend.sh withdraw-reserve-assets-from-asset-hub-westend-local +``` + ### Claim relayer's rewards on BridgeHubRococo and BridgeHubWestend **Accounts of BridgeHub parachains:** diff --git a/cumulus/scripts/bridges_rococo_westend.sh b/cumulus/scripts/bridges_rococo_westend.sh index ce8480685aad..82b5f1942b2f 100755 --- a/cumulus/scripts/bridges_rococo_westend.sh +++ b/cumulus/scripts/bridges_rococo_westend.sh @@ -301,9 +301,21 @@ case "$1" in 0 \ "Unlimited" ;; + withdraw-reserve-assets-from-asset-hub-rococo-local) + ensure_polkadot_js_api + # send back only 100000000000 wrappedWNDs to Alice account on AHW + limited_reserve_transfer_assets \ + "ws://127.0.0.1:9910" \ + "//Alice" \ + "$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Westend" }, { "Parachain": 1000 } ] } } }')" \ + "$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \ + "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 2, "interior": { "X1": { "GlobalConsensus": "Westend" } } } }, "fun": { "Fungible": 140000000000 } } ] }')" \ + 0 \ + "Unlimited" + ;; reserve-transfer-assets-from-asset-hub-westend-local) ensure_polkadot_js_api - # send WOCs to Alice account on AHR + # send WNDs to Alice account on AHR limited_reserve_transfer_assets \ "ws://127.0.0.1:9010" \ "//Alice" \ @@ -313,6 +325,18 @@ case "$1" in 0 \ "Unlimited" ;; + withdraw-reserve-assets-from-asset-hub-westend-local) + ensure_polkadot_js_api + # send back only 100000000000 wrappedROCs to Alice account on AHR + limited_reserve_transfer_assets \ + "ws://127.0.0.1:9010" \ + "//Alice" \ + "$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Rococo" }, { "Parachain": 1000 } ] } } }')" \ + "$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \ + "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 2, "interior": { "X1": { "GlobalConsensus": "Rococo" } } } }, "fun": { "Fungible": 100000000000 } } ] }')" \ + 0 \ + "Unlimited" + ;; claim-rewards-bridge-hub-rococo-local) ensure_polkadot_js_api # bhwd -> [62, 68, 77, 64] -> 0x62687764 @@ -360,7 +384,9 @@ case "$1" in - init-asset-hub-westend-local - init-bridge-hub-westend-local - reserve-transfer-assets-from-asset-hub-rococo-local + - withdraw-reserve-assets-from-asset-hub-rococo-local - reserve-transfer-assets-from-asset-hub-westend-local + - withdraw-reserve-assets-from-asset-hub-westend-local - claim-rewards-bridge-hub-rococo-local - claim-rewards-bridge-hub-westend-local"; exit 1 From 44e19184f191c19ef4cebcb606edac9fe828a748 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 2 Nov 2023 13:39:02 +0200 Subject: [PATCH 80/98] bridge-hub-westend-runtime: fix benchmarks --- .../bridge-hubs/bridge-hub-westend/src/lib.rs | 26 ++++++++++++++++++- .../bridge-hub-westend/src/xcm_config.rs | 7 ----- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 7d4cb03aa06d..5ffe1f37a1a6 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -508,7 +508,7 @@ mod benches { [pallet_collator_selection, CollatorSelection] [cumulus_pallet_xcmp_queue, XcmpQueue] // XCM - [pallet_xcm, PolkadotXcm] + [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] @@ -736,6 +736,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -777,6 +778,29 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + impl pallet_xcm::benchmarking::Config for Runtime { + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Relay/native token can be teleported between BH and Relay. + Some(( + MultiAsset { + fun: Fungible(EXISTENTIAL_DEPOSIT), + id: Concrete(Parent.into()) + }, + Parent.into(), + )) + } + + fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { + // Reserve transfers are disabled on BH. + None + } + } + use xcm::latest::prelude::*; use xcm_config::WestendLocation; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs index 8efc75ed13eb..393767a17efd 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs @@ -284,11 +284,6 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); -} - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type XcmRouter = XcmRouter; @@ -316,8 +311,6 @@ impl pallet_xcm::Config for Runtime { type SovereignAccountOf = LocationToAccountId; type MaxLockers = ConstU32<8>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); From a59ccf3abdbfd1ca1aa2f091d0e47476bdbb1125 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 3 Nov 2023 11:14:09 +0200 Subject: [PATCH 81/98] xcm-emulator: add ah to penpal multiple mixed assets transfer test --- .../assets/asset-hub-rococo/src/lib.rs | 3 +- .../src/tests/reserve_transfer.rs | 114 +++++++++++++++--- .../asset-hub-rococo/src/tests/teleport.rs | 8 +- .../emulated/common/src/impls.rs | 12 +- .../emulated/common/src/lib.rs | 13 +- .../runtimes/testing/penpal/src/lib.rs | 11 +- .../runtimes/testing/penpal/src/xcm_config.rs | 21 ++-- polkadot/xcm/src/v3/multiasset.rs | 4 +- 8 files changed, 137 insertions(+), 49 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs index 6da7537e82f4..a46a2efcead1 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs @@ -78,6 +78,7 @@ pub fn para_test_args( amount: Balance, assets: MultiAssets, asset_id: Option, + fee_asset_item: u32, ) -> TestArgs { TestArgs { dest, @@ -85,7 +86,7 @@ pub fn para_test_args( amount, assets, asset_id, - fee_asset_item: 0, + fee_asset_item, weight_limit: WeightLimit::Unlimited, } } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index 98e2ba18df17..38abc3dea740 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -135,7 +135,7 @@ fn para_to_system_para_receiver_assertions(t: ParaToSystemParaTest) { ); } -fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { +fn system_para_to_para_assets_sender_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( @@ -161,6 +161,18 @@ fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { ); } +fn system_para_to_para_assets_receiver_assertions(_: Test) { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + PenpalRococoA, + vec![ + RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::Assets(pallet_assets::Event::Issued { .. }) => {}, + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) => {}, + ] + ); +} + fn relay_to_para_limited_reserve_transfer_assets(t: RelayToParaTest) -> DispatchResult { ::XcmPallet::limited_reserve_transfer_assets( t.signed_origin, @@ -315,7 +327,7 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { let test_args = TestContext { sender: AssetHubRococoSender::get(), receiver: PenpalRococoAReceiver::get(), - args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0), }; let mut test = SystemParaToParaTest::new(test_args); @@ -355,7 +367,7 @@ fn limited_reserve_transfer_native_asset_from_para_to_system_para() { let test_args = TestContext { sender: PenpalRococoASender::get(), receiver: AssetHubRococoReceiver::get(), - args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0), }; let mut test = ParaToSystemParaTest::new(test_args); @@ -363,7 +375,6 @@ fn limited_reserve_transfer_native_asset_from_para_to_system_para() { let sender_balance_before = test.sender.balance; let receiver_balance_before = test.receiver.balance; - // MultiLocation { parents: 1, interior: X1(Parachain(PenpalRococoA::para_id().into())) }; let penpal_location_as_seen_by_ahr = AssetHubRococo::sibling_location_of(PenpalRococoA::para_id()); let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location_as_seen_by_ahr); @@ -391,38 +402,101 @@ fn limited_reserve_transfer_native_asset_from_para_to_system_para() { assert!(receiver_balance_after > receiver_balance_before); } -/// Limited Reserve Transfers of a local asset from System Parachain to Parachain should work +/// Limited Reserve Transfers of a local asset and native asset from System Parachain to Parachain +/// should work #[test] -fn limited_reserve_transfer_asset_from_system_para_to_para() { - // Force create asset from Relay Chain and mint assets for System Parachain's sender account +fn limited_reserve_transfer_assets_from_system_para_to_para() { + // Force create asset on AssetHubRococo and PenpalRococoA from Relay Chain AssetHubRococo::force_create_and_mint_asset( ASSET_ID, ASSET_MIN_BALANCE, - true, + false, AssetHubRococoSender::get(), Some(Weight::from_parts(1_019_445_000, 200_000)), - ASSET_MIN_BALANCE * 1000000, + ASSET_MIN_BALANCE * 1_000_000, + ); + PenpalRococoA::force_create_and_mint_asset( + ASSET_ID, + ASSET_MIN_BALANCE, + false, + PenpalRococoASender::get(), + Some(Weight::from_parts(1_019_445_000, 200_000)), + 0, ); // Init values for System Parachain let destination = AssetHubRococo::sibling_location_of(PenpalRococoA::para_id()); let beneficiary_id = PenpalRococoAReceiver::get(); - let amount_to_send = ASSET_MIN_BALANCE * 1000; - let assets = - (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send) - .into(); + let fee_amount_to_send = ASSET_HUB_ROCOCO_ED * 1000; + let asset_amount_to_send = ASSET_MIN_BALANCE * 1000; + let assets: MultiAssets = vec![ + (Parent, fee_amount_to_send).into(), + (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), asset_amount_to_send) + .into(), + ] + .into(); + let fee_asset_index = assets + .inner() + .iter() + .position(|r| r == &(Parent, fee_amount_to_send).into()) + .unwrap() as u32; let para_test_args = TestContext { sender: AssetHubRococoSender::get(), receiver: PenpalRococoAReceiver::get(), - args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args( + destination, + beneficiary_id, + asset_amount_to_send, + assets, + None, + fee_asset_index, + ), }; - let mut system_para_test = SystemParaToParaTest::new(para_test_args); + let mut test = SystemParaToParaTest::new(para_test_args); + + // Create SA-of-Penpal-on-AHR with ED. + let penpal_location = AssetHubRococo::sibling_location_of(PenpalRococoA::para_id()); + let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location); + AssetHubRococo::fund_accounts(vec![(sov_penpal_on_ahr.into(), ROCOCO_ED)]); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + let sender_assets_before = AssetHubRococo::execute_with(|| { + type Assets = ::Assets; + >::balance(ASSET_ID, &AssetHubRococoSender::get()) + }); + let receiver_assets_before = PenpalRococoA::execute_with(|| { + type Assets = ::Assets; + >::balance(ASSET_ID, &PenpalRococoAReceiver::get()) + }); + + test.set_assertion::(system_para_to_para_assets_sender_assertions); + test.set_assertion::(system_para_to_para_assets_receiver_assertions); + test.set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert!(sender_balance_after < sender_balance_before); + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); - system_para_test.set_assertion::(system_para_to_para_assets_assertions); - // TODO: Add assertions when Penpal is able to manage assets - system_para_test - .set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); - system_para_test.assert(); + let sender_assets_after = AssetHubRococo::execute_with(|| { + type Assets = ::Assets; + >::balance(ASSET_ID, &AssetHubRococoSender::get()) + }); + let receiver_assets_after = PenpalRococoA::execute_with(|| { + type Assets = ::Assets; + >::balance(ASSET_ID, &PenpalRococoAReceiver::get()) + }); + + // Sender's balance is reduced + assert_eq!(sender_assets_before - asset_amount_to_send, sender_assets_after); + // Receiver's balance is increased + assert!(receiver_assets_after > receiver_assets_before); } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs index 217bac6865c8..f8017f7a1c54 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs @@ -206,7 +206,7 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { let test_args = TestContext { sender: AssetHubRococoSender::get(), receiver: RococoReceiver::get(), - args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0), }; let mut test = SystemParaToRelayTest::new(test_args); @@ -247,7 +247,7 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { let test_args = TestContext { sender: AssetHubRococoSender::get(), receiver: RococoReceiver::get(), - args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0), }; let mut test = SystemParaToRelayTest::new(test_args); @@ -329,7 +329,7 @@ fn teleport_native_assets_back_from_system_para_to_relay_works() { let test_args = TestContext { sender: AssetHubRococoSender::get(), receiver: RococoReceiver::get(), - args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0), }; let mut test = SystemParaToRelayTest::new(test_args); @@ -370,7 +370,7 @@ fn teleport_native_assets_from_system_para_to_relay_fails() { let test_args = TestContext { sender: AssetHubRococoSender::get(), receiver: RococoReceiver::get(), - args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0), }; let mut test = SystemParaToRelayTest::new(test_args); diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index bb4c9d102e98..b93c148dabc0 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -401,7 +401,7 @@ macro_rules! impl_accounts_helpers_for_parachain { #[macro_export] macro_rules! impl_assert_events_helpers_for_parachain { - ( $chain:ident ) => { + ( $chain:ident, $ignore_weight:expr ) => { $crate::impls::paste::paste! { type [<$chain RuntimeEvent>] = <$chain as $crate::impls::Chain>::RuntimeEvent; @@ -414,7 +414,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { [<$chain RuntimeEvent>]::PolkadotXcm( $crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Complete(weight) } ) => { - weight: $crate::impls::weight_within_threshold( + weight: $ignore_weight || $crate::impls::weight_within_threshold( ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight @@ -436,7 +436,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { [<$chain RuntimeEvent>]::PolkadotXcm( $crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Incomplete(weight, error) } ) => { - weight: $crate::impls::weight_within_threshold( + weight: $ignore_weight || $crate::impls::weight_within_threshold( ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight @@ -492,7 +492,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { [<$chain RuntimeEvent>]::DmpQueue($crate::impls::cumulus_pallet_dmp_queue::Event::ExecutedDownward { outcome: $crate::impls::Outcome::Complete(weight), .. }) => { - weight: $crate::impls::weight_within_threshold( + weight: $ignore_weight || $crate::impls::weight_within_threshold( ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight @@ -513,7 +513,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { [<$chain RuntimeEvent>]::DmpQueue($crate::impls::cumulus_pallet_dmp_queue::Event::ExecutedDownward { outcome: $crate::impls::Outcome::Incomplete(weight, error), .. }) => { - weight: $crate::impls::weight_within_threshold( + weight: $ignore_weight || $crate::impls::weight_within_threshold( ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight @@ -548,7 +548,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { [<$chain RuntimeEvent>]::XcmpQueue( $crate::impls::cumulus_pallet_xcmp_queue::Event::Success { weight, .. } ) => { - weight: $crate::impls::weight_within_threshold( + weight: $ignore_weight || $crate::impls::weight_within_threshold( ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), expected_weight.unwrap_or(*weight), *weight diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 1ec006f4510b..ac06b921e46d 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -312,24 +312,25 @@ impl_send_transact_helpers_for_relay_chain!(Wococo); // AssetHubWestend implementation impl_accounts_helpers_for_parachain!(AssetHubWestend); impl_assets_helpers_for_parachain!(AssetHubWestend, Westend); -impl_assert_events_helpers_for_parachain!(AssetHubWestend); +impl_assert_events_helpers_for_parachain!(AssetHubWestend, false); // AssetHubRococo implementation impl_accounts_helpers_for_parachain!(AssetHubRococo); impl_assets_helpers_for_parachain!(AssetHubRococo, Rococo); -impl_assert_events_helpers_for_parachain!(AssetHubRococo); +impl_assert_events_helpers_for_parachain!(AssetHubRococo, false); // PenpalWestendA implementation -impl_assert_events_helpers_for_parachain!(PenpalWestendA); +impl_assert_events_helpers_for_parachain!(PenpalWestendA, true); // BridgeHubRococo implementation impl_accounts_helpers_for_parachain!(BridgeHubRococo); -impl_assert_events_helpers_for_parachain!(BridgeHubRococo); +impl_assert_events_helpers_for_parachain!(BridgeHubRococo, false); // PenpalRococo implementations impl_accounts_helpers_for_parachain!(PenpalRococoA); -impl_assert_events_helpers_for_parachain!(PenpalRococoA); -impl_assert_events_helpers_for_parachain!(PenpalRococoB); +impl_assets_helpers_for_parachain!(PenpalRococoA, Rococo); +impl_assert_events_helpers_for_parachain!(PenpalRococoA, true); +impl_assert_events_helpers_for_parachain!(PenpalRococoB, true); decl_test_sender_receiver_accounts_parameter_types! { // Relays diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index 522cbf1faced..b5ef56e72711 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -432,7 +432,7 @@ parameter_types! { // pub type AssetsForceOrigin = // EnsureOneOf, EnsureXcm>>; -impl pallet_assets::Config for Runtime { +impl pallet_assets::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; type AssetId = AssetId; @@ -557,7 +557,12 @@ impl pallet_asset_tx_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Fungibles = Assets; type OnChargeAssetTransaction = pallet_asset_tx_payment::FungiblesAdapter< - pallet_assets::BalanceToAssetBalance, + pallet_assets::BalanceToAssetBalance< + Balances, + Runtime, + ConvertInto, + pallet_assets::Instance1, + >, AssetsToBlockAuthor, >; } @@ -599,7 +604,7 @@ construct_runtime!( DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 33, // The main stage. - Assets: pallet_assets::{Pallet, Call, Storage, Event} = 50, + Assets: pallet_assets::::{Pallet, Call, Storage, Event} = 50, Sudo: pallet_sudo::{Pallet, Call, Storage, Event, Config} = 255, } diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index 7dde53452d35..74d9a0b071d8 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -38,6 +38,7 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_asset_tx_payment::HandleCredit; +use pallet_assets::Instance1; use pallet_xcm::XcmPassthrough; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::impls::ToAuthor; @@ -48,9 +49,10 @@ use xcm_builder::{ AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex, ConvertedConcreteId, CurrencyAdapter, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, FungiblesAdapter, IsConcrete, LocalMint, NativeAsset, - ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, + ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::{traits::JustTry, XcmExecutor}; @@ -126,6 +128,9 @@ pub type XcmOriginToTransactDispatchOrigin = ( // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when // recognized. SiblingParachainAsNative, + // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a + // transaction from the Root origin. + ParentAsSuperuser, // Native signed account converter; this just converts an `AccountId32` origin into a normal // `RuntimeOrigin::Signed` origin of the same 32-byte value. SignedAccountId32AsNative, @@ -189,7 +194,7 @@ impl> ContainsPair for AssetsFr let loc = T::get(); &loc == origin && matches!(asset, MultiAsset { id: AssetId::Concrete(asset_loc), fun: Fungible(_a) } - if asset_loc.match_and_split(&loc).is_some()) + if asset_loc.starts_with(&loc)) } } @@ -219,15 +224,15 @@ where /// A `HandleCredit` implementation that naively transfers the fees to the block author. /// Will drop and burn the assets in case the transfer fails. pub struct AssetsToBlockAuthor(PhantomData); -impl HandleCredit, pallet_assets::Pallet> for AssetsToBlockAuthor +impl HandleCredit, pallet_assets::Pallet> for AssetsToBlockAuthor where - R: pallet_authorship::Config + pallet_assets::Config, + R: pallet_authorship::Config + pallet_assets::Config, AccountIdOf: From + Into, { - fn handle_credit(credit: Credit, pallet_assets::Pallet>) { + fn handle_credit(credit: Credit, pallet_assets::Pallet>) { if let Some(author) = pallet_authorship::Pallet::::author() { // In case of error: Will drop the result triggering the `OnDrop` of the imbalance. - let _ = pallet_assets::Pallet::::resolve(&author, credit); + let _ = pallet_assets::Pallet::::resolve(&author, credit); } } } diff --git a/polkadot/xcm/src/v3/multiasset.rs b/polkadot/xcm/src/v3/multiasset.rs index 9d86fb8deff8..aeba5389b39c 100644 --- a/polkadot/xcm/src/v3/multiasset.rs +++ b/polkadot/xcm/src/v3/multiasset.rs @@ -694,7 +694,9 @@ impl MultiAssets { target: &MultiLocation, context: InteriorMultiLocation, ) -> Result<(), ()> { - self.0.iter_mut().try_for_each(|i| i.reanchor(target, context)) + self.0.iter_mut().try_for_each(|i| i.reanchor(target, context))?; + self.0.sort(); + Ok(()) } /// Return a reference to an item at a specific index or `None` if it doesn't exist. From 582c616d697665bb116f7d6d8ab9426993293f49 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 3 Nov 2023 15:46:55 +0200 Subject: [PATCH 82/98] fix merge damage --- Cargo.lock | 1 + .../assets/asset-hub-rococo/Cargo.toml | 1 + .../src/tests/reserve_transfer.rs | 19 ++++++++++++------- .../src/tests/reserve_transfer.rs | 4 +++- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5bb0cfe52d2f..2bebcfe5ece3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -889,6 +889,7 @@ dependencies = [ "pallet-asset-conversion", "pallet-assets", "pallet-balances", + "pallet-message-queue", "pallet-xcm", "parachains-common", "parity-scale-codec", diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml index 820429deae45..e13d996830c6 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml @@ -18,6 +18,7 @@ frame-system = { path = "../../../../../../substrate/frame/system", default-feat pallet-balances = { path = "../../../../../../substrate/frame/balances", default-features = false} pallet-assets = { path = "../../../../../../substrate/frame/assets", default-features = false} pallet-asset-conversion = { path = "../../../../../../substrate/frame/asset-conversion", default-features = false} +pallet-message-queue = { path = "../../../../../../substrate/frame/message-queue", default-features = false } # Polkadot polkadot-core-primitives = { path = "../../../../../../polkadot/core-primitives", default-features = false} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index 38abc3dea740..0ab293f1746b 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -46,10 +46,9 @@ fn relay_to_para_receiver_assertions(_: Test) { PenpalRococoA, vec![ RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, - RuntimeEvent::DmpQueue(cumulus_pallet_dmp_queue::Event::ExecutedDownward { - outcome: Outcome::Complete(_), - .. - }) => {}, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, ] ); } @@ -85,7 +84,9 @@ fn system_para_to_para_receiver_assertions(_: Test) { PenpalRococoA, vec![ RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) => {}, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, ] ); } @@ -130,7 +131,9 @@ fn para_to_system_para_receiver_assertions(t: ParaToSystemParaTest) { amount: *amount == t.args.amount, }, RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) => {}, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, ] ); } @@ -168,7 +171,9 @@ fn system_para_to_para_assets_receiver_assertions(_: Test) { vec![ RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, RuntimeEvent::Assets(pallet_assets::Event::Issued { .. }) => {}, - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) => {}, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, ] ); } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs index 518e117c1074..3000ac2eb02d 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -47,7 +47,9 @@ fn para_receiver_assertions(_: Test) { PenpalWestendA, vec![ RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) => {}, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, ] ); } From 94aaffd47729fdc034784d091abb9d52f1b735e6 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 3 Nov 2023 16:03:53 +0200 Subject: [PATCH 83/98] remove limited from test names, all transfers use limited method now --- .../src/tests/reserve_transfer.rs | 27 +++++++++---------- .../src/tests/reserve_transfer.rs | 17 ++++++------ 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index 0ab293f1746b..48ecfe5b639f 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -211,10 +211,9 @@ fn para_to_system_para_limited_reserve_transfer_assets(t: ParaToSystemParaTest) ) } -/// Limited Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't -/// work +/// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work #[test] -fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() { +fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { let signed_origin = ::RuntimeOrigin::signed(RococoSender::get().into()); let destination = Rococo::child_location_of(AssetHubRococo::para_id()); let beneficiary: MultiLocation = @@ -244,9 +243,9 @@ fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() { }); } -/// Limited Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work +/// Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work #[test] -fn limited_reserve_transfer_native_asset_from_system_para_to_relay_fails() { +fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { // Init values for System Parachain let signed_origin = ::RuntimeOrigin::signed(AssetHubRococoSender::get().into()); @@ -281,9 +280,9 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_relay_fails() { }); } -/// Limited Reserve Transfers of native asset from Relay to Parachain should work +/// Reserve Transfers of native asset from Relay to Parachain should work #[test] -fn limited_reserve_transfer_native_asset_from_relay_to_para() { +fn reserve_transfer_native_asset_from_relay_to_para() { // Init values for Relay let destination = Rococo::child_location_of(PenpalRococoA::para_id()); let beneficiary_id = PenpalRococoAReceiver::get(); @@ -320,9 +319,9 @@ fn limited_reserve_transfer_native_asset_from_relay_to_para() { assert!(receiver_balance_after > receiver_balance_before); } -/// Limited Reserve Transfers of native asset from System Parachain to Parachain should work +/// Reserve Transfers of native asset from System Parachain to Parachain should work #[test] -fn limited_reserve_transfer_native_asset_from_system_para_to_para() { +fn reserve_transfer_native_asset_from_system_para_to_para() { // Init values for System Parachain let destination = AssetHubRococo::sibling_location_of(PenpalRococoA::para_id()); let beneficiary_id = PenpalRococoAReceiver::get(); @@ -360,9 +359,9 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { assert!(receiver_balance_after > receiver_balance_before); } -/// Limited Reserve Transfers of native asset from Parachain to System Parachain should work +/// Reserve Transfers of native asset from Parachain to System Parachain should work #[test] -fn limited_reserve_transfer_native_asset_from_para_to_system_para() { +fn reserve_transfer_native_asset_from_para_to_system_para() { // Init values for Penpal Parachain let destination = PenpalRococoA::sibling_location_of(AssetHubRococo::para_id()); let beneficiary_id = AssetHubRococoReceiver::get(); @@ -407,10 +406,10 @@ fn limited_reserve_transfer_native_asset_from_para_to_system_para() { assert!(receiver_balance_after > receiver_balance_before); } -/// Limited Reserve Transfers of a local asset and native asset from System Parachain to Parachain -/// should work +/// Reserve Transfers of a local asset and native asset from System Parachain to Parachain should +/// work #[test] -fn limited_reserve_transfer_assets_from_system_para_to_para() { +fn reserve_transfer_assets_from_system_para_to_para() { // Force create asset on AssetHubRococo and PenpalRococoA from Relay Chain AssetHubRococo::force_create_and_mint_asset( ASSET_ID, diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs index 3000ac2eb02d..694ec97c4a66 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -91,10 +91,9 @@ fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) ) } -/// Limited Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't -/// work +/// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work #[test] -fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() { +fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { let signed_origin = ::RuntimeOrigin::signed(WestendSender::get().into()); let destination = Westend::child_location_of(AssetHubWestend::para_id()); let beneficiary: MultiLocation = @@ -124,9 +123,9 @@ fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() { }); } -/// Limited Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work +/// Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work #[test] -fn limited_reserve_transfer_native_asset_from_system_para_to_relay_fails() { +fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { // Init values for System Parachain let signed_origin = ::RuntimeOrigin::signed(AssetHubWestendSender::get().into()); @@ -160,9 +159,9 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_relay_fails() { }); } -/// Limited Reserve Transfers of native asset from System Parachain to Parachain should work +/// Reserve Transfers of native asset from System Parachain to Parachain should work #[test] -fn limited_reserve_transfer_native_asset_from_system_para_to_para() { +fn reserve_transfer_native_asset_from_system_para_to_para() { // Init values for System Parachain let destination = AssetHubWestend::sibling_location_of(PenpalWestendA::para_id()); let beneficiary_id = PenpalWestendAReceiver::get(); @@ -204,9 +203,9 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { assert!(receiver_balance_after > receiver_balance_before); } -/// Limited Reserve Transfers of a local asset from System Parachain to Parachain should work +/// Reserve Transfers of a local asset from System Parachain to Parachain should work #[test] -fn limited_reserve_transfer_asset_from_system_para_to_para() { +fn reserve_transfer_asset_from_system_para_to_para() { // Force create asset from Relay Chain and mint assets for System Parachain's sender account AssetHubWestend::force_create_and_mint_asset( ASSET_ID, From fe2cb6a9f111726edf03246ba0b6e6a6891895c7 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Sun, 5 Nov 2023 11:55:42 +0200 Subject: [PATCH 84/98] barriers: allow withdrawing multiple assets in AllowTopLevelPaidExecutionFrom --- polkadot/xcm/xcm-builder/src/barriers.rs | 25 ++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/polkadot/xcm/xcm-builder/src/barriers.rs b/polkadot/xcm/xcm-builder/src/barriers.rs index 3b13cab2c1ea..5639d7f8cc15 100644 --- a/polkadot/xcm/xcm-builder/src/barriers.rs +++ b/polkadot/xcm/xcm-builder/src/barriers.rs @@ -74,20 +74,29 @@ impl> ShouldExecute for AllowTopLevelPaidExecutionFro ); ensure!(T::contains(origin), ProcessMessageError::Unsupported); - // We will read up to 5 instructions. This allows up to 3 `ClearOrigin` instructions. We - // allow for more than one since anything beyond the first is a no-op and it's conceivable - // that composition of operations might result in more than one being appended. - let end = instructions.len().min(5); - instructions[..end] - .matcher() - .match_next_inst(|inst| match inst { + fn funds_holding_register( + inst: &Instruction, + ) -> Result<(), ProcessMessageError> { + match inst { ReceiveTeleportedAsset(..) | ReserveAssetDeposited(..) => Ok(()), WithdrawAsset(ref assets) if assets.len() <= MAX_ASSETS_FOR_BUY_EXECUTION => Ok(()), ClaimAsset { ref assets, .. } if assets.len() <= MAX_ASSETS_FOR_BUY_EXECUTION => Ok(()), _ => Err(ProcessMessageError::BadFormat), - })? + } + } + // We will read up to 6 instructions. This allows up to 3 `ClearOrigin` instructions. We + // allow for more than one since anything beyond the first is a no-op and it's conceivable + // that composition of operations might result in more than one being appended. + let end = instructions.len().min(6); + instructions[..end] + .matcher() + // ensure there is at least one instruction loading funds in holding register + .match_next_inst(|inst| funds_holding_register(inst))? + .skip_inst_while(|inst| funds_holding_register(inst).is_ok())? + // skip `ClearOrigin` instructions .skip_inst_while(|inst| matches!(inst, ClearOrigin))? + // ensure required weight is bought using funds prepared above .match_next_inst(|inst| match inst { BuyExecution { weight_limit: Limited(ref mut weight), .. } if weight.all_gte(max_weight) => From 2ebefc075fc076db871370ff61cdc161bd67eeee Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 6 Nov 2023 13:49:57 +0200 Subject: [PATCH 85/98] pallet-xcm: add trace logs --- polkadot/xcm/pallet-xcm/src/lib.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index a89baedb7f4c..f71865220762 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1247,6 +1247,11 @@ impl Pallet { let beneficiary: MultiLocation = (*beneficiary).try_into().map_err(|()| Error::::BadVersion)?; let assets: MultiAssets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; + log::trace!( + target: "xcm::pallet_xcm::do_reserve_transfer_assets", + "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, fee-idx {:?}", + origin_location, dest, beneficiary, assets, fee_asset_item, + ); ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::::TooManyAssets); let value = (origin_location, assets.into_inner()); @@ -1357,6 +1362,11 @@ impl Pallet { prefund_fees_messages: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, weight_limit: WeightLimit, ) -> DispatchResult { + log::trace!( + target: "xcm::pallet_xcm::build_and_execute_xcm_transfer_type", + "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, transfer_type {:?}, fees {:?}, prefund_xcm: {:?}", + origin, dest, beneficiary, assets, transfer_type, fees, prefund_fees_messages, + ); let (mut local_xcm, remote_xcm) = match transfer_type { TransferType::LocalReserve => { let (local, remote) = Self::local_reserve_transfer_messages( @@ -1584,11 +1594,17 @@ impl Pallet { dest: MultiLocation, beneficiary: MultiLocation, assets: Vec, - fees: MultiAsset, + mut fees: MultiAsset, weight_limit: WeightLimit, ) -> Result::RuntimeCall>, Error> { let max_assets = assets.len() as u32; let context = T::UniversalLocation::get(); + // we spend up to half of fees for execution on reserve and other half for execution on + // destination + match &mut fees.fun { + Fungible(amount) => *amount = amount.saturating_div(2), + NonFungible(_) => return Err(Error::::FeesNotMet), + }; // identifies fee item as seen by `reserve` - to be used at reserve chain let reserve_fees = fees .clone() From 56c52f107c2801a2cc16c214902ad1f2e9a6d235 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 6 Nov 2023 15:30:49 +0200 Subject: [PATCH 86/98] fix runtime-benchmarks --- .../emulated/assets/asset-hub-rococo/Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml index e13d996830c6..d64604cf0b07 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml @@ -44,14 +44,18 @@ integration-tests-common = { path = "../../common", default-features = false} [features] runtime-benchmarks = [ "asset-hub-rococo-runtime/runtime-benchmarks", + "cumulus-pallet-dmp-queue/runtime-benchmarks", + "cumulus-pallet-xcmp-queue/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "integration-tests-common/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "parachains-common/runtime-benchmarks", + "penpal-runtime/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", "rococo-runtime/runtime-benchmarks", From ba91cd61d80f2a100b574407ef8a069a0354899c Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 6 Nov 2023 18:40:19 +0200 Subject: [PATCH 87/98] pallet-xcm: fix tests --- .../pallet-xcm/src/tests/assets_transfer.rs | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index 7a9b7be8dff2..36a041180d92 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -977,10 +977,15 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work // reanchor according to test-case let context = UniversalLocation::get(); let expected_dest_on_reserve = dest.reanchored(&usdc_chain, context).unwrap(); - let expected_fee_on_reserve = - assets.get(fee_index).unwrap().clone().reanchored(&usdc_chain, context).unwrap(); - let mut expected_assets = assets.clone(); - expected_assets.reanchor(&dest, context).unwrap(); + let mut fees = assets.get(fee_index).unwrap().clone(); + match &mut fees.fun { + Fungible(amount) => *amount = amount.saturating_div(2), + NonFungible(_) => unreachable!(), + }; + let mut expected_assets_on_reserve = assets.clone(); + expected_assets_on_reserve.reanchor(&usdc_chain, context).unwrap(); + let expected_fee_on_reserve = fees.clone().reanchored(&usdc_chain, context).unwrap(); + let expected_fee_on_dest = fees.clone().reanchored(&dest, context).unwrap(); // balances checks before assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); @@ -1022,7 +1027,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work // first message sent to reserve chain usdc_chain, Xcm(vec![ - WithdrawAsset(expected_fee_on_reserve.clone().into()), + WithdrawAsset(expected_assets_on_reserve), ClearOrigin, BuyExecution { fees: expected_fee_on_reserve, weight_limit: Unlimited }, DepositReserveAsset { @@ -1031,10 +1036,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work dest: expected_dest_on_reserve, // message sent onward to `dest` xcm: Xcm(vec![ - buy_limited_execution( - expected_assets.get(0).unwrap().clone(), - Unlimited - ), + buy_limited_execution(expected_fee_on_dest, Unlimited), DepositAsset { assets: AllCounted(1).into(), beneficiary } ]) } From 8951238e21d95f49d6d46199f230c7a451776f75 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 7 Nov 2023 11:49:42 +0200 Subject: [PATCH 88/98] xcm-emulator: remove unused pallet import --- Cargo.lock | 2 -- .../emulated/assets/asset-hub-rococo/Cargo.toml | 2 -- .../emulated/assets/asset-hub-westend/Cargo.toml | 1 - 3 files changed, 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c8cb46eb973..decf2fa5eba5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -882,7 +882,6 @@ dependencies = [ "asset-hub-rococo-runtime", "asset-test-utils", "cumulus-pallet-dmp-queue", - "cumulus-pallet-xcmp-queue", "frame-support", "frame-system", "integration-tests-common", @@ -995,7 +994,6 @@ dependencies = [ "asset-test-utils", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", - "cumulus-pallet-xcmp-queue", "frame-support", "frame-system", "integration-tests-common", diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml index d64604cf0b07..0f373f7e1224 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml @@ -35,7 +35,6 @@ parachains-common = { path = "../../../../common" } asset-hub-rococo-runtime = { path = "../../../../runtimes/assets/asset-hub-rococo" } penpal-runtime = { path = "../../../../runtimes/testing/penpal" } cumulus-pallet-dmp-queue = { path = "../../../../../pallets/dmp-queue", default-features = false} -cumulus-pallet-xcmp-queue = { path = "../../../../../pallets/xcmp-queue", default-features = false} # Local xcm-emulator = { path = "../../../../../xcm/xcm-emulator", default-features = false} @@ -45,7 +44,6 @@ integration-tests-common = { path = "../../common", default-features = false} runtime-benchmarks = [ "asset-hub-rococo-runtime/runtime-benchmarks", "cumulus-pallet-dmp-queue/runtime-benchmarks", - "cumulus-pallet-xcmp-queue/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "integration-tests-common/runtime-benchmarks", diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/Cargo.toml index 4a156604dfab..2043431dcc27 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/Cargo.toml @@ -40,7 +40,6 @@ asset-hub-westend-runtime = { path = "../../../../runtimes/assets/asset-hub-west asset-test-utils = { path = "../../../../runtimes/assets/test-utils", default-features = false } cumulus-pallet-dmp-queue = { default-features = false, path = "../../../../../pallets/dmp-queue" } cumulus-pallet-parachain-system = { default-features = false, path = "../../../../../pallets/parachain-system" } -cumulus-pallet-xcmp-queue = { path = "../../../../../pallets/xcmp-queue", default-features = false} # Local xcm-emulator = { path = "../../../../../xcm/xcm-emulator", default-features = false} From dd2a06f6c0877d5d193a32558c8b27a970d3ebae Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 7 Nov 2023 11:51:17 +0200 Subject: [PATCH 89/98] xcm-barrier: enforce MAX_ASSETS_FOR_BUY_EXECUTION --- polkadot/xcm/xcm-builder/src/barriers.rs | 61 ++++++++++++++---------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/polkadot/xcm/xcm-builder/src/barriers.rs b/polkadot/xcm/xcm-builder/src/barriers.rs index 5639d7f8cc15..9ef915fd6560 100644 --- a/polkadot/xcm/xcm-builder/src/barriers.rs +++ b/polkadot/xcm/xcm-builder/src/barriers.rs @@ -74,41 +74,50 @@ impl> ShouldExecute for AllowTopLevelPaidExecutionFro ); ensure!(T::contains(origin), ProcessMessageError::Unsupported); - fn funds_holding_register( - inst: &Instruction, - ) -> Result<(), ProcessMessageError> { - match inst { - ReceiveTeleportedAsset(..) | ReserveAssetDeposited(..) => Ok(()), - WithdrawAsset(ref assets) if assets.len() <= MAX_ASSETS_FOR_BUY_EXECUTION => Ok(()), - ClaimAsset { ref assets, .. } if assets.len() <= MAX_ASSETS_FOR_BUY_EXECUTION => - Ok(()), - _ => Err(ProcessMessageError::BadFormat), - } - } - // We will read up to 6 instructions. This allows up to 3 `ClearOrigin` instructions. We + let mut assets_in_holding = 0; + // We will read up to 5 instructions. This allows up to 3 `ClearOrigin` instructions. We // allow for more than one since anything beyond the first is a no-op and it's conceivable // that composition of operations might result in more than one being appended. let end = instructions.len().min(6); instructions[..end] .matcher() // ensure there is at least one instruction loading funds in holding register - .match_next_inst(|inst| funds_holding_register(inst))? - .skip_inst_while(|inst| funds_holding_register(inst).is_ok())? + .match_next_inst_while( + |_| true, + |inst| match inst { + ReceiveTeleportedAsset(ref assets) | + ReserveAssetDeposited(ref assets) | + WithdrawAsset(ref assets) | + ClaimAsset { ref assets, .. } => { + assets_in_holding += assets.len(); + Ok(ControlFlow::Continue(())) + }, + _ => Ok(ControlFlow::Break(())), + }, + )? // skip `ClearOrigin` instructions .skip_inst_while(|inst| matches!(inst, ClearOrigin))? // ensure required weight is bought using funds prepared above - .match_next_inst(|inst| match inst { - BuyExecution { weight_limit: Limited(ref mut weight), .. } - if weight.all_gte(max_weight) => - { - *weight = max_weight; - Ok(()) - }, - BuyExecution { ref mut weight_limit, .. } if weight_limit == &Unlimited => { - *weight_limit = Limited(max_weight); - Ok(()) - }, - _ => Err(ProcessMessageError::Overweight(max_weight)), + .match_next_inst(|inst| { + // ensure there were `0 < assets <= MAX_ASSETS_FOR_BUY_EXECUTION` added to holding + // for BuyExecution + ensure!( + assets_in_holding > 0 && assets_in_holding <= MAX_ASSETS_FOR_BUY_EXECUTION, + ProcessMessageError::BadFormat + ); + match inst { + BuyExecution { weight_limit: Limited(ref mut weight), .. } + if weight.all_gte(max_weight) => + { + *weight = max_weight; + Ok(()) + }, + BuyExecution { ref mut weight_limit, .. } if weight_limit == &Unlimited => { + *weight_limit = Limited(max_weight); + Ok(()) + }, + _ => Err(ProcessMessageError::Overweight(max_weight)), + } })?; Ok(()) } From 6d67ea1ee4bc71b99757ecf0bfdcb5f61f3e27eb Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 7 Nov 2023 17:02:09 +0200 Subject: [PATCH 90/98] rename some variables and fns --- polkadot/xcm/pallet-xcm/src/lib.rs | 54 ++++++++++++++++-------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index f71865220762..07783447bb7e 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1273,29 +1273,32 @@ impl Pallet { Self::validate_assets_and_find_reserve(&assets, &dest)? }; - let prefund_fees_messages: Option<(Xcm<::RuntimeCall>, Xcm<()>)>; + // local and remote XCM programs to potentially prefund fees + let prefund_fees_instructions: Option<(Xcm<::RuntimeCall>, Xcm<()>)>; if fees_transfer_type == assets_transfer_type { // Same reserve location (fees not teleportable), we can batch together fees and assets // in same reserve-based-transfer. assets.push(fees.clone()); - // no need for custom prefund messages, fees are batched with assets - prefund_fees_messages = None; + // no need for custom prefund instructions, fees are batched with assets + prefund_fees_instructions = None; } 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. - if let TransferType::RemoteReserve(_) = assets_transfer_type { - return Err(Error::::InvalidAssetUnsupportedReserve.into()) - } + ensure!( + !matches!(assets_transfer_type, TransferType::RemoteReserve(_)), + Error::::InvalidAssetUnsupportedReserve + ); // build fees transfer instructions to be added to assets transfers XCM programs - prefund_fees_messages = Some(match fees_transfer_type { + prefund_fees_instructions = Some(match fees_transfer_type { TransferType::LocalReserve => - Self::prefund_local_reserve_fees_messages(dest, fees.clone())?, + Self::prefund_local_reserve_fees_instructions(dest, fees.clone())?, TransferType::DestinationReserve => - Self::prefund_destination_reserve_fees_messages(dest, fees.clone())?, - TransferType::Teleport => Self::prefund_teleport_fees_messages(dest, fees.clone())?, + Self::prefund_destination_reserve_fees_instructions(dest, fees.clone())?, + TransferType::Teleport => + Self::prefund_teleport_fees_instructions(dest, fees.clone())?, TransferType::RemoteReserve(_) => return Err(Error::::InvalidAssetUnsupportedReserve.into()), }); @@ -1310,7 +1313,7 @@ impl Pallet { assets, assets_transfer_type, fees, - prefund_fees_messages, + prefund_fees_instructions, weight_limit, ) } @@ -1359,13 +1362,14 @@ impl Pallet { assets: Vec, transfer_type: TransferType, fees: MultiAsset, - prefund_fees_messages: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, + prefund_fees_instructions: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, weight_limit: WeightLimit, ) -> DispatchResult { log::trace!( target: "xcm::pallet_xcm::build_and_execute_xcm_transfer_type", - "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, transfer_type {:?}, fees {:?}, prefund_xcm: {:?}", - origin, dest, beneficiary, assets, transfer_type, fees, prefund_fees_messages, + "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, transfer_type {:?}, \ + fees {:?}, prefund_xcm: {:?}, weight_limit: {:?}", + origin, dest, beneficiary, assets, transfer_type, fees, prefund_fees_instructions, weight_limit, ); let (mut local_xcm, remote_xcm) = match transfer_type { TransferType::LocalReserve => { @@ -1374,7 +1378,7 @@ impl Pallet { beneficiary, assets, fees, - prefund_fees_messages, + prefund_fees_instructions, weight_limit, )?; (local, Some(remote)) @@ -1385,7 +1389,7 @@ impl Pallet { beneficiary, assets, fees, - prefund_fees_messages, + prefund_fees_instructions, weight_limit, )?; (local, Some(remote)) @@ -1426,7 +1430,7 @@ impl Pallet { Ok(()) } - fn prefund_local_reserve_fees_messages( + fn prefund_local_reserve_fees_instructions( dest: MultiLocation, fees: MultiAsset, ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { @@ -1452,12 +1456,12 @@ impl Pallet { beneficiary: MultiLocation, assets: Vec, fees: MultiAsset, - prefund_fees_messages: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, + prefund_fees_instructions: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, weight_limit: WeightLimit, ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { // max assets is `assets` ( + potentially separately handled fee) let max_assets = - assets.len() as u32 + prefund_fees_messages.as_ref().map(|_| 1).unwrap_or(0); + assets.len() as u32 + prefund_fees_instructions.as_ref().map(|_| 1).unwrap_or(0); let assets: MultiAssets = assets.into(); let context = T::UniversalLocation::get(); let reanchored_fees = @@ -1467,7 +1471,7 @@ impl Pallet { .reanchor(&dest, context) .map_err(|_| Error::::CannotReanchor)?; - let (prefund_local_xcm, prefund_remote_xcm) = prefund_fees_messages + let (prefund_local_xcm, prefund_remote_xcm) = prefund_fees_instructions .map(|(local, remote)| (local.into_inner(), remote.into_inner())) .unwrap_or_default(); @@ -1501,7 +1505,7 @@ impl Pallet { Ok((local_execute_xcm, xcm_on_dest)) } - fn prefund_destination_reserve_fees_messages( + fn prefund_destination_reserve_fees_instructions( dest: MultiLocation, fees: MultiAsset, ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { @@ -1530,12 +1534,12 @@ impl Pallet { beneficiary: MultiLocation, assets: Vec, fees: MultiAsset, - prefund_fees_messages: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, + prefund_fees_instructions: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, weight_limit: WeightLimit, ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { // max assets is `assets` ( + potentially separately handled fee) let max_assets = - assets.len() as u32 + prefund_fees_messages.as_ref().map(|_| 1).unwrap_or(0); + assets.len() as u32 + prefund_fees_instructions.as_ref().map(|_| 1).unwrap_or(0); let assets: MultiAssets = assets.into(); let context = T::UniversalLocation::get(); let reanchored_fees = @@ -1545,7 +1549,7 @@ impl Pallet { .reanchor(&dest, context) .map_err(|_| Error::::CannotReanchor)?; - let (prefund_local_xcm, prefund_remote_xcm) = prefund_fees_messages + let (prefund_local_xcm, prefund_remote_xcm) = prefund_fees_instructions .map(|(local, remote)| (local.into_inner(), remote.into_inner())) // default is empty vec, so no prefund instructions required .unwrap_or_default(); @@ -1634,7 +1638,7 @@ impl Pallet { ])) } - fn prefund_teleport_fees_messages( + fn prefund_teleport_fees_instructions( dest: MultiLocation, fees: MultiAsset, ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { From db1e8268c0d7b19a2c05d1a38b2936779831f780 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 7 Nov 2023 17:32:11 +0200 Subject: [PATCH 91/98] add explicit incomplete local execution error --- polkadot/xcm/pallet-xcm/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 07783447bb7e..1cfbaaaf7d76 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -446,6 +446,8 @@ pub mod pallet { InvalidAssetUnsupportedReserve, /// Too many assets with different reserve locations have been attempted for transfer. TooManyReserves, + /// Local XCM execution of asset transfer incomplete. + LocalExecutionIncomplete, } impl From for Error { @@ -1415,7 +1417,7 @@ impl Pallet { T::XcmExecutor::execute_xcm_in_credit(origin, local_xcm, hash, weight, weight); Self::deposit_event(Event::Attempted { outcome: outcome.clone() }); if let Some(remote_xcm) = remote_xcm { - outcome.ensure_complete().map_err(|_| Error::::FeesNotMet)?; + outcome.ensure_complete().map_err(|_| Error::::LocalExecutionIncomplete)?; let (ticket, price) = validate_send::(dest, remote_xcm.clone()) .map_err(Error::::from)?; From 54d7465125d14cb5dd6fd409ae9f043f039547b6 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 7 Nov 2023 17:34:12 +0200 Subject: [PATCH 92/98] rename fns --- polkadot/xcm/pallet-xcm/src/lib.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 1cfbaaaf7d76..674d681fe56d 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1375,7 +1375,7 @@ impl Pallet { ); let (mut local_xcm, remote_xcm) = match transfer_type { TransferType::LocalReserve => { - let (local, remote) = Self::local_reserve_transfer_messages( + let (local, remote) = Self::local_reserve_transfer_programs( dest, beneficiary, assets, @@ -1386,7 +1386,7 @@ impl Pallet { (local, Some(remote)) }, TransferType::DestinationReserve => { - let (local, remote) = Self::destination_reserve_transfer_messages( + let (local, remote) = Self::destination_reserve_transfer_programs( dest, beneficiary, assets, @@ -1397,7 +1397,7 @@ impl Pallet { (local, Some(remote)) }, TransferType::RemoteReserve(reserve) => ( - Self::remote_reserve_transfer_message( + Self::remote_reserve_transfer_program( reserve, dest, beneficiary, @@ -1407,8 +1407,10 @@ impl Pallet { )?, None, ), - TransferType::Teleport => - (Self::teleport_asset_message(dest, beneficiary, assets, fees, weight_limit)?, None), + TransferType::Teleport => ( + Self::teleport_assets_program(dest, beneficiary, assets, fees, weight_limit)?, + None, + ), }; let weight = T::Weigher::weight(&mut local_xcm).map_err(|()| Error::::UnweighableMessage)?; @@ -1453,7 +1455,7 @@ impl Pallet { Ok((local_execute_xcm, xcm_on_dest)) } - fn local_reserve_transfer_messages( + fn local_reserve_transfer_programs( dest: MultiLocation, beneficiary: MultiLocation, assets: Vec, @@ -1531,7 +1533,7 @@ impl Pallet { Ok((local_execute_xcm, xcm_on_dest)) } - fn destination_reserve_transfer_messages( + fn destination_reserve_transfer_programs( dest: MultiLocation, beneficiary: MultiLocation, assets: Vec, @@ -1595,7 +1597,7 @@ impl Pallet { } // function assumes fees and assets have the same remote reserve - fn remote_reserve_transfer_message( + fn remote_reserve_transfer_program( reserve: MultiLocation, dest: MultiLocation, beneficiary: MultiLocation, @@ -1683,7 +1685,7 @@ impl Pallet { Ok((local_execute_xcm, xcm_on_dest)) } - fn teleport_asset_message( + fn teleport_assets_program( dest: MultiLocation, beneficiary: MultiLocation, assets: Vec, From 39e7b6649ff112de59d590f3e688123c9711f799 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 7 Nov 2023 17:51:33 +0200 Subject: [PATCH 93/98] pallet-xcm: fix pallet extrinsic default weights --- polkadot/xcm/pallet-xcm/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 674d681fe56d..24134791d276 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -828,11 +828,7 @@ pub mod pallet { let mut message = Xcm(vec![ WithdrawAsset(assets), SetFeesMode { jit_withdraw: true }, - InitiateTeleport { - assets: Wild(AllCounted(count)), - dest, - xcm: Xcm(vec![]), - }, + 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)) } @@ -875,6 +871,8 @@ pub mod pallet { 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![]) } @@ -1050,6 +1048,8 @@ pub mod pallet { 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![]) } From ceddec59029fb900a216c9d9bce6ff221c8db7f9 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 8 Nov 2023 15:13:34 +0200 Subject: [PATCH 94/98] pallet-xcm: also buy execution as part of custom fee handling --- polkadot/xcm/pallet-xcm/src/lib.rs | 199 +++++++++--------- .../pallet-xcm/src/tests/assets_transfer.rs | 8 +- polkadot/xcm/xcm-builder/src/barriers.rs | 61 +++--- 3 files changed, 128 insertions(+), 140 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 24134791d276..0804a3783dc0 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1275,14 +1275,14 @@ impl Pallet { Self::validate_assets_and_find_reserve(&assets, &dest)? }; - // local and remote XCM programs to potentially prefund fees - let prefund_fees_instructions: Option<(Xcm<::RuntimeCall>, Xcm<()>)>; + // local and remote XCM programs to potentially handle fees separately + let separate_fees_instructions: Option<(Xcm<::RuntimeCall>, Xcm<()>)>; if fees_transfer_type == assets_transfer_type { // Same reserve location (fees not teleportable), we can batch together fees and assets // in same reserve-based-transfer. assets.push(fees.clone()); - // no need for custom prefund instructions, fees are batched with assets - prefund_fees_instructions = None; + // no need for custom fees instructions, fees are batched with assets + separate_fees_instructions = None; } 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 @@ -1293,21 +1293,21 @@ impl Pallet { !matches!(assets_transfer_type, TransferType::RemoteReserve(_)), Error::::InvalidAssetUnsupportedReserve ); + let fees = fees.clone(); + let weight_limit = weight_limit.clone(); // build fees transfer instructions to be added to assets transfers XCM programs - prefund_fees_instructions = Some(match fees_transfer_type { + separate_fees_instructions = Some(match fees_transfer_type { TransferType::LocalReserve => - Self::prefund_local_reserve_fees_instructions(dest, fees.clone())?, + Self::local_reserve_fees_instructions(dest, fees, weight_limit)?, TransferType::DestinationReserve => - Self::prefund_destination_reserve_fees_instructions(dest, fees.clone())?, + Self::destination_reserve_fees_instructions(dest, fees, weight_limit)?, TransferType::Teleport => - Self::prefund_teleport_fees_instructions(dest, fees.clone())?, + Self::teleport_fees_instructions(dest, fees, weight_limit)?, TransferType::RemoteReserve(_) => return Err(Error::::InvalidAssetUnsupportedReserve.into()), }); }; - // Fees have been prefunded/transferred (or batched together with assets to be transferred - // here), now do reserve-transfer assets. Self::build_and_execute_xcm_transfer_type( origin_location, dest, @@ -1315,7 +1315,7 @@ impl Pallet { assets, assets_transfer_type, fees, - prefund_fees_instructions, + separate_fees_instructions, weight_limit, ) } @@ -1364,14 +1364,14 @@ impl Pallet { assets: Vec, transfer_type: TransferType, fees: MultiAsset, - prefund_fees_instructions: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, + separate_fees_instructions: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, weight_limit: WeightLimit, ) -> DispatchResult { log::trace!( target: "xcm::pallet_xcm::build_and_execute_xcm_transfer_type", "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, transfer_type {:?}, \ - fees {:?}, prefund_xcm: {:?}, weight_limit: {:?}", - origin, dest, beneficiary, assets, transfer_type, fees, prefund_fees_instructions, weight_limit, + fees {:?}, fees_xcm: {:?}, weight_limit: {:?}", + origin, dest, beneficiary, assets, transfer_type, fees, separate_fees_instructions, weight_limit, ); let (mut local_xcm, remote_xcm) = match transfer_type { TransferType::LocalReserve => { @@ -1380,7 +1380,7 @@ impl Pallet { beneficiary, assets, fees, - prefund_fees_instructions, + separate_fees_instructions, weight_limit, )?; (local, Some(remote)) @@ -1391,7 +1391,7 @@ impl Pallet { beneficiary, assets, fees, - prefund_fees_instructions, + separate_fees_instructions, weight_limit, )?; (local, Some(remote)) @@ -1434,9 +1434,10 @@ impl Pallet { Ok(()) } - fn prefund_local_reserve_fees_instructions( + fn local_reserve_fees_instructions( dest: MultiLocation, fees: MultiAsset, + weight_limit: WeightLimit, ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { let context = T::UniversalLocation::get(); let reanchored_fees = fees @@ -1450,7 +1451,9 @@ impl Pallet { ]); let xcm_on_dest = Xcm(vec![ // let (dest) chain know `fees` are in its SA on reserve - ReserveAssetDeposited(reanchored_fees.into()), + ReserveAssetDeposited(reanchored_fees.clone().into()), + // buy exec using `fees` in holding deposited in above instruction + BuyExecution { fees: reanchored_fees, weight_limit }, ]); Ok((local_execute_xcm, xcm_on_dest)) } @@ -1460,58 +1463,57 @@ impl Pallet { beneficiary: MultiLocation, assets: Vec, fees: MultiAsset, - prefund_fees_instructions: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, + separate_fees_instructions: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, weight_limit: WeightLimit, ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { - // max assets is `assets` ( + potentially separately handled fee) + // max assets is `assets` (+ potentially separately handled fee) let max_assets = - assets.len() as u32 + prefund_fees_instructions.as_ref().map(|_| 1).unwrap_or(0); + assets.len() as u32 + separate_fees_instructions.as_ref().map(|_| 1).unwrap_or(0); let assets: MultiAssets = assets.into(); let context = T::UniversalLocation::get(); - let reanchored_fees = - fees.reanchored(&dest, context).map_err(|_| Error::::CannotReanchor)?; let mut reanchored_assets = assets.clone(); reanchored_assets .reanchor(&dest, context) .map_err(|_| Error::::CannotReanchor)?; - let (prefund_local_xcm, prefund_remote_xcm) = prefund_fees_instructions + // fees are either handled through dedicated instructions, or batched together with assets + let fees_already_handled = separate_fees_instructions.is_some(); + let (fees_local_xcm, fees_remote_xcm) = separate_fees_instructions .map(|(local, remote)| (local.into_inner(), remote.into_inner())) .unwrap_or_default(); - let local_execute_xcm = Xcm( - // run any necessary local prefund fees instructions - prefund_local_xcm - .into_iter() - // move `assets` to `dest`s local sovereign account - .chain([TransferAsset { assets, beneficiary: dest }].into_iter()) - .collect(), - ); - let xcm_on_dest = Xcm( - // run any necessary remote prefund fees instructions - prefund_remote_xcm - .into_iter() - .chain( - [ - // let (dest) chain know assets are in its SA on reserve - ReserveAssetDeposited(reanchored_assets), - // following instructions are not exec'ed on behalf of origin chain anymore - ClearOrigin, - // buy exec using `fees` in holding deposited in top instruction here - BuyExecution { fees: reanchored_fees, weight_limit }, - // deposit all assets in holding to `beneficiary` location - DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, - ] - .into_iter(), - ) - .collect(), - ); - Ok((local_execute_xcm, xcm_on_dest)) + // start off with any necessary local fees specific instructions + let mut local_execute_xcm = fees_local_xcm; + // move `assets` to `dest`s local sovereign account + local_execute_xcm.push(TransferAsset { assets, beneficiary: dest }); + + // on destination chain, start off with custom fee instructions + let mut xcm_on_dest = fees_remote_xcm; + // continue with rest of assets + xcm_on_dest.extend_from_slice(&[ + // let (dest) chain know assets are in its SA on reserve + ReserveAssetDeposited(reanchored_assets), + // following instructions are not exec'ed on behalf of origin chain anymore + ClearOrigin, + ]); + if !fees_already_handled { + // no custom fees instructions, they are batched together with `assets` transfer; + // BuyExecution happens after receiving all `assets` + let reanchored_fees = + fees.reanchored(&dest, context).map_err(|_| Error::::CannotReanchor)?; + // buy execution using `fees` batched together with above `reanchored_assets` + xcm_on_dest.push(BuyExecution { fees: reanchored_fees, weight_limit }); + } + // deposit all remaining assets in holding to `beneficiary` location + xcm_on_dest.push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }); + + Ok((Xcm(local_execute_xcm), Xcm(xcm_on_dest))) } - fn prefund_destination_reserve_fees_instructions( + fn destination_reserve_fees_instructions( dest: MultiLocation, fees: MultiAsset, + weight_limit: WeightLimit, ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { let context = T::UniversalLocation::get(); let reanchored_fees = fees @@ -1528,7 +1530,9 @@ impl Pallet { ]); let xcm_on_dest = Xcm(vec![ // withdraw `fees` from origin chain's sovereign account - WithdrawAsset(reanchored_fees.into()), + WithdrawAsset(reanchored_fees.clone().into()), + // buy exec using `fees` in holding withdrawn in above instruction + BuyExecution { fees: reanchored_fees, weight_limit }, ]); Ok((local_execute_xcm, xcm_on_dest)) } @@ -1538,62 +1542,56 @@ impl Pallet { beneficiary: MultiLocation, assets: Vec, fees: MultiAsset, - prefund_fees_instructions: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, + separate_fees_instructions: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, weight_limit: WeightLimit, ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { - // max assets is `assets` ( + potentially separately handled fee) + // max assets is `assets` (+ potentially separately handled fee) let max_assets = - assets.len() as u32 + prefund_fees_instructions.as_ref().map(|_| 1).unwrap_or(0); + assets.len() as u32 + separate_fees_instructions.as_ref().map(|_| 1).unwrap_or(0); let assets: MultiAssets = assets.into(); let context = T::UniversalLocation::get(); - let reanchored_fees = - fees.reanchored(&dest, context).map_err(|_| Error::::CannotReanchor)?; let mut reanchored_assets = assets.clone(); reanchored_assets .reanchor(&dest, context) .map_err(|_| Error::::CannotReanchor)?; - let (prefund_local_xcm, prefund_remote_xcm) = prefund_fees_instructions + // fees are either handled through dedicated instructions, or batched together with assets + let fees_already_handled = separate_fees_instructions.is_some(); + let (fees_local_xcm, fees_remote_xcm) = separate_fees_instructions .map(|(local, remote)| (local.into_inner(), remote.into_inner())) - // default is empty vec, so no prefund instructions required .unwrap_or_default(); - let local_execute_xcm = Xcm( - // run any necessary local prefund fees instructions - prefund_local_xcm - .into_iter() - // move `assets` to `dest`s local sovereign account - .chain( - [ - // withdraw reserve-based assets - WithdrawAsset(assets.clone()), - // burn reserve-based assets - BurnAsset(assets), - ] - .into_iter(), - ) - .collect(), - ); - let xcm_on_dest = Xcm( - // run any necessary remote prefund fees instructions - prefund_remote_xcm - .into_iter() - .chain( - [ - // withdraw `assets` from origin chain's sovereign account - WithdrawAsset(reanchored_assets), - // following instructions are not exec'ed on behalf of origin chain anymore - ClearOrigin, - // buy exec using `fees` in holding deposited in top instruction here - BuyExecution { fees: reanchored_fees, weight_limit }, - // deposit all assets in holding to `beneficiary` account(s) - DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, - ] - .into_iter(), - ) - .collect(), - ); - Ok((local_execute_xcm, xcm_on_dest)) + // start off with any necessary local fees specific instructions + let mut local_execute_xcm = fees_local_xcm; + // continue with rest of assets + local_execute_xcm.extend_from_slice(&[ + // withdraw reserve-based assets + WithdrawAsset(assets.clone()), + // burn reserve-based assets + BurnAsset(assets), + ]); + + // on destination chain, start off with custom fee instructions + let mut xcm_on_dest = fees_remote_xcm; + // continue with rest of assets + xcm_on_dest.extend_from_slice(&[ + // withdraw `assets` from origin chain's sovereign account + WithdrawAsset(reanchored_assets), + // following instructions are not exec'ed on behalf of origin chain anymore + ClearOrigin, + ]); + if !fees_already_handled { + // no custom fees instructions, they are batched together with `assets` transfer; + // BuyExecution happens after receiving all `assets` + let reanchored_fees = + fees.reanchored(&dest, context).map_err(|_| Error::::CannotReanchor)?; + // buy execution using `fees` batched together with above `reanchored_assets` + xcm_on_dest.push(BuyExecution { fees: reanchored_fees, weight_limit }); + } + // deposit all remaining assets in holding to `beneficiary` location + xcm_on_dest.push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }); + + Ok((Xcm(local_execute_xcm), Xcm(xcm_on_dest))) } // function assumes fees and assets have the same remote reserve @@ -1642,9 +1640,10 @@ impl Pallet { ])) } - fn prefund_teleport_fees_instructions( + fn teleport_fees_instructions( dest: MultiLocation, fees: MultiAsset, + weight_limit: WeightLimit, ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { let context = T::UniversalLocation::get(); let reanchored_fees = fees @@ -1680,7 +1679,9 @@ impl Pallet { ]); let xcm_on_dest = Xcm(vec![ // (dest) chain receive teleported assets burned on origin chain - ReceiveTeleportedAsset(reanchored_fees.into()), + ReceiveTeleportedAsset(reanchored_fees.clone().into()), + // buy exec using `fees` in holding received in above instruction + BuyExecution { fees: reanchored_fees, weight_limit }, ]); Ok((local_execute_xcm, xcm_on_dest)) } diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index 36a041180d92..3f93de148fd9 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -420,9 +420,9 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ // local chain; `assets` are burned on source and withdrawn from SA here Xcm(vec![ ReserveAssetDeposited((Parent, FEE_AMOUNT).into()), + buy_limited_execution(expected_fee, Unlimited), WithdrawAsset(expected_asset.into()), ClearOrigin, - buy_limited_execution(expected_fee, Unlimited), DepositAsset { assets: AllCounted(2).into(), beneficiary }, ]) )] @@ -606,11 +606,11 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ // fees are being sent through destination-reserve transfer because fee reserve // is destination chain WithdrawAsset(expected_fee.clone().into()), + buy_limited_execution(expected_fee, Unlimited), // transfer is through local-reserve transfer because `assets` (native asset) // have local reserve ReserveAssetDeposited(expected_asset.into()), ClearOrigin, - buy_limited_execution(expected_fee, Unlimited), DepositAsset { assets: AllCounted(2).into(), beneficiary }, ]) )] @@ -1140,11 +1140,11 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { Xcm(vec![ // fees are teleported to destination chain ReceiveTeleportedAsset(expected_fee.clone().into()), + buy_limited_execution(expected_fee, Unlimited), // transfer is through local-reserve transfer because `assets` (native // asset) have local reserve ReserveAssetDeposited(expected_asset.into()), ClearOrigin, - buy_limited_execution(expected_fee, Unlimited), DepositAsset { assets: AllCounted(2).into(), beneficiary }, ]) )] @@ -1271,10 +1271,10 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_wor Xcm(vec![ // fees are teleported to destination chain ReceiveTeleportedAsset(expected_fee.clone().into()), + buy_limited_execution(expected_fee, Unlimited), // assets are withdrawn from origin's local SA WithdrawAsset(expected_asset.into()), ClearOrigin, - buy_limited_execution(expected_fee, Unlimited), DepositAsset { assets: AllCounted(2).into(), beneficiary }, ]) )] diff --git a/polkadot/xcm/xcm-builder/src/barriers.rs b/polkadot/xcm/xcm-builder/src/barriers.rs index 9ef915fd6560..c2b62751c688 100644 --- a/polkadot/xcm/xcm-builder/src/barriers.rs +++ b/polkadot/xcm/xcm-builder/src/barriers.rs @@ -74,50 +74,37 @@ impl> ShouldExecute for AllowTopLevelPaidExecutionFro ); ensure!(T::contains(origin), ProcessMessageError::Unsupported); - let mut assets_in_holding = 0; // We will read up to 5 instructions. This allows up to 3 `ClearOrigin` instructions. We // allow for more than one since anything beyond the first is a no-op and it's conceivable // that composition of operations might result in more than one being appended. - let end = instructions.len().min(6); + let end = instructions.len().min(5); instructions[..end] .matcher() - // ensure there is at least one instruction loading funds in holding register - .match_next_inst_while( - |_| true, - |inst| match inst { - ReceiveTeleportedAsset(ref assets) | - ReserveAssetDeposited(ref assets) | - WithdrawAsset(ref assets) | - ClaimAsset { ref assets, .. } => { - assets_in_holding += assets.len(); - Ok(ControlFlow::Continue(())) - }, - _ => Ok(ControlFlow::Break(())), - }, - )? - // skip `ClearOrigin` instructions - .skip_inst_while(|inst| matches!(inst, ClearOrigin))? - // ensure required weight is bought using funds prepared above - .match_next_inst(|inst| { - // ensure there were `0 < assets <= MAX_ASSETS_FOR_BUY_EXECUTION` added to holding - // for BuyExecution - ensure!( - assets_in_holding > 0 && assets_in_holding <= MAX_ASSETS_FOR_BUY_EXECUTION, - ProcessMessageError::BadFormat - ); - match inst { - BuyExecution { weight_limit: Limited(ref mut weight), .. } - if weight.all_gte(max_weight) => - { - *weight = max_weight; - Ok(()) - }, - BuyExecution { ref mut weight_limit, .. } if weight_limit == &Unlimited => { - *weight_limit = Limited(max_weight); + .match_next_inst(|inst| match inst { + ReceiveTeleportedAsset(ref assets) | + ReserveAssetDeposited(ref assets) | + WithdrawAsset(ref assets) | + ClaimAsset { ref assets, .. } => + if assets.len() <= MAX_ASSETS_FOR_BUY_EXECUTION { Ok(()) + } else { + Err(ProcessMessageError::BadFormat) }, - _ => Err(ProcessMessageError::Overweight(max_weight)), - } + _ => Err(ProcessMessageError::BadFormat), + })? + .skip_inst_while(|inst| matches!(inst, ClearOrigin))? + .match_next_inst(|inst| match inst { + BuyExecution { weight_limit: Limited(ref mut weight), .. } + if weight.all_gte(max_weight) => + { + *weight = max_weight; + Ok(()) + }, + BuyExecution { ref mut weight_limit, .. } if weight_limit == &Unlimited => { + *weight_limit = Limited(max_weight); + Ok(()) + }, + _ => Err(ProcessMessageError::Overweight(max_weight)), })?; Ok(()) } From 7f78c73b52bb9e7f5fecc125e5fcf54171a6b42a Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 8 Nov 2023 15:29:16 +0200 Subject: [PATCH 95/98] pallet-xcm: fix lossy fees math --- polkadot/xcm/pallet-xcm/src/lib.rs | 27 +++++++++++++------ .../pallet-xcm/src/tests/assets_transfer.rs | 11 +++----- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 0804a3783dc0..ca71c4ede56f 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1600,24 +1600,21 @@ impl Pallet { dest: MultiLocation, beneficiary: MultiLocation, assets: Vec, - mut fees: MultiAsset, + fees: MultiAsset, weight_limit: WeightLimit, ) -> Result::RuntimeCall>, Error> { let max_assets = assets.len() as u32; let context = T::UniversalLocation::get(); // we spend up to half of fees for execution on reserve and other half for execution on // destination - match &mut fees.fun { - Fungible(amount) => *amount = amount.saturating_div(2), - NonFungible(_) => return Err(Error::::FeesNotMet), - }; + let (fees_half_1, fees_half_2) = Self::halve_fees(fees)?; // identifies fee item as seen by `reserve` - to be used at reserve chain - let reserve_fees = fees - .clone() + let reserve_fees = fees_half_1 .reanchored(&reserve, context) .map_err(|_| Error::::CannotReanchor)?; // identifies fee item as seen by `dest` - to be used at destination chain - let dest_fees = fees.reanchored(&dest, context).map_err(|_| Error::::CannotReanchor)?; + let dest_fees = + fees_half_2.reanchored(&dest, context).map_err(|_| Error::::CannotReanchor)?; // identifies `dest` as seen by `reserve` let dest = dest.reanchored(&reserve, context).map_err(|_| Error::::CannotReanchor)?; // xcm to be executed at dest @@ -1707,6 +1704,20 @@ impl Pallet { ])) } + /// Halve `fees` fungible amount. + pub(crate) fn halve_fees(fees: MultiAsset) -> Result<(MultiAsset, MultiAsset), Error> { + match fees.fun { + Fungible(amount) => { + let fee1 = amount.saturating_div(2); + let fee2 = amount.saturating_sub(fee1); + ensure!(fee1 > 0, Error::::FeesNotMet); + ensure!(fee2 > 0, Error::::FeesNotMet); + Ok((MultiAsset::from((fees.id, fee1)), MultiAsset::from((fees.id, fee2)))) + }, + NonFungible(_) => Err(Error::::FeesNotMet), + } + } + /// Will always make progress, and will do its best not to use much more than `weight_cutoff` /// in doing so. pub(crate) fn check_xcm_version_change( diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index 3f93de148fd9..b02b0fd33c32 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -977,15 +977,12 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work // reanchor according to test-case let context = UniversalLocation::get(); let expected_dest_on_reserve = dest.reanchored(&usdc_chain, context).unwrap(); - let mut fees = assets.get(fee_index).unwrap().clone(); - match &mut fees.fun { - Fungible(amount) => *amount = amount.saturating_div(2), - NonFungible(_) => unreachable!(), - }; + let fees = assets.get(fee_index).unwrap().clone(); + let (fees_half_1, fees_half_2) = XcmPallet::halve_fees(fees).unwrap(); let mut expected_assets_on_reserve = assets.clone(); expected_assets_on_reserve.reanchor(&usdc_chain, context).unwrap(); - let expected_fee_on_reserve = fees.clone().reanchored(&usdc_chain, context).unwrap(); - let expected_fee_on_dest = fees.clone().reanchored(&dest, context).unwrap(); + let expected_fee_on_reserve = fees_half_1.reanchored(&usdc_chain, context).unwrap(); + let expected_fee_on_dest = fees_half_2.reanchored(&dest, context).unwrap(); // balances checks before assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); From cb8226d1d63ebc427f9501256cfde015e72ab772 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 8 Nov 2023 15:38:13 +0200 Subject: [PATCH 96/98] fix merge damage --- cumulus/parachains/integration-tests/emulated/common/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index b933cd8fb48a..e14e7ff20707 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -344,7 +344,7 @@ impl_assert_events_helpers_for_parachain!(PenpalWestendA, true); // BridgeHubWestend implementation impl_accounts_helpers_for_parachain!(BridgeHubWestend); -impl_assert_events_helpers_for_parachain!(BridgeHubWestend); +impl_assert_events_helpers_for_parachain!(BridgeHubWestend, false); // BridgeHubRococo implementation impl_accounts_helpers_for_parachain!(BridgeHubRococo); From c5522e451ae1215a87c2a8736ba00a3314630b83 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 8 Nov 2023 19:31:09 +0200 Subject: [PATCH 97/98] fix merge damage --- Cargo.lock | 6 +- .../assets/asset-hub-rococo/src/lib.rs | 6 +- .../assets/asset-hub-westend/src/lib.rs | 6 +- .../assets/asset-hub-wococo/src/lib.rs | 6 +- .../bridges/bridge-hub-rococo/src/lib.rs | 2 +- .../bridges/bridge-hub-westend/src/lib.rs | 2 +- .../bridges/bridge-hub-wococo/src/lib.rs | 2 +- .../parachains/testing/penpal/Cargo.toml | 1 + .../parachains/testing/penpal/src/lib.rs | 12 ++- .../emulated/chains/relays/westend/src/lib.rs | 2 +- .../emulated/common/src/impls.rs | 2 +- .../tests/assets/asset-hub-rococo/Cargo.toml | 4 +- .../src/tests/reserve_transfer.rs | 76 +++++++++---------- .../src/tests/reserve_transfer.rs | 6 +- 14 files changed, 69 insertions(+), 64 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index baa6de10acc6..d7ad930a6143 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -896,6 +896,7 @@ dependencies = [ "assert_matches", "asset-hub-rococo-runtime", "asset-test-utils", + "emulated-integration-tests-common", "frame-support", "pallet-asset-conversion", "pallet-assets", @@ -904,9 +905,7 @@ dependencies = [ "pallet-xcm", "parachains-common", "parity-scale-codec", - "polkadot-core-primitives", - "polkadot-parachain-primitives", - "polkadot-runtime-parachains", + "penpal-runtime", "rococo-runtime", "rococo-system-emulated-network", "sp-runtime", @@ -11609,6 +11608,7 @@ dependencies = [ "frame-support", "parachains-common", "penpal-runtime", + "rococo-emulated-chain", "serde_json", "sp-core", "sp-runtime", diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs index 0580d61eae9b..f94c4c3d2558 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs @@ -21,7 +21,7 @@ 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_system_parachain, xcm_emulator::decl_test_parachains, + impl_assets_helpers_for_parachain, xcm_emulator::decl_test_parachains, }; use rococo_emulated_chain::Rococo; @@ -51,5 +51,5 @@ decl_test_parachains! { // AssetHubRococo implementation impl_accounts_helpers_for_parachain!(AssetHubRococo); -impl_assert_events_helpers_for_parachain!(AssetHubRococo); -impl_assets_helpers_for_system_parachain!(AssetHubRococo, Rococo); +impl_assert_events_helpers_for_parachain!(AssetHubRococo, false); +impl_assets_helpers_for_parachain!(AssetHubRococo, Rococo); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs index 804b727c33f8..73d777247a5f 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs @@ -21,7 +21,7 @@ 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_system_parachain, xcm_emulator::decl_test_parachains, + impl_assets_helpers_for_parachain, xcm_emulator::decl_test_parachains, }; use westend_emulated_chain::Westend; @@ -51,5 +51,5 @@ decl_test_parachains! { // AssetHubWestend implementation impl_accounts_helpers_for_parachain!(AssetHubWestend); -impl_assert_events_helpers_for_parachain!(AssetHubWestend); -impl_assets_helpers_for_system_parachain!(AssetHubWestend, Westend); +impl_assert_events_helpers_for_parachain!(AssetHubWestend, false); +impl_assets_helpers_for_parachain!(AssetHubWestend, Westend); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/src/lib.rs index 677ca1763cfd..38a6ece3472e 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-wococo/src/lib.rs @@ -19,7 +19,7 @@ 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_system_parachain, xcm_emulator::decl_test_parachains, + impl_assets_helpers_for_parachain, xcm_emulator::decl_test_parachains, }; use wococo_emulated_chain::Wococo; @@ -49,5 +49,5 @@ decl_test_parachains! { // AssetHubWococo implementation impl_accounts_helpers_for_parachain!(AssetHubWococo); -impl_assert_events_helpers_for_parachain!(AssetHubWococo); -impl_assets_helpers_for_system_parachain!(AssetHubWococo, Wococo); +impl_assert_events_helpers_for_parachain!(AssetHubWococo, false); +impl_assets_helpers_for_parachain!(AssetHubWococo, Wococo); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs index d7630954c868..f4557021f62b 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs @@ -46,4 +46,4 @@ decl_test_parachains! { // BridgeHubRococo implementation impl_accounts_helpers_for_parachain!(BridgeHubRococo); -impl_assert_events_helpers_for_parachain!(BridgeHubRococo); +impl_assert_events_helpers_for_parachain!(BridgeHubRococo, false); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs index 436b65cb916b..1f1126d4565f 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs @@ -46,4 +46,4 @@ decl_test_parachains! { // BridgeHubWestend implementation impl_accounts_helpers_for_parachain!(BridgeHubWestend); -impl_assert_events_helpers_for_parachain!(BridgeHubWestend); +impl_assert_events_helpers_for_parachain!(BridgeHubWestend, false); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/src/lib.rs index 6807a2ab8c80..e643f104aa31 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-wococo/src/lib.rs @@ -44,4 +44,4 @@ decl_test_parachains! { // BridgeHubWococo implementation impl_accounts_helpers_for_parachain!(BridgeHubWococo); -impl_assert_events_helpers_for_parachain!(BridgeHubWococo); +impl_assert_events_helpers_for_parachain!(BridgeHubWococo, false); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml index 42aaee3f1020..c55b10d7180c 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml @@ -22,3 +22,4 @@ parachains-common = { path = "../../../../../../../parachains/common" } cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } emulated-integration-tests-common = { path = "../../../../common", default-features = false } penpal-runtime = { path = "../../../../../../runtimes/testing/penpal" } +rococo-emulated-chain = { path = "../../../relays/rococo" } 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 8709d4e91969..537f96f45b47 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 @@ -21,8 +21,10 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ - impl_assert_events_helpers_for_parachain, xcm_emulator::decl_test_parachains, + impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, + impl_assets_helpers_for_parachain, xcm_emulator::decl_test_parachains, }; +use rococo_emulated_chain::Rococo; // Penpal Parachain declaration decl_test_parachains! { @@ -40,6 +42,7 @@ decl_test_parachains! { pallets = { PolkadotXcm: penpal_runtime::PolkadotXcm, Assets: penpal_runtime::Assets, + Balances: penpal_runtime::Balances, } }, pub struct PenpalB { @@ -56,10 +59,13 @@ decl_test_parachains! { pallets = { PolkadotXcm: penpal_runtime::PolkadotXcm, Assets: penpal_runtime::Assets, + Balances: penpal_runtime::Balances, } }, } // Penpal implementation -impl_assert_events_helpers_for_parachain!(PenpalA); -impl_assert_events_helpers_for_parachain!(PenpalB); +impl_accounts_helpers_for_parachain!(PenpalA); +impl_assets_helpers_for_parachain!(PenpalA, Rococo); +impl_assert_events_helpers_for_parachain!(PenpalA, true); +impl_assert_events_helpers_for_parachain!(PenpalB, true); diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs index af45d8db4e62..d4ba1b6cfe72 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs @@ -30,7 +30,7 @@ decl_test_relay_chains! { on_init = (), runtime = westend_runtime, core = { - SovereignAccountOf: westend_runtime::xcm_config::LocationConverter, //TODO: rename to SovereignAccountOf, + SovereignAccountOf: westend_runtime::xcm_config::LocationConverter, }, pallets = { XcmPallet: westend_runtime::XcmPallet, diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index d37179b51a1d..82f27b932008 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -556,7 +556,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { } #[macro_export] -macro_rules! impl_assets_helpers_for_system_parachain { +macro_rules! impl_assets_helpers_for_parachain { ( $chain:ident, $relay_chain:ident ) => { $crate::impls::paste::paste! { impl $chain { diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml index 6e592f04ba1e..23f80f33f78e 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml @@ -17,6 +17,7 @@ frame-support = { path = "../../../../../../../substrate/frame/support", default pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false} pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false} pallet-asset-conversion = { path = "../../../../../../../substrate/frame/asset-conversion", default-features = false} +pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue", default-features = false } # Polkadot xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false} @@ -28,5 +29,6 @@ rococo-runtime = { path = "../../../../../../../polkadot/runtime/rococo" } asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } parachains-common = { path = "../../../../../../parachains/common" } asset-hub-rococo-runtime = { path = "../../../../../runtimes/assets/asset-hub-rococo" } -emulated-integration-tests-common = { path = "../../../common", default-features = false} +emulated-integration-tests-common = { path = "../../../common", default-features = false } +penpal-runtime = { path = "../../../../../runtimes/testing/penpal" } rococo-system-emulated-network ={ path = "../../../networks/rococo-system" } 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 caff1fc2c474..d0e9b72176bc 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 @@ -41,9 +41,9 @@ fn relay_to_para_sender_assertions(t: RelayToParaTest) { } fn relay_to_para_receiver_assertions(_: Test) { - type RuntimeEvent = ::RuntimeEvent; + type RuntimeEvent = ::RuntimeEvent; assert_expected_events!( - PenpalRococoA, + PenpalA, vec![ RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, RuntimeEvent::MessageQueue( @@ -79,9 +79,9 @@ fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { } fn system_para_to_para_receiver_assertions(_: Test) { - type RuntimeEvent = ::RuntimeEvent; + type RuntimeEvent = ::RuntimeEvent; assert_expected_events!( - PenpalRococoA, + PenpalA, vec![ RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, RuntimeEvent::MessageQueue( @@ -92,15 +92,12 @@ fn system_para_to_para_receiver_assertions(_: Test) { } fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; + type RuntimeEvent = ::RuntimeEvent; - PenpalRococoA::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 864_610_000, - 8_799, - ))); + PenpalA::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799))); assert_expected_events!( - PenpalRococoA, + PenpalA, vec![ // Amount to reserve transfer is transferred to Parachain's Sovereign account RuntimeEvent::Balances( @@ -117,7 +114,7 @@ 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(PenpalRococoA::para_id()), + AssetHubRococo::sibling_location_of(PenpalA::para_id()), ); assert_expected_events!( @@ -165,9 +162,9 @@ fn system_para_to_para_assets_sender_assertions(t: SystemParaToParaTest) { } fn system_para_to_para_assets_receiver_assertions(_: Test) { - type RuntimeEvent = ::RuntimeEvent; + type RuntimeEvent = ::RuntimeEvent; assert_expected_events!( - PenpalRococoA, + PenpalA, vec![ RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, RuntimeEvent::Assets(pallet_assets::Event::Issued { .. }) => {}, @@ -201,7 +198,7 @@ fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) } fn para_to_system_para_limited_reserve_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { - ::PolkadotXcm::limited_reserve_transfer_assets( + ::PolkadotXcm::limited_reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), bx!(t.args.beneficiary.into()), @@ -284,13 +281,13 @@ fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { #[test] fn reserve_transfer_native_asset_from_relay_to_para() { // Init values for Relay - let destination = Rococo::child_location_of(PenpalRococoA::para_id()); - let beneficiary_id = PenpalRococoAReceiver::get(); + let destination = Rococo::child_location_of(PenpalA::para_id()); + let beneficiary_id = PenpalAReceiver::get(); let amount_to_send: Balance = ROCOCO_ED * 1000; let test_args = TestContext { sender: RococoSender::get(), - receiver: PenpalRococoAReceiver::get(), + receiver: PenpalAReceiver::get(), args: relay_test_args(destination, beneficiary_id, amount_to_send), }; @@ -300,7 +297,7 @@ fn reserve_transfer_native_asset_from_relay_to_para() { let receiver_balance_before = test.receiver.balance; test.set_assertion::(relay_to_para_sender_assertions); - test.set_assertion::(relay_to_para_receiver_assertions); + test.set_assertion::(relay_to_para_receiver_assertions); test.set_dispatchable::(relay_to_para_limited_reserve_transfer_assets); test.assert(); @@ -340,7 +337,7 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { let receiver_balance_before = test.receiver.balance; test.set_assertion::(system_para_to_para_sender_assertions); - test.set_assertion::(system_para_to_para_receiver_assertions); + test.set_assertion::(system_para_to_para_receiver_assertions); test.set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); test.assert(); @@ -363,13 +360,13 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { #[test] fn reserve_transfer_native_asset_from_para_to_system_para() { // Init values for Penpal Parachain - let destination = PenpalRococoA::sibling_location_of(AssetHubRococo::para_id()); + let destination = PenpalA::sibling_location_of(AssetHubRococo::para_id()); let beneficiary_id = AssetHubRococoReceiver::get(); let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; let assets = (Parent, amount_to_send).into(); let test_args = TestContext { - sender: PenpalRococoASender::get(), + sender: PenpalASender::get(), receiver: AssetHubRococoReceiver::get(), args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0), }; @@ -379,22 +376,21 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { let sender_balance_before = test.sender.balance; let receiver_balance_before = test.receiver.balance; - let penpal_location_as_seen_by_ahr = - AssetHubRococo::sibling_location_of(PenpalRococoA::para_id()); + let penpal_location_as_seen_by_ahr = AssetHubRococo::sibling_location_of(PenpalA::para_id()); let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location_as_seen_by_ahr); // fund the Penpal's SA on AHR with the native tokens held in reserve AssetHubRococo::fund_accounts(vec![(sov_penpal_on_ahr.into(), amount_to_send * 2)]); - test.set_assertion::(para_to_system_para_sender_assertions); + test.set_assertion::(para_to_system_para_sender_assertions); test.set_assertion::(para_to_system_para_receiver_assertions); - test.set_dispatchable::(para_to_system_para_limited_reserve_transfer_assets); + test.set_dispatchable::(para_to_system_para_limited_reserve_transfer_assets); test.assert(); let sender_balance_after = test.sender.balance; let receiver_balance_after = test.receiver.balance; - let delivery_fees = PenpalRococoA::execute_with(|| { + 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) @@ -410,7 +406,7 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { /// work #[test] fn reserve_transfer_assets_from_system_para_to_para() { - // Force create asset on AssetHubRococo and PenpalRococoA from Relay Chain + // Force create asset on AssetHubRococo and PenpalA from Relay Chain AssetHubRococo::force_create_and_mint_asset( ASSET_ID, ASSET_MIN_BALANCE, @@ -419,18 +415,18 @@ fn reserve_transfer_assets_from_system_para_to_para() { Some(Weight::from_parts(1_019_445_000, 200_000)), ASSET_MIN_BALANCE * 1_000_000, ); - PenpalRococoA::force_create_and_mint_asset( + PenpalA::force_create_and_mint_asset( ASSET_ID, ASSET_MIN_BALANCE, false, - PenpalRococoASender::get(), + PenpalASender::get(), Some(Weight::from_parts(1_019_445_000, 200_000)), 0, ); // Init values for System Parachain - let destination = AssetHubRococo::sibling_location_of(PenpalRococoA::para_id()); - let beneficiary_id = PenpalRococoAReceiver::get(); + let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let beneficiary_id = PenpalAReceiver::get(); let fee_amount_to_send = ASSET_HUB_ROCOCO_ED * 1000; let asset_amount_to_send = ASSET_MIN_BALANCE * 1000; let assets: MultiAssets = vec![ @@ -447,7 +443,7 @@ fn reserve_transfer_assets_from_system_para_to_para() { let para_test_args = TestContext { sender: AssetHubRococoSender::get(), - receiver: PenpalRococoAReceiver::get(), + receiver: PenpalAReceiver::get(), args: para_test_args( destination, beneficiary_id, @@ -461,7 +457,7 @@ fn reserve_transfer_assets_from_system_para_to_para() { let mut test = SystemParaToParaTest::new(para_test_args); // Create SA-of-Penpal-on-AHR with ED. - let penpal_location = AssetHubRococo::sibling_location_of(PenpalRococoA::para_id()); + let penpal_location = AssetHubRococo::sibling_location_of(PenpalA::para_id()); let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location); AssetHubRococo::fund_accounts(vec![(sov_penpal_on_ahr.into(), ROCOCO_ED)]); @@ -472,13 +468,13 @@ fn reserve_transfer_assets_from_system_para_to_para() { type Assets = ::Assets; >::balance(ASSET_ID, &AssetHubRococoSender::get()) }); - let receiver_assets_before = PenpalRococoA::execute_with(|| { - type Assets = ::Assets; - >::balance(ASSET_ID, &PenpalRococoAReceiver::get()) + let receiver_assets_before = PenpalA::execute_with(|| { + type Assets = ::Assets; + >::balance(ASSET_ID, &PenpalAReceiver::get()) }); test.set_assertion::(system_para_to_para_assets_sender_assertions); - test.set_assertion::(system_para_to_para_assets_receiver_assertions); + test.set_assertion::(system_para_to_para_assets_receiver_assertions); test.set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); test.assert(); @@ -494,9 +490,9 @@ fn reserve_transfer_assets_from_system_para_to_para() { type Assets = ::Assets; >::balance(ASSET_ID, &AssetHubRococoSender::get()) }); - let receiver_assets_after = PenpalRococoA::execute_with(|| { - type Assets = ::Assets; - >::balance(ASSET_ID, &PenpalRococoAReceiver::get()) + let receiver_assets_after = PenpalA::execute_with(|| { + type Assets = ::Assets; + >::balance(ASSET_ID, &PenpalAReceiver::get()) }); // Sender's balance is reduced 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 db0e24c37883..5b2c648b7b08 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 @@ -42,9 +42,9 @@ fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { } fn para_receiver_assertions(_: Test) { - type RuntimeEvent = ::RuntimeEvent; + type RuntimeEvent = ::RuntimeEvent; assert_expected_events!( - PenpalWestendA, + PenpalA, vec![ RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, RuntimeEvent::MessageQueue( @@ -180,7 +180,7 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { let receiver_balance_before = test.receiver.balance; test.set_assertion::(system_para_to_para_sender_assertions); - test.set_assertion::(para_receiver_assertions); + test.set_assertion::(para_receiver_assertions); test.set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); test.assert(); From 0cc32e35e2d9844ac1c6c6c55ca27b279a601d73 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 13 Nov 2023 10:52:44 +0200 Subject: [PATCH 98/98] fix merge damage --- polkadot/xcm/pallet-xcm/src/benchmarking.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs index e334c3d78b97..3aca24791fc2 100644 --- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs @@ -274,14 +274,14 @@ benchmarks! { let timeout = 1u32.into(); let match_querier = MultiLocation::from(Here); }: { - Pallet::::new_query(responder, timeout, match_querier); + crate::Pallet::::new_query(responder, timeout, match_querier); } take_response { let responder = MultiLocation::from(Parent); let timeout = 1u32.into(); let match_querier = MultiLocation::from(Here); - let query_id = Pallet::::new_query(responder, timeout, match_querier); + let query_id = crate::Pallet::::new_query(responder, timeout, match_querier); let infos = (0 .. xcm::v3::MaxPalletsInfo::get()).map(|_| PalletInfo::new( u32::MAX, (0..xcm::v3::MaxPalletNameLen::get()).map(|_| 97u8).collect::>().try_into().unwrap(), @@ -290,10 +290,10 @@ benchmarks! { u32::MAX, u32::MAX, ).unwrap()).collect::>(); - Pallet::::expect_response(query_id, Response::PalletsInfo(infos.try_into().unwrap())); + crate::Pallet::::expect_response(query_id, Response::PalletsInfo(infos.try_into().unwrap())); }: { - as QueryHandler>::take_response(query_id); + as QueryHandler>::take_response(query_id); } impl_benchmark_test_suite!(