#![cfg(test)]
use crate::{
mock::*,
tests::{ALICE, BOB, FEE_AMOUNT, INITIAL_BALANCE, SEND_AMOUNT},
xcm_helpers::find_xcm_sent_message_id,
DispatchResult, OriginFor,
};
use pezframe_support::{
assert_err, assert_ok,
traits::{tokens::fungibles::Inspect, Currency},
weights::Weight,
};
use pezkuwi_teyrchain_primitives::primitives::Id as ParaId;
use pezsp_runtime::traits::AccountIdConversion;
use xcm::prelude::*;
use xcm_executor::traits::ConvertLocation;
#[test]
fn limited_teleport_assets_works() {
let origin_location: Location = AccountId32 { network: None, id: ALICE.into() }.into();
let expected_beneficiary: Location = AccountId32 { network: None, id: BOB.into() }.into();
let weight_limit = WeightLimit::Limited(Weight::from_parts(5000, 5000));
let expected_weight_limit = weight_limit.clone();
let balances = vec![
(ALICE, INITIAL_BALANCE),
(ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE),
];
let dest = RelayLocation::get().into();
new_test_ext_with_balances(balances).execute_with(|| {
let weight = BaseXcmWeight::get() * 2;
assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE);
assert_ok!(XcmPallet::limited_teleport_assets(
RuntimeOrigin::signed(ALICE),
Box::new(RelayLocation::get().into()),
Box::new(expected_beneficiary.clone().into()),
Box::new((Here, SEND_AMOUNT).into()),
Box::new(RelayLocation::get().into()),
weight_limit,
));
assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT);
assert_eq!(
sent_xcm(),
vec![(
dest,
Xcm(vec![
ReceiveTeleportedAsset((Here, SEND_AMOUNT).into()),
ClearOrigin,
buy_limited_execution((Here, SEND_AMOUNT), expected_weight_limit),
DepositAsset {
assets: AllCounted(1).into(),
beneficiary: expected_beneficiary
},
]),
)]
);
let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1);
let _check_v3_ok: xcm::v3::Xcm<()> = versioned_sent.try_into().unwrap();
let mut last_events = last_events(3).into_iter();
assert_eq!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::Attempted {
outcome: Outcome::Complete { used: weight }
})
);
assert_eq!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::FeesPaid {
paying: origin_location,
fees: Assets::new(),
})
);
assert!(matches!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::Sent { .. })
));
});
}
#[test]
fn limited_teleport_filtered_assets_disallowed() {
let beneficiary: Location = AccountId32 { network: None, id: BOB.into() }.into();
new_test_ext_with_balances(vec![(ALICE, INITIAL_BALANCE)]).execute_with(|| {
let result = XcmPallet::limited_teleport_assets(
RuntimeOrigin::signed(ALICE),
Box::new(FilteredTeleportLocation::get().into()),
Box::new(beneficiary.into()),
Box::new(FilteredTeleportAsset::get().into()),
Box::new(FilteredTeleportAsset::get().id.into()),
Unlimited,
);
let expected_result = Err(crate::Error::<Test>::Filtered.into());
assert_eq!(result, expected_result);
});
}
#[test]
fn reserve_transfer_assets_with_paid_router_works() {
let user_account = AccountId::from(XCM_FEES_NOT_WAIVED_USER_ACCOUNT);
let paid_para_id = Para3000::get();
let balances = vec![
(user_account.clone(), INITIAL_BALANCE),
(ParaId::from(paid_para_id).into_account_truncating(), INITIAL_BALANCE),
(XcmFeesTargetAccount::get(), INITIAL_BALANCE),
];
new_test_ext_with_balances(balances).execute_with(|| {
let xcm_router_fee_amount = Para3000PaymentAmount::get();
let weight = BaseXcmWeight::get();
let dest: Location =
Junction::AccountId32 { network: None, id: user_account.clone().into() }.into();
assert_eq!(Balances::total_balance(&user_account), INITIAL_BALANCE);
assert_ok!(XcmPallet::limited_reserve_transfer_assets(
RuntimeOrigin::signed(user_account.clone()),
Box::new(Teyrchain(paid_para_id).into()),
Box::new(dest.clone().into()),
Box::new((Here, SEND_AMOUNT).into()),
Box::new(Here.into()),
Unlimited,
));
assert_eq!(
Balances::free_balance(user_account),
INITIAL_BALANCE - SEND_AMOUNT - xcm_router_fee_amount
);
let para_acc: AccountId = ParaId::from(paid_para_id).into_account_truncating();
assert_eq!(Balances::free_balance(para_acc), INITIAL_BALANCE + SEND_AMOUNT);
assert_eq!(
Balances::free_balance(XcmFeesTargetAccount::get()),
INITIAL_BALANCE + xcm_router_fee_amount
);
let dest_para: Location = Teyrchain(paid_para_id).into();
assert_eq!(
sent_xcm(),
vec![(
dest_para,
Xcm(vec![
ReserveAssetDeposited((Parent, SEND_AMOUNT).into()),
ClearOrigin,
buy_execution((Parent, SEND_AMOUNT)),
DepositAsset { assets: AllCounted(1).into(), beneficiary: dest.clone() },
]),
)]
);
let mut last_events = last_events(5).into_iter();
assert_eq!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::Attempted {
outcome: Outcome::Complete { used: weight }
})
);
last_events.next().unwrap();
last_events.next().unwrap();
assert_eq!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::FeesPaid {
paying: dest,
fees: Para3000PaymentAssets::get(),
})
);
assert!(matches!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::Sent { .. })
));
});
}
pub(crate) fn set_up_foreign_asset(
reserve_para_id: u32,
inner_junction: Option<Junction>,
beneficiary: AccountId,
initial_amount: u128,
is_sufficient: bool,
) -> (Location, AccountId, Location) {
let reserve_location =
RelayLocation::get().pushed_with_interior(Teyrchain(reserve_para_id)).unwrap();
let reserve_sovereign_account =
SovereignAccountOf::convert_location(&reserve_location).unwrap();
let foreign_asset_id_location = if let Some(junction) = inner_junction {
reserve_location.clone().pushed_with_interior(junction).unwrap()
} else {
reserve_location.clone()
};
assert_ok!(AssetsPallet::force_create(
RuntimeOrigin::root(),
foreign_asset_id_location.clone(),
BOB,
is_sufficient,
1
));
assert_ok!(AssetsPallet::mint(
RuntimeOrigin::signed(BOB),
foreign_asset_id_location.clone(),
beneficiary,
initial_amount
));
(reserve_location, reserve_sovereign_account, foreign_asset_id_location)
}
pub(crate) fn into_assets_checked(
fee_asset: Asset,
transfer_asset: Asset,
) -> (Assets, Asset, Asset) {
let assets: Assets = vec![fee_asset.clone(), transfer_asset.clone()].into();
(assets, fee_asset, transfer_asset)
}
fn local_asset_reserve_and_local_fee_reserve_call<Call>(
tested_call: Call,
expected_result: DispatchResult,
) where
Call: FnOnce(
OriginFor<Test>,
Box<VersionedLocation>,
Box<VersionedLocation>,
Box<VersionedAssets>,
Box<VersionedAssetId>,
WeightLimit,
) -> DispatchResult,
{
let balances = vec![
(ALICE, INITIAL_BALANCE),
(ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE),
];
let origin_location: Location =
Junction::AccountId32 { network: None, id: ALICE.into() }.into();
let beneficiary: Location = 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.clone();
let dest: Location = Teyrchain(OTHER_PARA_ID).into();
new_test_ext_with_balances(balances).execute_with(|| {
let weight = BaseXcmWeight::get();
assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE);
let result = tested_call(
RuntimeOrigin::signed(ALICE),
Box::new(dest.clone().into()),
Box::new(beneficiary.clone().into()),
Box::new((Here, SEND_AMOUNT).into()),
Box::new(Here.into()),
weight_limit,
);
assert_eq!(result, expected_result);
if expected_result.is_err() {
return;
}
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT);
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![(
dest,
Xcm(vec![
ReserveAssetDeposited((Parent, SEND_AMOUNT).into()),
ClearOrigin,
buy_limited_execution((Parent, SEND_AMOUNT), expected_weight_limit),
DepositAsset {
assets: AllCounted(1).into(),
beneficiary: expected_beneficiary.clone()
},
]),
)]
);
let mut last_events = last_events(3).into_iter();
assert_eq!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::Attempted {
outcome: Outcome::Complete { used: weight }
})
);
assert_eq!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::FeesPaid {
paying: origin_location,
fees: Assets::new(),
})
);
assert!(matches!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::Sent { .. })
));
});
}
#[test]
fn transfer_assets_with_local_asset_reserve_and_local_fee_reserve_works() {
let expected_result = Ok(());
local_asset_reserve_and_local_fee_reserve_call(XcmPallet::transfer_assets, expected_result);
}
#[test]
fn reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserve_works() {
let expected_result = Ok(());
local_asset_reserve_and_local_fee_reserve_call(
XcmPallet::limited_reserve_transfer_assets,
expected_result,
);
}
#[test]
fn teleport_assets_with_local_asset_reserve_and_local_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::Filtered.into());
local_asset_reserve_and_local_fee_reserve_call(
XcmPallet::limited_teleport_assets,
expected_result,
);
}
fn destination_asset_reserve_and_local_fee_reserve_call<Call>(
tested_call: Call,
expected_result: DispatchResult,
) where
Call: FnOnce(
OriginFor<Test>,
Box<VersionedLocation>,
Box<VersionedLocation>,
Box<VersionedAssets>,
Box<VersionedAssetId>,
WeightLimit,
) -> DispatchResult,
{
let weight = BaseXcmWeight::get() * 3;
let balances = vec![(ALICE, INITIAL_BALANCE)];
let origin_location: Location =
Junction::AccountId32 { network: None, id: ALICE.into() }.into();
let beneficiary: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into();
new_test_ext_with_balances(balances).execute_with(|| {
let foreign_initial_amount = 142;
let (reserve_location, reserve_sovereign_account, foreign_asset_id_location) =
set_up_foreign_asset(
FOREIGN_ASSET_RESERVE_PARA_ID,
Some(FOREIGN_ASSET_INNER_JUNCTION),
ALICE,
foreign_initial_amount,
false,
);
let dest = reserve_location;
let (assets, fee_asset, xfer_asset) = into_assets_checked(
(Location::here(), FEE_AMOUNT).into(),
(foreign_asset_id_location.clone(), SEND_AMOUNT).into(),
);
let context = UniversalLocation::get();
let expected_fee = fee_asset.clone().reanchored(&dest, &context).unwrap();
let expected_asset = xfer_asset.reanchored(&dest, &context).unwrap();
assert_eq!(
AssetsPallet::balance(foreign_asset_id_location.clone(), ALICE),
foreign_initial_amount
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
let result = tested_call(
RuntimeOrigin::signed(ALICE),
Box::new(dest.clone().into()),
Box::new(beneficiary.clone().into()),
Box::new(assets.into()),
Box::new(fee_asset.id.into()),
Unlimited,
);
assert_eq!(result, expected_result);
if expected_result.is_err() {
return;
}
let mut last_events = last_events(3).into_iter();
assert_eq!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::Attempted {
outcome: Outcome::Complete { used: weight }
})
);
assert_eq!(
AssetsPallet::balance(foreign_asset_id_location.clone(), ALICE),
foreign_initial_amount - SEND_AMOUNT
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - FEE_AMOUNT);
assert_eq!(Balances::free_balance(reserve_sovereign_account.clone()), FEE_AMOUNT);
assert_eq!(
AssetsPallet::balance(foreign_asset_id_location.clone(), reserve_sovereign_account),
0
);
let expected_issuance = foreign_initial_amount - SEND_AMOUNT;
assert_eq!(
AssetsPallet::total_issuance(foreign_asset_id_location.clone()),
expected_issuance
);
assert_eq!(AssetsPallet::active_issuance(foreign_asset_id_location), expected_issuance);
assert_eq!(
sent_xcm(),
vec![(
dest,
Xcm(vec![
ReserveAssetDeposited((Parent, FEE_AMOUNT).into()),
buy_limited_execution(expected_fee, Unlimited),
WithdrawAsset(expected_asset.into()),
ClearOrigin,
DepositAsset { assets: AllCounted(2).into(), beneficiary: beneficiary.clone() },
])
)]
);
assert_eq!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::FeesPaid {
paying: origin_location,
fees: Assets::new(),
})
);
assert!(matches!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::Sent { .. })
));
});
}
#[test]
fn transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_works() {
let expected_result = Ok(());
destination_asset_reserve_and_local_fee_reserve_call(
XcmPallet::transfer_assets,
expected_result,
);
}
#[test]
fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::TooManyReserves.into());
destination_asset_reserve_and_local_fee_reserve_call(
XcmPallet::limited_reserve_transfer_assets,
expected_result,
);
}
#[test]
fn teleport_assets_with_destination_asset_reserve_and_local_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::Filtered.into());
destination_asset_reserve_and_local_fee_reserve_call(
XcmPallet::limited_teleport_assets,
expected_result,
);
}
fn remote_asset_reserve_and_local_fee_reserve_call_disallowed<Call>(
tested_call: Call,
expected_result: DispatchResult,
) where
Call: FnOnce(
OriginFor<Test>,
Box<VersionedLocation>,
Box<VersionedLocation>,
Box<VersionedAssets>,
Box<VersionedAssetId>,
WeightLimit,
) -> DispatchResult,
{
let balances = vec![(ALICE, INITIAL_BALANCE)];
let beneficiary: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into();
new_test_ext_with_balances(balances).execute_with(|| {
let foreign_initial_amount = 142;
let (_, _, foreign_asset_id_location) = set_up_foreign_asset(
FOREIGN_ASSET_RESERVE_PARA_ID,
Some(FOREIGN_ASSET_INNER_JUNCTION),
ALICE,
foreign_initial_amount,
false,
);
let dest = RelayLocation::get().pushed_with_interior(Teyrchain(OTHER_PARA_ID)).unwrap();
let (assets, fee_asset, _) = into_assets_checked(
(Location::here(), FEE_AMOUNT).into(),
(foreign_asset_id_location.clone(), SEND_AMOUNT).into(),
);
assert_eq!(
AssetsPallet::balance(foreign_asset_id_location.clone(), ALICE),
foreign_initial_amount
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
let result = tested_call(
RuntimeOrigin::signed(ALICE),
Box::new(dest.into()),
Box::new(beneficiary.into()),
Box::new(assets.into()),
Box::new(fee_asset.id.into()),
Unlimited,
);
assert_eq!(result, expected_result);
assert_eq!(
AssetsPallet::balance(foreign_asset_id_location.clone(), ALICE),
foreign_initial_amount
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
let expected_issuance = foreign_initial_amount;
assert_eq!(
AssetsPallet::total_issuance(foreign_asset_id_location.clone()),
expected_issuance
);
assert_eq!(AssetsPallet::active_issuance(foreign_asset_id_location), expected_issuance);
});
}
#[test]
fn transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::InvalidAssetUnsupportedReserve.into());
remote_asset_reserve_and_local_fee_reserve_call_disallowed(
XcmPallet::transfer_assets,
expected_result,
);
}
#[test]
fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::TooManyReserves.into());
remote_asset_reserve_and_local_fee_reserve_call_disallowed(
XcmPallet::limited_reserve_transfer_assets,
expected_result,
);
}
#[test]
fn teleport_assets_with_remote_asset_reserve_and_local_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::Filtered.into());
remote_asset_reserve_and_local_fee_reserve_call_disallowed(
XcmPallet::limited_teleport_assets,
expected_result,
);
}
fn local_asset_reserve_and_destination_fee_reserve_call<Call>(
tested_call: Call,
expected_result: DispatchResult,
) where
Call: FnOnce(
OriginFor<Test>,
Box<VersionedLocation>,
Box<VersionedLocation>,
Box<VersionedAssets>,
Box<VersionedAssetId>,
WeightLimit,
) -> DispatchResult,
{
let balances = vec![(ALICE, INITIAL_BALANCE)];
let origin_location: Location =
Junction::AccountId32 { network: None, id: ALICE.into() }.into();
let beneficiary: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into();
new_test_ext_with_balances(balances).execute_with(|| {
let usdc_initial_local_amount = 142;
let (usdc_reserve_location, usdc_chain_sovereign_account, usdc_id_location) =
set_up_foreign_asset(
USDC_RESERVE_PARA_ID,
Some(USDC_INNER_JUNCTION),
ALICE,
usdc_initial_local_amount,
true,
);
let dest = usdc_reserve_location;
let (assets, fee_asset, xfer_asset) = into_assets_checked(
(usdc_id_location.clone(), FEE_AMOUNT).into(),
(Location::here(), SEND_AMOUNT).into(),
);
let context = UniversalLocation::get();
let expected_fee = fee_asset.clone().reanchored(&dest, &context).unwrap();
let expected_asset = xfer_asset.reanchored(&dest, &context).unwrap();
assert_eq!(
AssetsPallet::balance(usdc_id_location.clone(), ALICE),
usdc_initial_local_amount
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
let result = tested_call(
RuntimeOrigin::signed(ALICE),
Box::new(dest.clone().into()),
Box::new(beneficiary.clone().into()),
Box::new(assets.into()),
Box::new(fee_asset.id.into()),
Unlimited,
);
assert_eq!(result, expected_result);
if expected_result.is_err() {
return;
}
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 { used: weight }
})
);
assert_eq!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::FeesPaid {
paying: origin_location.clone(),
fees: Assets::new(),
})
);
assert!(matches!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::Sent { .. })
));
assert_eq!(
AssetsPallet::balance(usdc_id_location.clone(), ALICE),
usdc_initial_local_amount - FEE_AMOUNT
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT);
assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), SEND_AMOUNT);
assert_eq!(
AssetsPallet::balance(usdc_id_location.clone(), usdc_chain_sovereign_account),
0
);
let expected_issuance = usdc_initial_local_amount - FEE_AMOUNT;
assert_eq!(AssetsPallet::total_issuance(usdc_id_location.clone()), expected_issuance);
assert_eq!(AssetsPallet::active_issuance(usdc_id_location), expected_issuance);
assert_eq!(
sent_xcm(),
vec![(
dest,
Xcm(vec![
WithdrawAsset(expected_fee.clone().into()),
buy_limited_execution(expected_fee, Unlimited),
ReserveAssetDeposited(expected_asset.into()),
ClearOrigin,
DepositAsset { assets: AllCounted(2).into(), beneficiary },
])
)]
);
});
}
#[test]
fn transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_works() {
let expected_result = Ok(());
local_asset_reserve_and_destination_fee_reserve_call(
XcmPallet::transfer_assets,
expected_result,
);
}
#[test]
fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::TooManyReserves.into());
local_asset_reserve_and_destination_fee_reserve_call(
XcmPallet::limited_reserve_transfer_assets,
expected_result,
);
}
#[test]
fn teleport_assets_with_local_asset_reserve_and_destination_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::Filtered.into());
local_asset_reserve_and_destination_fee_reserve_call(
XcmPallet::limited_teleport_assets,
expected_result,
);
}
fn destination_asset_reserve_and_destination_fee_reserve_call<Call>(
tested_call: Call,
expected_result: DispatchResult,
) where
Call: FnOnce(
OriginFor<Test>,
Box<VersionedLocation>,
Box<VersionedLocation>,
Box<VersionedAssets>,
Box<VersionedAssetId>,
WeightLimit,
) -> DispatchResult,
{
let balances = vec![(ALICE, INITIAL_BALANCE)];
let origin_location: Location =
Junction::AccountId32 { network: None, id: ALICE.into() }.into();
let beneficiary: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into();
new_test_ext_with_balances(balances).execute_with(|| {
let foreign_initial_amount = 142;
let (reserve_location, reserve_sovereign_account, foreign_asset_id_location) =
set_up_foreign_asset(
FOREIGN_ASSET_RESERVE_PARA_ID,
Some(FOREIGN_ASSET_INNER_JUNCTION),
ALICE,
foreign_initial_amount,
true,
);
let dest = reserve_location;
let assets: Assets = vec![(foreign_asset_id_location.clone(), SEND_AMOUNT).into()].into();
let fee_asset_id = foreign_asset_id_location.clone();
let mut expected_assets = assets.clone();
expected_assets.reanchor(&dest, &UniversalLocation::get()).unwrap();
assert_eq!(
AssetsPallet::balance(foreign_asset_id_location.clone(), ALICE),
foreign_initial_amount
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
let result = tested_call(
RuntimeOrigin::signed(ALICE),
Box::new(dest.clone().into()),
Box::new(beneficiary.clone().into()),
Box::new(assets.into()),
Box::new(fee_asset_id.into()),
Unlimited,
);
assert_eq!(result, expected_result);
if expected_result.is_err() {
return;
}
let weight = BaseXcmWeight::get() * 2;
let mut last_events = last_events(3).into_iter();
assert_eq!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::Attempted {
outcome: Outcome::Complete { used: weight }
})
);
assert_eq!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::FeesPaid {
paying: origin_location.clone(),
fees: Assets::new(),
})
);
assert!(matches!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::Sent { .. })
));
assert_eq!(
AssetsPallet::balance(foreign_asset_id_location.clone(), ALICE),
foreign_initial_amount - SEND_AMOUNT
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
assert_eq!(Balances::free_balance(reserve_sovereign_account.clone()), 0);
assert_eq!(
AssetsPallet::balance(foreign_asset_id_location.clone(), reserve_sovereign_account),
0
);
let expected_issuance = foreign_initial_amount - SEND_AMOUNT;
assert_eq!(
AssetsPallet::total_issuance(foreign_asset_id_location.clone()),
expected_issuance
);
assert_eq!(AssetsPallet::active_issuance(foreign_asset_id_location), expected_issuance);
assert_eq!(
sent_xcm(),
vec![(
Teyrchain(FOREIGN_ASSET_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: beneficiary.clone() },
]),
)]
);
});
}
#[test]
fn transfer_assets_with_destination_asset_reserve_and_destination_fee_reserve_works() {
let expected_result = Ok(());
destination_asset_reserve_and_destination_fee_reserve_call(
XcmPallet::transfer_assets,
expected_result,
);
}
#[test]
fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_reserve_works() {
let expected_result = Ok(());
destination_asset_reserve_and_destination_fee_reserve_call(
XcmPallet::limited_reserve_transfer_assets,
expected_result,
);
}
#[test]
fn teleport_assets_with_destination_asset_reserve_and_destination_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::Filtered.into());
destination_asset_reserve_and_destination_fee_reserve_call(
XcmPallet::limited_teleport_assets,
expected_result,
);
}
fn remote_asset_reserve_and_destination_fee_reserve_call_disallowed<Call>(
tested_call: Call,
expected_result: DispatchResult,
) where
Call: FnOnce(
OriginFor<Test>,
Box<VersionedLocation>,
Box<VersionedLocation>,
Box<VersionedAssets>,
Box<VersionedAssetId>,
WeightLimit,
) -> DispatchResult,
{
let balances = vec![(ALICE, INITIAL_BALANCE)];
let beneficiary: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into();
new_test_ext_with_balances(balances).execute_with(|| {
let usdc_initial_local_amount = 42;
let (usdc_chain, _, usdc_id_location) = set_up_foreign_asset(
USDC_RESERVE_PARA_ID,
Some(USDC_INNER_JUNCTION),
ALICE,
usdc_initial_local_amount,
true,
);
let foreign_initial_amount = 142;
let (_, _, foreign_asset_id_location) = set_up_foreign_asset(
FOREIGN_ASSET_RESERVE_PARA_ID,
Some(FOREIGN_ASSET_INNER_JUNCTION),
ALICE,
foreign_initial_amount,
false,
);
let dest = usdc_chain;
let (assets, fee_asset, _) = into_assets_checked(
(usdc_id_location.clone(), FEE_AMOUNT).into(),
(foreign_asset_id_location.clone(), SEND_AMOUNT).into(),
);
assert_eq!(
AssetsPallet::balance(usdc_id_location.clone(), ALICE),
usdc_initial_local_amount
);
assert_eq!(
AssetsPallet::balance(foreign_asset_id_location.clone(), ALICE),
foreign_initial_amount
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
let result = tested_call(
RuntimeOrigin::signed(ALICE),
Box::new(dest.into()),
Box::new(beneficiary.into()),
Box::new(assets.into()),
Box::new(fee_asset.id.into()),
Unlimited,
);
assert_eq!(result, expected_result);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
assert_eq!(
AssetsPallet::balance(usdc_id_location.clone(), ALICE),
usdc_initial_local_amount
);
assert_eq!(
AssetsPallet::balance(foreign_asset_id_location.clone(), ALICE),
foreign_initial_amount
);
let expected_usdc_issuance = usdc_initial_local_amount;
assert_eq!(AssetsPallet::total_issuance(usdc_id_location.clone()), expected_usdc_issuance);
assert_eq!(AssetsPallet::active_issuance(usdc_id_location.clone()), expected_usdc_issuance);
let expected_bla_issuance = foreign_initial_amount;
assert_eq!(
AssetsPallet::total_issuance(foreign_asset_id_location.clone()),
expected_bla_issuance
);
assert_eq!(AssetsPallet::active_issuance(foreign_asset_id_location), expected_bla_issuance);
});
}
#[test]
fn transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::InvalidAssetUnsupportedReserve.into());
remote_asset_reserve_and_destination_fee_reserve_call_disallowed(
XcmPallet::transfer_assets,
expected_result,
);
}
#[test]
fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::TooManyReserves.into());
remote_asset_reserve_and_destination_fee_reserve_call_disallowed(
XcmPallet::limited_reserve_transfer_assets,
expected_result,
);
}
#[test]
fn teleport_assets_with_remote_asset_reserve_and_destination_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::Filtered.into());
remote_asset_reserve_and_destination_fee_reserve_call_disallowed(
XcmPallet::limited_teleport_assets,
expected_result,
);
}
fn local_asset_reserve_and_remote_fee_reserve_call_disallowed<Call>(
tested_call: Call,
expected_result: DispatchResult,
) where
Call: FnOnce(
OriginFor<Test>,
Box<VersionedLocation>,
Box<VersionedLocation>,
Box<VersionedAssets>,
Box<VersionedAssetId>,
WeightLimit,
) -> DispatchResult,
{
let balances = vec![(ALICE, INITIAL_BALANCE)];
let beneficiary: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into();
new_test_ext_with_balances(balances).execute_with(|| {
let usdc_initial_local_amount = 142;
let (_, usdc_chain_sovereign_account, usdc_id_location) = set_up_foreign_asset(
USDC_RESERVE_PARA_ID,
Some(USDC_INNER_JUNCTION),
ALICE,
usdc_initial_local_amount,
true,
);
let dest = RelayLocation::get().pushed_with_interior(Teyrchain(OTHER_PARA_ID)).unwrap();
let dest_sovereign_account = SovereignAccountOf::convert_location(&dest).unwrap();
let (assets, fee_asset, _) = into_assets_checked(
(usdc_id_location.clone(), FEE_AMOUNT).into(),
(Location::here(), SEND_AMOUNT).into(),
);
assert_eq!(
AssetsPallet::balance(usdc_id_location.clone(), ALICE),
usdc_initial_local_amount
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
let result = tested_call(
RuntimeOrigin::signed(ALICE),
Box::new(dest.into()),
Box::new(beneficiary.into()),
Box::new(assets.into()),
Box::new(fee_asset.id.into()),
Unlimited,
);
assert_eq!(result, expected_result);
assert_eq!(
AssetsPallet::balance(usdc_id_location.clone(), ALICE),
usdc_initial_local_amount
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), 0);
assert_eq!(
AssetsPallet::balance(usdc_id_location.clone(), usdc_chain_sovereign_account),
0
);
assert_eq!(Balances::free_balance(dest_sovereign_account), 0);
let expected_usdc_issuance = usdc_initial_local_amount;
assert_eq!(AssetsPallet::total_issuance(usdc_id_location.clone()), expected_usdc_issuance);
assert_eq!(AssetsPallet::active_issuance(usdc_id_location), expected_usdc_issuance);
});
}
#[test]
fn transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::InvalidAssetUnsupportedReserve.into());
local_asset_reserve_and_remote_fee_reserve_call_disallowed(
XcmPallet::transfer_assets,
expected_result,
);
}
#[test]
fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::TooManyReserves.into());
local_asset_reserve_and_remote_fee_reserve_call_disallowed(
XcmPallet::limited_reserve_transfer_assets,
expected_result,
);
}
#[test]
fn teleport_assets_with_local_asset_reserve_and_remote_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::Filtered.into());
local_asset_reserve_and_remote_fee_reserve_call_disallowed(
XcmPallet::limited_teleport_assets,
expected_result,
);
}
fn destination_asset_reserve_and_remote_fee_reserve_call_disallowed<Call>(
tested_call: Call,
expected_result: DispatchResult,
) where
Call: FnOnce(
OriginFor<Test>,
Box<VersionedLocation>,
Box<VersionedLocation>,
Box<VersionedAssets>,
Box<VersionedAssetId>,
WeightLimit,
) -> DispatchResult,
{
let balances = vec![(ALICE, INITIAL_BALANCE)];
let beneficiary: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into();
new_test_ext_with_balances(balances).execute_with(|| {
let usdc_initial_local_amount = 42;
let (_, usdc_chain_sovereign_account, usdc_id_location) = set_up_foreign_asset(
USDC_RESERVE_PARA_ID,
Some(USDC_INNER_JUNCTION),
ALICE,
usdc_initial_local_amount,
true,
);
let foreign_initial_amount = 142;
let (reserve_location, foreign_sovereign_account, foreign_asset_id_location) =
set_up_foreign_asset(
FOREIGN_ASSET_RESERVE_PARA_ID,
Some(FOREIGN_ASSET_INNER_JUNCTION),
ALICE,
foreign_initial_amount,
false,
);
let dest = reserve_location;
let dest_sovereign_account = foreign_sovereign_account;
let (assets, fee_asset, _) = into_assets_checked(
(usdc_id_location.clone(), FEE_AMOUNT).into(),
(foreign_asset_id_location.clone(), SEND_AMOUNT).into(),
);
assert_eq!(
AssetsPallet::balance(usdc_id_location.clone(), ALICE),
usdc_initial_local_amount
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
let result = tested_call(
RuntimeOrigin::signed(ALICE),
Box::new(dest.into()),
Box::new(beneficiary.into()),
Box::new(assets.into()),
Box::new(fee_asset.id.into()),
Unlimited,
);
assert_eq!(result, expected_result);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
assert_eq!(
AssetsPallet::balance(usdc_id_location.clone(), ALICE),
usdc_initial_local_amount
);
assert_eq!(
AssetsPallet::balance(foreign_asset_id_location.clone(), ALICE),
foreign_initial_amount
);
assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), 0);
assert_eq!(
AssetsPallet::balance(usdc_id_location.clone(), usdc_chain_sovereign_account),
0
);
assert_eq!(Balances::free_balance(dest_sovereign_account.clone()), 0);
assert_eq!(
AssetsPallet::balance(foreign_asset_id_location.clone(), dest_sovereign_account),
0
);
let expected_usdc_issuance = usdc_initial_local_amount;
assert_eq!(AssetsPallet::total_issuance(usdc_id_location.clone()), expected_usdc_issuance);
assert_eq!(AssetsPallet::active_issuance(usdc_id_location.clone()), expected_usdc_issuance);
let expected_bla_issuance = foreign_initial_amount;
assert_eq!(
AssetsPallet::total_issuance(foreign_asset_id_location.clone()),
expected_bla_issuance
);
assert_eq!(AssetsPallet::active_issuance(foreign_asset_id_location), expected_bla_issuance);
});
}
#[test]
fn transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::InvalidAssetUnsupportedReserve.into());
destination_asset_reserve_and_remote_fee_reserve_call_disallowed(
XcmPallet::transfer_assets,
expected_result,
);
}
#[test]
fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::TooManyReserves.into());
destination_asset_reserve_and_remote_fee_reserve_call_disallowed(
XcmPallet::limited_reserve_transfer_assets,
expected_result,
);
}
#[test]
fn teleport_assets_with_destination_asset_reserve_and_remote_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::Filtered.into());
destination_asset_reserve_and_remote_fee_reserve_call_disallowed(
XcmPallet::limited_teleport_assets,
expected_result,
);
}
fn remote_asset_reserve_and_remote_fee_reserve_call<Call>(
tested_call: Call,
expected_result: DispatchResult,
) where
Call: FnOnce(
OriginFor<Test>,
Box<VersionedLocation>,
Box<VersionedLocation>,
Box<VersionedAssets>,
Box<VersionedAssetId>,
WeightLimit,
) -> DispatchResult,
{
let balances = vec![(ALICE, INITIAL_BALANCE)];
let beneficiary: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into();
new_test_ext_with_balances(balances).execute_with(|| {
let usdc_initial_local_amount = 142;
let (usdc_chain, usdc_chain_sovereign_account, usdc_id_location) = set_up_foreign_asset(
USDC_RESERVE_PARA_ID,
Some(USDC_INNER_JUNCTION),
ALICE,
usdc_initial_local_amount,
true,
);
let dest = RelayLocation::get().pushed_with_interior(Teyrchain(OTHER_PARA_ID)).unwrap();
let assets: Assets = vec![(usdc_id_location.clone(), SEND_AMOUNT).into()].into();
let fee_asset_id: AssetId = usdc_id_location.clone().into();
let context = UniversalLocation::get();
let expected_dest_on_reserve = dest.clone().reanchored(&usdc_chain, &context).unwrap();
let fees = assets.inner().iter().find(|a| a.id == fee_asset_id).unwrap();
let (fees_half_1, fees_half_2) = XcmPallet::halve_fees(fees.clone()).unwrap();
let mut expected_assets_on_reserve = assets.clone();
expected_assets_on_reserve.reanchor(&usdc_chain, &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();
assert_eq!(
AssetsPallet::balance(usdc_id_location.clone(), ALICE),
usdc_initial_local_amount
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
let result = tested_call(
RuntimeOrigin::signed(ALICE),
Box::new(dest.clone().into()),
Box::new(beneficiary.clone().into()),
Box::new(assets.into()),
Box::new(fee_asset_id.into()),
Unlimited,
);
assert_eq!(result, expected_result);
if expected_result.is_err() {
return;
}
assert!(matches!(
last_event(),
RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete { .. } })
));
assert_eq!(
AssetsPallet::balance(usdc_id_location.clone(), ALICE),
usdc_initial_local_amount - SEND_AMOUNT
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), 0);
assert_eq!(
AssetsPallet::balance(usdc_id_location.clone(), usdc_chain_sovereign_account),
0
);
let expected_usdc_issuance = usdc_initial_local_amount - SEND_AMOUNT;
assert_eq!(AssetsPallet::total_issuance(usdc_id_location.clone()), expected_usdc_issuance);
assert_eq!(AssetsPallet::active_issuance(usdc_id_location.clone()), expected_usdc_issuance);
let expected_hash =
find_xcm_sent_message_id::<Test>(all_events()).expect("Missing XcmPallet::Sent event");
assert_eq!(
sent_xcm(),
vec![(
usdc_chain,
Xcm(vec![
WithdrawAsset(expected_assets_on_reserve),
ClearOrigin,
BuyExecution { fees: expected_fee_on_reserve, weight_limit: Unlimited },
DepositReserveAsset {
assets: Wild(AllCounted(1)),
dest: expected_dest_on_reserve,
xcm: Xcm(vec![
buy_limited_execution(expected_fee_on_dest, Unlimited),
DepositAsset { assets: AllCounted(1).into(), beneficiary }
])
},
SetTopic(expected_hash),
])
)],
);
});
}
#[test]
fn transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_works() {
let expected_result = Ok(());
remote_asset_reserve_and_remote_fee_reserve_call(XcmPallet::transfer_assets, expected_result);
}
#[test]
fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_works() {
let expected_result = Ok(());
remote_asset_reserve_and_remote_fee_reserve_call(
XcmPallet::limited_reserve_transfer_assets,
expected_result,
);
}
#[test]
fn teleport_assets_with_remote_asset_reserve_and_remote_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::Filtered.into());
remote_asset_reserve_and_remote_fee_reserve_call(
XcmPallet::limited_teleport_assets,
expected_result,
);
}
fn local_asset_reserve_and_teleported_fee_call<Call>(
tested_call: Call,
expected_result: DispatchResult,
) where
Call: FnOnce(
OriginFor<Test>,
Box<VersionedLocation>,
Box<VersionedLocation>,
Box<VersionedAssets>,
Box<VersionedAssetId>,
WeightLimit,
) -> DispatchResult,
{
let balances = vec![(ALICE, INITIAL_BALANCE)];
let origin_location: Location =
Junction::AccountId32 { network: None, id: ALICE.into() }.into();
let beneficiary: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into();
new_test_ext_with_balances(balances).execute_with(|| {
let usdt_initial_local_amount = 42;
let (usdt_chain, usdt_chain_sovereign_account, usdt_id_location) =
set_up_foreign_asset(USDT_PARA_ID, None, ALICE, usdt_initial_local_amount, true);
let dest = usdt_chain;
let (assets, fee_asset, xfer_asset) = into_assets_checked(
(usdt_id_location.clone(), FEE_AMOUNT).into(),
(Location::here(), SEND_AMOUNT).into(),
);
let context = UniversalLocation::get();
let expected_fee = fee_asset.clone().reanchored(&dest, &context).unwrap();
let expected_asset = xfer_asset.reanchored(&dest, &context).unwrap();
assert_eq!(
AssetsPallet::balance(usdt_id_location.clone(), ALICE),
usdt_initial_local_amount
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
let result = tested_call(
RuntimeOrigin::signed(ALICE),
Box::new(dest.clone().into()),
Box::new(beneficiary.clone().into()),
Box::new(assets.into()),
Box::new(fee_asset.id.into()),
Unlimited,
);
assert_eq!(result, expected_result);
if expected_result.is_err() {
return;
}
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 { used: weight }
})
);
assert_eq!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::FeesPaid {
paying: origin_location.clone(),
fees: Assets::new(),
})
);
assert!(matches!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::Sent { .. })
));
assert_eq!(
AssetsPallet::balance(usdt_id_location.clone(), ALICE),
usdt_initial_local_amount - FEE_AMOUNT
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT);
assert_eq!(Balances::free_balance(usdt_chain_sovereign_account.clone()), SEND_AMOUNT);
assert_eq!(
AssetsPallet::balance(usdt_id_location.clone(), usdt_chain_sovereign_account),
0
);
let expected_usdt_issuance = usdt_initial_local_amount - FEE_AMOUNT;
assert_eq!(AssetsPallet::total_issuance(usdt_id_location.clone()), expected_usdt_issuance);
assert_eq!(AssetsPallet::active_issuance(usdt_id_location), expected_usdt_issuance);
assert_eq!(
sent_xcm(),
vec![(
dest,
Xcm(vec![
ReceiveTeleportedAsset(expected_fee.clone().into()),
buy_limited_execution(expected_fee, Unlimited),
ReserveAssetDeposited(expected_asset.into()),
ClearOrigin,
DepositAsset { assets: AllCounted(2).into(), beneficiary },
])
)]
);
});
}
#[test]
fn transfer_assets_with_local_asset_reserve_and_teleported_fee_works() {
let expected_result = Ok(());
local_asset_reserve_and_teleported_fee_call(XcmPallet::transfer_assets, expected_result);
}
#[test]
fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_disallowed() {
let expected_result = Err(crate::Error::<Test>::TooManyReserves.into());
local_asset_reserve_and_teleported_fee_call(
XcmPallet::limited_reserve_transfer_assets,
expected_result,
);
}
#[test]
fn teleport_assets_with_local_asset_reserve_and_teleported_fee_disallowed() {
let expected_result = Err(crate::Error::<Test>::Filtered.into());
local_asset_reserve_and_teleported_fee_call(
XcmPallet::limited_teleport_assets,
expected_result,
);
}
fn destination_asset_reserve_and_teleported_fee_call<Call>(
tested_call: Call,
expected_result: DispatchResult,
) where
Call: FnOnce(
OriginFor<Test>,
Box<VersionedLocation>,
Box<VersionedLocation>,
Box<VersionedAssets>,
Box<VersionedAssetId>,
WeightLimit,
) -> DispatchResult,
{
let balances = vec![(ALICE, INITIAL_BALANCE)];
let origin_location: Location =
Junction::AccountId32 { network: None, id: ALICE.into() }.into();
let beneficiary: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into();
new_test_ext_with_balances(balances).execute_with(|| {
let usdt_initial_local_amount = 42;
let (_, usdt_chain_sovereign_account, usdt_id_location) =
set_up_foreign_asset(USDT_PARA_ID, None, ALICE, usdt_initial_local_amount, true);
let foreign_initial_amount = 142;
let (reserve_location, foreign_sovereign_account, foreign_asset_id_location) =
set_up_foreign_asset(
FOREIGN_ASSET_RESERVE_PARA_ID,
Some(FOREIGN_ASSET_INNER_JUNCTION),
ALICE,
foreign_initial_amount,
false,
);
let dest = reserve_location;
let dest_sovereign_account = foreign_sovereign_account;
let (assets, fee_asset, xfer_asset) = into_assets_checked(
(usdt_id_location.clone(), FEE_AMOUNT).into(),
(foreign_asset_id_location.clone(), SEND_AMOUNT).into(),
);
let context = UniversalLocation::get();
let expected_fee = fee_asset.clone().reanchored(&dest, &context).unwrap();
let expected_asset = xfer_asset.reanchored(&dest, &context).unwrap();
assert_eq!(
AssetsPallet::balance(usdt_id_location.clone(), ALICE),
usdt_initial_local_amount
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
let result = tested_call(
RuntimeOrigin::signed(ALICE),
Box::new(dest.clone().into()),
Box::new(beneficiary.clone().into()),
Box::new(assets.into()),
Box::new(fee_asset.id.into()),
Unlimited,
);
assert_eq!(result, expected_result);
if expected_result.is_err() {
return;
}
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 { used: weight }
})
);
assert_eq!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::FeesPaid {
paying: origin_location.clone(),
fees: Assets::new(),
})
);
assert!(matches!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::Sent { .. })
));
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
assert_eq!(
AssetsPallet::balance(usdt_id_location.clone(), ALICE),
usdt_initial_local_amount - FEE_AMOUNT
);
assert_eq!(
AssetsPallet::balance(foreign_asset_id_location.clone(), ALICE),
foreign_initial_amount - SEND_AMOUNT
);
assert_eq!(Balances::free_balance(usdt_chain_sovereign_account.clone()), 0);
assert_eq!(
AssetsPallet::balance(usdt_id_location.clone(), usdt_chain_sovereign_account),
0
);
assert_eq!(Balances::free_balance(dest_sovereign_account.clone()), 0);
assert_eq!(
AssetsPallet::balance(foreign_asset_id_location.clone(), dest_sovereign_account),
0
);
let expected_usdt_issuance = usdt_initial_local_amount - FEE_AMOUNT;
assert_eq!(AssetsPallet::total_issuance(usdt_id_location.clone()), expected_usdt_issuance);
assert_eq!(AssetsPallet::active_issuance(usdt_id_location.clone()), expected_usdt_issuance);
let expected_bla_issuance = foreign_initial_amount - SEND_AMOUNT;
assert_eq!(
AssetsPallet::total_issuance(foreign_asset_id_location.clone()),
expected_bla_issuance
);
assert_eq!(AssetsPallet::active_issuance(foreign_asset_id_location), expected_bla_issuance);
assert_eq!(
sent_xcm(),
vec![(
dest,
Xcm(vec![
ReceiveTeleportedAsset(expected_fee.clone().into()),
buy_limited_execution(expected_fee, Unlimited),
WithdrawAsset(expected_asset.into()),
ClearOrigin,
DepositAsset { assets: AllCounted(2).into(), beneficiary },
])
)]
);
});
}
#[test]
fn transfer_assets_with_destination_asset_reserve_and_teleported_fee_works() {
let expected_result = Ok(());
destination_asset_reserve_and_teleported_fee_call(XcmPallet::transfer_assets, expected_result);
}
#[test]
fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_disallowed() {
let expected_result = Err(crate::Error::<Test>::TooManyReserves.into());
destination_asset_reserve_and_teleported_fee_call(
XcmPallet::limited_reserve_transfer_assets,
expected_result,
);
}
#[test]
fn teleport_assets_with_destination_asset_reserve_and_teleported_fee_disallowed() {
let expected_result = Err(crate::Error::<Test>::Filtered.into());
destination_asset_reserve_and_teleported_fee_call(
XcmPallet::limited_teleport_assets,
expected_result,
);
}
fn remote_asset_reserve_and_teleported_fee_reserve_call_disallowed<Call>(
tested_call: Call,
expected_result: DispatchResult,
) where
Call: FnOnce(
OriginFor<Test>,
Box<VersionedLocation>,
Box<VersionedLocation>,
Box<VersionedAssets>,
Box<VersionedAssetId>,
WeightLimit,
) -> DispatchResult,
{
let balances = vec![(ALICE, INITIAL_BALANCE)];
let beneficiary: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into();
new_test_ext_with_balances(balances).execute_with(|| {
let usdt_initial_local_amount = 42;
let (usdt_chain, usdt_chain_sovereign_account, usdt_id_location) =
set_up_foreign_asset(USDT_PARA_ID, None, ALICE, usdt_initial_local_amount, true);
let foreign_initial_amount = 142;
let (_, reserve_sovereign_account, foreign_asset_id_location) = set_up_foreign_asset(
FOREIGN_ASSET_RESERVE_PARA_ID,
Some(FOREIGN_ASSET_INNER_JUNCTION),
ALICE,
foreign_initial_amount,
false,
);
let dest = usdt_chain;
let (assets, fee_asset, _) = into_assets_checked(
(usdt_id_location.clone(), FEE_AMOUNT).into(),
(foreign_asset_id_location.clone(), SEND_AMOUNT).into(),
);
assert_eq!(
AssetsPallet::balance(usdt_id_location.clone(), ALICE),
usdt_initial_local_amount
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
let result = tested_call(
RuntimeOrigin::signed(ALICE),
Box::new(dest.into()),
Box::new(beneficiary.into()),
Box::new(assets.into()),
Box::new(fee_asset.id.into()),
Unlimited,
);
assert_eq!(result, expected_result);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
assert_eq!(
AssetsPallet::balance(usdt_id_location.clone(), ALICE),
usdt_initial_local_amount
);
assert_eq!(
AssetsPallet::balance(foreign_asset_id_location.clone(), ALICE),
foreign_initial_amount
);
assert_eq!(Balances::free_balance(usdt_chain_sovereign_account.clone()), 0);
assert_eq!(
AssetsPallet::balance(usdt_id_location.clone(), usdt_chain_sovereign_account),
0
);
assert_eq!(Balances::free_balance(reserve_sovereign_account.clone()), 0);
assert_eq!(
AssetsPallet::balance(foreign_asset_id_location.clone(), reserve_sovereign_account),
0
);
let expected_usdt_issuance = usdt_initial_local_amount;
assert_eq!(AssetsPallet::total_issuance(usdt_id_location.clone()), expected_usdt_issuance);
assert_eq!(AssetsPallet::active_issuance(usdt_id_location.clone()), expected_usdt_issuance);
let expected_bla_issuance = foreign_initial_amount;
assert_eq!(
AssetsPallet::total_issuance(foreign_asset_id_location.clone()),
expected_bla_issuance
);
assert_eq!(AssetsPallet::active_issuance(foreign_asset_id_location), expected_bla_issuance);
});
}
#[test]
fn transfer_assets_with_remote_asset_reserve_and_teleported_fee_disallowed() {
let expected_result = Err(crate::Error::<Test>::InvalidAssetUnsupportedReserve.into());
remote_asset_reserve_and_teleported_fee_reserve_call_disallowed(
XcmPallet::transfer_assets,
expected_result,
);
}
#[test]
fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_disallowed() {
let expected_result = Err(crate::Error::<Test>::TooManyReserves.into());
remote_asset_reserve_and_teleported_fee_reserve_call_disallowed(
XcmPallet::limited_reserve_transfer_assets,
expected_result,
);
}
#[test]
fn teleport_assets_with_remote_asset_reserve_and_teleported_fee_disallowed() {
let expected_result = Err(crate::Error::<Test>::Filtered.into());
remote_asset_reserve_and_teleported_fee_reserve_call_disallowed(
XcmPallet::limited_teleport_assets,
expected_result,
);
}
#[test]
fn reserve_transfer_assets_with_teleportable_asset_disallowed() {
let balances = vec![(ALICE, INITIAL_BALANCE)];
let beneficiary: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into();
new_test_ext_with_balances(balances).execute_with(|| {
let usdt_initial_local_amount = 42;
let (usdt_chain, usdt_chain_sovereign_account, usdt_id_location) =
set_up_foreign_asset(USDT_PARA_ID, None, ALICE, usdt_initial_local_amount, true);
let dest = usdt_chain;
let assets: Assets = vec![(usdt_id_location.clone(), FEE_AMOUNT).into()].into();
let fee_asset_id = usdt_id_location.clone();
assert_eq!(
AssetsPallet::balance(usdt_id_location.clone(), ALICE),
usdt_initial_local_amount
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
let res = XcmPallet::limited_reserve_transfer_assets(
RuntimeOrigin::signed(ALICE),
Box::new(dest.into()),
Box::new(beneficiary.into()),
Box::new(assets.into()),
Box::new(fee_asset_id.into()),
Unlimited,
);
assert_err!(res, crate::Error::<Test>::Filtered);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
assert_eq!(
AssetsPallet::balance(usdt_id_location.clone(), ALICE),
usdt_initial_local_amount
);
assert_eq!(
AssetsPallet::balance(usdt_id_location.clone(), usdt_chain_sovereign_account),
0
);
assert_eq!(
AssetsPallet::total_issuance(usdt_id_location.clone()),
usdt_initial_local_amount
);
assert_eq!(AssetsPallet::active_issuance(usdt_id_location), usdt_initial_local_amount);
});
}
#[test]
fn transfer_assets_with_filtered_teleported_fee_disallowed() {
let beneficiary: Location = AccountId32 { network: None, id: BOB.into() }.into();
new_test_ext_with_balances(vec![(ALICE, INITIAL_BALANCE)]).execute_with(|| {
let (assets, fee_asset, _) = into_assets_checked(
FilteredTeleportAsset::get().into(),
(Location::here(), SEND_AMOUNT).into(),
);
let result = XcmPallet::transfer_assets(
RuntimeOrigin::signed(ALICE),
Box::new(FilteredTeleportLocation::get().into()),
Box::new(beneficiary.into()),
Box::new(assets.into()),
Box::new(fee_asset.id.into()),
Unlimited,
);
assert_err!(result, crate::Error::<Test>::Filtered);
});
}
#[test]
fn intermediary_error_reverts_side_effects() {
use pezsp_tracing::{
test_log_capture::init_log_capture,
tracing::{subscriber, Level},
};
let balances = vec![(ALICE, INITIAL_BALANCE)];
let beneficiary: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into();
new_test_ext_with_balances(balances).execute_with(|| {
let usdc_initial_local_amount = 142;
let (_, usdc_chain_sovereign_account, usdc_id_location) = set_up_foreign_asset(
USDC_RESERVE_PARA_ID,
Some(USDC_INNER_JUNCTION),
ALICE,
usdc_initial_local_amount,
true,
);
let dest = RelayLocation::get().pushed_with_interior(Teyrchain(OTHER_PARA_ID)).unwrap();
let assets: Assets = vec![(usdc_id_location.clone(), SEND_AMOUNT).into()].into();
let fee_asset_id = usdc_id_location.clone();
assert_eq!(
AssetsPallet::balance(usdc_id_location.clone(), ALICE),
usdc_initial_local_amount
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
set_send_xcm_artificial_failure(true);
let (log_capture, subscriber) = init_log_capture(Level::DEBUG, true);
subscriber::with_default(subscriber, || {
let result = XcmPallet::limited_reserve_transfer_assets(
RuntimeOrigin::signed(ALICE),
Box::new(dest.into()),
Box::new(beneficiary.into()),
Box::new(assets.into()),
Box::new(fee_asset_id.into()),
Unlimited,
);
assert!(result.is_err());
assert!(log_capture.contains(
"xcm::process: XCM execution failed at instruction index=2 error=Transport(\"Intentional send failure used in tests\")"
), "Expected transport error log message not found");
let process_xcm_error_emitted = System::events().iter().any(|r| {
matches!(r.event, RuntimeEvent::XcmPallet(crate::Event::ProcessXcmError { .. }))
});
assert!(
!process_xcm_error_emitted,
"Expected no `XcmPallet::ProcessXcmError` event due to rollback, but it was emitted"
);
});
assert_eq!(
AssetsPallet::balance(usdc_id_location.clone(), ALICE),
usdc_initial_local_amount
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
assert_eq!(Balances::free_balance(usdc_chain_sovereign_account.clone()), 0);
assert_eq!(
AssetsPallet::balance(usdc_id_location.clone(), usdc_chain_sovereign_account),
0
);
assert_eq!(
AssetsPallet::total_issuance(usdc_id_location.clone()),
usdc_initial_local_amount
);
assert_eq!(AssetsPallet::active_issuance(usdc_id_location), usdc_initial_local_amount);
assert_eq!(sent_xcm(), vec![]);
});
}
fn teleport_asset_using_local_fee_reserve_call<Call>(
tested_call: Call,
expected_result: DispatchResult,
) where
Call: FnOnce(
OriginFor<Test>,
Box<VersionedLocation>,
Box<VersionedLocation>,
Box<VersionedAssets>,
Box<VersionedAssetId>,
WeightLimit,
) -> DispatchResult,
{
let weight = BaseXcmWeight::get() * 3;
let balances = vec![(ALICE, INITIAL_BALANCE)];
let origin_location: Location = AccountId32 { network: None, id: ALICE.into() }.into();
let beneficiary: Location = AccountId32 { network: None, id: ALICE.into() }.into();
new_test_ext_with_balances(balances).execute_with(|| {
let usdt_initial_local_amount = 42;
let (usdt_chain, usdt_chain_sovereign_account, usdt_id_location) =
set_up_foreign_asset(USDT_PARA_ID, None, ALICE, usdt_initial_local_amount, false);
let dest = usdt_chain;
let (assets, fee_asset, xfer_asset) = into_assets_checked(
(Location::here(), FEE_AMOUNT).into(),
(usdt_id_location.clone(), SEND_AMOUNT).into(),
);
let context = UniversalLocation::get();
let expected_fee = fee_asset.clone().reanchored(&dest, &context).unwrap();
let expected_asset = xfer_asset.reanchored(&dest, &context).unwrap();
assert_eq!(
AssetsPallet::balance(usdt_id_location.clone(), ALICE),
usdt_initial_local_amount
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
let result = tested_call(
RuntimeOrigin::signed(ALICE),
Box::new(dest.clone().into()),
Box::new(beneficiary.clone().into()),
Box::new(assets.into()),
Box::new(fee_asset.id.into()),
Unlimited,
);
assert_eq!(result, expected_result);
if expected_result.is_err() {
return;
}
let mut last_events = last_events(3).into_iter();
assert_eq!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::Attempted {
outcome: Outcome::Complete { used: weight }
})
);
assert_eq!(
AssetsPallet::balance(usdt_id_location.clone(), ALICE),
usdt_initial_local_amount - SEND_AMOUNT
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - FEE_AMOUNT);
assert_eq!(Balances::free_balance(usdt_chain_sovereign_account.clone()), FEE_AMOUNT);
assert_eq!(
AssetsPallet::balance(usdt_id_location.clone(), usdt_chain_sovereign_account),
0
);
let expected_issuance = usdt_initial_local_amount - SEND_AMOUNT;
assert_eq!(AssetsPallet::total_issuance(usdt_id_location.clone()), expected_issuance);
assert_eq!(AssetsPallet::active_issuance(usdt_id_location), expected_issuance);
assert_eq!(
sent_xcm(),
vec![(
dest,
Xcm(vec![
ReserveAssetDeposited(expected_fee.clone().into()),
buy_limited_execution(expected_fee, Unlimited),
ReceiveTeleportedAsset(expected_asset.into()),
ClearOrigin,
DepositAsset { assets: AllCounted(2).into(), beneficiary },
])
)]
);
assert_eq!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::FeesPaid {
paying: origin_location,
fees: Assets::new(),
})
);
assert!(matches!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::Sent { .. })
));
});
}
#[test]
fn transfer_assets_with_teleportable_asset_and_local_fee_reserve_works() {
let expected_result = Ok(());
teleport_asset_using_local_fee_reserve_call(XcmPallet::transfer_assets, expected_result);
}
#[test]
fn reserve_transfer_assets_with_teleportable_asset_and_local_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::Filtered.into());
teleport_asset_using_local_fee_reserve_call(
XcmPallet::limited_reserve_transfer_assets,
expected_result,
);
}
#[test]
fn teleport_assets_with_teleportable_asset_and_local_fee_reserve_disallowed() {
let expected_result = Err(crate::Error::<Test>::Filtered.into());
teleport_asset_using_local_fee_reserve_call(
XcmPallet::limited_teleport_assets,
expected_result,
);
}
fn teleported_asset_using_destination_reserve_fee_call<Call>(
tested_call: Call,
expected_result: DispatchResult,
) where
Call: FnOnce(
OriginFor<Test>,
Box<VersionedLocation>,
Box<VersionedLocation>,
Box<VersionedAssets>,
Box<VersionedAssetId>,
WeightLimit,
) -> DispatchResult,
{
let balances = vec![(ALICE, INITIAL_BALANCE)];
let origin_location: Location = AccountId32 { network: None, id: ALICE.into() }.into();
let beneficiary: Location = AccountId32 { network: None, id: ALICE.into() }.into();
new_test_ext_with_balances(balances).execute_with(|| {
let foreign_initial_amount = 142;
let (reserve_location, foreign_sovereign_account, foreign_asset_id_location) =
set_up_foreign_asset(
FOREIGN_ASSET_RESERVE_PARA_ID,
Some(FOREIGN_ASSET_INNER_JUNCTION),
ALICE,
foreign_initial_amount,
true,
);
let usdt_initial_local_amount = 42;
let (_, usdt_chain_sovereign_account, usdt_id_location) =
set_up_foreign_asset(USDT_PARA_ID, None, ALICE, usdt_initial_local_amount, false);
let dest = reserve_location;
let dest_sovereign_account = foreign_sovereign_account;
let (assets, fee_asset, xfer_asset) = into_assets_checked(
(foreign_asset_id_location.clone(), FEE_AMOUNT).into(),
(usdt_id_location.clone(), SEND_AMOUNT).into(),
);
let context = UniversalLocation::get();
let expected_fee = fee_asset.clone().reanchored(&dest, &context).unwrap();
let expected_asset = xfer_asset.reanchored(&dest, &context).unwrap();
assert_eq!(
AssetsPallet::balance(usdt_id_location.clone(), ALICE),
usdt_initial_local_amount
);
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
let result = tested_call(
RuntimeOrigin::signed(ALICE),
Box::new(dest.clone().into()),
Box::new(beneficiary.clone().into()),
Box::new(assets.into()),
Box::new(fee_asset.id.into()),
Unlimited,
);
assert_eq!(result, expected_result);
if expected_result.is_err() {
return;
}
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 { used: weight }
})
);
assert_eq!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::FeesPaid {
paying: origin_location,
fees: Assets::new(),
})
);
assert!(matches!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::Sent { .. })
));
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE);
assert_eq!(
AssetsPallet::balance(usdt_id_location.clone(), ALICE),
usdt_initial_local_amount - SEND_AMOUNT
);
assert_eq!(
AssetsPallet::balance(foreign_asset_id_location.clone(), ALICE),
foreign_initial_amount - FEE_AMOUNT
);
assert_eq!(Balances::free_balance(usdt_chain_sovereign_account.clone()), 0);
assert_eq!(
AssetsPallet::balance(usdt_id_location.clone(), usdt_chain_sovereign_account),
0
);
assert_eq!(Balances::free_balance(dest_sovereign_account.clone()), 0);
assert_eq!(
AssetsPallet::balance(foreign_asset_id_location.clone(), dest_sovereign_account),
0
);
let expected_usdt_issuance = usdt_initial_local_amount - SEND_AMOUNT;
assert_eq!(AssetsPallet::total_issuance(usdt_id_location.clone()), expected_usdt_issuance);
assert_eq!(AssetsPallet::active_issuance(usdt_id_location), expected_usdt_issuance);
let expected_bla_issuance = foreign_initial_amount - FEE_AMOUNT;
assert_eq!(
AssetsPallet::total_issuance(foreign_asset_id_location.clone()),
expected_bla_issuance
);
assert_eq!(AssetsPallet::active_issuance(foreign_asset_id_location), expected_bla_issuance);
assert_eq!(
sent_xcm(),
vec![(
dest,
Xcm(vec![
WithdrawAsset(expected_fee.clone().into()),
buy_limited_execution(expected_fee, Unlimited),
ReceiveTeleportedAsset(expected_asset.into()),
ClearOrigin,
DepositAsset { assets: AllCounted(2).into(), beneficiary },
])
)]
);
});
}
#[test]
fn transfer_teleported_assets_using_destination_reserve_fee_works() {
let expected_result = Ok(());
teleported_asset_using_destination_reserve_fee_call(
XcmPallet::transfer_assets,
expected_result,
);
}
#[test]
fn reserve_transfer_teleported_assets_using_destination_reserve_fee_disallowed() {
let expected_result = Err(crate::Error::<Test>::Filtered.into());
teleported_asset_using_destination_reserve_fee_call(
XcmPallet::limited_reserve_transfer_assets,
expected_result,
);
}
#[test]
fn teleport_assets_using_destination_reserve_fee_disallowed() {
let expected_result = Err(crate::Error::<Test>::Filtered.into());
teleported_asset_using_destination_reserve_fee_call(
XcmPallet::limited_teleport_assets,
expected_result,
);
}
fn remote_asset_reserve_and_remote_fee_reserve_paid_call<Call>(
tested_call: Call,
expected_result: DispatchResult,
) where
Call: FnOnce(
OriginFor<Test>,
Box<VersionedLocation>,
Box<VersionedLocation>,
Box<VersionedAssets>,
Box<VersionedAssetId>,
WeightLimit,
) -> DispatchResult,
{
let weight = BaseXcmWeight::get() * 3;
let user_account = AccountId::from(XCM_FEES_NOT_WAIVED_USER_ACCOUNT);
let xcm_router_fee_amount = Para3000PaymentAmount::get();
let paid_para_id = Para3000::get();
let balances = vec![
(user_account.clone(), INITIAL_BALANCE),
(ParaId::from(paid_para_id).into_account_truncating(), INITIAL_BALANCE),
(XcmFeesTargetAccount::get(), INITIAL_BALANCE),
];
let beneficiary: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into();
new_test_ext_with_balances(balances).execute_with(|| {
let foreign_initial_amount = 142;
let (reserve_location, _, foreign_asset_id_location) = set_up_foreign_asset(
paid_para_id,
None,
user_account.clone(),
foreign_initial_amount,
true,
);
let dest = RelayLocation::get().pushed_with_interior(Teyrchain(OTHER_PARA_ID)).unwrap();
let transferred_asset: Assets = (foreign_asset_id_location.clone(), SEND_AMOUNT).into();
assert_eq!(
AssetsPallet::balance(foreign_asset_id_location.clone(), user_account.clone()),
foreign_initial_amount
);
assert_eq!(Balances::free_balance(user_account.clone()), INITIAL_BALANCE);
let result = tested_call(
RuntimeOrigin::signed(user_account.clone()),
Box::new(dest.clone().into()),
Box::new(beneficiary.clone().into()),
Box::new(transferred_asset.into()),
Box::new(foreign_asset_id_location.clone().into()),
Unlimited,
);
assert_eq!(result, expected_result);
if expected_result.is_err() {
return;
}
let context = UniversalLocation::get();
let foreign_id_location_reanchored =
foreign_asset_id_location.clone().reanchored(&dest, &context).unwrap();
let dest_reanchored = dest.reanchored(&reserve_location, &context).unwrap();
let sent_msg_id = find_xcm_sent_message_id::<Test>(all_events()).unwrap();
let sent_message = Xcm(vec![
WithdrawAsset((Location::here(), SEND_AMOUNT).into()),
ClearOrigin,
buy_execution((Location::here(), SEND_AMOUNT / 2)),
DepositReserveAsset {
assets: Wild(AllCounted(1)),
dest: dest_reanchored,
xcm: Xcm(vec![
buy_execution((foreign_id_location_reanchored, SEND_AMOUNT / 2)),
DepositAsset { assets: AllCounted(1).into(), beneficiary },
]),
},
SetTopic(sent_msg_id),
]);
let mut last_events = last_events(7).into_iter();
last_events.next().unwrap();
last_events.next().unwrap();
last_events.next().unwrap();
last_events.next().unwrap();
last_events.next().unwrap();
assert_eq!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::Sent {
origin: user_account.clone().into(),
destination: Teyrchain(paid_para_id).into(),
message: Xcm::default(),
message_id: sent_msg_id,
})
);
assert_eq!(
last_events.next().unwrap(),
RuntimeEvent::XcmPallet(crate::Event::Attempted {
outcome: Outcome::Complete { used: weight }
})
);
assert_eq!(
AssetsPallet::balance(foreign_asset_id_location.clone(), user_account.clone()),
foreign_initial_amount - SEND_AMOUNT
);
assert_eq!(Balances::free_balance(user_account), INITIAL_BALANCE - xcm_router_fee_amount);
assert_eq!(
Balances::free_balance(XcmFeesTargetAccount::get()),
INITIAL_BALANCE + xcm_router_fee_amount
);
let expected_issuance = foreign_initial_amount - SEND_AMOUNT;
assert_eq!(
AssetsPallet::total_issuance(foreign_asset_id_location.clone()),
expected_issuance
);
assert_eq!(AssetsPallet::active_issuance(foreign_asset_id_location), expected_issuance);
assert_eq!(
sent_xcm(),
vec![(
reserve_location,
sent_message,
)]
);
});
}
#[test]
fn transfer_assets_with_remote_asset_reserve_and_remote_asset_fee_reserve_paid_works() {
let expected_result = Ok(());
remote_asset_reserve_and_remote_fee_reserve_paid_call(
XcmPallet::transfer_assets,
expected_result,
);
}
#[test]
fn limited_reserve_transfer_assets_with_remote_asset_reserve_and_remote_asset_fee_reserve_paid_works(
) {
let expected_result = Ok(());
remote_asset_reserve_and_remote_fee_reserve_paid_call(
XcmPallet::limited_reserve_transfer_assets,
expected_result,
);
}