fix: Complete snowbridge pezpallet rebrand and critical bug fixes

- snowbridge-pezpallet-* → pezsnowbridge-pezpallet-* (201 refs)
- pallet/ directories → pezpallet/ (4 locations)
- Fixed pezpallet.rs self-include recursion bug
- Fixed sc-chain-spec hardcoded crate name in derive macro
- Reverted .pezpallet_by_name() to .pallet_by_name() (subxt API)
- Added BizinikiwiConfig type alias for zombienet tests
- Deleted obsolete session state files

Verified: pezsnowbridge-pezpallet-*, pezpallet-staking,
pezpallet-staking-async, pezframe-benchmarking-cli all pass cargo check
This commit is contained in:
2025-12-16 09:57:23 +03:00
parent eea003e14d
commit 3139ffa25e
3022 changed files with 42157 additions and 23579 deletions
@@ -0,0 +1,89 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#[cfg(test)]
mod imports {
// Bizinikiwi
pub(crate) use codec::Encode;
pub(crate) use pezframe_support::{assert_err, assert_ok, pezpallet_prelude::DispatchResult};
pub(crate) use pezsp_runtime::DispatchError;
// Pezkuwi
pub(crate) use xcm::{
latest::{ParentThen, PEZKUWICHAIN_GENESIS_HASH, ZAGROS_GENESIS_HASH},
prelude::{AccountId32 as AccountId32Junction, *},
};
pub(crate) use xcm_builder::ExternalConsensusLocationsConverterFor;
pub(crate) use xcm_executor::traits::TransferType;
// Pezcumulus
pub(crate) use emulated_integration_tests_common::{
accounts::ALICE,
impls::Inspect,
test_dry_run_transfer_across_pk_bridge, test_relay_is_trusted_teleporter,
test_teyrchain_is_trusted_teleporter, test_teyrchain_is_trusted_teleporter_for_relay,
xcm_pez_emulator::{
assert_expected_events, bx, Chain, RelayChain as Relay, TestExt, Teyrchain as Para,
},
xcm_helpers::xcm_transact_paid_execution,
ASSETS_PALLET_ID, USDT_ID,
};
pub(crate) use pezkuwichain_zagros_system_emulated_network::{
asset_hub_pezkuwichain_emulated_chain::{
asset_hub_pezkuwichain_runtime::{
xcm_config::TreasuryAccount, ForeignAssetReserveData,
},
genesis::ED as ASSET_HUB_PEZKUWICHAIN_ED,
AssetHubPezkuwichainParaPallet as AssetHubPezkuwichainPallet,
},
asset_hub_zagros_emulated_chain::{
genesis::{AssetHubZagrosAssetOwner, ED as ASSET_HUB_ZAGROS_ED},
AssetHubZagrosParaPallet as AssetHubZagrosPallet,
},
pezbridge_hub_pezkuwichain_emulated_chain::{
genesis::ED as BRIDGE_HUB_PEZKUWICHAIN_ED, BridgeHubPezkuwichainExistentialDeposit,
BridgeHubPezkuwichainParaPallet as BridgeHubPezkuwichainPallet,
},
pez_penpal_emulated_chain::{
pez_penpal_runtime::xcm_config::{
CustomizableAssetFromSystemAssetHub as PenpalCustomizableAssetFromSystemAssetHub,
UniversalLocation as PenpalUniversalLocation,
},
PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner,
},
pezkuwichain_emulated_chain::{
genesis::ED as PEZKUWICHAIN_ED, PezkuwichainRelayPallet as PezkuwichainPallet,
},
AssetHubPezkuwichainPara as AssetHubPezkuwichain,
AssetHubPezkuwichainParaReceiver as AssetHubPezkuwichainReceiver,
AssetHubPezkuwichainParaSender as AssetHubPezkuwichainSender,
AssetHubZagrosPara as AssetHubZagros, AssetHubZagrosParaReceiver as AssetHubZagrosReceiver,
AssetHubZagrosParaSender as AssetHubZagrosSender,
BridgeHubPezkuwichainPara as BridgeHubPezkuwichain,
BridgeHubPezkuwichainParaReceiver as BridgeHubPezkuwichainReceiver,
BridgeHubPezkuwichainParaSender as BridgeHubPezkuwichainSender,
BridgeHubZagrosPara as BridgeHubZagros, PenpalAPara as PenpalA,
PenpalAParaSender as PenpalASender, PezkuwichainRelay as Pezkuwichain,
PezkuwichainRelayReceiver as PezkuwichainReceiver,
PezkuwichainRelaySender as PezkuwichainSender,
};
pub(crate) use teyrchains_common::AccountId;
pub(crate) const ASSET_ID: u32 = 1;
pub(crate) const ASSET_MIN_BALANCE: u128 = 1000;
}
#[cfg(test)]
mod tests;
@@ -0,0 +1,617 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::tests::*;
fn send_assets_over_bridge<F: FnOnce()>(send_fn: F) {
// fund the AHR's SA on BHR for paying bridge delivery fees
BridgeHubPezkuwichain::fund_para_sovereign(
AssetHubPezkuwichain::para_id(),
10_000_000_000_000u128,
);
// set XCM versions
let local_asset_hub = PenpalA::sibling_location_of(AssetHubPezkuwichain::para_id());
PenpalA::force_xcm_version(local_asset_hub.clone(), XCM_VERSION);
AssetHubPezkuwichain::force_xcm_version(asset_hub_zagros_location(), XCM_VERSION);
BridgeHubPezkuwichain::force_xcm_version(bridge_hub_zagros_location(), XCM_VERSION);
// send message over bridge
send_fn();
// process and verify intermediary hops
assert_bridge_hub_pezkuwichain_message_accepted(true);
assert_bridge_hub_zagros_message_received();
}
fn set_up_rocs_for_penpal_pezkuwichain_through_ahr_to_ahw(
sender: &AccountId,
amount: u128,
) -> (Location, v5::Location) {
let roc_at_pezkuwichain_teyrchains = roc_at_ah_pezkuwichain();
let roc_at_asset_hub_zagros = bridged_roc_at_ah_zagros();
let reserves = vec![(asset_hub_pezkuwichain_global_location(), false).into()];
create_foreign_on_ah_zagros(roc_at_asset_hub_zagros.clone(), true, reserves);
let penpal_location = AssetHubPezkuwichain::sibling_location_of(PenpalA::para_id());
let sov_penpal_on_ahr = AssetHubPezkuwichain::sovereign_account_id_of(penpal_location);
// fund Penpal's sovereign account on AssetHub
AssetHubPezkuwichain::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_pezkuwichain_teyrchains.clone(),
sender.clone(),
amount * 2,
);
(roc_at_pezkuwichain_teyrchains, roc_at_asset_hub_zagros)
}
fn send_assets_from_penpal_pezkuwichain_through_pezkuwichain_ah_to_zagros_ah(
destination: Location,
assets: (Assets, TransferType),
fees: (AssetId, TransferType),
custom_xcm_on_dest: Xcm<()>,
) {
send_assets_over_bridge(|| {
let sov_penpal_on_ahr = AssetHubPezkuwichain::sovereign_account_id_of(
AssetHubPezkuwichain::sibling_location_of(PenpalA::para_id()),
);
// send message over bridge
assert_ok!(PenpalA::execute_with(|| {
let signed_origin = <PenpalA as Chain>::RuntimeOrigin::signed(PenpalASender::get());
<PenpalA as PenpalAPallet>::PezkuwiXcm::transfer_assets_using_type_and_then(
signed_origin,
bx!(destination.into()),
bx!(assets.0.into()),
bx!(assets.1),
bx!(fees.0.into()),
bx!(fees.1),
bx!(VersionedXcm::from(custom_xcm_on_dest)),
WeightLimit::Unlimited,
)
}));
// verify intermediary AH Pezkuwichain hop
AssetHubPezkuwichain::execute_with(|| {
type RuntimeEvent = <AssetHubPezkuwichain as Chain>::RuntimeEvent;
assert_expected_events!(
AssetHubPezkuwichain,
vec![
// Amount to reserve transfer is withdrawn from Penpal's sovereign account
RuntimeEvent::Balances(
pezpallet_balances::Event::Burned { who, .. }
) => {
who: *who == sov_penpal_on_ahr.clone().into(),
},
// Amount deposited in AHW's sovereign account
RuntimeEvent::Balances(pezpallet_balances::Event::Minted { who, .. }) => {
who: *who == TreasuryAccount::get(),
},
RuntimeEvent::XcmpQueue(
pezcumulus_pezpallet_xcmp_queue::Event::XcmpMessageSent { .. }
) => {},
]
);
});
});
}
#[test]
/// Test transfer of TYR from AssetHub Pezkuwichain to AssetHub Zagros.
fn send_roc_from_asset_hub_pezkuwichain_to_asset_hub_zagros() {
let amount = ASSET_HUB_PEZKUWICHAIN_ED * 1_000_000;
let sender = AssetHubPezkuwichainSender::get();
let receiver = AssetHubZagrosReceiver::get();
let roc_at_asset_hub_pezkuwichain = roc_at_ah_pezkuwichain();
let bridged_roc_at_asset_hub_zagros = bridged_roc_at_ah_zagros();
let reserves = vec![(asset_hub_pezkuwichain_global_location(), false).into()];
create_foreign_on_ah_zagros(bridged_roc_at_asset_hub_zagros.clone(), true, reserves);
set_up_pool_with_wnd_on_ah_zagros(bridged_roc_at_asset_hub_zagros.clone(), true);
let sov_ahw_on_ahr =
AssetHubPezkuwichain::sovereign_account_of_teyrchain_on_other_global_consensus(
ByGenesis(ZAGROS_GENESIS_HASH),
AssetHubZagros::para_id(),
);
let rocs_in_reserve_on_ahr_before =
<AssetHubPezkuwichain as Chain>::account_data_of(sov_ahw_on_ahr.clone()).free;
let sender_rocs_before = <AssetHubPezkuwichain as Chain>::account_data_of(sender.clone()).free;
let receiver_rocs_before =
foreign_balance_on_ah_zagros(bridged_roc_at_asset_hub_zagros.clone(), &receiver);
// send TYRs, use them for fees
send_assets_over_bridge(|| {
let destination = asset_hub_zagros_location();
let assets: Assets = (roc_at_asset_hub_pezkuwichain.clone(), amount).into();
let fee_idx = 0;
let transfer_type = TransferType::LocalReserve;
assert_ok!(send_assets_from_asset_hub_pezkuwichain(
destination,
assets,
fee_idx,
transfer_type
));
});
// verify expected events on final destination
let roc = Location::new(2, [GlobalConsensus(ByGenesis(PEZKUWICHAIN_GENESIS_HASH))]);
AssetHubZagros::execute_with(|| {
type RuntimeEvent = <AssetHubZagros as Chain>::RuntimeEvent;
assert_expected_events!(
AssetHubZagros,
vec![
// issue TYRs on AHW
RuntimeEvent::ForeignAssets(pezpallet_assets::Event::Issued { asset_id, owner, .. }) => {
asset_id: *asset_id == roc,
owner: owner == &receiver,
},
// message processed successfully
RuntimeEvent::MessageQueue(
pezpallet_message_queue::Event::Processed { success: true, .. }
) => {},
]
);
});
let sender_rocs_after = <AssetHubPezkuwichain as Chain>::account_data_of(sender.clone()).free;
let receiver_rocs_after =
foreign_balance_on_ah_zagros(bridged_roc_at_asset_hub_zagros, &receiver);
let rocs_in_reserve_on_ahr_after =
<AssetHubPezkuwichain as Chain>::account_data_of(sov_ahw_on_ahr.clone()).free;
// Sender's TYR balance is reduced
assert!(sender_rocs_before > sender_rocs_after);
// Receiver's TYR balance is increased
assert!(receiver_rocs_after > receiver_rocs_before);
// Reserve TYR balance is increased by sent amount
assert_eq!(rocs_in_reserve_on_ahr_after, rocs_in_reserve_on_ahr_before + amount);
}
#[test]
/// Send bridged assets "back" from AssetHub Pezkuwichain to AssetHub Zagros.
///
/// This mix of assets should cover the whole range:
/// - bridged native assets: TYR,
/// - bridged trust-based assets: USDT (exists only on Zagros, Pezkuwichain gets it from Zagros over
/// bridge),
/// - bridged foreign asset / double-bridged asset (other bridge / Snowfork): wETH (bridged from
/// Ethereum to Zagros over Snowbridge, then bridged over to Pezkuwichain through this bridge).
fn send_back_wnds_usdt_and_weth_from_asset_hub_pezkuwichain_to_asset_hub_zagros() {
let prefund_amount = 10_000_000_000_000u128;
let amount_to_send = ASSET_HUB_ZAGROS_ED * 1_000;
let sender = AssetHubPezkuwichainSender::get();
let receiver = AssetHubZagrosReceiver::get();
let wnd_at_asset_hub_pezkuwichain = bridged_wnd_at_ah_pezkuwichain();
let prefund_accounts = vec![(sender.clone(), prefund_amount)];
let reserves = vec![(asset_hub_zagros_location(), false).into()];
create_foreign_on_ah_pezkuwichain(
wnd_at_asset_hub_pezkuwichain.clone(),
true,
reserves,
prefund_accounts,
);
////////////////////////////////////////////////////////////
// Let's first send back just some ZGRs as a simple example
////////////////////////////////////////////////////////////
// fund the AHR's SA on AHW with the ZGR tokens held in reserve
let sov_ahr_on_ahw = AssetHubZagros::sovereign_account_of_teyrchain_on_other_global_consensus(
ByGenesis(PEZKUWICHAIN_GENESIS_HASH),
AssetHubPezkuwichain::para_id(),
);
AssetHubZagros::fund_accounts(vec![(sov_ahr_on_ahw.clone(), prefund_amount)]);
let wnds_in_reserve_on_ahw_before =
<AssetHubZagros as Chain>::account_data_of(sov_ahr_on_ahw.clone()).free;
assert_eq!(wnds_in_reserve_on_ahw_before, prefund_amount);
let sender_wnds_before =
foreign_balance_on_ah_pezkuwichain(wnd_at_asset_hub_pezkuwichain.clone(), &sender);
assert_eq!(sender_wnds_before, prefund_amount);
let receiver_wnds_before = <AssetHubZagros as Chain>::account_data_of(receiver.clone()).free;
// send back WNDs, use them for fees
send_assets_over_bridge(|| {
let destination = asset_hub_zagros_location();
let assets: Assets = (wnd_at_asset_hub_pezkuwichain.clone(), amount_to_send).into();
let fee_idx = 0;
let transfer_type = TransferType::DestinationReserve;
assert_ok!(send_assets_from_asset_hub_pezkuwichain(
destination,
assets,
fee_idx,
transfer_type
));
});
AssetHubZagros::execute_with(|| {
type RuntimeEvent = <AssetHubZagros as Chain>::RuntimeEvent;
assert_expected_events!(
AssetHubZagros,
vec![
// ZGR is withdrawn from AHR's SA on AHW
RuntimeEvent::Balances(
pezpallet_balances::Event::Burned { who, amount }
) => {
who: *who == sov_ahr_on_ahw,
amount: *amount == amount_to_send,
},
// ZGRs deposited to beneficiary
RuntimeEvent::Balances(pezpallet_balances::Event::Minted { who, .. }) => {
who: who == &receiver,
},
// message processed successfully
RuntimeEvent::MessageQueue(
pezpallet_message_queue::Event::Processed { success: true, .. }
) => {},
]
);
});
let sender_wnds_after =
foreign_balance_on_ah_pezkuwichain(wnd_at_asset_hub_pezkuwichain, &sender);
let receiver_wnds_after = <AssetHubZagros as Chain>::account_data_of(receiver.clone()).free;
let wnds_in_reserve_on_ahw_after =
<AssetHubZagros as Chain>::account_data_of(sov_ahr_on_ahw).free;
// Sender's balance is reduced
assert!(sender_wnds_before > sender_wnds_after);
// Receiver's balance is increased
assert!(receiver_wnds_after > receiver_wnds_before);
// Reserve balance is reduced by sent amount
assert_eq!(wnds_in_reserve_on_ahw_after, wnds_in_reserve_on_ahw_before - amount_to_send);
//////////////////////////////////////////////////////////////////
// Now let's send back over USDTs + wETH (and pay fees with USDT)
//////////////////////////////////////////////////////////////////
// wETH has same relative location on both Zagros and Pezkuwichain AssetHubs
let bridged_weth_at_ah = weth_at_asset_hubs();
let bridged_usdt_at_asset_hub_pezkuwichain = bridged_usdt_at_ah_pezkuwichain();
// set up destination chain AH Zagros:
// create a ZGR/USDT pool to be able to pay fees with USDT (USDT created in genesis)
set_up_pool_with_wnd_on_ah_zagros(usdt_at_ah_zagros(), false);
// prefund AHR's sovereign account on AHW to be able to withdraw USDT and wETH from reserves
let sov_ahr_on_ahw = AssetHubZagros::sovereign_account_of_teyrchain_on_other_global_consensus(
ByGenesis(PEZKUWICHAIN_GENESIS_HASH),
AssetHubPezkuwichain::para_id(),
);
let sov_ahw_on_ahr =
AssetHubPezkuwichain::sovereign_account_of_teyrchain_on_other_global_consensus(
ByGenesis(ZAGROS_GENESIS_HASH),
AssetHubZagros::para_id(),
);
AssetHubZagros::mint_asset(
<AssetHubZagros as Chain>::RuntimeOrigin::signed(AssetHubZagrosAssetOwner::get()),
USDT_ID,
sov_ahr_on_ahw.clone(),
amount_to_send * 2,
);
AssetHubZagros::mint_foreign_asset(
<AssetHubZagros as Chain>::RuntimeOrigin::signed(snowbridge_sovereign()),
bridged_weth_at_ah.clone(),
sov_ahr_on_ahw.clone(),
amount_to_send * 2,
);
AssetHubPezkuwichain::mint_foreign_asset(
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(sov_ahw_on_ahr.clone()),
bridged_weth_at_ah.clone(),
sov_ahr_on_ahw,
prefund_amount,
);
AssetHubPezkuwichain::mint_foreign_asset(
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(sov_ahw_on_ahr),
bridged_weth_at_ah.clone(),
sender.clone(),
prefund_amount,
);
// set up source chain AH Pezkuwichain:
// create wETH and USDT foreign assets on Pezkuwichain and prefund sender's account
let prefund_accounts = vec![(sender.clone(), amount_to_send * 2)];
let reserves = vec![(asset_hub_zagros_location(), false).into()];
create_foreign_on_ah_pezkuwichain(
bridged_usdt_at_asset_hub_pezkuwichain.clone(),
true,
reserves,
prefund_accounts,
);
// check balances before
let receiver_usdts_before = AssetHubZagros::execute_with(|| {
type Assets = <AssetHubZagros as AssetHubZagrosPallet>::Assets;
<Assets as Inspect<_>>::balance(USDT_ID, &receiver)
});
let receiver_weth_before = foreign_balance_on_ah_zagros(bridged_weth_at_ah.clone(), &receiver);
let usdt_id: AssetId =
Location::try_from(bridged_usdt_at_asset_hub_pezkuwichain).unwrap().into();
// send USDTs and wETHs
let assets: Assets = vec![
(usdt_id.clone(), amount_to_send).into(),
(Location::try_from(bridged_weth_at_ah.clone()).unwrap(), amount_to_send).into(),
]
.into();
// use USDT for fees
let fee = usdt_id;
// use the more involved transfer extrinsic
let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset {
assets: Wild(AllCounted(assets.len() as u32)),
beneficiary: AccountId32Junction { network: None, id: receiver.clone().into() }.into(),
}]);
assert_ok!(AssetHubPezkuwichain::execute_with(|| {
<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::PezkuwiXcm::transfer_assets_using_type_and_then(
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(sender.into()),
bx!(asset_hub_zagros_location().into()),
bx!(assets.into()),
bx!(TransferType::DestinationReserve),
bx!(fee.into()),
bx!(TransferType::DestinationReserve),
bx!(VersionedXcm::from(custom_xcm_on_dest)),
WeightLimit::Unlimited,
)
}));
// verify hops (also advances the message through the hops)
assert_bridge_hub_pezkuwichain_message_accepted(true);
assert_bridge_hub_zagros_message_received();
AssetHubZagros::execute_with(|| {
AssetHubZagros::assert_xcmp_queue_success(None);
});
let receiver_usdts_after = AssetHubZagros::execute_with(|| {
type Assets = <AssetHubZagros as AssetHubZagrosPallet>::Assets;
<Assets as Inspect<_>>::balance(USDT_ID, &receiver)
});
let receiver_weth_after = foreign_balance_on_ah_zagros(bridged_weth_at_ah, &receiver);
// Receiver's USDT balance is increased by almost `amount_to_send` (minus fees)
assert!(receiver_usdts_after > receiver_usdts_before);
assert!(receiver_usdts_after < receiver_usdts_before + amount_to_send);
// Receiver's wETH balance is increased by `amount_to_send`
assert_eq!(receiver_weth_after, receiver_weth_before + amount_to_send);
}
#[test]
fn send_rocs_from_penpal_pezkuwichain_through_asset_hub_pezkuwichain_to_asset_hub_zagros() {
let amount = ASSET_HUB_PEZKUWICHAIN_ED * 10_000_000;
let sender = PenpalASender::get();
let receiver = AssetHubZagrosReceiver::get();
let local_asset_hub = PenpalA::sibling_location_of(AssetHubPezkuwichain::para_id());
let (roc_at_pezkuwichain_teyrchains, roc_at_asset_hub_zagros) =
set_up_rocs_for_penpal_pezkuwichain_through_ahr_to_ahw(&sender, amount);
set_up_pool_with_wnd_on_ah_zagros(roc_at_asset_hub_zagros.clone(), true);
let sov_ahw_on_ahr =
AssetHubPezkuwichain::sovereign_account_of_teyrchain_on_other_global_consensus(
ByGenesis(ZAGROS_GENESIS_HASH),
AssetHubZagros::para_id(),
);
let rocs_in_reserve_on_ahr_before =
<AssetHubPezkuwichain 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_pezkuwichain_teyrchains.clone(), &sender)
});
let receiver_rocs_before =
foreign_balance_on_ah_zagros(roc_at_asset_hub_zagros.clone(), &receiver);
// Send TYRs over bridge
{
let destination = asset_hub_zagros_location();
let assets: Assets = (roc_at_pezkuwichain_teyrchains.clone(), amount).into();
let asset_transfer_type = TransferType::RemoteReserve(local_asset_hub.clone().into());
let fees_id: AssetId = roc_at_pezkuwichain_teyrchains.clone().into();
let fees_transfer_type = TransferType::RemoteReserve(local_asset_hub.into());
let beneficiary: Location =
AccountId32Junction { network: None, id: receiver.clone().into() }.into();
let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset {
assets: Wild(AllCounted(assets.len() as u32)),
beneficiary,
}]);
send_assets_from_penpal_pezkuwichain_through_pezkuwichain_ah_to_zagros_ah(
destination,
(assets, asset_transfer_type),
(fees_id, fees_transfer_type),
custom_xcm_on_dest,
);
}
// process AHW incoming message and check events
let roc = Location::new(2, [GlobalConsensus(ByGenesis(PEZKUWICHAIN_GENESIS_HASH))]);
AssetHubZagros::execute_with(|| {
type RuntimeEvent = <AssetHubZagros as Chain>::RuntimeEvent;
assert_expected_events!(
AssetHubZagros,
vec![
// issue TYRs on AHW
RuntimeEvent::ForeignAssets(pezpallet_assets::Event::Issued { asset_id, owner, .. }) => {
asset_id: *asset_id == roc,
owner: owner == &receiver,
},
// message processed successfully
RuntimeEvent::MessageQueue(
pezpallet_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_pezkuwichain_teyrchains, &sender)
});
let receiver_rocs_after = foreign_balance_on_ah_zagros(roc_at_asset_hub_zagros, &receiver);
let rocs_in_reserve_on_ahr_after =
<AssetHubPezkuwichain 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);
}
#[test]
fn send_back_wnds_from_penpal_pezkuwichain_through_asset_hub_pezkuwichain_to_asset_hub_zagros() {
let wnd_at_pezkuwichain_teyrchains = bridged_wnd_at_ah_pezkuwichain();
let amount = ASSET_HUB_PEZKUWICHAIN_ED * 10_000_000;
let sender = PenpalASender::get();
let receiver = AssetHubZagrosReceiver::get();
// set up TYRs for transfer
let (roc_at_pezkuwichain_teyrchains, _) =
set_up_rocs_for_penpal_pezkuwichain_through_ahr_to_ahw(&sender, amount);
// set up ZGRs for transfer
let penpal_location = AssetHubPezkuwichain::sibling_location_of(PenpalA::para_id());
let sov_penpal_on_ahr = AssetHubPezkuwichain::sovereign_account_id_of(penpal_location);
let prefund_accounts = vec![(sov_penpal_on_ahr, amount * 2)];
let reserves = vec![(asset_hub_zagros_location(), false).into()];
create_foreign_on_ah_pezkuwichain(
wnd_at_pezkuwichain_teyrchains.clone(),
true,
reserves,
prefund_accounts,
);
let asset_owner: AccountId = AssetHubPezkuwichain::account_id_of(ALICE);
PenpalA::force_create_foreign_asset(
wnd_at_pezkuwichain_teyrchains.clone(),
asset_owner.clone(),
true,
ASSET_MIN_BALANCE,
vec![(sender.clone(), amount * 2)],
);
// Configure source Penpal chain to trust local AH as reserve of bridged ZGR
PenpalA::execute_with(|| {
assert_ok!(<PenpalA as Chain>::System::set_storage(
<PenpalA as Chain>::RuntimeOrigin::root(),
vec![(
PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(),
wnd_at_pezkuwichain_teyrchains.encode(),
)],
));
});
// fund the AHR's SA on AHW with the ZGR tokens held in reserve
let sov_ahr_on_ahw = AssetHubZagros::sovereign_account_of_teyrchain_on_other_global_consensus(
NetworkId::ByGenesis(PEZKUWICHAIN_GENESIS_HASH),
AssetHubPezkuwichain::para_id(),
);
AssetHubZagros::fund_accounts(vec![(sov_ahr_on_ahw.clone(), amount * 2)]);
// balances before
let sender_wnds_before = PenpalA::execute_with(|| {
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
<ForeignAssets as Inspect<_>>::balance(
wnd_at_pezkuwichain_teyrchains.clone().into(),
&sender,
)
});
let receiver_wnds_before = <AssetHubZagros as Chain>::account_data_of(receiver.clone()).free;
// send ZGRs over the bridge, TYRs only used to pay fees on local AH, pay with ZGR on remote AH
{
let final_destination = asset_hub_zagros_location();
let intermediary_hop = PenpalA::sibling_location_of(AssetHubPezkuwichain::para_id());
let context = PenpalA::execute_with(|| PenpalUniversalLocation::get());
// what happens at final destination
let beneficiary = AccountId32Junction { network: None, id: receiver.clone().into() }.into();
// use ZGR as fees on the final destination (AHW)
let remote_fees: Asset = (wnd_at_pezkuwichain_teyrchains.clone(), amount).into();
let remote_fees = remote_fees.reanchored(&final_destination, &context).unwrap();
// buy execution using WNDs, then deposit all remaining WNDs
let xcm_on_final_dest = Xcm::<()>(vec![
BuyExecution { fees: remote_fees, weight_limit: WeightLimit::Unlimited },
DepositAsset { assets: Wild(AllCounted(1)), beneficiary },
]);
// what happens at intermediary hop
// reanchor final dest (Asset Hub Zagros) to the view of hop (Asset Hub Pezkuwichain)
let mut final_destination = final_destination.clone();
final_destination.reanchor(&intermediary_hop, &context).unwrap();
// reanchor ZGRs to the view of hop (Asset Hub Pezkuwichain)
let asset: Asset = (wnd_at_pezkuwichain_teyrchains.clone(), amount).into();
let asset = asset.reanchored(&intermediary_hop, &context).unwrap();
// on Asset Hub Pezkuwichain, forward a request to withdraw ZGRs from reserve on Asset Hub
// Zagros
let xcm_on_hop = Xcm::<()>(vec![InitiateReserveWithdraw {
assets: Definite(asset.into()), // WNDs
reserve: final_destination, // AHW
xcm: xcm_on_final_dest, // XCM to execute on AHW
}]);
// assets to send from Penpal and how they reach the intermediary hop
let assets: Assets = vec![
(wnd_at_pezkuwichain_teyrchains.clone(), amount).into(),
(roc_at_pezkuwichain_teyrchains.clone(), amount).into(),
]
.into();
let asset_transfer_type = TransferType::DestinationReserve;
let fees_id: AssetId = roc_at_pezkuwichain_teyrchains.into();
let fees_transfer_type = TransferType::DestinationReserve;
// initiate the transfer
send_assets_from_penpal_pezkuwichain_through_pezkuwichain_ah_to_zagros_ah(
intermediary_hop,
(assets, asset_transfer_type),
(fees_id, fees_transfer_type),
xcm_on_hop,
);
}
// process AHW incoming message and check events
AssetHubZagros::execute_with(|| {
type RuntimeEvent = <AssetHubZagros as Chain>::RuntimeEvent;
assert_expected_events!(
AssetHubZagros,
vec![
// issue TYRs on AHW
RuntimeEvent::Balances(pezpallet_balances::Event::Issued { .. }) => {},
// message processed successfully
RuntimeEvent::MessageQueue(
pezpallet_message_queue::Event::Processed { success: true, .. }
) => {},
]
);
});
let sender_wnds_after = PenpalA::execute_with(|| {
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
<ForeignAssets as Inspect<_>>::balance(wnd_at_pezkuwichain_teyrchains.into(), &sender)
});
let receiver_wnds_after = <AssetHubZagros as Chain>::account_data_of(receiver).free;
// Sender's balance is reduced by sent "amount"
assert_eq!(sender_wnds_after, sender_wnds_before - amount);
// Receiver's balance is increased by no more than "amount"
assert!(receiver_wnds_after > receiver_wnds_before);
assert!(receiver_wnds_after <= receiver_wnds_before + amount);
}
#[test]
fn dry_run_transfer_to_zagros_sends_xcm_to_bridge_hub() {
test_dry_run_transfer_across_pk_bridge!(
AssetHubPezkuwichain,
BridgeHubPezkuwichain,
asset_hub_zagros_location()
);
}
@@ -0,0 +1,34 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Tests related to claiming assets trapped during XCM execution.
use crate::imports::*;
use emulated_integration_tests_common::test_chain_can_claim_assets;
#[test]
fn assets_can_be_claimed() {
let amount = BridgeHubPezkuwichainExistentialDeposit::get();
let assets: Assets = (Parent, amount).into();
test_chain_can_claim_assets!(
AssetHubPezkuwichain,
RuntimeCall,
NetworkId::ByGenesis(PEZKUWICHAIN_GENESIS_HASH),
assets,
amount
);
}
@@ -0,0 +1,303 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::imports::*;
use emulated_integration_tests_common::{snowbridge, snowbridge::WETH};
use testnet_teyrchains_constants::pezkuwichain::snowbridge::EthereumNetwork;
use xcm::opaque::v5;
use xcm_executor::traits::ConvertLocation;
mod asset_transfers;
mod claim_assets;
mod register_bridged_assets;
mod send_xcm;
mod teleport;
pub(crate) fn asset_hub_zagros_location() -> Location {
Location::new(
2,
[
GlobalConsensus(ByGenesis(ZAGROS_GENESIS_HASH)),
Teyrchain(AssetHubZagros::para_id().into()),
],
)
}
pub(crate) fn asset_hub_pezkuwichain_global_location() -> Location {
Location::new(
2,
[
GlobalConsensus(ByGenesis(PEZKUWICHAIN_GENESIS_HASH)),
Teyrchain(AssetHubPezkuwichain::para_id().into()),
],
)
}
pub(crate) fn bridge_hub_zagros_location() -> Location {
Location::new(
2,
[
GlobalConsensus(ByGenesis(ZAGROS_GENESIS_HASH)),
Teyrchain(BridgeHubZagros::para_id().into()),
],
)
}
// TYR and wTYR
pub(crate) fn roc_at_ah_pezkuwichain() -> Location {
Parent.into()
}
pub(crate) fn bridged_roc_at_ah_zagros() -> Location {
Location::new(2, [GlobalConsensus(ByGenesis(PEZKUWICHAIN_GENESIS_HASH))])
}
// ZGR and wWND
pub(crate) fn bridged_wnd_at_ah_pezkuwichain() -> Location {
Location::new(2, [GlobalConsensus(ByGenesis(ZAGROS_GENESIS_HASH))])
}
// USDT and wUSDT
pub(crate) fn usdt_at_ah_zagros() -> Location {
Location::new(0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into())])
}
pub(crate) fn bridged_usdt_at_ah_pezkuwichain() -> Location {
Location::new(
2,
[
GlobalConsensus(ByGenesis(ZAGROS_GENESIS_HASH)),
Teyrchain(AssetHubZagros::para_id().into()),
PalletInstance(ASSETS_PALLET_ID),
GeneralIndex(USDT_ID.into()),
],
)
}
// wETH has same relative location on both Pezkuwichain and Zagros AssetHubs
pub(crate) fn weth_at_asset_hubs() -> Location {
Location::new(
2,
[
GlobalConsensus(Ethereum { chain_id: snowbridge::SEPOLIA_ID }),
AccountKey20 { network: None, key: WETH },
],
)
}
pub(crate) fn create_foreign_on_ah_pezkuwichain(
id: v5::Location,
sufficient: bool,
reserves: Vec<ForeignAssetReserveData>,
prefund_accounts: Vec<(AccountId, u128)>,
) {
let owner = AssetHubPezkuwichain::account_id_of(ALICE);
let min = ASSET_MIN_BALANCE;
AssetHubPezkuwichain::force_create_foreign_asset(
id.clone(),
owner.clone(),
sufficient,
min,
prefund_accounts,
);
AssetHubPezkuwichain::set_foreign_asset_reserves(id, owner, reserves);
}
pub(crate) fn create_foreign_on_ah_zagros(
id: v5::Location,
sufficient: bool,
reserves: Vec<ForeignAssetReserveData>,
) {
let owner = AssetHubZagros::account_id_of(ALICE);
AssetHubZagros::force_create_foreign_asset(
id.clone(),
owner.clone(),
sufficient,
ASSET_MIN_BALANCE,
vec![],
);
AssetHubZagros::set_foreign_asset_reserves(id, owner, reserves);
}
pub(crate) fn foreign_balance_on_ah_pezkuwichain(id: v5::Location, who: &AccountId) -> u128 {
AssetHubPezkuwichain::execute_with(|| {
type Assets = <AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::ForeignAssets;
<Assets as Inspect<_>>::balance(id, who)
})
}
pub(crate) fn foreign_balance_on_ah_zagros(id: v5::Location, who: &AccountId) -> u128 {
AssetHubZagros::execute_with(|| {
type Assets = <AssetHubZagros as AssetHubZagrosPallet>::ForeignAssets;
<Assets as Inspect<_>>::balance(id, who)
})
}
// set up pool
pub(crate) fn set_up_pool_with_wnd_on_ah_zagros(asset: v5::Location, is_foreign: bool) {
let wnd: v5::Location = v5::Parent.into();
AssetHubZagros::execute_with(|| {
type RuntimeEvent = <AssetHubZagros as Chain>::RuntimeEvent;
let owner = AssetHubZagrosSender::get();
let signed_owner = <AssetHubZagros as Chain>::RuntimeOrigin::signed(owner.clone());
if is_foreign {
assert_ok!(<AssetHubZagros as AssetHubZagrosPallet>::ForeignAssets::mint(
signed_owner.clone(),
asset.clone().into(),
owner.clone().into(),
3_000_000_000_000,
));
} else {
let asset_id = match asset.interior.last() {
Some(GeneralIndex(id)) => *id as u32,
_ => unreachable!(),
};
assert_ok!(<AssetHubZagros as AssetHubZagrosPallet>::Assets::mint(
signed_owner.clone(),
asset_id.into(),
owner.clone().into(),
3_000_000_000_000,
));
}
assert_ok!(<AssetHubZagros as AssetHubZagrosPallet>::AssetConversion::create_pool(
signed_owner.clone(),
Box::new(wnd.clone()),
Box::new(asset.clone()),
));
assert_expected_events!(
AssetHubZagros,
vec![
RuntimeEvent::AssetConversion(pezpallet_asset_conversion::Event::PoolCreated { .. }) => {},
]
);
assert_ok!(<AssetHubZagros as AssetHubZagrosPallet>::AssetConversion::add_liquidity(
signed_owner.clone(),
Box::new(wnd),
Box::new(asset),
1_000_000_000_000,
2_000_000_000_000,
1,
1,
owner.into()
));
assert_expected_events!(
AssetHubZagros,
vec![
RuntimeEvent::AssetConversion(pezpallet_asset_conversion::Event::LiquidityAdded {..}) => {},
]
);
});
}
pub(crate) fn send_assets_from_asset_hub_pezkuwichain(
destination: Location,
assets: Assets,
fee_idx: u32,
// For knowing what reserve to pick.
// We only allow using the same transfer type for assets and fees right now.
// And only `LocalReserve` or `DestinationReserve`.
transfer_type: TransferType,
) -> DispatchResult {
let signed_origin =
<AssetHubPezkuwichain as Chain>::RuntimeOrigin::signed(AssetHubPezkuwichainSender::get());
let beneficiary: Location =
AccountId32Junction { network: None, id: AssetHubZagrosReceiver::get().into() }.into();
type Runtime = <AssetHubPezkuwichain as Chain>::Runtime;
let remote_fee_id: AssetId = assets
.clone()
.into_inner()
.get(fee_idx as usize)
.ok_or(pezpallet_xcm::Error::<Runtime>::Empty)?
.clone()
.id;
AssetHubPezkuwichain::execute_with(|| {
<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::PezkuwiXcm::transfer_assets_using_type_and_then(
signed_origin,
bx!(destination.into()),
bx!(assets.into()),
bx!(transfer_type.clone()),
bx!(remote_fee_id.into()),
bx!(transfer_type),
bx!(VersionedXcm::from(
Xcm::<()>::builder_unsafe().deposit_asset(AllCounted(1), beneficiary).build()
)),
WeightLimit::Unlimited,
)
})
}
pub(crate) fn assert_bridge_hub_pezkuwichain_message_accepted(expected_processed: bool) {
BridgeHubPezkuwichain::execute_with(|| {
type RuntimeEvent = <BridgeHubPezkuwichain as Chain>::RuntimeEvent;
if expected_processed {
assert_expected_events!(
BridgeHubPezkuwichain,
vec![
// pay for bridge fees
RuntimeEvent::Balances(pezpallet_balances::Event::Burned { .. }) => {},
// message exported
RuntimeEvent::BridgeZagrosMessages(
pezpallet_bridge_messages::Event::MessageAccepted { .. }
) => {},
// message processed successfully
RuntimeEvent::MessageQueue(
pezpallet_message_queue::Event::Processed { success: true, .. }
) => {},
]
);
} else {
assert_expected_events!(
BridgeHubPezkuwichain,
vec![
RuntimeEvent::MessageQueue(pezpallet_message_queue::Event::Processed {
success: false,
..
}) => {},
]
);
}
});
}
pub(crate) fn assert_bridge_hub_zagros_message_received() {
BridgeHubZagros::execute_with(|| {
type RuntimeEvent = <BridgeHubZagros as Chain>::RuntimeEvent;
assert_expected_events!(
BridgeHubZagros,
vec![
// message sent to destination
RuntimeEvent::XcmpQueue(
pezcumulus_pezpallet_xcmp_queue::Event::XcmpMessageSent { .. }
) => {},
]
);
})
}
pub fn snowbridge_sovereign() -> pezsp_runtime::AccountId32 {
use asset_hub_pezkuwichain_runtime::xcm_config::UniversalLocation as AssetHubPezkuwichainUniversalLocation;
let ethereum_sovereign: AccountId = AssetHubPezkuwichain::execute_with(|| {
ExternalConsensusLocationsConverterFor::<
AssetHubPezkuwichainUniversalLocation,
[u8; 32],
>::convert_location(&Location::new(
2,
[xcm::v5::Junction::GlobalConsensus(EthereumNetwork::get())],
))
.unwrap()
.into()
});
ethereum_sovereign
}
@@ -0,0 +1,109 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::{imports::*, tests::*};
const XCM_FEE: u128 = 4_000_000_000_000;
/// Tests the registering of a Pezkuwichain Asset as a bridged asset on Zagros Asset Hub.
#[test]
fn register_pezkuwichain_asset_on_wah_from_rah() {
let sa_of_rah_on_wah = AssetHubZagros::sovereign_account_of_teyrchain_on_other_global_consensus(
ByGenesis(PEZKUWICHAIN_GENESIS_HASH),
AssetHubPezkuwichain::para_id(),
);
// Pezkuwichain Asset Hub asset when bridged to Zagros Asset Hub.
let bridged_asset_at_wah = Location::new(
2,
[
GlobalConsensus(ByGenesis(PEZKUWICHAIN_GENESIS_HASH)),
Teyrchain(AssetHubPezkuwichain::para_id().into()),
PalletInstance(ASSETS_PALLET_ID),
GeneralIndex(ASSET_ID.into()),
],
);
// Encoded `create_asset` call to be executed in Zagros Asset Hub ForeignAssets pezpallet.
let call = AssetHubZagros::create_foreign_asset_call(
bridged_asset_at_wah.clone(),
ASSET_MIN_BALANCE,
sa_of_rah_on_wah.clone(),
);
let origin_kind = OriginKind::Xcm;
let fee_amount = XCM_FEE;
let fees = (Parent, fee_amount).into();
let xcm = xcm_transact_paid_execution(call, origin_kind, fees, sa_of_rah_on_wah.clone());
// SA-of-RAH-on-WAH needs to have balance to pay for fees and asset creation deposit
AssetHubZagros::fund_accounts(vec![(
sa_of_rah_on_wah.clone(),
ASSET_HUB_ZAGROS_ED * 10000000000,
)]);
let destination = asset_hub_zagros_location();
// fund the RAH's SA on RBH for paying bridge delivery fees
BridgeHubPezkuwichain::fund_para_sovereign(
AssetHubPezkuwichain::para_id(),
10_000_000_000_000u128,
);
// set XCM versions
AssetHubPezkuwichain::force_xcm_version(destination.clone(), XCM_VERSION);
BridgeHubPezkuwichain::force_xcm_version(bridge_hub_zagros_location(), XCM_VERSION);
let root_origin = <AssetHubPezkuwichain as Chain>::RuntimeOrigin::root();
AssetHubPezkuwichain::execute_with(|| {
assert_ok!(<AssetHubPezkuwichain as AssetHubPezkuwichainPallet>::PezkuwiXcm::send(
root_origin,
bx!(destination.into()),
bx!(xcm),
));
AssetHubPezkuwichain::assert_xcm_pallet_sent();
});
assert_bridge_hub_pezkuwichain_message_accepted(true);
assert_bridge_hub_zagros_message_received();
AssetHubZagros::execute_with(|| {
type RuntimeEvent = <AssetHubZagros as Chain>::RuntimeEvent;
AssetHubZagros::assert_xcmp_queue_success(None);
assert_expected_events!(
AssetHubZagros,
vec![
// Burned the fee
RuntimeEvent::Balances(pezpallet_balances::Event::Burned { who, amount }) => {
who: *who == sa_of_rah_on_wah.clone(),
amount: *amount == fee_amount,
},
// Foreign Asset created
RuntimeEvent::ForeignAssets(pezpallet_assets::Event::Created { asset_id, creator, owner }) => {
asset_id: asset_id == &bridged_asset_at_wah,
creator: *creator == sa_of_rah_on_wah.clone(),
owner: *owner == sa_of_rah_on_wah,
},
// Unspent fee minted to origin
RuntimeEvent::Balances(pezpallet_balances::Event::Minted { who, .. }) => {
who: *who == sa_of_rah_on_wah.clone(),
},
]
);
type ForeignAssets = <AssetHubZagros as AssetHubZagrosPallet>::ForeignAssets;
assert!(ForeignAssets::asset_exists(bridged_asset_at_wah));
});
}
@@ -0,0 +1,155 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use pezkuwichain_system_emulated_network::pezkuwichain_emulated_chain::pezkuwichain_runtime::Dmp;
use crate::tests::*;
#[test]
fn send_xcm_from_pezkuwichain_relay_to_zagros_asset_hub_should_fail_on_not_applicable() {
// Init tests variables
// XcmPallet send arguments
let sudo_origin = <Pezkuwichain as Chain>::RuntimeOrigin::root();
let destination = Pezkuwichain::child_location_of(BridgeHubPezkuwichain::para_id()).into();
let weight_limit = WeightLimit::Unlimited;
let check_origin = None;
let remote_xcm = Xcm(vec![ClearOrigin]);
let xcm = VersionedXcm::from(Xcm(vec![
UnpaidExecution { weight_limit, check_origin },
ExportMessage {
network: ByGenesis(ZAGROS_GENESIS_HASH),
destination: [Teyrchain(AssetHubZagros::para_id().into())].into(),
xcm: remote_xcm,
},
]));
// Pezkuwichain Global Consensus
// Send XCM message from Relay Chain to Bridge Hub source Teyrchain
Pezkuwichain::execute_with(|| {
Dmp::make_teyrchain_reachable(BridgeHubPezkuwichain::para_id());
assert_ok!(<Pezkuwichain as PezkuwichainPallet>::XcmPallet::send(
sudo_origin,
bx!(destination),
bx!(xcm),
));
type RuntimeEvent = <Pezkuwichain as Chain>::RuntimeEvent;
assert_expected_events!(
Pezkuwichain,
vec![
RuntimeEvent::XcmPallet(pezpallet_xcm::Event::Sent { .. }) => {},
]
);
});
// Receive XCM message in Bridge Hub source Teyrchain, it should fail, because we don't have
// opened bridge/lane.
assert_bridge_hub_pezkuwichain_message_accepted(false);
}
#[test]
fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() {
// prepare data
let destination = asset_hub_zagros_location();
let native_token = Location::parent();
let amount = ASSET_HUB_PEZKUWICHAIN_ED * 1_000;
// fund the AHR's SA on BHR for paying bridge delivery fees
BridgeHubPezkuwichain::fund_para_sovereign(
AssetHubPezkuwichain::para_id(),
10_000_000_000_000u128,
);
// fund sender
AssetHubPezkuwichain::fund_accounts(vec![(
AssetHubPezkuwichainSender::get().into(),
amount * 10,
)]);
// Initially set only default version on all runtimes
let newer_xcm_version = xcm::prelude::XCM_VERSION;
let older_xcm_version = newer_xcm_version - 1;
AssetHubPezkuwichain::force_default_xcm_version(Some(older_xcm_version));
BridgeHubPezkuwichain::force_default_xcm_version(Some(older_xcm_version));
BridgeHubZagros::force_default_xcm_version(Some(older_xcm_version));
AssetHubZagros::force_default_xcm_version(Some(older_xcm_version));
// send XCM from AssetHubPezkuwichain - fails - destination version not known
assert_err!(
send_assets_from_asset_hub_pezkuwichain(
destination.clone(),
(native_token.clone(), amount).into(),
0,
TransferType::LocalReserve
),
DispatchError::Module(pezsp_runtime::ModuleError {
index: 31,
error: [1, 0, 0, 0],
message: Some("SendFailure")
})
);
// set destination version
AssetHubPezkuwichain::force_xcm_version(destination.clone(), newer_xcm_version);
// set version with `ExportMessage` for BridgeHubPezkuwichain
AssetHubPezkuwichain::force_xcm_version(
ParentThen(Teyrchain(BridgeHubPezkuwichain::para_id().into()).into()).into(),
newer_xcm_version,
);
// send XCM from AssetHubPezkuwichain - ok
assert_ok!(send_assets_from_asset_hub_pezkuwichain(
destination.clone(),
(native_token.clone(), amount).into(),
0,
TransferType::LocalReserve
));
// `ExportMessage` on local BridgeHub - fails - remote BridgeHub version not known
assert_bridge_hub_pezkuwichain_message_accepted(false);
// set version for remote BridgeHub on BridgeHubPezkuwichain
BridgeHubPezkuwichain::force_xcm_version(bridge_hub_zagros_location(), newer_xcm_version);
// set version for AssetHubZagros on BridgeHubZagros
BridgeHubZagros::force_xcm_version(
ParentThen(Teyrchain(AssetHubZagros::para_id().into()).into()).into(),
newer_xcm_version,
);
// send XCM from AssetHubPezkuwichain - ok
assert_ok!(send_assets_from_asset_hub_pezkuwichain(
destination.clone(),
(native_token.clone(), amount).into(),
0,
TransferType::LocalReserve
));
assert_bridge_hub_pezkuwichain_message_accepted(true);
assert_bridge_hub_zagros_message_received();
// message delivered and processed at destination
AssetHubZagros::execute_with(|| {
type RuntimeEvent = <AssetHubZagros as Chain>::RuntimeEvent;
assert_expected_events!(
AssetHubZagros,
vec![
// message processed with failure, but for this scenario it is ok, important is that was delivered
RuntimeEvent::MessageQueue(
pezpallet_message_queue::Event::Processed { success: false, .. }
) => {},
]
);
});
}
@@ -0,0 +1,84 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::imports::*;
#[test]
fn teleport_via_limited_teleport_assets_to_other_system_teyrchains_works() {
let amount = BRIDGE_HUB_PEZKUWICHAIN_ED * 100;
let native_asset: Assets = (Parent, amount).into();
let fee_asset_id: AssetId = Parent.into();
test_teyrchain_is_trusted_teleporter!(
BridgeHubPezkuwichain, // Origin
vec![AssetHubPezkuwichain], // Destinations
(native_asset, amount),
fee_asset_id,
limited_teleport_assets
);
}
#[test]
fn teleport_via_transfer_assets_to_other_system_teyrchains_works() {
let amount = BRIDGE_HUB_PEZKUWICHAIN_ED * 100;
let native_asset: Assets = (Parent, amount).into();
let fee_asset_id: AssetId = Parent.into();
test_teyrchain_is_trusted_teleporter!(
BridgeHubPezkuwichain, // Origin
vec![AssetHubPezkuwichain], // Destinations
(native_asset, amount),
fee_asset_id,
transfer_assets
);
}
#[test]
fn teleport_via_limited_teleport_assets_from_and_to_relay() {
let amount = PEZKUWICHAIN_ED * 100;
test_relay_is_trusted_teleporter!(
Pezkuwichain,
vec![BridgeHubPezkuwichain],
amount,
limited_teleport_assets
);
test_teyrchain_is_trusted_teleporter_for_relay!(
BridgeHubPezkuwichain,
Pezkuwichain,
amount,
limited_teleport_assets
);
}
#[test]
fn teleport_via_transfer_assets_from_and_to_relay() {
let amount = PEZKUWICHAIN_ED * 100;
test_relay_is_trusted_teleporter!(
Pezkuwichain,
vec![BridgeHubPezkuwichain],
amount,
transfer_assets
);
test_teyrchain_is_trusted_teleporter_for_relay!(
BridgeHubPezkuwichain,
Pezkuwichain,
amount,
transfer_assets
);
}