feat: Rebrand Polkadot/Substrate references to PezkuwiChain
This commit systematically rebrands various references from Parity Technologies' Polkadot/Substrate ecosystem to PezkuwiChain within the kurdistan-sdk. Key changes include: - Updated external repository URLs (zombienet-sdk, parity-db, parity-scale-codec, wasm-instrument) to point to pezkuwichain forks. - Modified internal documentation and code comments to reflect PezkuwiChain naming and structure. - Replaced direct references to with or specific paths within the for XCM, Pezkuwi, and other modules. - Cleaned up deprecated issue and PR references in various and files, particularly in and modules. - Adjusted image and logo URLs in documentation to point to PezkuwiChain assets. - Removed or rephrased comments related to external Polkadot/Substrate PRs and issues. This is a significant step towards fully customizing the SDK for the PezkuwiChain ecosystem.
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
[package]
|
||||
name = "asset-test-utils"
|
||||
version = "7.0.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
description = "Test utils for Asset Hub runtimes."
|
||||
license = "Apache-2.0"
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
codec = { features = ["derive", "max-encoded-len"], workspace = true }
|
||||
|
||||
# Bizinikiwi
|
||||
pezframe-support = { workspace = true }
|
||||
pezframe-system = { workspace = true }
|
||||
pezpallet-asset-conversion = { workspace = true }
|
||||
pezpallet-assets = { workspace = true }
|
||||
pezpallet-balances = { workspace = true }
|
||||
pezpallet-session = { workspace = true }
|
||||
pezpallet-timestamp = { workspace = true }
|
||||
pezsp-io = { workspace = true }
|
||||
pezsp-runtime = { workspace = true }
|
||||
|
||||
# Pezcumulus
|
||||
assets-common = { workspace = true }
|
||||
pezcumulus-pezpallet-teyrchain-system = { workspace = true }
|
||||
pezcumulus-pezpallet-xcmp-queue = { workspace = true }
|
||||
pezcumulus-primitives-core = { workspace = true }
|
||||
pezpallet-collator-selection = { workspace = true }
|
||||
teyrchain-info = { workspace = true }
|
||||
teyrchains-common = { workspace = true }
|
||||
teyrchains-runtimes-test-utils = { workspace = true }
|
||||
|
||||
# Pezkuwi
|
||||
pezpallet-xcm = { workspace = true }
|
||||
xcm = { workspace = true }
|
||||
xcm-builder = { workspace = true }
|
||||
xcm-executor = { workspace = true }
|
||||
xcm-runtime-apis = { workspace = true }
|
||||
|
||||
# Bridges
|
||||
pezpallet-xcm-bridge-hub-router = { workspace = true }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"assets-common/std",
|
||||
"codec/std",
|
||||
"pezcumulus-pezpallet-teyrchain-system/std",
|
||||
"pezcumulus-pezpallet-xcmp-queue/std",
|
||||
"pezcumulus-primitives-core/std",
|
||||
"pezframe-support/std",
|
||||
"pezframe-system/std",
|
||||
"pezpallet-asset-conversion/std",
|
||||
"pezpallet-assets/std",
|
||||
"pezpallet-balances/std",
|
||||
"pezpallet-collator-selection/std",
|
||||
"pezpallet-session/std",
|
||||
"pezpallet-timestamp/std",
|
||||
"pezpallet-xcm-bridge-hub-router/std",
|
||||
"pezpallet-xcm/std",
|
||||
"pezsp-io/std",
|
||||
"pezsp-runtime/std",
|
||||
"teyrchain-info/std",
|
||||
"teyrchains-common/std",
|
||||
"teyrchains-runtimes-test-utils/std",
|
||||
"xcm-builder/std",
|
||||
"xcm-executor/std",
|
||||
"xcm-runtime-apis/std",
|
||||
"xcm/std",
|
||||
]
|
||||
try-runtime = [
|
||||
"assets-common/try-runtime",
|
||||
"pezcumulus-pezpallet-teyrchain-system/try-runtime",
|
||||
"pezcumulus-pezpallet-xcmp-queue/try-runtime",
|
||||
"pezframe-support/try-runtime",
|
||||
"pezframe-system/try-runtime",
|
||||
"pezpallet-asset-conversion/try-runtime",
|
||||
"pezpallet-assets/try-runtime",
|
||||
"pezpallet-balances/try-runtime",
|
||||
"pezpallet-collator-selection/try-runtime",
|
||||
"pezpallet-session/try-runtime",
|
||||
"pezpallet-timestamp/try-runtime",
|
||||
"pezpallet-xcm-bridge-hub-router/try-runtime",
|
||||
"pezpallet-xcm/try-runtime",
|
||||
"pezsp-runtime/try-runtime",
|
||||
"teyrchain-info/try-runtime",
|
||||
"teyrchains-common/try-runtime",
|
||||
]
|
||||
runtime-benchmarks = [
|
||||
"assets-common/runtime-benchmarks",
|
||||
"pezcumulus-pezpallet-teyrchain-system/runtime-benchmarks",
|
||||
"pezcumulus-pezpallet-xcmp-queue/runtime-benchmarks",
|
||||
"pezcumulus-primitives-core/runtime-benchmarks",
|
||||
"pezframe-support/runtime-benchmarks",
|
||||
"pezframe-system/runtime-benchmarks",
|
||||
"pezpallet-asset-conversion/runtime-benchmarks",
|
||||
"pezpallet-assets/runtime-benchmarks",
|
||||
"pezpallet-balances/runtime-benchmarks",
|
||||
"pezpallet-collator-selection/runtime-benchmarks",
|
||||
"pezpallet-session/runtime-benchmarks",
|
||||
"pezpallet-timestamp/runtime-benchmarks",
|
||||
"pezpallet-xcm-bridge-hub-router/runtime-benchmarks",
|
||||
"pezpallet-xcm/runtime-benchmarks",
|
||||
"pezsp-io/runtime-benchmarks",
|
||||
"pezsp-runtime/runtime-benchmarks",
|
||||
"teyrchain-info/runtime-benchmarks",
|
||||
"teyrchains-common/runtime-benchmarks",
|
||||
"teyrchains-runtimes-test-utils/runtime-benchmarks",
|
||||
"xcm-builder/runtime-benchmarks",
|
||||
"xcm-executor/runtime-benchmarks",
|
||||
"xcm-runtime-apis/runtime-benchmarks",
|
||||
"xcm/runtime-benchmarks",
|
||||
]
|
||||
@@ -0,0 +1,81 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Pezcumulus.
|
||||
// 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.
|
||||
|
||||
//! Module contains predefined test-case scenarios for `Runtime` with various assets.
|
||||
|
||||
pub mod test_cases;
|
||||
pub mod test_cases_over_bridge;
|
||||
pub mod xcm_helpers;
|
||||
|
||||
use pezframe_support::traits::ProcessMessageError;
|
||||
use std::fmt::Debug;
|
||||
pub use teyrchains_runtimes_test_utils::*;
|
||||
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_builder::{CreateMatcher, MatchXcm};
|
||||
|
||||
/// Given a message, a sender, and a destination, it returns the delivery fees
|
||||
fn get_fungible_delivery_fees<S: SendXcm>(destination: Location, message: Xcm<()>) -> u128 {
|
||||
let Ok((_, delivery_fees)) = validate_send::<S>(destination, message) else {
|
||||
unreachable!("message can be sent; qed")
|
||||
};
|
||||
if let Some(delivery_fee) = delivery_fees.inner().first() {
|
||||
let Fungible(delivery_fee_amount) = delivery_fee.fun else {
|
||||
unreachable!("asset is fungible; qed");
|
||||
};
|
||||
delivery_fee_amount
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function to verify `xcm` contains all relevant instructions expected on destination
|
||||
/// chain as part of a reserve-asset-transfer.
|
||||
pub(crate) fn assert_matches_reserve_asset_deposited_instructions<RuntimeCall: Debug>(
|
||||
xcm: &mut Xcm<RuntimeCall>,
|
||||
expected_reserve_assets_deposited: &Assets,
|
||||
expected_beneficiary: &Location,
|
||||
) {
|
||||
let _ = xcm
|
||||
.0
|
||||
.matcher()
|
||||
.skip_inst_while(|inst| !matches!(inst, ReserveAssetDeposited(..)))
|
||||
.expect("no instruction ReserveAssetDeposited?")
|
||||
.match_next_inst(|instr| match instr {
|
||||
ReserveAssetDeposited(reserve_assets) => {
|
||||
assert_eq!(reserve_assets, expected_reserve_assets_deposited);
|
||||
Ok(())
|
||||
},
|
||||
_ => Err(ProcessMessageError::BadFormat),
|
||||
})
|
||||
.expect("expected instruction ReserveAssetDeposited")
|
||||
.match_next_inst(|instr| match instr {
|
||||
ClearOrigin => Ok(()),
|
||||
_ => Err(ProcessMessageError::BadFormat),
|
||||
})
|
||||
.expect("expected instruction ClearOrigin")
|
||||
.match_next_inst(|instr| match instr {
|
||||
BuyExecution { .. } => Ok(()),
|
||||
_ => Err(ProcessMessageError::BadFormat),
|
||||
})
|
||||
.expect("expected instruction BuyExecution")
|
||||
.match_next_inst(|instr| match instr {
|
||||
DepositAsset { assets: _, beneficiary } if beneficiary == expected_beneficiary =>
|
||||
Ok(()),
|
||||
_ => Err(ProcessMessageError::BadFormat),
|
||||
})
|
||||
.expect("expected instruction DepositAsset");
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,581 @@
|
||||
// Copyright (C) 2023 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.
|
||||
|
||||
//! Module contains predefined test-case scenarios for `Runtime` with various assets transferred
|
||||
//! over a bridge.
|
||||
|
||||
use crate::{assert_matches_reserve_asset_deposited_instructions, get_fungible_delivery_fees};
|
||||
use assets_common::local_and_foreign_assets::ForeignAssetReserveData;
|
||||
use codec::Encode;
|
||||
use cumulus_primitives_core::XcmpMessageSource;
|
||||
use pezframe_support::{
|
||||
assert_ok,
|
||||
traits::{Currency, Get, OnFinalize, OnInitialize, OriginTrait, ProcessMessageError},
|
||||
};
|
||||
use pezframe_system::pezpallet_prelude::BlockNumberFor;
|
||||
use pezsp_runtime::{traits::StaticLookup, Saturating};
|
||||
use teyrchains_common::{AccountId, Balance};
|
||||
use teyrchains_runtimes_test_utils::{
|
||||
mock_open_hrmp_channel, AccountIdOf, BalanceOf, CollatorSessionKeys, ExtBuilder, RuntimeHelper,
|
||||
SlotDurations, ValidatorIdOf, XcmReceivedFrom,
|
||||
};
|
||||
use xcm::{latest::prelude::*, VersionedAssetId, VersionedAssets, VersionedXcm};
|
||||
use xcm_builder::{CreateMatcher, MatchXcm};
|
||||
use xcm_executor::{
|
||||
traits::{ConvertLocation, TransferType},
|
||||
XcmExecutor,
|
||||
};
|
||||
|
||||
pub struct TestBridgingConfig {
|
||||
pub bridged_network: NetworkId,
|
||||
pub local_bridge_hub_para_id: u32,
|
||||
pub local_bridge_hub_location: Location,
|
||||
pub bridged_target_location: Location,
|
||||
}
|
||||
|
||||
/// Test-case makes sure that `Runtime` can initiate **reserve transfer assets** over bridge.
|
||||
pub fn limited_reserve_transfer_assets_for_native_asset_works<
|
||||
Runtime,
|
||||
AllPalletsWithoutSystem,
|
||||
XcmConfig,
|
||||
HrmpChannelOpener,
|
||||
HrmpChannelSource,
|
||||
LocationToAccountId,
|
||||
>(
|
||||
collator_session_keys: CollatorSessionKeys<Runtime>,
|
||||
slot_durations: SlotDurations,
|
||||
existential_deposit: BalanceOf<Runtime>,
|
||||
alice_account: AccountIdOf<Runtime>,
|
||||
unwrap_pallet_xcm_event: Box<dyn Fn(Vec<u8>) -> Option<pezpallet_xcm::Event<Runtime>>>,
|
||||
unwrap_xcmp_queue_event: Box<
|
||||
dyn Fn(Vec<u8>) -> Option<cumulus_pallet_xcmp_queue::Event<Runtime>>,
|
||||
>,
|
||||
prepare_configuration: fn() -> TestBridgingConfig,
|
||||
weight_limit: WeightLimit,
|
||||
maybe_paid_export_message: Option<AssetId>,
|
||||
delivery_fees_account: Option<AccountIdOf<Runtime>>,
|
||||
) where
|
||||
Runtime: pezframe_system::Config
|
||||
+ pezpallet_balances::Config
|
||||
+ pezpallet_session::Config
|
||||
+ pezpallet_xcm::Config
|
||||
+ teyrchain_info::Config
|
||||
+ pezpallet_collator_selection::Config
|
||||
+ cumulus_pallet_teyrchain_system::Config
|
||||
+ cumulus_pallet_xcmp_queue::Config
|
||||
+ pezpallet_timestamp::Config,
|
||||
AllPalletsWithoutSystem:
|
||||
OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
|
||||
AccountIdOf<Runtime>: Into<[u8; 32]>,
|
||||
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
|
||||
BalanceOf<Runtime>: From<Balance>,
|
||||
<Runtime as pezpallet_balances::Config>::Balance: From<Balance> + Into<u128>,
|
||||
XcmConfig: xcm_executor::Config,
|
||||
LocationToAccountId: ConvertLocation<AccountIdOf<Runtime>>,
|
||||
<Runtime as pezframe_system::Config>::AccountId:
|
||||
Into<<<Runtime as pezframe_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
|
||||
<<Runtime as pezframe_system::Config>::Lookup as StaticLookup>::Source:
|
||||
From<<Runtime as pezframe_system::Config>::AccountId>,
|
||||
<Runtime as pezframe_system::Config>::AccountId: From<AccountId>,
|
||||
HrmpChannelOpener: pezframe_support::inherent::ProvideInherent<
|
||||
Call = cumulus_pallet_teyrchain_system::Call<Runtime>,
|
||||
>,
|
||||
HrmpChannelSource: XcmpMessageSource,
|
||||
{
|
||||
let runtime_para_id = 1000;
|
||||
ExtBuilder::<Runtime>::default()
|
||||
.with_collators(collator_session_keys.collators())
|
||||
.with_session_keys(collator_session_keys.session_keys())
|
||||
.with_tracing()
|
||||
.with_safe_xcm_version(3)
|
||||
.with_para_id(runtime_para_id.into())
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
let mut alice = [0u8; 32];
|
||||
alice[0] = 1;
|
||||
let included_head = RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::run_to_block(
|
||||
2,
|
||||
AccountId::from(alice).into(),
|
||||
);
|
||||
|
||||
// prepare bridge config
|
||||
let TestBridgingConfig {
|
||||
bridged_network,
|
||||
local_bridge_hub_para_id,
|
||||
bridged_target_location: target_location_from_different_consensus,
|
||||
..
|
||||
} = prepare_configuration();
|
||||
|
||||
let reserve_account =
|
||||
LocationToAccountId::convert_location(&target_location_from_different_consensus)
|
||||
.expect("Sovereign account for reserves");
|
||||
let balance_to_transfer = 1_000_000_000_000_u128;
|
||||
let native_asset = Location::parent();
|
||||
|
||||
// open HRMP to bridge hub
|
||||
mock_open_hrmp_channel::<Runtime, HrmpChannelOpener>(
|
||||
runtime_para_id.into(),
|
||||
local_bridge_hub_para_id.into(),
|
||||
included_head,
|
||||
&alice,
|
||||
&slot_durations,
|
||||
);
|
||||
|
||||
// we calculate exact delivery fees _after_ sending the message by weighing the sent
|
||||
// xcm, and this delivery fee varies for different runtimes, so just add enough buffer,
|
||||
// then verify the arithmetics check out on final balance.
|
||||
let delivery_fees_buffer = 8_000_000_000_000u128;
|
||||
// drip ED + transfer_amount + delivery_fees_buffer to Alice account
|
||||
let alice_account_init_balance =
|
||||
existential_deposit + balance_to_transfer.into() + delivery_fees_buffer.into();
|
||||
let _ = <pezpallet_balances::Pallet<Runtime>>::deposit_creating(
|
||||
&alice_account,
|
||||
alice_account_init_balance,
|
||||
);
|
||||
// SA of target location needs to have at least ED, otherwise making reserve fails
|
||||
let _ = <pezpallet_balances::Pallet<Runtime>>::deposit_creating(
|
||||
&reserve_account,
|
||||
existential_deposit,
|
||||
);
|
||||
|
||||
// we just check here, that user retains enough balance after withdrawal
|
||||
// and also we check if `balance_to_transfer` is more than `existential_deposit`,
|
||||
assert!(
|
||||
(<pezpallet_balances::Pallet<Runtime>>::free_balance(&alice_account) -
|
||||
balance_to_transfer.into()) >=
|
||||
existential_deposit
|
||||
);
|
||||
// SA has just ED
|
||||
assert_eq!(
|
||||
<pezpallet_balances::Pallet<Runtime>>::free_balance(&reserve_account),
|
||||
existential_deposit
|
||||
);
|
||||
|
||||
let delivery_fees_account_balance_before = delivery_fees_account
|
||||
.as_ref()
|
||||
.map(|dfa| <pezpallet_balances::Pallet<Runtime>>::free_balance(dfa))
|
||||
.unwrap_or(0.into());
|
||||
|
||||
// local native asset (pezpallet_balances)
|
||||
let asset_to_transfer =
|
||||
Asset { fun: Fungible(balance_to_transfer.into()), id: native_asset.into() };
|
||||
|
||||
// destination is (some) account relative to the destination different consensus
|
||||
let target_destination_account = Location::new(
|
||||
0,
|
||||
[AccountId32 {
|
||||
network: Some(bridged_network),
|
||||
id: pezsp_runtime::AccountId32::new([3; 32]).into(),
|
||||
}],
|
||||
);
|
||||
|
||||
let assets_to_transfer = Assets::from(asset_to_transfer);
|
||||
let mut expected_assets = assets_to_transfer.clone();
|
||||
let context = XcmConfig::UniversalLocation::get();
|
||||
expected_assets
|
||||
.reanchor(&target_location_from_different_consensus, &context)
|
||||
.unwrap();
|
||||
|
||||
let expected_beneficiary = target_destination_account.clone();
|
||||
|
||||
// do cross-chain transfer
|
||||
assert_ok!(<pezpallet_xcm::Pallet<Runtime>>::transfer_assets_using_type_and_then(
|
||||
RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::origin_of(alice_account.clone()),
|
||||
Box::new(target_location_from_different_consensus.clone().into_versioned()),
|
||||
Box::new(VersionedAssets::from(assets_to_transfer)),
|
||||
Box::new(TransferType::LocalReserve),
|
||||
Box::new(VersionedAssetId::from(AssetId(Location::parent()))),
|
||||
Box::new(TransferType::LocalReserve),
|
||||
Box::new(VersionedXcm::from(
|
||||
Xcm::<()>::builder_unsafe()
|
||||
.deposit_asset(AllCounted(1), target_destination_account)
|
||||
.build()
|
||||
)),
|
||||
weight_limit,
|
||||
));
|
||||
|
||||
// check events
|
||||
// check pezpallet_xcm attempted
|
||||
RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::assert_pallet_xcm_event_outcome(
|
||||
&unwrap_pallet_xcm_event,
|
||||
|outcome| {
|
||||
assert_ok!(outcome.ensure_complete());
|
||||
},
|
||||
);
|
||||
|
||||
// check that xcm was sent
|
||||
let xcm_sent_message_hash = <pezframe_system::Pallet<Runtime>>::events()
|
||||
.into_iter()
|
||||
.filter_map(|e| unwrap_xcmp_queue_event(e.event.encode()))
|
||||
.find_map(|e| match e {
|
||||
cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { message_hash } =>
|
||||
Some(message_hash),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
// read xcm
|
||||
let xcm_sent = RuntimeHelper::<HrmpChannelSource, AllPalletsWithoutSystem>::take_xcm(
|
||||
local_bridge_hub_para_id.into(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
xcm_sent_message_hash,
|
||||
Some(xcm_sent.using_encoded(pezsp_io::hashing::blake2_256))
|
||||
);
|
||||
let mut xcm_sent: Xcm<()> = xcm_sent.try_into().expect("versioned xcm");
|
||||
|
||||
// check sent XCM ExportMessage to BridgeHub
|
||||
|
||||
let mut delivery_fees = 0;
|
||||
// 1. check paid or unpaid
|
||||
if let Some(expected_fee_asset_id) = maybe_paid_export_message {
|
||||
xcm_sent
|
||||
.0
|
||||
.matcher()
|
||||
.match_next_inst(|instr| match instr {
|
||||
WithdrawAsset(_) => Ok(()),
|
||||
_ => Err(ProcessMessageError::BadFormat),
|
||||
})
|
||||
.expect("contains WithdrawAsset")
|
||||
.match_next_inst(|instr| match instr {
|
||||
BuyExecution { fees, .. } if fees.id.eq(&expected_fee_asset_id) => Ok(()),
|
||||
_ => Err(ProcessMessageError::BadFormat),
|
||||
})
|
||||
.expect("contains BuyExecution")
|
||||
.match_next_inst(|instr| match instr {
|
||||
SetAppendix(_) => Ok(()),
|
||||
_ => Err(ProcessMessageError::BadFormat),
|
||||
})
|
||||
.expect("contains SetAppendix")
|
||||
} else {
|
||||
xcm_sent
|
||||
.0
|
||||
.matcher()
|
||||
.match_next_inst(|instr| match instr {
|
||||
// first instruction could be UnpaidExecution (because we could have
|
||||
// explicit unpaid execution on BridgeHub)
|
||||
UnpaidExecution { weight_limit, check_origin }
|
||||
if weight_limit == &Unlimited && check_origin.is_none() =>
|
||||
Ok(()),
|
||||
_ => Err(ProcessMessageError::BadFormat),
|
||||
})
|
||||
.expect("contains UnpaidExecution")
|
||||
}
|
||||
// 2. check ExportMessage
|
||||
.match_next_inst(|instr| match instr {
|
||||
// next instruction is ExportMessage
|
||||
ExportMessage { network, destination, xcm: inner_xcm } => {
|
||||
assert_eq!(network, &bridged_network);
|
||||
let (_, target_location_junctions_without_global_consensus) =
|
||||
target_location_from_different_consensus
|
||||
.interior
|
||||
.clone()
|
||||
.split_global()
|
||||
.expect("split works");
|
||||
assert_eq!(destination, &target_location_junctions_without_global_consensus);
|
||||
// Call `SendXcm::validate` to get delivery fees.
|
||||
delivery_fees = get_fungible_delivery_fees::<
|
||||
<XcmConfig as xcm_executor::Config>::XcmSender,
|
||||
>(
|
||||
target_location_from_different_consensus.clone(),
|
||||
inner_xcm.clone(),
|
||||
);
|
||||
assert_matches_reserve_asset_deposited_instructions(
|
||||
inner_xcm,
|
||||
&expected_assets,
|
||||
&expected_beneficiary,
|
||||
);
|
||||
Ok(())
|
||||
},
|
||||
_ => Err(ProcessMessageError::BadFormat),
|
||||
})
|
||||
.expect("contains ExportMessage");
|
||||
|
||||
// check alice account decreased by balance_to_transfer
|
||||
assert_eq!(
|
||||
<pezpallet_balances::Pallet<Runtime>>::free_balance(&alice_account),
|
||||
alice_account_init_balance
|
||||
.saturating_sub(balance_to_transfer.into())
|
||||
.saturating_sub(delivery_fees.into())
|
||||
);
|
||||
|
||||
// check reserve account increased by balance_to_transfer
|
||||
assert_eq!(
|
||||
<pezpallet_balances::Pallet<Runtime>>::free_balance(&reserve_account),
|
||||
existential_deposit + balance_to_transfer.into()
|
||||
);
|
||||
|
||||
// check dedicated account increased by delivery fees (if configured)
|
||||
if let Some(delivery_fees_account) = delivery_fees_account {
|
||||
let delivery_fees_account_balance_after =
|
||||
<pezpallet_balances::Pallet<Runtime>>::free_balance(&delivery_fees_account);
|
||||
assert!(
|
||||
delivery_fees_account_balance_after - delivery_fees.into() >=
|
||||
delivery_fees_account_balance_before
|
||||
);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn receive_reserve_asset_deposited_from_different_consensus_works<
|
||||
Runtime,
|
||||
AllPalletsWithoutSystem,
|
||||
XcmConfig,
|
||||
ForeignAssetsPalletInstance,
|
||||
>(
|
||||
collator_session_keys: CollatorSessionKeys<Runtime>,
|
||||
existential_deposit: BalanceOf<Runtime>,
|
||||
target_account: AccountIdOf<Runtime>,
|
||||
block_author_account: AccountIdOf<Runtime>,
|
||||
(
|
||||
foreign_asset_owner,
|
||||
foreign_asset_id_location,
|
||||
foreign_asset_reserve_data,
|
||||
foreign_asset_id_minimum_balance,
|
||||
): (AccountIdOf<Runtime>, xcm::v5::Location, ForeignAssetReserveData, u128),
|
||||
foreign_asset_id_amount_to_transfer: u128,
|
||||
prepare_configuration: impl FnOnce() -> TestBridgingConfig,
|
||||
(bridge_instance, universal_origin, descend_origin): (Junctions, Junction, Junctions), /* bridge adds origin manipulation on the way */
|
||||
additional_checks_before: impl FnOnce(),
|
||||
additional_checks_after: impl FnOnce(),
|
||||
) where
|
||||
Runtime: pezframe_system::Config
|
||||
+ pezpallet_balances::Config
|
||||
+ pezpallet_session::Config
|
||||
+ pezpallet_xcm::Config
|
||||
+ teyrchain_info::Config
|
||||
+ pezpallet_collator_selection::Config
|
||||
+ cumulus_pallet_teyrchain_system::Config
|
||||
+ cumulus_pallet_xcmp_queue::Config
|
||||
+ pezpallet_assets::Config<ForeignAssetsPalletInstance, ReserveData = ForeignAssetReserveData>
|
||||
+ pezpallet_timestamp::Config,
|
||||
AllPalletsWithoutSystem:
|
||||
OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
|
||||
AccountIdOf<Runtime>: Into<[u8; 32]> + From<[u8; 32]>,
|
||||
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
|
||||
BalanceOf<Runtime>: From<Balance> + Into<Balance>,
|
||||
XcmConfig: xcm_executor::Config,
|
||||
<Runtime as pezpallet_assets::Config<ForeignAssetsPalletInstance>>::AssetId:
|
||||
From<xcm::v5::Location> + Into<xcm::v5::Location>,
|
||||
<Runtime as pezpallet_assets::Config<ForeignAssetsPalletInstance>>::AssetIdParameter:
|
||||
From<xcm::v5::Location> + Into<xcm::v5::Location>,
|
||||
<Runtime as pezpallet_assets::Config<ForeignAssetsPalletInstance>>::Balance:
|
||||
From<Balance> + Into<u128> + From<u128>,
|
||||
<Runtime as pezframe_system::Config>::AccountId: Into<<<Runtime as pezframe_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>
|
||||
+ Into<AccountId>,
|
||||
<<Runtime as pezframe_system::Config>::Lookup as StaticLookup>::Source:
|
||||
From<<Runtime as pezframe_system::Config>::AccountId>,
|
||||
ForeignAssetsPalletInstance: 'static,
|
||||
{
|
||||
ExtBuilder::<Runtime>::default()
|
||||
.with_collators(collator_session_keys.collators())
|
||||
.with_session_keys(collator_session_keys.session_keys())
|
||||
.with_tracing()
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
// Set account as block author, who will receive fees
|
||||
RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::run_to_block(
|
||||
2,
|
||||
block_author_account.clone().into(),
|
||||
);
|
||||
|
||||
// drip 'ED' user target account
|
||||
let _ = <pezpallet_balances::Pallet<Runtime>>::deposit_creating(
|
||||
&target_account,
|
||||
existential_deposit,
|
||||
);
|
||||
|
||||
// create foreign asset for wrapped/derived representation
|
||||
assert_ok!(
|
||||
<pezpallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::force_create(
|
||||
RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::root_origin(),
|
||||
foreign_asset_id_location.clone().into(),
|
||||
foreign_asset_owner.clone().into(),
|
||||
true, // is_sufficient=true
|
||||
foreign_asset_id_minimum_balance.into()
|
||||
)
|
||||
);
|
||||
// set the right reserve for the foreign asset
|
||||
assert_ok!(
|
||||
<pezpallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::set_reserves(
|
||||
RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::origin_of(
|
||||
foreign_asset_owner
|
||||
),
|
||||
foreign_asset_id_location.clone().into(),
|
||||
vec![foreign_asset_reserve_data],
|
||||
)
|
||||
);
|
||||
|
||||
// prepare bridge config
|
||||
let TestBridgingConfig { local_bridge_hub_location, .. } = prepare_configuration();
|
||||
|
||||
// Balances before
|
||||
assert_eq!(
|
||||
<pezpallet_balances::Pallet<Runtime>>::free_balance(&target_account),
|
||||
existential_deposit.clone()
|
||||
);
|
||||
|
||||
// ForeignAssets balances before
|
||||
assert_eq!(
|
||||
<pezpallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::balance(
|
||||
foreign_asset_id_location.clone().into(),
|
||||
&target_account
|
||||
),
|
||||
0.into()
|
||||
);
|
||||
|
||||
// additional check before
|
||||
additional_checks_before();
|
||||
|
||||
let expected_assets = Assets::from(vec![Asset {
|
||||
id: AssetId(foreign_asset_id_location.clone()),
|
||||
fun: Fungible(foreign_asset_id_amount_to_transfer),
|
||||
}]);
|
||||
let expected_beneficiary = Location::new(
|
||||
0,
|
||||
[AccountId32 { network: None, id: target_account.clone().into() }],
|
||||
);
|
||||
|
||||
// Call received XCM execution
|
||||
let xcm = Xcm(vec![
|
||||
DescendOrigin(bridge_instance),
|
||||
UniversalOrigin(universal_origin),
|
||||
DescendOrigin(descend_origin),
|
||||
ReserveAssetDeposited(expected_assets.clone()),
|
||||
ClearOrigin,
|
||||
BuyExecution {
|
||||
fees: Asset {
|
||||
id: AssetId(foreign_asset_id_location.clone()),
|
||||
fun: Fungible(foreign_asset_id_amount_to_transfer),
|
||||
},
|
||||
weight_limit: Unlimited,
|
||||
},
|
||||
DepositAsset {
|
||||
assets: Wild(AllCounted(1)),
|
||||
beneficiary: expected_beneficiary.clone(),
|
||||
},
|
||||
SetTopic([
|
||||
220, 188, 144, 32, 213, 83, 111, 175, 44, 210, 111, 19, 90, 165, 191, 112, 140,
|
||||
247, 192, 124, 42, 17, 153, 141, 114, 34, 189, 20, 83, 69, 237, 173,
|
||||
]),
|
||||
]);
|
||||
assert_matches_reserve_asset_deposited_instructions(
|
||||
&mut xcm.clone(),
|
||||
&expected_assets,
|
||||
&expected_beneficiary,
|
||||
);
|
||||
|
||||
let mut hash = xcm.using_encoded(pezsp_io::hashing::blake2_256);
|
||||
|
||||
// execute xcm as XcmpQueue would do
|
||||
let outcome = XcmExecutor::<XcmConfig>::prepare_and_execute(
|
||||
local_bridge_hub_location,
|
||||
xcm,
|
||||
&mut hash,
|
||||
RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::xcm_max_weight(
|
||||
XcmReceivedFrom::Sibling,
|
||||
),
|
||||
Weight::zero(),
|
||||
);
|
||||
assert_ok!(outcome.ensure_complete());
|
||||
|
||||
// Balances after
|
||||
assert_eq!(
|
||||
<pezpallet_balances::Pallet<Runtime>>::free_balance(&target_account),
|
||||
existential_deposit.clone()
|
||||
);
|
||||
|
||||
// ForeignAssets balances after
|
||||
assert!(
|
||||
<pezpallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::balance(
|
||||
foreign_asset_id_location.into(),
|
||||
&target_account
|
||||
) > 0.into()
|
||||
);
|
||||
|
||||
// additional check after
|
||||
additional_checks_after();
|
||||
})
|
||||
}
|
||||
|
||||
pub fn report_bridge_status_from_xcm_bridge_router_works<
|
||||
Runtime,
|
||||
AllPalletsWithoutSystem,
|
||||
XcmConfig,
|
||||
LocationToAccountId,
|
||||
XcmBridgeHubRouterInstance,
|
||||
>(
|
||||
collator_session_keys: CollatorSessionKeys<Runtime>,
|
||||
prepare_configuration: fn() -> TestBridgingConfig,
|
||||
congested_message: fn() -> Xcm<XcmConfig::RuntimeCall>,
|
||||
uncongested_message: fn() -> Xcm<XcmConfig::RuntimeCall>,
|
||||
) where
|
||||
Runtime: pezframe_system::Config
|
||||
+ pezpallet_balances::Config
|
||||
+ pezpallet_session::Config
|
||||
+ pezpallet_xcm::Config
|
||||
+ teyrchain_info::Config
|
||||
+ pezpallet_collator_selection::Config
|
||||
+ cumulus_pallet_teyrchain_system::Config
|
||||
+ cumulus_pallet_xcmp_queue::Config
|
||||
+ pezpallet_xcm_bridge_hub_router::Config<XcmBridgeHubRouterInstance>
|
||||
+ pezpallet_timestamp::Config,
|
||||
AllPalletsWithoutSystem:
|
||||
OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
|
||||
AccountIdOf<Runtime>: Into<[u8; 32]>,
|
||||
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
|
||||
BalanceOf<Runtime>: From<Balance>,
|
||||
<Runtime as pezpallet_balances::Config>::Balance: From<Balance> + Into<u128>,
|
||||
XcmConfig: xcm_executor::Config,
|
||||
LocationToAccountId: ConvertLocation<AccountIdOf<Runtime>>,
|
||||
<Runtime as pezframe_system::Config>::AccountId:
|
||||
Into<<<Runtime as pezframe_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
|
||||
<<Runtime as pezframe_system::Config>::Lookup as StaticLookup>::Source:
|
||||
From<<Runtime as pezframe_system::Config>::AccountId>,
|
||||
<Runtime as pezframe_system::Config>::AccountId: From<AccountId>,
|
||||
XcmBridgeHubRouterInstance: 'static,
|
||||
{
|
||||
ExtBuilder::<Runtime>::default()
|
||||
.with_collators(collator_session_keys.collators())
|
||||
.with_session_keys(collator_session_keys.session_keys())
|
||||
.with_tracing()
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
let report_bridge_status = |is_congested: bool| {
|
||||
// prepare bridge config
|
||||
let TestBridgingConfig { local_bridge_hub_location, .. } = prepare_configuration();
|
||||
|
||||
// Call received XCM execution
|
||||
let xcm = if is_congested { congested_message() } else { uncongested_message() };
|
||||
let mut hash = xcm.using_encoded(pezsp_io::hashing::blake2_256);
|
||||
|
||||
// execute xcm as XcmpQueue would do
|
||||
let outcome = XcmExecutor::<XcmConfig>::prepare_and_execute(
|
||||
local_bridge_hub_location.clone(),
|
||||
xcm,
|
||||
&mut hash,
|
||||
RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::xcm_max_weight(
|
||||
XcmReceivedFrom::Sibling,
|
||||
),
|
||||
Weight::zero(),
|
||||
);
|
||||
assert_ok!(outcome.ensure_complete());
|
||||
assert_eq!(is_congested, pezpallet_xcm_bridge_hub_router::Pallet::<Runtime, XcmBridgeHubRouterInstance>::bridge().is_congested);
|
||||
};
|
||||
|
||||
report_bridge_status(true);
|
||||
report_bridge_status(false);
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Pezcumulus.
|
||||
// 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.
|
||||
|
||||
//! Helpers for calculating XCM delivery fees.
|
||||
|
||||
use xcm::latest::prelude::*;
|
||||
|
||||
/// Returns the delivery fees amount for pallet xcm's `teleport_assets` extrinsics.
|
||||
/// Because it returns only a `u128`, it assumes delivery fees are only paid
|
||||
/// in one asset and that asset is known.
|
||||
pub fn teleport_assets_delivery_fees<S: SendXcm>(
|
||||
assets: Assets,
|
||||
fee_asset_id: AssetId,
|
||||
weight_limit: WeightLimit,
|
||||
beneficiary: Location,
|
||||
destination: Location,
|
||||
) -> u128 {
|
||||
let message = teleport_assets_dummy_message(assets, fee_asset_id, weight_limit, beneficiary);
|
||||
get_fungible_delivery_fees::<S>(destination, message)
|
||||
}
|
||||
|
||||
/// Returns the delivery fees amount for a query response as a result of the execution
|
||||
/// of a `ExpectError` instruction with no error.
|
||||
pub fn query_response_delivery_fees<S: SendXcm>(querier: Location) -> u128 {
|
||||
// Message to calculate delivery fees, it's encoded size is what's important.
|
||||
// This message reports that there was no error, if an error is reported, the encoded size would
|
||||
// be different.
|
||||
let message = Xcm(vec![
|
||||
SetFeesMode { jit_withdraw: true },
|
||||
QueryResponse {
|
||||
query_id: 0, // Dummy query id
|
||||
response: Response::ExecutionResult(None),
|
||||
max_weight: Weight::zero(),
|
||||
querier: Some(querier.clone()),
|
||||
},
|
||||
SetTopic([0u8; 32]), // Dummy topic
|
||||
]);
|
||||
get_fungible_delivery_fees::<S>(querier, message)
|
||||
}
|
||||
|
||||
/// Returns the delivery fees amount for the execution of `PayOverXcm`
|
||||
pub fn pay_over_xcm_delivery_fees<S: SendXcm>(
|
||||
interior: Junctions,
|
||||
destination: Location,
|
||||
beneficiary: Location,
|
||||
asset: Asset,
|
||||
) -> u128 {
|
||||
// This is a dummy message.
|
||||
// The encoded size is all that matters for delivery fees.
|
||||
let message = Xcm(vec![
|
||||
DescendOrigin(interior),
|
||||
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
|
||||
SetAppendix(Xcm(vec![
|
||||
SetFeesMode { jit_withdraw: true },
|
||||
ReportError(QueryResponseInfo {
|
||||
destination: destination.clone(),
|
||||
query_id: 0,
|
||||
max_weight: Weight::zero(),
|
||||
}),
|
||||
])),
|
||||
TransferAsset { beneficiary, assets: vec![asset].into() },
|
||||
]);
|
||||
get_fungible_delivery_fees::<S>(destination, message)
|
||||
}
|
||||
|
||||
/// Approximates the actual message sent by the teleport extrinsic.
|
||||
/// The assets are not reanchored and the topic is a dummy one.
|
||||
/// However, it should have the same encoded size, which is what matters for delivery fees.
|
||||
/// Also has same encoded size as the one created by the reserve transfer assets extrinsic.
|
||||
fn teleport_assets_dummy_message(
|
||||
assets: Assets,
|
||||
fee_asset_id: AssetId,
|
||||
weight_limit: WeightLimit,
|
||||
beneficiary: Location,
|
||||
) -> Xcm<()> {
|
||||
Xcm(vec![
|
||||
ReceiveTeleportedAsset(assets.clone()), // Same encoded size as `ReserveAssetDeposited`
|
||||
ClearOrigin,
|
||||
BuyExecution {
|
||||
fees: assets.inner().iter().find(|a| a.id == fee_asset_id).unwrap().clone(),
|
||||
weight_limit,
|
||||
},
|
||||
DepositAsset { assets: Wild(AllCounted(assets.len() as u32)), beneficiary },
|
||||
SetTopic([0u8; 32]), // Dummy topic
|
||||
])
|
||||
}
|
||||
|
||||
/// Given a message, a sender, and a destination, it returns the delivery fees
|
||||
fn get_fungible_delivery_fees<S: SendXcm>(destination: Location, message: Xcm<()>) -> u128 {
|
||||
let delivery_fees = match validate_send::<S>(destination, message) {
|
||||
Ok((_, delivery_fees)) => delivery_fees,
|
||||
Err(e) => unreachable!("message can be sent - {:?}; qed", e),
|
||||
};
|
||||
if let Some(delivery_fee) = delivery_fees.inner().first() {
|
||||
let Fungible(delivery_fee_amount) = delivery_fee.fun else {
|
||||
unreachable!("asset is fungible; qed");
|
||||
};
|
||||
delivery_fee_amount
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user