mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 05:11:02 +00:00
pallet-xcm: add new extrinsic for asset transfers using explicit XCM transfer types (#3695)
# Description Add `transfer_assets_using()` for transferring assets from local chain to destination chain using explicit XCM transfer types such as: - `TransferType::LocalReserve`: transfer assets to sovereign account of destination chain and forward a notification XCM to `dest` to mint and deposit reserve-based assets to `beneficiary`. - `TransferType::DestinationReserve`: burn local assets and forward a notification to `dest` chain to withdraw the reserve assets from this chain's sovereign account and deposit them to `beneficiary`. - `TransferType::RemoteReserve(reserve)`: burn local assets, forward XCM to `reserve` chain to move reserves from this chain's SA to `dest` chain's SA, and forward another XCM to `dest` to mint and deposit reserve-based assets to `beneficiary`. Typically the remote `reserve` is Asset Hub. - `TransferType::Teleport`: burn local assets and forward XCM to `dest` chain to mint/teleport assets and deposit them to `beneficiary`. By default, an asset's reserve is its origin chain. But sometimes we may want to explicitly use another chain as reserve (as long as allowed by runtime `IsReserve` filter). This is very helpful for transferring assets with multiple configured reserves (such as Asset Hub ForeignAssets), when the transfer strictly depends on the used reserve. E.g. For transferring Foreign Assets over a bridge, Asset Hub must be used as the reserve location. # Example usage scenarios ## Transfer bridged ethereum ERC20-tokenX between ecosystem parachains. ERC20-tokenX is registered on AssetHub as a ForeignAsset by the Polkadot<>Ethereum bridge (Snowbridge). Its asset_id is something like `(parents:2, (GlobalConsensus(Ethereum), Address(tokenX_contract)))`. Its _original_ reserve is Ethereum (only we can't use Ethereum as a reserve in local transfers); but, since tokenX is also registered on AssetHub as a ForeignAsset, we can use AssetHub as a reserve. With this PR we can transfer tokenX from ParaA to ParaB while using AssetHub as a reserve. ## Transfer AssetHub ForeignAssets between parachains AssetA created on ParaA but also registered as foreign asset on Asset Hub. Can use AssetHub as a reserve. And all of the above can be done while still controlling transfer type for `fees` so mixing assets in same transfer is supported. # Tests Added integration tests for showcasing: - transferring local (not bridged) assets from parachain over bridge using local Asset Hub reserve, - transferring foreign assets from parachain to Asset Hub, - transferring foreign assets from Asset Hub to parachain, - transferring foreign assets from parachain to parachain using local Asset Hub reserve. --------- Co-authored-by: Branislav Kontur <bkontur@gmail.com> Co-authored-by: command-bot <>
This commit is contained in:
+2
-1
@@ -25,6 +25,7 @@ mod imports {
|
||||
prelude::{AccountId32 as AccountId32Junction, *},
|
||||
v3::{self, NetworkId::Westend as WestendId},
|
||||
};
|
||||
pub use xcm_executor::traits::TransferType;
|
||||
|
||||
// Cumulus
|
||||
pub use emulated_integration_tests_common::{
|
||||
@@ -46,7 +47,7 @@ mod imports {
|
||||
bridge_hub_rococo_emulated_chain::{
|
||||
genesis::ED as BRIDGE_HUB_ROCOCO_ED, BridgeHubRococoParaPallet as BridgeHubRococoPallet,
|
||||
},
|
||||
penpal_emulated_chain::PenpalAParaPallet as PenpalAPallet,
|
||||
penpal_emulated_chain::{PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner},
|
||||
rococo_emulated_chain::{genesis::ED as ROCOCO_ED, RococoRelayPallet as RococoPallet},
|
||||
AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver,
|
||||
AssetHubRococoParaSender as AssetHubRococoSender, AssetHubWestendPara as AssetHubWestend,
|
||||
|
||||
+162
-4
@@ -31,6 +31,73 @@ fn send_asset_from_asset_hub_rococo_to_asset_hub_westend(id: Location, amount: u
|
||||
assert_bridge_hub_westend_message_received();
|
||||
}
|
||||
|
||||
fn send_asset_from_penpal_rococo_through_local_asset_hub_to_westend_asset_hub(
|
||||
id: Location,
|
||||
transfer_amount: u128,
|
||||
) {
|
||||
let destination = asset_hub_westend_location();
|
||||
let local_asset_hub: Location = PenpalA::sibling_location_of(AssetHubRococo::para_id());
|
||||
let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(
|
||||
AssetHubRococo::sibling_location_of(PenpalA::para_id()),
|
||||
);
|
||||
let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus(
|
||||
Westend,
|
||||
AssetHubWestend::para_id(),
|
||||
);
|
||||
|
||||
// fund the AHR's SA on BHR for paying bridge transport fees
|
||||
BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), 10_000_000_000_000u128);
|
||||
|
||||
// set XCM versions
|
||||
PenpalA::force_xcm_version(local_asset_hub.clone(), XCM_VERSION);
|
||||
AssetHubRococo::force_xcm_version(destination.clone(), XCM_VERSION);
|
||||
BridgeHubRococo::force_xcm_version(bridge_hub_westend_location(), XCM_VERSION);
|
||||
|
||||
// send message over bridge
|
||||
assert_ok!(PenpalA::execute_with(|| {
|
||||
let signed_origin = <PenpalA as Chain>::RuntimeOrigin::signed(PenpalASender::get());
|
||||
let beneficiary: Location =
|
||||
AccountId32Junction { network: None, id: AssetHubWestendReceiver::get().into() }.into();
|
||||
let assets: Assets = (id.clone(), transfer_amount).into();
|
||||
let fees_id: AssetId = id.into();
|
||||
|
||||
<PenpalA as PenpalAPallet>::PolkadotXcm::transfer_assets_using_type(
|
||||
signed_origin,
|
||||
bx!(destination.into()),
|
||||
bx!(beneficiary.into()),
|
||||
bx!(assets.clone().into()),
|
||||
bx!(TransferType::RemoteReserve(local_asset_hub.clone().into())),
|
||||
bx!(fees_id.into()),
|
||||
bx!(TransferType::RemoteReserve(local_asset_hub.into())),
|
||||
WeightLimit::Unlimited,
|
||||
)
|
||||
}));
|
||||
AssetHubRococo::execute_with(|| {
|
||||
type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
|
||||
assert_expected_events!(
|
||||
AssetHubRococo,
|
||||
vec![
|
||||
// Amount to reserve transfer is withdrawn from Penpal's sovereign account
|
||||
RuntimeEvent::Balances(
|
||||
pallet_balances::Event::Burned { who, amount }
|
||||
) => {
|
||||
who: *who == sov_penpal_on_ahr.clone().into(),
|
||||
amount: *amount == transfer_amount,
|
||||
},
|
||||
// Amount deposited in AHW's sovereign account
|
||||
RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => {
|
||||
who: *who == sov_ahw_on_ahr.clone().into(),
|
||||
},
|
||||
RuntimeEvent::XcmpQueue(
|
||||
cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }
|
||||
) => {},
|
||||
]
|
||||
);
|
||||
});
|
||||
assert_bridge_hub_rococo_message_accepted(true);
|
||||
assert_bridge_hub_westend_message_received();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_rocs_from_asset_hub_rococo_to_asset_hub_westend() {
|
||||
let roc_at_asset_hub_rococo: v3::Location = v3::Parent.into();
|
||||
@@ -45,7 +112,7 @@ fn send_rocs_from_asset_hub_rococo_to_asset_hub_westend() {
|
||||
vec![],
|
||||
);
|
||||
let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus(
|
||||
NetworkId::Westend,
|
||||
Westend,
|
||||
AssetHubWestend::para_id(),
|
||||
);
|
||||
|
||||
@@ -135,7 +202,7 @@ fn send_rocs_from_asset_hub_rococo_to_asset_hub_westend() {
|
||||
assert!(sender_rocs_before > sender_rocs_after);
|
||||
// Receiver's balance is increased
|
||||
assert!(receiver_rocs_after > receiver_rocs_before);
|
||||
// Reserve balance is reduced by sent amount
|
||||
// Reserve balance is increased by sent amount
|
||||
assert_eq!(rocs_in_reserve_on_ahr_after, rocs_in_reserve_on_ahr_before + amount);
|
||||
}
|
||||
|
||||
@@ -144,7 +211,7 @@ fn send_wnds_from_asset_hub_rococo_to_asset_hub_westend() {
|
||||
let prefund_amount = 10_000_000_000_000u128;
|
||||
let wnd_at_asset_hub_rococo =
|
||||
v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Westend)]);
|
||||
let owner: AccountId = AssetHubWestend::account_id_of(ALICE);
|
||||
let owner: AccountId = AssetHubRococo::account_id_of(ALICE);
|
||||
AssetHubRococo::force_create_foreign_asset(
|
||||
wnd_at_asset_hub_rococo,
|
||||
owner,
|
||||
@@ -155,7 +222,7 @@ fn send_wnds_from_asset_hub_rococo_to_asset_hub_westend() {
|
||||
|
||||
// fund the AHR's SA on AHW with the WND tokens held in reserve
|
||||
let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus(
|
||||
NetworkId::Rococo,
|
||||
Rococo,
|
||||
AssetHubRococo::para_id(),
|
||||
);
|
||||
AssetHubWestend::fund_accounts(vec![(sov_ahr_on_ahw.clone(), prefund_amount)]);
|
||||
@@ -217,3 +284,94 @@ fn send_wnds_from_asset_hub_rococo_to_asset_hub_westend() {
|
||||
// Reserve balance is reduced by sent amount
|
||||
assert_eq!(wnds_in_reserve_on_ahw_after, wnds_in_reserve_on_ahw_before - amount_to_send);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_rocs_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_westend() {
|
||||
let roc_at_rococo_parachains: v3::Location = v3::Parent.into();
|
||||
let roc_at_asset_hub_westend =
|
||||
v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Rococo)]);
|
||||
let roc_at_rococo_parachains_latest: Location = roc_at_rococo_parachains.try_into().unwrap();
|
||||
let owner: AccountId = AssetHubWestend::account_id_of(ALICE);
|
||||
AssetHubWestend::force_create_foreign_asset(
|
||||
roc_at_asset_hub_westend,
|
||||
owner,
|
||||
true,
|
||||
ASSET_MIN_BALANCE,
|
||||
vec![],
|
||||
);
|
||||
let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus(
|
||||
Westend,
|
||||
AssetHubWestend::para_id(),
|
||||
);
|
||||
|
||||
let amount = ASSET_HUB_ROCOCO_ED * 10_000_000;
|
||||
let penpal_location = AssetHubRococo::sibling_location_of(PenpalA::para_id());
|
||||
let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location);
|
||||
// fund Penpal's sovereign account on AssetHub
|
||||
AssetHubRococo::fund_accounts(vec![(sov_penpal_on_ahr.into(), amount * 2)]);
|
||||
// fund Penpal's sender account
|
||||
PenpalA::mint_foreign_asset(
|
||||
<PenpalA as Chain>::RuntimeOrigin::signed(PenpalAssetOwner::get()),
|
||||
roc_at_rococo_parachains,
|
||||
PenpalASender::get(),
|
||||
amount * 2,
|
||||
);
|
||||
|
||||
let rocs_in_reserve_on_ahr_before =
|
||||
<AssetHubRococo as Chain>::account_data_of(sov_ahw_on_ahr.clone()).free;
|
||||
let sender_rocs_before = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(
|
||||
roc_at_rococo_parachains.into(),
|
||||
&PenpalASender::get(),
|
||||
)
|
||||
});
|
||||
let receiver_rocs_before = AssetHubWestend::execute_with(|| {
|
||||
type Assets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
|
||||
<Assets as Inspect<_>>::balance(roc_at_asset_hub_westend, &AssetHubWestendReceiver::get())
|
||||
});
|
||||
send_asset_from_penpal_rococo_through_local_asset_hub_to_westend_asset_hub(
|
||||
roc_at_rococo_parachains_latest,
|
||||
amount,
|
||||
);
|
||||
|
||||
AssetHubWestend::execute_with(|| {
|
||||
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
|
||||
assert_expected_events!(
|
||||
AssetHubWestend,
|
||||
vec![
|
||||
// issue ROCs on AHW
|
||||
RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => {
|
||||
asset_id: *asset_id == roc_at_rococo_parachains,
|
||||
owner: *owner == AssetHubWestendReceiver::get(),
|
||||
},
|
||||
// message processed successfully
|
||||
RuntimeEvent::MessageQueue(
|
||||
pallet_message_queue::Event::Processed { success: true, .. }
|
||||
) => {},
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
let sender_rocs_after = PenpalA::execute_with(|| {
|
||||
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(
|
||||
roc_at_rococo_parachains.into(),
|
||||
&PenpalASender::get(),
|
||||
)
|
||||
});
|
||||
let receiver_rocs_after = AssetHubWestend::execute_with(|| {
|
||||
type Assets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
|
||||
<Assets as Inspect<_>>::balance(roc_at_asset_hub_westend, &AssetHubWestendReceiver::get())
|
||||
});
|
||||
let rocs_in_reserve_on_ahr_after =
|
||||
<AssetHubRococo as Chain>::account_data_of(sov_ahw_on_ahr.clone()).free;
|
||||
|
||||
// Sender's balance is reduced
|
||||
assert!(sender_rocs_after < sender_rocs_before);
|
||||
// Receiver's balance is increased
|
||||
assert!(receiver_rocs_after > receiver_rocs_before);
|
||||
// Reserve balance is increased by sent amount (less fess)
|
||||
assert!(rocs_in_reserve_on_ahr_after > rocs_in_reserve_on_ahr_before);
|
||||
assert!(rocs_in_reserve_on_ahr_after <= rocs_in_reserve_on_ahr_before + amount);
|
||||
}
|
||||
|
||||
+2
-4
@@ -381,10 +381,8 @@ fn send_token_from_ethereum_to_penpal() {
|
||||
#[test]
|
||||
fn send_weth_asset_from_asset_hub_to_ethereum() {
|
||||
use asset_hub_rococo_runtime::xcm_config::bridging::to_ethereum::DefaultBridgeHubEthereumBaseFee;
|
||||
let assethub_sovereign = BridgeHubRococo::sovereign_account_id_of(Location::new(
|
||||
1,
|
||||
[Parachain(AssetHubRococo::para_id().into())],
|
||||
));
|
||||
let assethub_location = BridgeHubRococo::sibling_location_of(AssetHubRococo::para_id());
|
||||
let assethub_sovereign = BridgeHubRococo::sovereign_account_id_of(assethub_location);
|
||||
|
||||
AssetHubRococo::force_default_xcm_version(Some(XCM_VERSION));
|
||||
BridgeHubRococo::force_default_xcm_version(Some(XCM_VERSION));
|
||||
|
||||
+4
-1
@@ -26,6 +26,7 @@ mod imports {
|
||||
v3,
|
||||
v4::NetworkId::Rococo as RococoId,
|
||||
};
|
||||
pub use xcm_executor::traits::TransferType;
|
||||
|
||||
// Cumulus
|
||||
pub use emulated_integration_tests_common::{
|
||||
@@ -48,13 +49,15 @@ mod imports {
|
||||
genesis::ED as BRIDGE_HUB_WESTEND_ED,
|
||||
BridgeHubWestendParaPallet as BridgeHubWestendPallet,
|
||||
},
|
||||
penpal_emulated_chain::{PenpalAssetOwner, PenpalBParaPallet as PenpalBPallet},
|
||||
westend_emulated_chain::WestendRelayPallet as WestendPallet,
|
||||
AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver,
|
||||
AssetHubRococoParaSender as AssetHubRococoSender, AssetHubWestendPara as AssetHubWestend,
|
||||
AssetHubWestendParaReceiver as AssetHubWestendReceiver,
|
||||
AssetHubWestendParaSender as AssetHubWestendSender, BridgeHubRococoPara as BridgeHubRococo,
|
||||
BridgeHubWestendPara as BridgeHubWestend,
|
||||
BridgeHubWestendParaSender as BridgeHubWestendSender, WestendRelay as Westend,
|
||||
BridgeHubWestendParaSender as BridgeHubWestendSender, PenpalBPara as PenpalB,
|
||||
PenpalBParaSender as PenpalBSender, WestendRelay as Westend,
|
||||
};
|
||||
|
||||
pub const ASSET_MIN_BALANCE: u128 = 1000;
|
||||
|
||||
+160
-2
@@ -30,6 +30,73 @@ fn send_asset_from_asset_hub_westend_to_asset_hub_rococo(id: Location, amount: u
|
||||
assert_bridge_hub_rococo_message_received();
|
||||
}
|
||||
|
||||
fn send_asset_from_penpal_westend_through_local_asset_hub_to_rococo_asset_hub(
|
||||
id: Location,
|
||||
transfer_amount: u128,
|
||||
) {
|
||||
let destination = asset_hub_rococo_location();
|
||||
let local_asset_hub: Location = PenpalB::sibling_location_of(AssetHubWestend::para_id());
|
||||
let sov_penpal_on_ahw = AssetHubWestend::sovereign_account_id_of(
|
||||
AssetHubWestend::sibling_location_of(PenpalB::para_id()),
|
||||
);
|
||||
let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus(
|
||||
Rococo,
|
||||
AssetHubRococo::para_id(),
|
||||
);
|
||||
|
||||
// fund the AHW's SA on BHW for paying bridge transport fees
|
||||
BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), 10_000_000_000_000u128);
|
||||
|
||||
// set XCM versions
|
||||
PenpalB::force_xcm_version(local_asset_hub.clone(), XCM_VERSION);
|
||||
AssetHubWestend::force_xcm_version(destination.clone(), XCM_VERSION);
|
||||
BridgeHubWestend::force_xcm_version(bridge_hub_rococo_location(), XCM_VERSION);
|
||||
|
||||
// send message over bridge
|
||||
assert_ok!(PenpalB::execute_with(|| {
|
||||
let signed_origin = <PenpalB as Chain>::RuntimeOrigin::signed(PenpalBSender::get());
|
||||
let beneficiary: Location =
|
||||
AccountId32Junction { network: None, id: AssetHubRococoReceiver::get().into() }.into();
|
||||
let assets: Assets = (id.clone(), transfer_amount).into();
|
||||
let fees_id: AssetId = id.into();
|
||||
|
||||
<PenpalB as PenpalBPallet>::PolkadotXcm::transfer_assets_using_type(
|
||||
signed_origin,
|
||||
bx!(destination.into()),
|
||||
bx!(beneficiary.into()),
|
||||
bx!(assets.into()),
|
||||
bx!(TransferType::RemoteReserve(local_asset_hub.clone().into())),
|
||||
bx!(fees_id.into()),
|
||||
bx!(TransferType::RemoteReserve(local_asset_hub.into())),
|
||||
WeightLimit::Unlimited,
|
||||
)
|
||||
}));
|
||||
AssetHubWestend::execute_with(|| {
|
||||
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
|
||||
assert_expected_events!(
|
||||
AssetHubWestend,
|
||||
vec![
|
||||
// Amount to reserve transfer is withdrawn from Penpal's sovereign account
|
||||
RuntimeEvent::Balances(
|
||||
pallet_balances::Event::Burned { who, amount }
|
||||
) => {
|
||||
who: *who == sov_penpal_on_ahw.clone().into(),
|
||||
amount: *amount == transfer_amount,
|
||||
},
|
||||
// Amount deposited in AHR's sovereign account
|
||||
RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => {
|
||||
who: *who == sov_ahr_on_ahw.clone().into(),
|
||||
},
|
||||
RuntimeEvent::XcmpQueue(
|
||||
cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }
|
||||
) => {},
|
||||
]
|
||||
);
|
||||
});
|
||||
assert_bridge_hub_westend_message_accepted(true);
|
||||
assert_bridge_hub_rococo_message_received();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_wnds_from_asset_hub_westend_to_asset_hub_rococo() {
|
||||
let wnd_at_asset_hub_westend: Location = Parent.into();
|
||||
@@ -44,7 +111,7 @@ fn send_wnds_from_asset_hub_westend_to_asset_hub_rococo() {
|
||||
vec![],
|
||||
);
|
||||
let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus(
|
||||
NetworkId::Rococo,
|
||||
Rococo,
|
||||
AssetHubRococo::para_id(),
|
||||
);
|
||||
|
||||
@@ -153,7 +220,7 @@ fn send_rocs_from_asset_hub_westend_to_asset_hub_rococo() {
|
||||
|
||||
// fund the AHW's SA on AHR with the ROC tokens held in reserve
|
||||
let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus(
|
||||
NetworkId::Westend,
|
||||
Westend,
|
||||
AssetHubWestend::para_id(),
|
||||
);
|
||||
AssetHubRococo::fund_accounts(vec![(sov_ahw_on_ahr.clone(), prefund_amount)]);
|
||||
@@ -215,3 +282,94 @@ fn send_rocs_from_asset_hub_westend_to_asset_hub_rococo() {
|
||||
// Reserve balance is reduced by sent amount
|
||||
assert_eq!(rocs_in_reserve_on_ahr_after, rocs_in_reserve_on_ahr_before - amount_to_send);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_wnds_from_penpal_westend_through_asset_hub_westend_to_asset_hub_rococo() {
|
||||
let wnd_at_westend_parachains: v3::Location = v3::Parent.into();
|
||||
let wnd_at_asset_hub_rococo =
|
||||
v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Westend)]);
|
||||
let wnd_at_westend_parachains_latest: Location = wnd_at_westend_parachains.try_into().unwrap();
|
||||
let owner: AccountId = AssetHubRococo::account_id_of(ALICE);
|
||||
AssetHubRococo::force_create_foreign_asset(
|
||||
wnd_at_asset_hub_rococo,
|
||||
owner,
|
||||
true,
|
||||
ASSET_MIN_BALANCE,
|
||||
vec![],
|
||||
);
|
||||
let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus(
|
||||
Rococo,
|
||||
AssetHubRococo::para_id(),
|
||||
);
|
||||
|
||||
let amount = ASSET_HUB_WESTEND_ED * 10_000_000;
|
||||
let penpal_location = AssetHubWestend::sibling_location_of(PenpalB::para_id());
|
||||
let sov_penpal_on_ahw = AssetHubWestend::sovereign_account_id_of(penpal_location);
|
||||
// fund Penpal's sovereign account on AssetHub
|
||||
AssetHubWestend::fund_accounts(vec![(sov_penpal_on_ahw.into(), amount * 2)]);
|
||||
// fund Penpal's sender account
|
||||
PenpalB::mint_foreign_asset(
|
||||
<PenpalB as Chain>::RuntimeOrigin::signed(PenpalAssetOwner::get()),
|
||||
wnd_at_westend_parachains,
|
||||
PenpalBSender::get(),
|
||||
amount * 2,
|
||||
);
|
||||
|
||||
let wnds_in_reserve_on_ahw_before =
|
||||
<AssetHubWestend as Chain>::account_data_of(sov_ahr_on_ahw.clone()).free;
|
||||
let sender_wnds_before = PenpalB::execute_with(|| {
|
||||
type ForeignAssets = <PenpalB as PenpalBPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(
|
||||
wnd_at_westend_parachains.into(),
|
||||
&PenpalBSender::get(),
|
||||
)
|
||||
});
|
||||
let receiver_wnds_before = AssetHubRococo::execute_with(|| {
|
||||
type Assets = <AssetHubRococo as AssetHubRococoPallet>::ForeignAssets;
|
||||
<Assets as Inspect<_>>::balance(wnd_at_asset_hub_rococo, &AssetHubRococoReceiver::get())
|
||||
});
|
||||
send_asset_from_penpal_westend_through_local_asset_hub_to_rococo_asset_hub(
|
||||
wnd_at_westend_parachains_latest,
|
||||
amount,
|
||||
);
|
||||
|
||||
AssetHubRococo::execute_with(|| {
|
||||
type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
|
||||
assert_expected_events!(
|
||||
AssetHubRococo,
|
||||
vec![
|
||||
// issue WNDs on AHR
|
||||
RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => {
|
||||
asset_id: *asset_id == wnd_at_westend_parachains,
|
||||
owner: *owner == AssetHubRococoReceiver::get(),
|
||||
},
|
||||
// message processed successfully
|
||||
RuntimeEvent::MessageQueue(
|
||||
pallet_message_queue::Event::Processed { success: true, .. }
|
||||
) => {},
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
let sender_wnds_after = PenpalB::execute_with(|| {
|
||||
type ForeignAssets = <PenpalB as PenpalBPallet>::ForeignAssets;
|
||||
<ForeignAssets as Inspect<_>>::balance(
|
||||
wnd_at_westend_parachains.into(),
|
||||
&PenpalBSender::get(),
|
||||
)
|
||||
});
|
||||
let receiver_wnds_after = AssetHubRococo::execute_with(|| {
|
||||
type Assets = <AssetHubRococo as AssetHubRococoPallet>::ForeignAssets;
|
||||
<Assets as Inspect<_>>::balance(wnd_at_asset_hub_rococo, &AssetHubRococoReceiver::get())
|
||||
});
|
||||
let wnds_in_reserve_on_ahw_after =
|
||||
<AssetHubWestend as Chain>::account_data_of(sov_ahr_on_ahw.clone()).free;
|
||||
|
||||
// Sender's balance is reduced
|
||||
assert!(sender_wnds_after < sender_wnds_before);
|
||||
// Receiver's balance is increased
|
||||
assert!(receiver_wnds_after > receiver_wnds_before);
|
||||
// Reserve balance is increased by sent amount (less fess)
|
||||
assert!(wnds_in_reserve_on_ahw_after > wnds_in_reserve_on_ahw_before);
|
||||
assert!(wnds_in_reserve_on_ahw_after <= wnds_in_reserve_on_ahw_before + amount);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user