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:
2025-12-14 00:04:10 +03:00
parent 286de54384
commit 1c0e57d984
9084 changed files with 997839 additions and 997557 deletions
+114
View File
@@ -0,0 +1,114 @@
[package]
name = "teyrchains-common"
version = "7.0.0"
authors.workspace = true
edition.workspace = true
description = "Logic which is common to all teyrchain runtimes"
license = "Apache-2.0"
homepage.workspace = true
repository.workspace = true
[lints]
workspace = true
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
codec = { features = ["derive"], workspace = true }
scale-info = { features = ["derive"], workspace = true }
tracing = { workspace = true }
# Bizinikiwi
pezframe-support = { workspace = true }
pezframe-system = { workspace = true }
pezpallet-asset-tx-payment = { workspace = true }
pezpallet-assets = { workspace = true }
pezpallet-authorship = { workspace = true }
pezpallet-balances = { workspace = true }
pezpallet-message-queue = { workspace = true }
pezpallet-treasury = { workspace = true }
pezsp-consensus-aura = { workspace = true }
pezsp-core = { workspace = true }
pezsp-io = { workspace = true }
pezsp-runtime = { workspace = true }
# Pezkuwi
pezpallet-xcm = { workspace = true }
pezkuwi-primitives = { workspace = true }
pezkuwi-runtime-common = { workspace = true }
xcm = { workspace = true }
xcm-executor = { workspace = true }
# Pezcumulus
pezcumulus-primitives-core = { workspace = true }
pezcumulus-primitives-utility = { workspace = true }
pezpallet-collator-selection = { workspace = true }
teyrchain-info = { workspace = true }
[features]
default = ["std"]
std = [
"codec/std",
"pezcumulus-primitives-core/std",
"pezcumulus-primitives-utility/std",
"pezframe-support/std",
"pezframe-system/std",
"pezpallet-asset-tx-payment/std",
"pezpallet-assets/std",
"pezpallet-authorship/std",
"pezpallet-balances/std",
"pezpallet-collator-selection/std",
"pezpallet-message-queue/std",
"pezpallet-treasury/std",
"pezpallet-xcm/std",
"pezkuwi-primitives/std",
"pezkuwi-runtime-common/std",
"scale-info/std",
"pezsp-consensus-aura/std",
"pezsp-core/std",
"pezsp-io/std",
"pezsp-runtime/std",
"teyrchain-info/std",
"tracing/std",
"xcm-executor/std",
"xcm/std",
]
runtime-benchmarks = [
"pezcumulus-primitives-core/runtime-benchmarks",
"pezcumulus-primitives-utility/runtime-benchmarks",
"pezframe-support/runtime-benchmarks",
"pezframe-system/runtime-benchmarks",
"pezpallet-asset-tx-payment/runtime-benchmarks",
"pezpallet-assets/runtime-benchmarks",
"pezpallet-authorship/runtime-benchmarks",
"pezpallet-balances/runtime-benchmarks",
"pezpallet-collator-selection/runtime-benchmarks",
"pezpallet-message-queue/runtime-benchmarks",
"pezpallet-treasury/runtime-benchmarks",
"pezpallet-xcm/runtime-benchmarks",
"pezkuwi-primitives/runtime-benchmarks",
"pezkuwi-runtime-common/runtime-benchmarks",
"pezsp-consensus-aura/runtime-benchmarks",
"pezsp-io/runtime-benchmarks",
"pezsp-runtime/runtime-benchmarks",
"teyrchain-info/runtime-benchmarks",
"xcm-executor/runtime-benchmarks",
"xcm/runtime-benchmarks",
]
try-runtime = [
"pezframe-support/try-runtime",
"pezframe-system/try-runtime",
"pezpallet-asset-tx-payment/try-runtime",
"pezpallet-assets/try-runtime",
"pezpallet-authorship/try-runtime",
"pezpallet-balances/try-runtime",
"pezpallet-collator-selection/try-runtime",
"pezpallet-message-queue/try-runtime",
"pezpallet-treasury/try-runtime",
"pezpallet-xcm/try-runtime",
"pezkuwi-runtime-common/try-runtime",
"pezsp-runtime/try-runtime",
"teyrchain-info/try-runtime",
]
+347
View File
@@ -0,0 +1,347 @@
// 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.
//! Auxiliary struct/enums for teyrchain runtimes.
//! Taken from pezkuwi/runtime/common (at a21cd64) and adapted for teyrchains.
use alloc::boxed::Box;
use core::marker::PhantomData;
use pezframe_support::traits::{
fungible, fungibles, tokens::imbalance::ResolveTo, Contains, ContainsPair, Currency, Defensive,
Get, Imbalance, OnUnbalanced, OriginTrait,
};
use pezpallet_asset_tx_payment::HandleCredit;
use pezpallet_collator_selection::StakingPotAccountId;
use pezsp_runtime::traits::Zero;
use xcm::latest::{
Asset, AssetId, Fungibility, Fungibility::Fungible, Junction, Junctions::Here, Location,
Parent, WeightLimit,
};
use xcm_executor::traits::ConvertLocation;
/// Type alias to conveniently refer to `pezframe_system`'s `Config::AccountId`.
pub type AccountIdOf<T> = <T as pezframe_system::Config>::AccountId;
/// Type alias to conveniently refer to the `Currency::NegativeImbalance` associated type.
pub type NegativeImbalance<T> = <pezpallet_balances::Pallet<T> as Currency<
<T as pezframe_system::Config>::AccountId,
>>::NegativeImbalance;
/// Implementation of `OnUnbalanced` that deposits the fees into a staking pot for later payout.
#[deprecated(
note = "ToStakingPot is deprecated and will be removed after March 2024. Please use pezframe_support::traits::tokens::imbalance::ResolveTo instead."
)]
pub struct ToStakingPot<R>(PhantomData<R>);
#[allow(deprecated)]
impl<R> OnUnbalanced<NegativeImbalance<R>> for ToStakingPot<R>
where
R: pezpallet_balances::Config + pezpallet_collator_selection::Config,
AccountIdOf<R>: From<pezkuwi_primitives::AccountId> + Into<pezkuwi_primitives::AccountId>,
<R as pezframe_system::Config>::RuntimeEvent: From<pezpallet_balances::Event<R>>,
{
fn on_nonzero_unbalanced(amount: NegativeImbalance<R>) {
let staking_pot = <pezpallet_collator_selection::Pallet<R>>::account_id();
// In case of error: Will drop the result triggering the `OnDrop` of the imbalance.
<pezpallet_balances::Pallet<R>>::resolve_creating(&staking_pot, amount);
}
}
/// Fungible implementation of `OnUnbalanced` that deals with the fees by combining tip and fee and
/// passing the result on to `ToStakingPot`.
pub struct DealWithFees<R>(PhantomData<R>);
impl<R> OnUnbalanced<fungible::Credit<R::AccountId, pezpallet_balances::Pallet<R>>> for DealWithFees<R>
where
R: pezpallet_balances::Config + pezpallet_collator_selection::Config,
AccountIdOf<R>: From<pezkuwi_primitives::AccountId> + Into<pezkuwi_primitives::AccountId>,
<R as pezframe_system::Config>::RuntimeEvent: From<pezpallet_balances::Event<R>>,
{
fn on_unbalanceds(
mut fees_then_tips: impl Iterator<
Item = fungible::Credit<R::AccountId, pezpallet_balances::Pallet<R>>,
>,
) {
if let Some(mut fees) = fees_then_tips.next() {
if let Some(tips) = fees_then_tips.next() {
tips.merge_into(&mut fees);
}
ResolveTo::<StakingPotAccountId<R>, pezpallet_balances::Pallet<R>>::on_unbalanced(fees)
}
}
}
/// A `HandleCredit` implementation that naively transfers the fees to the block author.
/// Will drop and burn the assets in case the transfer fails.
pub struct AssetsToBlockAuthor<R, I>(PhantomData<(R, I)>);
impl<R, I> HandleCredit<AccountIdOf<R>, pezpallet_assets::Pallet<R, I>> for AssetsToBlockAuthor<R, I>
where
I: 'static,
R: pezpallet_authorship::Config + pezpallet_assets::Config<I>,
AccountIdOf<R>: From<pezkuwi_primitives::AccountId> + Into<pezkuwi_primitives::AccountId>,
{
fn handle_credit(credit: fungibles::Credit<AccountIdOf<R>, pezpallet_assets::Pallet<R, I>>) {
use pezframe_support::traits::fungibles::Balanced;
if let Some(author) = pezpallet_authorship::Pallet::<R>::author() {
// In case of error: Will drop the result triggering the `OnDrop` of the imbalance.
let _ = pezpallet_assets::Pallet::<R, I>::resolve(&author, credit).defensive();
}
}
}
/// Allow checking in assets that have issuance > 0.
pub struct NonZeroIssuance<AccountId, Assets>(PhantomData<(AccountId, Assets)>);
impl<AccountId, Assets> Contains<<Assets as fungibles::Inspect<AccountId>>::AssetId>
for NonZeroIssuance<AccountId, Assets>
where
Assets: fungibles::Inspect<AccountId>,
{
fn contains(id: &<Assets as fungibles::Inspect<AccountId>>::AssetId) -> bool {
!Assets::total_issuance(id.clone()).is_zero()
}
}
/// Allow checking in assets that exists.
pub struct AssetExists<AccountId, Assets>(PhantomData<(AccountId, Assets)>);
impl<AccountId, Assets> Contains<<Assets as fungibles::Inspect<AccountId>>::AssetId>
for AssetExists<AccountId, Assets>
where
Assets: fungibles::Inspect<AccountId>,
{
fn contains(id: &<Assets as fungibles::Inspect<AccountId>>::AssetId) -> bool {
Assets::asset_exists(id.clone())
}
}
/// Asset filter that allows all assets from a certain location.
pub struct AssetsFrom<T>(PhantomData<T>);
impl<T: Get<Location>> ContainsPair<Asset, Location> for AssetsFrom<T> {
fn contains(asset: &Asset, origin: &Location) -> bool {
let loc = T::get();
&loc == origin &&
matches!(asset, Asset { id: AssetId(asset_loc), fun: Fungible(_a) }
if asset_loc.match_and_split(&loc).is_some())
}
}
/// Type alias to conveniently refer to the `Currency::Balance` associated type.
pub type BalanceOf<T> =
<pezpallet_balances::Pallet<T> as Currency<<T as pezframe_system::Config>::AccountId>>::Balance;
/// Implements `OnUnbalanced::on_unbalanced` to teleport slashed assets to relay chain treasury
/// account.
pub struct ToParentTreasury<TreasuryAccount, AccountIdConverter, T>(
PhantomData<(TreasuryAccount, AccountIdConverter, T)>,
);
impl<TreasuryAccount, AccountIdConverter, T> OnUnbalanced<NegativeImbalance<T>>
for ToParentTreasury<TreasuryAccount, AccountIdConverter, T>
where
T: pezpallet_balances::Config + pezpallet_xcm::Config + pezframe_system::Config,
<<T as pezframe_system::Config>::RuntimeOrigin as OriginTrait>::AccountId: From<AccountIdOf<T>>,
[u8; 32]: From<<T as pezframe_system::Config>::AccountId>,
TreasuryAccount: Get<AccountIdOf<T>>,
AccountIdConverter: ConvertLocation<AccountIdOf<T>>,
BalanceOf<T>: Into<Fungibility>,
{
fn on_unbalanced(amount: NegativeImbalance<T>) {
let amount = match amount.drop_zero() {
Ok(..) => return,
Err(amount) => amount,
};
let imbalance = amount.peek();
let root_location: Location = Here.into();
let root_account: AccountIdOf<T> =
match AccountIdConverter::convert_location(&root_location) {
Some(a) => a,
None => {
tracing::warn!(target: "xcm::on_unbalanced", "Failed to convert root origin into account id");
return;
},
};
let treasury_account: AccountIdOf<T> = TreasuryAccount::get();
<pezpallet_balances::Pallet<T>>::resolve_creating(&root_account, amount);
let result = <pezpallet_xcm::Pallet<T>>::limited_teleport_assets(
<<T as pezframe_system::Config>::RuntimeOrigin>::root(),
Box::new(Parent.into()),
Box::new(
Junction::AccountId32 { network: None, id: treasury_account.into() }
.into_location()
.into(),
),
Box::new((Parent, imbalance).into()),
Box::new(Parent.into()),
WeightLimit::Unlimited,
);
if let Err(err) = result {
tracing::warn!(target: "xcm::on_unbalanced", error=?err, "Failed to teleport slashed assets");
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use pezframe_support::{
derive_impl, parameter_types,
traits::{ConstU32, FindAuthor, ValidatorRegistration},
PalletId,
};
use pezframe_system::{limits, EnsureRoot};
use pezpallet_collator_selection::IdentityCollator;
use pezkuwi_primitives::AccountId;
use pezsp_core::H256;
use pezsp_runtime::{
traits::{BlakeTwo256, IdentityLookup},
BuildStorage, Perbill,
};
use xcm::prelude::*;
type Block = pezframe_system::mocking::MockBlock<Test>;
const TEST_ACCOUNT: AccountId = AccountId::new([1; 32]);
pezframe_support::construct_runtime!(
pub enum Test
{
System: pezframe_system::{Pallet, Call, Config<T>, Storage, Event<T>},
Balances: pezpallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
CollatorSelection: pezpallet_collator_selection::{Pallet, Call, Storage, Event<T>},
}
);
parameter_types! {
pub BlockLength: limits::BlockLength = limits::BlockLength::max(2 * 1024);
pub const AvailableBlockRatio: Perbill = Perbill::one();
}
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
impl pezframe_system::Config for Test {
type BaseCallFilter = pezframe_support::traits::Everything;
type RuntimeOrigin = RuntimeOrigin;
type Nonce = u64;
type RuntimeCall = RuntimeCall;
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = AccountId;
type Lookup = IdentityLookup<Self::AccountId>;
type Block = Block;
type RuntimeEvent = RuntimeEvent;
type BlockLength = BlockLength;
type BlockWeights = ();
type DbWeight = ();
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = pezpallet_balances::AccountData<u64>;
type OnNewAccount = ();
type OnKilledAccount = ();
type SystemWeightInfo = ();
type SS58Prefix = ();
type OnSetCode = ();
type MaxConsumers = pezframe_support::traits::ConstU32<16>;
}
#[derive_impl(pezpallet_balances::config_preludes::TestDefaultConfig)]
impl pezpallet_balances::Config for Test {
type AccountStore = System;
}
pub struct OneAuthor;
impl FindAuthor<AccountId> for OneAuthor {
fn find_author<'a, I>(_: I) -> Option<AccountId>
where
I: 'a,
{
Some(TEST_ACCOUNT)
}
}
pub struct IsRegistered;
impl ValidatorRegistration<AccountId> for IsRegistered {
fn is_registered(_id: &AccountId) -> bool {
true
}
}
parameter_types! {
pub const PotId: PalletId = PalletId(*b"PotStake");
}
impl pezpallet_collator_selection::Config for Test {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type UpdateOrigin = EnsureRoot<AccountId>;
type PotId = PotId;
type MaxCandidates = ConstU32<20>;
type MinEligibleCollators = ConstU32<1>;
type MaxInvulnerables = ConstU32<20>;
type ValidatorId = <Self as pezframe_system::Config>::AccountId;
type ValidatorIdOf = IdentityCollator;
type ValidatorRegistration = IsRegistered;
type KickThreshold = ();
type WeightInfo = ();
}
impl pezpallet_authorship::Config for Test {
type FindAuthor = OneAuthor;
type EventHandler = ();
}
pub fn new_test_ext() -> pezsp_io::TestExternalities {
let mut t = pezframe_system::GenesisConfig::<Test>::default().build_storage().unwrap();
// We use default for brevity, but you can configure as desired if needed.
pezpallet_balances::GenesisConfig::<Test>::default()
.assimilate_storage(&mut t)
.unwrap();
t.into()
}
#[test]
fn test_fees_and_tip_split() {
new_test_ext().execute_with(|| {
let fee =
<pezpallet_balances::Pallet<Test> as pezframe_support::traits::fungible::Balanced<
AccountId,
>>::issue(10);
let tip =
<pezpallet_balances::Pallet<Test> as pezframe_support::traits::fungible::Balanced<
AccountId,
>>::issue(20);
assert_eq!(Balances::free_balance(TEST_ACCOUNT), 0);
DealWithFees::on_unbalanceds(vec![fee, tip].into_iter());
// Author gets 100% of tip and 100% of fee = 30
assert_eq!(Balances::free_balance(CollatorSelection::account_id()), 30);
});
}
#[test]
fn assets_from_filters_correctly() {
parameter_types! {
pub SomeSiblingTeyrchain: Location = (Parent, Teyrchain(1234)).into();
}
let asset_location = SomeSiblingTeyrchain::get()
.pushed_with_interior(GeneralIndex(42))
.expect("location will only have 2 junctions; qed");
let asset = Asset { id: AssetId(asset_location), fun: 1_000_000u128.into() };
assert!(
AssetsFrom::<SomeSiblingTeyrchain>::contains(&asset, &SomeSiblingTeyrchain::get()),
"AssetsFrom should allow assets from any of its interior locations"
);
}
}
+139
View File
@@ -0,0 +1,139 @@
// 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_attr(not(feature = "std"), no_std)]
extern crate alloc;
pub mod impls;
pub mod message_queue;
pub mod pay;
pub mod xcm_config;
pub use constants::*;
pub use opaque::*;
pub use types::*;
/// Common types of teyrchains.
mod types {
use pezsp_runtime::traits::{IdentifyAccount, Verify};
/// An index to a block.
pub type BlockNumber = u32;
/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
pub type Signature = pezsp_runtime::MultiSignature;
/// Some way of identifying an account on the chain. We intentionally make it equivalent
/// to the public key of our transaction signing scheme.
pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
/// never know...
pub type AccountIndex = u32;
/// Balance of an account.
pub type Balance = u128;
/// Index of a transaction in the chain.
pub type Nonce = u32;
/// A hash of some data used by the chain.
pub type Hash = pezsp_core::H256;
/// Digest item type.
pub type DigestItem = pezsp_runtime::generic::DigestItem;
// Aura consensus authority.
pub type AuraId = pezsp_consensus_aura::sr25519::AuthorityId;
// Aura consensus authority used by Asset Hub Pezkuwi.
//
// Because of registering the authorities with an ed25519 key before switching from Shell
// to Asset Hub Pezkuwi, we were required to deploy a hotfix that changed Asset Hub Pezkuwi's
// Aura keys to ed22519. In the future that may change again.
pub type AssetHubPezkuwiAuraId = pezsp_consensus_aura::ed25519::AuthorityId;
// Id used for identifying assets.
pub type AssetIdForTrustBackedAssets = u32;
// Id used for identifying non-fungible collections.
pub type CollectionId = u32;
// Id used for identifying non-fungible items.
pub type ItemId = u32;
}
/// Common constants of teyrchains.
mod constants {
use super::types::BlockNumber;
use pezframe_support::{
weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight},
PalletId,
};
use pezsp_runtime::Perbill;
/// This determines the average expected block time that we are targeting. Blocks will be
/// produced at a minimum duration defined by `SLOT_DURATION`. `SLOT_DURATION` is picked up by
/// `pezpallet_timestamp` which is in turn picked up by `pezpallet_aura` to implement `fn
/// slot_duration()`.
///
/// Change this to adjust the block time.
pub const MILLISECS_PER_BLOCK: u64 = 12000;
pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
// Time is measured by number of blocks.
pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
pub const HOURS: BlockNumber = MINUTES * 60;
pub const DAYS: BlockNumber = HOURS * 24;
/// We assume that ~5% of the block weight is consumed by `on_initialize` handlers. This is
/// used to limit the maximal weight of a single extrinsic.
pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(5);
/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used by
/// Operational extrinsics.
pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
/// We allow for 0.5 seconds of compute with a 6 second average block time.
pub const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(
WEIGHT_REF_TIME_PER_SECOND.saturating_div(2),
pezkuwi_primitives::MAX_POV_SIZE as u64,
);
/// We allow for 2 seconds of compute with a 6 second average block.
pub const MAXIMUM_BLOCK_WEIGHT_FOR_ASYNC_BACKING: Weight = Weight::from_parts(
WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2),
pezkuwi_primitives::MAX_POV_SIZE as u64,
);
/// Treasury pallet id of the local chain, used to convert into AccountId
pub const TREASURY_PALLET_ID: PalletId = PalletId(*b"py/trsry");
}
/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
/// the specifics of the runtime. They can then be made to be agnostic over specific formats
/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
/// to even the core data structures.
pub mod opaque {
use super::*;
use pezsp_runtime::{generic, traits::BlakeTwo256};
pub use pezsp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;
/// Opaque block header type.
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
/// Opaque block type.
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
/// Opaque block identifier type.
pub type BlockId = generic::BlockId<Block>;
}
@@ -0,0 +1,55 @@
// 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 to deal with configuring the message queue in the runtime.
use core::marker::PhantomData;
use cumulus_primitives_core::{AggregateMessageOrigin, ParaId};
use pezframe_support::traits::{QueueFootprint, QueuePausedQuery};
use pezpallet_message_queue::OnQueueChanged;
/// Narrow the scope of the `Inner` query from `AggregateMessageOrigin` to `ParaId`.
///
/// All non-`Sibling` variants will be ignored.
pub struct NarrowOriginToSibling<Inner>(PhantomData<Inner>);
impl<Inner: QueuePausedQuery<ParaId>> QueuePausedQuery<AggregateMessageOrigin>
for NarrowOriginToSibling<Inner>
{
fn is_paused(origin: &AggregateMessageOrigin) -> bool {
match origin {
AggregateMessageOrigin::Sibling(id) => Inner::is_paused(id),
_ => false,
}
}
}
impl<Inner: OnQueueChanged<ParaId>> OnQueueChanged<AggregateMessageOrigin>
for NarrowOriginToSibling<Inner>
{
fn on_queue_changed(origin: AggregateMessageOrigin, fp: QueueFootprint) {
if let AggregateMessageOrigin::Sibling(id) = origin {
Inner::on_queue_changed(id, fp)
}
}
}
/// Convert a sibling `ParaId` to an `AggregateMessageOrigin`.
pub struct ParaIdToSibling;
impl pezsp_runtime::traits::Convert<ParaId, AggregateMessageOrigin> for ParaIdToSibling {
fn convert(para_id: ParaId) -> AggregateMessageOrigin {
AggregateMessageOrigin::Sibling(para_id)
}
}
+159
View File
@@ -0,0 +1,159 @@
// 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.
use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
use pezframe_support::traits::{
fungibles,
tokens::{PaymentStatus, Preservation},
};
use pezkuwi_runtime_common::impls::VersionedLocatableAsset;
use pezsp_runtime::{traits::TypedGet, DispatchError, RuntimeDebug};
use xcm::latest::prelude::*;
use xcm_executor::traits::ConvertLocation;
/// Versioned locatable account type which contains both an XCM `location` and `account_id` to
/// identify an account which exists on some chain.
#[derive(
Encode,
Decode,
Eq,
PartialEq,
Clone,
RuntimeDebug,
scale_info::TypeInfo,
MaxEncodedLen,
DecodeWithMemTracking,
)]
pub enum VersionedLocatableAccount {
#[codec(index = 4)]
V4 { location: xcm::v4::Location, account_id: xcm::v4::Location },
#[codec(index = 5)]
V5 { location: xcm::v5::Location, account_id: xcm::v5::Location },
}
/// Pay on the local chain with `fungibles` implementation if the beneficiary and the asset are both
/// local.
pub struct LocalPay<F, A, C>(core::marker::PhantomData<(F, A, C)>);
impl<A, F, C> pezframe_support::traits::tokens::Pay for LocalPay<F, A, C>
where
A: TypedGet,
F: fungibles::Mutate<A::Type, AssetId = xcm::v5::Location> + fungibles::Create<A::Type>,
C: ConvertLocation<A::Type>,
A::Type: Eq + Clone,
{
type Balance = F::Balance;
type Beneficiary = VersionedLocatableAccount;
type AssetKind = VersionedLocatableAsset;
type Id = QueryId;
type Error = DispatchError;
fn pay(
who: &Self::Beneficiary,
asset: Self::AssetKind,
amount: Self::Balance,
) -> Result<Self::Id, Self::Error> {
let who = Self::match_location(who).map_err(|_| DispatchError::Unavailable)?;
let asset = Self::match_asset(&asset).map_err(|_| DispatchError::Unavailable)?;
<F as fungibles::Mutate<_>>::transfer(
asset,
&A::get(),
&who,
amount,
Preservation::Expendable,
)?;
// We use `QueryId::MAX` as a constant identifier for these payments since they are always
// processed immediately and successfully on the local chain. The `QueryId` type is used to
// maintain compatibility with XCM payment implementations.
Ok(Self::Id::MAX)
}
fn check_payment(_: Self::Id) -> PaymentStatus {
PaymentStatus::Success
}
#[cfg(feature = "runtime-benchmarks")]
fn ensure_successful(_: &Self::Beneficiary, asset: Self::AssetKind, amount: Self::Balance) {
let asset = Self::match_asset(&asset).expect("invalid asset");
<F as fungibles::Create<_>>::create(asset.clone(), A::get(), true, amount).unwrap();
<F as fungibles::Mutate<_>>::mint_into(asset, &A::get(), amount).unwrap();
}
#[cfg(feature = "runtime-benchmarks")]
fn ensure_concluded(_: Self::Id) {}
}
impl<A, F, C> LocalPay<F, A, C>
where
A: TypedGet,
F: fungibles::Mutate<A::Type> + fungibles::Create<A::Type>,
C: ConvertLocation<A::Type>,
A::Type: Eq + Clone,
{
fn match_location(who: &VersionedLocatableAccount) -> Result<A::Type, ()> {
// only applicable for the local accounts
let account_id = match who {
VersionedLocatableAccount::V4 { location, account_id } if location.is_here() =>
&account_id.clone().try_into().map_err(|_| ())?,
VersionedLocatableAccount::V5 { location, account_id } if location.is_here() =>
account_id,
_ => return Err(()),
};
C::convert_location(account_id).ok_or(())
}
fn match_asset(asset: &VersionedLocatableAsset) -> Result<xcm::v5::Location, ()> {
match asset {
VersionedLocatableAsset::V4 { location, asset_id } if location.is_here() =>
asset_id.clone().try_into().map(|a: xcm::v5::AssetId| a.0).map_err(|_| ()),
VersionedLocatableAsset::V5 { location, asset_id } if location.is_here() =>
Ok(asset_id.clone().0),
_ => Err(()),
}
}
}
#[cfg(feature = "runtime-benchmarks")]
pub mod benchmarks {
use super::*;
use core::marker::PhantomData;
use pezframe_support::traits::Get;
use pezpallet_treasury::ArgumentsFactory as TreasuryArgumentsFactory;
use pezsp_core::ConstU8;
/// Provides factory methods for the `AssetKind` and the `Beneficiary` that are applicable for
/// the payout made by [`LocalPay`].
///
/// ### Parameters:
/// - `PalletId`: The ID of the assets registry pallet.
/// - `AssetId`: The ID of the asset that will be created for the benchmark within `PalletId`.
pub struct LocalPayArguments<PalletId = ConstU8<0>>(PhantomData<PalletId>);
impl<PalletId: Get<u8>>
TreasuryArgumentsFactory<VersionedLocatableAsset, VersionedLocatableAccount>
for LocalPayArguments<PalletId>
{
fn create_asset_kind(seed: u32) -> VersionedLocatableAsset {
VersionedLocatableAsset::V5 {
location: Location::new(0, []),
asset_id: Location::new(
0,
[PalletInstance(PalletId::get()), GeneralIndex(seed.into())],
)
.into(),
}
}
fn create_beneficiary(seed: [u8; 32]) -> VersionedLocatableAccount {
VersionedLocatableAccount::V5 {
location: Location::new(0, []),
account_id: Location::new(0, [AccountId32 { network: None, id: seed }]),
}
}
}
}
@@ -0,0 +1,315 @@
// 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::impls::AccountIdOf;
use core::marker::PhantomData;
use cumulus_primitives_core::{IsSystem, ParaId};
use pezframe_support::{
traits::{fungibles::Inspect, tokens::ConversionToAssetBalance, Contains, ContainsPair},
weights::Weight,
};
use pezsp_runtime::traits::Get;
use xcm::latest::prelude::*;
/// A `ChargeFeeInFungibles` implementation that converts the output of
/// a given WeightToFee implementation an amount charged in
/// a particular assetId from pezpallet-assets
pub struct AssetFeeAsExistentialDepositMultiplier<
Runtime,
WeightToFee,
BalanceConverter,
AssetInstance: 'static,
>(PhantomData<(Runtime, WeightToFee, BalanceConverter, AssetInstance)>);
impl<CurrencyBalance, Runtime, WeightToFee, BalanceConverter, AssetInstance>
cumulus_primitives_utility::ChargeWeightInFungibles<
AccountIdOf<Runtime>,
pezpallet_assets::Pallet<Runtime, AssetInstance>,
> for AssetFeeAsExistentialDepositMultiplier<Runtime, WeightToFee, BalanceConverter, AssetInstance>
where
Runtime: pezpallet_assets::Config<AssetInstance>,
WeightToFee: pezframe_support::weights::WeightToFee<Balance = CurrencyBalance>,
BalanceConverter: ConversionToAssetBalance<
CurrencyBalance,
<Runtime as pezpallet_assets::Config<AssetInstance>>::AssetId,
<Runtime as pezpallet_assets::Config<AssetInstance>>::Balance,
>,
<BalanceConverter as ConversionToAssetBalance<
CurrencyBalance,
<Runtime as pezpallet_assets::Config<AssetInstance>>::AssetId,
<Runtime as pezpallet_assets::Config<AssetInstance>>::Balance,
>>::Error: core::fmt::Debug,
{
fn charge_weight_in_fungibles(
asset_id: <pezpallet_assets::Pallet<Runtime, AssetInstance> as Inspect<
AccountIdOf<Runtime>,
>>::AssetId,
weight: Weight,
) -> Result<
<pezpallet_assets::Pallet<Runtime, AssetInstance> as Inspect<AccountIdOf<Runtime>>>::Balance,
XcmError,
> {
let amount = WeightToFee::weight_to_fee(&weight);
// If the amount gotten is not at least the ED, then make it be the ED of the asset
// This is to avoid burning assets and decreasing the supply
let asset_amount = BalanceConverter::to_asset_balance(amount, asset_id)
.map_err(|error| {
tracing::debug!(target: "xcm::charge_weight_in_fungibles", ?error, "AssetFeeAsExistentialDepositMultiplier cannot convert to valid balance (possibly below ED)");
XcmError::TooExpensive
})?;
Ok(asset_amount)
}
}
/// Accepts an asset if it is a native asset from a particular `Location`.
pub struct ConcreteNativeAssetFrom<LocationValue>(PhantomData<LocationValue>);
impl<LocationValue: Get<Location>> ContainsPair<Asset, Location>
for ConcreteNativeAssetFrom<LocationValue>
{
fn contains(asset: &Asset, origin: &Location) -> bool {
tracing::trace!(
target: "xcm::filter_asset_location",
?asset, ?origin, location=?LocationValue::get(),
"ConcreteNativeAsset"
);
asset.id.0 == *origin && origin == &LocationValue::get()
}
}
pub struct RelayOrOtherSystemTeyrchains<
SystemTeyrchainMatcher: Contains<Location>,
Runtime: teyrchain_info::Config,
> {
_runtime: PhantomData<(SystemTeyrchainMatcher, Runtime)>,
}
impl<SystemTeyrchainMatcher: Contains<Location>, Runtime: teyrchain_info::Config> Contains<Location>
for RelayOrOtherSystemTeyrchains<SystemTeyrchainMatcher, Runtime>
{
fn contains(l: &Location) -> bool {
let self_para_id: u32 = teyrchain_info::Pallet::<Runtime>::get().into();
if let (0, [Teyrchain(para_id)]) = l.unpack() {
if *para_id == self_para_id {
return false;
}
}
matches!(l.unpack(), (1, [])) || SystemTeyrchainMatcher::contains(l)
}
}
/// Contains all sibling system teyrchains, including the one where this matcher is used.
///
/// This structure can only be used at a teyrchain level. In the Relay Chain, please use
/// the `xcm_builder::IsChildSystemTeyrchain` matcher.
pub struct AllSiblingSystemTeyrchains;
impl Contains<Location> for AllSiblingSystemTeyrchains {
fn contains(l: &Location) -> bool {
tracing::trace!(target: "xcm::contains", location=?l, "AllSiblingSystemTeyrchains");
match l.unpack() {
// System teyrchain
(1, [Teyrchain(id)]) => ParaId::from(*id).is_system(),
// Everything else
_ => false,
}
}
}
/// Accepts an asset if it is a concrete asset from the system (Relay Chain or system teyrchain).
pub struct ConcreteAssetFromSystem<AssetLocation>(PhantomData<AssetLocation>);
impl<AssetLocation: Get<Location>> ContainsPair<Asset, Location>
for ConcreteAssetFromSystem<AssetLocation>
{
fn contains(asset: &Asset, origin: &Location) -> bool {
tracing::trace!(target: "xcm::contains", ?asset, ?origin, "ConcreteAssetFromSystem");
let is_system = match origin.unpack() {
// The Relay Chain
(1, []) => true,
// System teyrchain
(1, [Teyrchain(id)]) => ParaId::from(*id).is_system(),
// Others
_ => false,
};
asset.id.0 == AssetLocation::get() && is_system
}
}
/// Filter to check if a given location is the parent Relay Chain or a sibling teyrchain.
///
/// This type should only be used within the context of a teyrchain, since it does not verify that
/// the parent is indeed a Relay Chain.
pub struct ParentRelayOrSiblingTeyrchains;
impl Contains<Location> for ParentRelayOrSiblingTeyrchains {
fn contains(location: &Location) -> bool {
matches!(location.unpack(), (1, []) | (1, [Teyrchain(_)]))
}
}
/// Filter to check if a given `target` location represents the same AccountId32 as `origin`,
/// but coming from another sibling system chain.
///
/// This type should only be used within the context of a teyrchain, to allow accounts on system
/// chains to Alias to the same accounts on the local chain.
pub struct AliasAccountId32FromSiblingSystemChain;
impl ContainsPair<Location, Location> for AliasAccountId32FromSiblingSystemChain {
fn contains(origin: &Location, target: &Location) -> bool {
let result = match origin.unpack() {
// `origin` is AccountId32 on sibling system teyrchain
(1, [Teyrchain(para_id), AccountId32 { network: _, id: origin }])
if ParaId::from(*para_id).is_system() =>
{
match target.unpack() {
// `target` is local AccountId32 and matches `origin` remote account
(0, [AccountId32 { network: _, id: target }]) => target.eq(origin),
_ => false,
}
},
_ => false,
};
tracing::trace!(
target: "xcm::contains",
?origin, ?target, ?result,
"AliasAccountId32FromSiblingSystemChain"
);
result
}
}
#[cfg(test)]
mod tests {
use pezframe_support::{parameter_types, traits::Contains};
use super::{
AliasAccountId32FromSiblingSystemChain, AllSiblingSystemTeyrchains, Asset,
ConcreteAssetFromSystem, ContainsPair, GeneralIndex, Here, Location, PalletInstance,
Parent, Teyrchain,
};
use pezkuwi_primitives::LOWEST_PUBLIC_ID;
use xcm::latest::prelude::*;
parameter_types! {
pub const RelayLocation: Location = Location::parent();
}
#[test]
fn concrete_asset_from_relay_works() {
let expected_asset: Asset = (Parent, 1000000).into();
let expected_origin: Location = (Parent, Here).into();
assert!(<ConcreteAssetFromSystem<RelayLocation>>::contains(
&expected_asset,
&expected_origin
));
}
#[test]
fn concrete_asset_from_sibling_system_para_fails_for_wrong_asset() {
let unexpected_assets: Vec<Asset> = vec![
(Here, 1000000).into(),
((PalletInstance(50), GeneralIndex(1)), 1000000).into(),
((Parent, Teyrchain(1000), PalletInstance(50), GeneralIndex(1)), 1000000).into(),
];
let expected_origin: Location = (Parent, Teyrchain(1000)).into();
unexpected_assets.iter().for_each(|asset| {
assert!(!<ConcreteAssetFromSystem<RelayLocation>>::contains(asset, &expected_origin));
});
}
#[test]
fn concrete_asset_from_sibling_system_para_works_for_correct_asset() {
// (para_id, expected_result)
let test_data = vec![
(0, true),
(1, true),
(1000, true),
(1999, true),
(2000, false), // Not a System Teyrchain
(2001, false), // Not a System Teyrchain
];
let expected_asset: Asset = (Parent, 1000000).into();
for (para_id, expected_result) in test_data {
let origin: Location = (Parent, Teyrchain(para_id)).into();
assert_eq!(
expected_result,
<ConcreteAssetFromSystem<RelayLocation>>::contains(&expected_asset, &origin)
);
}
}
#[test]
fn all_sibling_system_teyrchains_works() {
// system teyrchain
assert!(AllSiblingSystemTeyrchains::contains(&Location::new(1, [Teyrchain(1)])));
// non-system teyrchain
assert!(!AllSiblingSystemTeyrchains::contains(&Location::new(
1,
[Teyrchain(LOWEST_PUBLIC_ID.into())]
)));
// when used at relay chain
assert!(!AllSiblingSystemTeyrchains::contains(&Location::new(0, [Teyrchain(1)])));
// when used with non-teyrchain
assert!(!AllSiblingSystemTeyrchains::contains(&Location::new(1, [OnlyChild])));
}
#[test]
fn alias_accountid32_from_sibling_system_teyrchains() {
let acc_42 = AccountId32 { network: None, id: [42u8; 32] };
let acc_13 = AccountId32 { network: None, id: [13u8; 32] };
// origin acc_42 on sibling system teyrchain aliases into local acc_42
assert!(AliasAccountId32FromSiblingSystemChain::contains(
&Location::new(1, [Teyrchain(1), acc_42]),
&Location::new(0, [acc_42])
));
// if target is not local account, always fails
assert!(!AliasAccountId32FromSiblingSystemChain::contains(
&Location::new(1, [Teyrchain(1), acc_42]),
&Location::new(0, [])
));
assert!(!AliasAccountId32FromSiblingSystemChain::contains(
&Location::new(1, [Teyrchain(1), acc_42]),
&Location::new(0, [Teyrchain(1)])
));
assert!(!AliasAccountId32FromSiblingSystemChain::contains(
&Location::new(1, [Teyrchain(1), acc_42]),
&Location::new(0, [GeneralIndex(42)])
));
assert!(!AliasAccountId32FromSiblingSystemChain::contains(
&Location::new(1, [Teyrchain(1), acc_42]),
&Location::new(1, [acc_42])
));
assert!(!AliasAccountId32FromSiblingSystemChain::contains(
&Location::new(1, [Teyrchain(1), acc_42]),
&Location::new(2, [acc_42])
));
// origin acc_13 on sibling system teyrchain CANNOT alias into local acc_42
assert!(!AliasAccountId32FromSiblingSystemChain::contains(
&Location::new(1, [Teyrchain(1), acc_13]),
&Location::new(0, [acc_42])
));
// origin acc_42 on sibling non-system teyrchain CANNOT alias into local acc_42
assert!(!AliasAccountId32FromSiblingSystemChain::contains(
&Location::new(1, [Teyrchain(LOWEST_PUBLIC_ID.into()), acc_42]),
&Location::new(0, [acc_42])
));
assert!(!AliasAccountId32FromSiblingSystemChain::contains(
&Location::new(0, [acc_13]),
&Location::new(0, [acc_13]),
));
assert!(!AliasAccountId32FromSiblingSystemChain::contains(
&Location::new(0, [acc_42]),
&Location::new(1, [Teyrchain(1), acc_42]),
));
}
}