diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index f1a60c7ed34a6..d951520f926d5 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 17374814c19dc..7135b8b5fe79e 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,96 @@ 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 + .clone() + .pushed_with_interior(GeneralIndex(1234567)) + .unwrap(); + let foreign_asset_amount = 142; + + // transfer destination is reserve location + let dest = foreign_creator_location.clone(); + 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() * 3; + 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 +675,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 +684,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 +693,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 +702,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 +711,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 +720,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 +729,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