use frame_system::RawOrigin;
use sp_api::ProvideRuntimeApi;
use sp_runtime::testing::H256;
use xcm::prelude::*;
use xcm_fee_payment_runtime_api::{dry_run::DryRunApi, fees::XcmPaymentApi};
mod mock;
use mock::{
fake_message_hash, new_test_ext_with_balances, new_test_ext_with_balances_and_assets,
DeliveryFees, ExistentialDeposit, HereLocation, OriginCaller, RuntimeCall, RuntimeEvent,
TestClient,
};
#[test]
fn fee_estimation_for_teleport() {
let _ = env_logger::builder().is_test(true).try_init();
let who = 1; let balances = vec![(who, 100 + DeliveryFees::get() + ExistentialDeposit::get())];
let assets = vec![(1, who, 50)];
new_test_ext_with_balances_and_assets(balances, assets).execute_with(|| {
let client = TestClient;
let runtime_api = client.runtime_api();
let call = RuntimeCall::XcmPallet(pallet_xcm::Call::transfer_assets {
dest: Box::new(VersionedLocation::from((Parent, Parachain(1000)))),
beneficiary: Box::new(VersionedLocation::from(AccountId32 {
id: [0u8; 32],
network: None,
})),
assets: Box::new(VersionedAssets::from(vec![
(Here, 100u128).into(),
(Parent, 20u128).into(),
])),
fee_asset_item: 1, weight_limit: Unlimited,
});
let origin = OriginCaller::system(RawOrigin::Signed(who));
let dry_run_effects =
runtime_api.dry_run_call(H256::zero(), origin, call).unwrap().unwrap();
assert_eq!(
dry_run_effects.local_xcm,
Some(VersionedXcm::from(
Xcm::builder_unsafe()
.withdraw_asset((Parent, 20u128))
.burn_asset((Parent, 20u128))
.withdraw_asset((Here, 100u128))
.burn_asset((Here, 100u128))
.build()
)),
);
let send_destination = Location::new(1, [Parachain(1000)]);
let send_message = Xcm::<()>::builder_unsafe()
.withdraw_asset((Parent, 20u128))
.buy_execution((Parent, 20u128), Unlimited)
.receive_teleported_asset(((Parent, Parachain(2000)), 100u128))
.clear_origin()
.deposit_asset(AllCounted(2), [0u8; 32])
.build();
assert_eq!(
dry_run_effects.forwarded_xcms,
vec![(
VersionedLocation::from(send_destination.clone()),
vec![VersionedXcm::from(send_message.clone())],
),],
);
assert_eq!(
dry_run_effects.emitted_events,
vec![
RuntimeEvent::System(frame_system::Event::NewAccount {
account: 8660274132218572653 }),
RuntimeEvent::Balances(pallet_balances::Event::Endowed {
account: 8660274132218572653,
free_balance: 100
}),
RuntimeEvent::Balances(pallet_balances::Event::Minted {
who: 8660274132218572653,
amount: 100
}),
RuntimeEvent::AssetsPallet(pallet_assets::Event::Burned {
asset_id: 1,
owner: 1,
balance: 20
}),
RuntimeEvent::Balances(pallet_balances::Event::Burned { who: 1, amount: 100 }),
RuntimeEvent::XcmPallet(pallet_xcm::Event::Attempted {
outcome: Outcome::Complete { used: Weight::from_parts(400, 40) },
}),
RuntimeEvent::Balances(pallet_balances::Event::Burned { who: 1, amount: 20 }),
RuntimeEvent::XcmPallet(pallet_xcm::Event::FeesPaid {
paying: AccountIndex64 { index: 1, network: None }.into(),
fees: (Here, 20u128).into(),
}),
RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent {
origin: AccountIndex64 { index: 1, network: None }.into(),
destination: (Parent, Parachain(1000)).into(),
message: send_message.clone(),
message_id: fake_message_hash(&send_message),
}),
]
);
let local_xcm = dry_run_effects.local_xcm.unwrap();
let weight =
runtime_api.query_xcm_weight(H256::zero(), local_xcm.clone()).unwrap().unwrap();
assert_eq!(weight, Weight::from_parts(400, 40));
let execution_fees = runtime_api
.query_weight_to_asset_fee(
H256::zero(),
weight,
VersionedAssetId::from(AssetId(HereLocation::get())),
)
.unwrap()
.unwrap();
assert_eq!(execution_fees, 440);
let mut forwarded_xcms_iter = dry_run_effects.forwarded_xcms.into_iter();
let (destination, remote_messages) = forwarded_xcms_iter.next().unwrap();
let remote_message = &remote_messages[0];
let delivery_fees = runtime_api
.query_delivery_fees(H256::zero(), destination.clone(), remote_message.clone())
.unwrap()
.unwrap();
assert_eq!(delivery_fees, VersionedAssets::from((Here, 20u128)));
let remote_execution_weight = runtime_api
.query_xcm_weight(H256::zero(), remote_message.clone())
.unwrap()
.unwrap();
let remote_execution_fees = runtime_api
.query_weight_to_asset_fee(
H256::zero(),
remote_execution_weight,
VersionedAssetId::from(AssetId(HereLocation::get())),
)
.unwrap()
.unwrap();
assert_eq!(remote_execution_fees, 550);
});
}
#[test]
fn dry_run_reserve_asset_transfer() {
let _ = env_logger::builder().is_test(true).try_init();
let who = 1; let balances = vec![(who, DeliveryFees::get() + ExistentialDeposit::get())];
let assets = vec![(1, who, 100)]; new_test_ext_with_balances_and_assets(balances, assets).execute_with(|| {
let client = TestClient;
let runtime_api = client.runtime_api();
let call = RuntimeCall::XcmPallet(pallet_xcm::Call::transfer_assets {
dest: Box::new(VersionedLocation::from((Parent, Parachain(1000)))),
beneficiary: Box::new(VersionedLocation::from(AccountId32 {
id: [0u8; 32],
network: None,
})),
assets: Box::new(VersionedAssets::from((Parent, 100u128))),
fee_asset_item: 0,
weight_limit: Unlimited,
});
let origin = OriginCaller::system(RawOrigin::Signed(who));
let dry_run_effects =
runtime_api.dry_run_call(H256::zero(), origin, call).unwrap().unwrap();
assert_eq!(
dry_run_effects.local_xcm,
Some(VersionedXcm::from(
Xcm::builder_unsafe()
.withdraw_asset((Parent, 100u128))
.burn_asset((Parent, 100u128))
.build()
)),
);
let send_destination = Location::new(1, Parachain(1000));
let send_message = Xcm::<()>::builder_unsafe()
.withdraw_asset((Parent, 100u128))
.clear_origin()
.buy_execution((Parent, 100u128), Unlimited)
.deposit_asset(AllCounted(1), [0u8; 32])
.build();
assert_eq!(
dry_run_effects.forwarded_xcms,
vec![(
VersionedLocation::from(send_destination.clone()),
vec![VersionedXcm::from(send_message.clone())],
),],
);
assert_eq!(
dry_run_effects.emitted_events,
vec![
RuntimeEvent::AssetsPallet(pallet_assets::Event::Burned {
asset_id: 1,
owner: 1,
balance: 100
}),
RuntimeEvent::XcmPallet(pallet_xcm::Event::Attempted {
outcome: Outcome::Complete { used: Weight::from_parts(200, 20) }
}),
RuntimeEvent::Balances(pallet_balances::Event::Burned { who: 1, amount: 20 }),
RuntimeEvent::XcmPallet(pallet_xcm::Event::FeesPaid {
paying: AccountIndex64 { index: 1, network: None }.into(),
fees: (Here, 20u128).into()
}),
RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent {
origin: AccountIndex64 { index: 1, network: None }.into(),
destination: send_destination.clone(),
message: send_message.clone(),
message_id: fake_message_hash(&send_message),
}),
]
);
});
}
#[test]
fn dry_run_xcm() {
let _ = env_logger::builder().is_test(true).try_init();
let who = 1; let transfer_amount = 100u128;
let inner_xcm = Xcm::<()>::builder_unsafe()
.buy_execution((Here, 1u128), Unlimited) .deposit_asset(AllCounted(1), [0u8; 32])
.build();
let xcm_to_weigh = Xcm::<RuntimeCall>::builder_unsafe()
.withdraw_asset((Here, transfer_amount))
.clear_origin()
.buy_execution((Here, transfer_amount), Unlimited)
.deposit_reserve_asset(AllCounted(1), (Parent, Parachain(2100)), inner_xcm.clone())
.build();
let client = TestClient;
let runtime_api = client.runtime_api();
let xcm_weight = runtime_api
.query_xcm_weight(H256::zero(), VersionedXcm::from(xcm_to_weigh.clone().into()))
.unwrap()
.unwrap();
let execution_fees = runtime_api
.query_weight_to_asset_fee(
H256::zero(),
xcm_weight,
VersionedAssetId::from(AssetId(Here.into())),
)
.unwrap()
.unwrap();
let xcm = Xcm::<RuntimeCall>::builder_unsafe()
.withdraw_asset((Here, transfer_amount + execution_fees))
.clear_origin()
.buy_execution((Here, execution_fees), Unlimited)
.deposit_reserve_asset(AllCounted(1), (Parent, Parachain(2100)), inner_xcm.clone())
.build();
let balances = vec![(
who,
transfer_amount + execution_fees + DeliveryFees::get() + ExistentialDeposit::get(),
)];
new_test_ext_with_balances(balances).execute_with(|| {
let dry_run_effects = runtime_api
.dry_run_xcm(
H256::zero(),
VersionedLocation::from([AccountIndex64 { index: 1, network: None }]),
VersionedXcm::from(xcm),
)
.unwrap()
.unwrap();
assert_eq!(
dry_run_effects.forwarded_xcms,
vec![(
VersionedLocation::from((Parent, Parachain(2100))),
vec![VersionedXcm::from(
Xcm::<()>::builder_unsafe()
.reserve_asset_deposited((
(Parent, Parachain(2000)),
transfer_amount + execution_fees - DeliveryFees::get()
))
.clear_origin()
.buy_execution((Here, 1u128), Unlimited)
.deposit_asset(AllCounted(1), [0u8; 32])
.build()
)],
),]
);
assert_eq!(
dry_run_effects.emitted_events,
vec![
RuntimeEvent::Balances(pallet_balances::Event::Burned { who: 1, amount: 540 }),
RuntimeEvent::System(frame_system::Event::NewAccount { account: 2100 }),
RuntimeEvent::Balances(pallet_balances::Event::Endowed {
account: 2100,
free_balance: 520
}),
RuntimeEvent::Balances(pallet_balances::Event::Minted { who: 2100, amount: 520 }),
]
);
});
}