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
@@ -0,0 +1,469 @@
// This file is part of Bizinikiwi.
// 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::*;
use pezframe_support::traits::tokens::{Fortitude::Polite, Preservation::Expendable};
use pezsp_staking::{Agent, DelegationInterface, DelegationMigrator, Delegator};
/// Types of stake strategies.
///
/// Useful for determining current staking strategy of a runtime and enforce integrity tests.
#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebugNoBound, PartialEq)]
pub enum StakeStrategyType {
/// Member funds are transferred to pool account and staked.
///
/// This is the older staking strategy used by pools. For a new runtime, it is recommended to
/// use [`StakeStrategyType::Delegate`] strategy instead.
Transfer,
/// Member funds are delegated to pool account and staked.
Delegate,
}
/// A type that only belongs in context of a pool.
///
/// Maps directly [`Agent`] account.
#[derive(Clone, Debug)]
pub struct Pool<T>(T);
impl<AccountID> Into<Agent<AccountID>> for Pool<AccountID> {
fn into(self) -> Agent<AccountID> {
Agent::from(self.0)
}
}
impl<T> From<T> for Pool<T> {
fn from(acc: T) -> Self {
Pool(acc)
}
}
impl<T> Pool<T> {
pub fn get(self) -> T {
self.0
}
}
/// A type that only belongs in context of a pool member.
///
/// Maps directly [`Delegator`] account.
#[derive(Clone, Debug)]
pub struct Member<T>(T);
impl<AccountID> Into<Delegator<AccountID>> for Member<AccountID> {
fn into(self) -> Delegator<AccountID> {
Delegator::from(self.0)
}
}
impl<T> From<T> for Member<T> {
fn from(acc: T) -> Self {
Member(acc)
}
}
impl<T> Member<T> {
pub fn get(self) -> T {
self.0
}
}
/// An adapter trait that can support multiple staking strategies.
///
/// Depending on which staking strategy we want to use, the staking logic can be slightly
/// different. Refer the two possible strategies currently: [`TransferStake`] and
/// [`DelegateStake`] for more detail.
pub trait StakeStrategy {
type Balance: pezframe_support::traits::tokens::Balance;
type AccountId: Clone + core::fmt::Debug;
type CoreStaking: StakingInterface<Balance = Self::Balance, AccountId = Self::AccountId>;
/// The type of staking strategy of the current adapter.
fn strategy_type() -> StakeStrategyType;
/// See [`StakingInterface::bonding_duration`].
fn bonding_duration() -> EraIndex {
Self::CoreStaking::bonding_duration()
}
/// See [`StakingInterface::current_era`].
fn current_era() -> EraIndex {
Self::CoreStaking::current_era()
}
/// See [`StakingInterface::minimum_nominator_bond`].
fn minimum_nominator_bond() -> Self::Balance {
Self::CoreStaking::minimum_nominator_bond()
}
/// Balance that can be transferred from pool account to member.
///
/// This is part of the pool balance that can be withdrawn.
fn transferable_balance(
pool_account: Pool<Self::AccountId>,
member_account: Member<Self::AccountId>,
) -> Self::Balance;
/// Total balance of the pool including amount that is actively staked.
fn total_balance(pool_account: Pool<Self::AccountId>) -> Option<Self::Balance>;
/// Amount of tokens delegated by the member.
fn member_delegation_balance(member_account: Member<Self::AccountId>) -> Option<Self::Balance>;
/// See [`StakingInterface::active_stake`].
fn active_stake(pool_account: Pool<Self::AccountId>) -> Self::Balance {
Self::CoreStaking::active_stake(&pool_account.0).unwrap_or_default()
}
/// See [`StakingInterface::total_stake`].
fn total_stake(pool_account: Pool<Self::AccountId>) -> Self::Balance {
Self::CoreStaking::total_stake(&pool_account.0).unwrap_or_default()
}
/// Which strategy the pool account is using.
///
/// This can be different from the [`Self::strategy_type`] of the adapter if the pool has not
/// migrated to the new strategy yet.
fn pool_strategy(pool_account: Pool<Self::AccountId>) -> StakeStrategyType {
match Self::CoreStaking::is_virtual_staker(&pool_account.0) {
true => StakeStrategyType::Delegate,
false => StakeStrategyType::Transfer,
}
}
/// See [`StakingInterface::nominate`].
fn nominate(
pool_account: Pool<Self::AccountId>,
validators: Vec<Self::AccountId>,
) -> DispatchResult {
Self::CoreStaking::nominate(&pool_account.0, validators)
}
/// See [`StakingInterface::chill`].
fn chill(pool_account: Pool<Self::AccountId>) -> DispatchResult {
Self::CoreStaking::chill(&pool_account.0)
}
/// Pledge `amount` towards `pool_account` and update the pool bond. Also see
/// [`StakingInterface::bond`].
fn pledge_bond(
who: Member<Self::AccountId>,
pool_account: Pool<Self::AccountId>,
reward_account: &Self::AccountId,
amount: Self::Balance,
bond_type: BondType,
) -> DispatchResult;
/// See [`StakingInterface::unbond`].
fn unbond(pool_account: Pool<Self::AccountId>, amount: Self::Balance) -> DispatchResult {
Self::CoreStaking::unbond(&pool_account.0, amount)
}
/// See [`StakingInterface::withdraw_unbonded`].
fn withdraw_unbonded(
pool_account: Pool<Self::AccountId>,
num_slashing_spans: u32,
) -> Result<bool, DispatchError> {
Self::CoreStaking::withdraw_unbonded(pool_account.0, num_slashing_spans)
}
/// Withdraw funds from pool account to member account.
fn member_withdraw(
who: Member<Self::AccountId>,
pool_account: Pool<Self::AccountId>,
amount: Self::Balance,
num_slashing_spans: u32,
) -> DispatchResult;
/// Dissolve the pool account.
fn dissolve(pool_account: Pool<Self::AccountId>) -> DispatchResult;
/// Check if there is any pending slash for the pool.
fn pending_slash(pool_account: Pool<Self::AccountId>) -> Self::Balance;
/// Slash the member account with `amount` against pending slashes for the pool.
fn member_slash(
who: Member<Self::AccountId>,
pool_account: Pool<Self::AccountId>,
amount: Self::Balance,
maybe_reporter: Option<Self::AccountId>,
) -> DispatchResult;
/// Migrate pool account from being a direct nominator to a delegated agent.
///
/// This is useful for migrating a pool account from [`StakeStrategyType::Transfer`] to
/// [`StakeStrategyType::Delegate`].
fn migrate_nominator_to_agent(
pool_account: Pool<Self::AccountId>,
reward_account: &Self::AccountId,
) -> DispatchResult;
/// Migrate member balance from pool account to member account.
///
/// This is useful for a pool account that migrated from [`StakeStrategyType::Transfer`] to
/// [`StakeStrategyType::Delegate`]. Its members can then migrate their delegated balance
/// back to their account.
///
/// Internally, the member funds that are locked in the pool account are transferred back and
/// locked in the member account.
fn migrate_delegation(
pool: Pool<Self::AccountId>,
delegator: Member<Self::AccountId>,
value: Self::Balance,
) -> DispatchResult;
/// List of validators nominated by the pool account.
#[cfg(feature = "runtime-benchmarks")]
fn nominations(pool_account: Pool<Self::AccountId>) -> Option<Vec<Self::AccountId>> {
Self::CoreStaking::nominations(&pool_account.0)
}
/// Remove the pool account as agent.
///
/// Useful for migrating pool account from a delegated agent to a direct nominator. Only used
/// in tests and benchmarks.
#[cfg(feature = "runtime-benchmarks")]
fn remove_as_agent(_pool: Pool<Self::AccountId>) {
// noop by default
}
}
/// A staking strategy implementation that supports transfer based staking.
///
/// In order to stake, this adapter transfers the funds from the member/delegator account to the
/// pool account and stakes through the pool account on `Staking`.
///
/// This is the older Staking strategy used by pools. To switch to the newer [`DelegateStake`]
/// strategy in an existing runtime, storage migration is required. See
/// [`migration::unversioned::DelegationStakeMigration`]. For new runtimes, it is highly recommended
/// to use the [`DelegateStake`] strategy.
#[deprecated = "consider migrating to DelegateStake"]
pub struct TransferStake<T: Config, Staking: StakingInterface>(PhantomData<(T, Staking)>);
#[allow(deprecated)]
impl<T: Config, Staking: StakingInterface<Balance = BalanceOf<T>, AccountId = T::AccountId>>
StakeStrategy for TransferStake<T, Staking>
{
type Balance = BalanceOf<T>;
type AccountId = T::AccountId;
type CoreStaking = Staking;
fn strategy_type() -> StakeStrategyType {
StakeStrategyType::Transfer
}
fn transferable_balance(
pool_account: Pool<Self::AccountId>,
_: Member<Self::AccountId>,
) -> BalanceOf<T> {
// free/liquid balance of the pool account.
T::Currency::reducible_balance(&pool_account.get(), Expendable, Polite)
}
fn total_balance(pool_account: Pool<Self::AccountId>) -> Option<BalanceOf<T>> {
Some(T::Currency::total_balance(&pool_account.get()))
}
fn member_delegation_balance(
_member_account: Member<T::AccountId>,
) -> Option<Staking::Balance> {
// for transfer stake, no delegation exists.
None
}
fn pledge_bond(
who: Member<T::AccountId>,
pool_account: Pool<Self::AccountId>,
reward_account: &Self::AccountId,
amount: BalanceOf<T>,
bond_type: BondType,
) -> DispatchResult {
match bond_type {
BondType::Create => {
// first bond
T::Currency::transfer(&who.0, &pool_account.0, amount, Preservation::Expendable)?;
Staking::bond(&pool_account.0, amount, &reward_account)
},
BondType::Extra => {
// additional bond
T::Currency::transfer(&who.0, &pool_account.0, amount, Preservation::Preserve)?;
Staking::bond_extra(&pool_account.0, amount)
},
}
}
fn member_withdraw(
who: Member<Self::AccountId>,
pool_account: Pool<Self::AccountId>,
amount: BalanceOf<T>,
_num_slashing_spans: u32,
) -> DispatchResult {
T::Currency::transfer(&pool_account.0, &who.0, amount, Preservation::Expendable)?;
Ok(())
}
fn dissolve(pool_account: Pool<Self::AccountId>) -> DispatchResult {
defensive_assert!(
T::Currency::total_balance(&pool_account.clone().get()).is_zero(),
"dissolving pool should not have any balance"
);
// Defensively force set balance to zero.
T::Currency::set_balance(&pool_account.get(), Zero::zero());
Ok(())
}
fn pending_slash(_: Pool<Self::AccountId>) -> Self::Balance {
// for transfer stake strategy, slashing is greedy and never deferred.
Zero::zero()
}
fn member_slash(
_who: Member<Self::AccountId>,
_pool: Pool<Self::AccountId>,
_amount: Staking::Balance,
_maybe_reporter: Option<T::AccountId>,
) -> DispatchResult {
Err(Error::<T>::Defensive(DefensiveError::DelegationUnsupported).into())
}
fn migrate_nominator_to_agent(
_pool: Pool<Self::AccountId>,
_reward_account: &Self::AccountId,
) -> DispatchResult {
Err(Error::<T>::Defensive(DefensiveError::DelegationUnsupported).into())
}
fn migrate_delegation(
_pool: Pool<Self::AccountId>,
_delegator: Member<Self::AccountId>,
_value: Self::Balance,
) -> DispatchResult {
Err(Error::<T>::Defensive(DefensiveError::DelegationUnsupported).into())
}
}
/// A staking strategy implementation that supports delegation based staking.
///
/// In this approach, first the funds are delegated from delegator to the pool account and later
/// staked with `Staking`. The advantage of this approach is that the funds are held in the
/// user account itself and not in the pool account.
///
/// This is the newer staking strategy used by pools. Once switched to this and migrated, ideally
/// the `TransferStake` strategy should not be used. Or a separate migration would be required for
/// it which is not provided by this pallet.
///
/// Use [`migration::unversioned::DelegationStakeMigration`] to migrate to this strategy.
pub struct DelegateStake<T: Config, Staking: StakingInterface, Delegation: DelegationInterface>(
PhantomData<(T, Staking, Delegation)>,
);
impl<
T: Config,
Staking: StakingInterface<Balance = BalanceOf<T>, AccountId = T::AccountId>,
Delegation: DelegationInterface<Balance = BalanceOf<T>, AccountId = T::AccountId>
+ DelegationMigrator<Balance = BalanceOf<T>, AccountId = T::AccountId>,
> StakeStrategy for DelegateStake<T, Staking, Delegation>
{
type Balance = BalanceOf<T>;
type AccountId = T::AccountId;
type CoreStaking = Staking;
fn strategy_type() -> StakeStrategyType {
StakeStrategyType::Delegate
}
fn transferable_balance(
pool_account: Pool<Self::AccountId>,
member_account: Member<Self::AccountId>,
) -> BalanceOf<T> {
Delegation::agent_transferable_balance(pool_account.clone().into())
// pool should always be an agent.
.defensive_unwrap_or_default()
.min(Delegation::delegator_balance(member_account.into()).unwrap_or_default())
}
fn total_balance(pool_account: Pool<Self::AccountId>) -> Option<BalanceOf<T>> {
Delegation::agent_balance(pool_account.into())
}
fn member_delegation_balance(member_account: Member<T::AccountId>) -> Option<BalanceOf<T>> {
Delegation::delegator_balance(member_account.into())
}
fn pledge_bond(
who: Member<T::AccountId>,
pool_account: Pool<Self::AccountId>,
reward_account: &Self::AccountId,
amount: BalanceOf<T>,
bond_type: BondType,
) -> DispatchResult {
match bond_type {
BondType::Create => {
// first delegation. Register agent first.
Delegation::register_agent(pool_account.clone().into(), reward_account)?;
Delegation::delegate(who.into(), pool_account.into(), amount)
},
BondType::Extra => {
// additional delegation
Delegation::delegate(who.into(), pool_account.into(), amount)
},
}
}
fn member_withdraw(
who: Member<Self::AccountId>,
pool_account: Pool<Self::AccountId>,
amount: BalanceOf<T>,
num_slashing_spans: u32,
) -> DispatchResult {
Delegation::withdraw_delegation(who.into(), pool_account.into(), amount, num_slashing_spans)
}
fn dissolve(pool_account: Pool<Self::AccountId>) -> DispatchResult {
Delegation::remove_agent(pool_account.into())
}
fn pending_slash(pool_account: Pool<Self::AccountId>) -> Self::Balance {
Delegation::pending_slash(pool_account.into()).defensive_unwrap_or_default()
}
fn member_slash(
who: Member<Self::AccountId>,
pool_account: Pool<Self::AccountId>,
amount: BalanceOf<T>,
maybe_reporter: Option<T::AccountId>,
) -> DispatchResult {
Delegation::delegator_slash(pool_account.into(), who.into(), amount, maybe_reporter)
}
fn migrate_nominator_to_agent(
pool: Pool<Self::AccountId>,
reward_account: &Self::AccountId,
) -> DispatchResult {
Delegation::migrate_nominator_to_agent(pool.into(), reward_account)
}
fn migrate_delegation(
pool: Pool<Self::AccountId>,
delegator: Member<Self::AccountId>,
value: Self::Balance,
) -> DispatchResult {
Delegation::migrate_delegation(pool.into(), delegator.into(), value)
}
#[cfg(feature = "runtime-benchmarks")]
fn remove_as_agent(pool: Pool<Self::AccountId>) {
Delegation::force_kill_agent(pool.into())
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,755 @@
// This file is part of Bizinikiwi.
// 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 super::*;
use crate::{self as pools};
use pezframe_support::{
assert_ok, derive_impl, ord_parameter_types, parameter_types,
traits::{fungible::Mutate, VariantCountOf},
PalletId,
};
use pezframe_system::{EnsureSignedBy, RawOrigin};
use pezsp_runtime::{BuildStorage, DispatchResult, FixedU128};
use pezsp_staking::{
Agent, DelegationInterface, DelegationMigrator, Delegator, OnStakingUpdate, Stake,
};
pub type BlockNumber = u64;
pub type AccountId = u128;
pub type Balance = u128;
pub type RewardCounter = FixedU128;
// This sneaky little hack allows us to write code exactly as we would do in the pallet in the tests
// as well, e.g. `StorageItem::<T>::get()`.
pub type T = Runtime;
pub type Currency = <T as Config>::Currency;
// Ext builder creates a pool with id 1.
pub fn default_bonded_account() -> AccountId {
Pools::generate_bonded_account(1)
}
// Ext builder creates a pool with id 1.
pub fn default_reward_account() -> AccountId {
Pools::generate_reward_account(1)
}
parameter_types! {
pub static MinJoinBondConfig: Balance = 2;
pub static CurrentEra: EraIndex = 0;
pub static BondingDuration: EraIndex = 3;
pub storage BondedBalanceMap: BTreeMap<AccountId, Balance> = Default::default();
// map from a user to a vec of eras and amounts being unlocked in each era.
pub storage UnbondingBalanceMap: BTreeMap<AccountId, Vec<(EraIndex, Balance)>> = Default::default();
#[derive(Clone, PartialEq)]
pub static MaxUnbonding: u32 = 8;
pub static StakingMinBond: Balance = 10;
pub storage Nominations: Option<Vec<AccountId>> = None;
pub static RestrictedAccounts: Vec<AccountId> = Vec::new();
}
pub struct StakingMock;
impl StakingMock {
pub(crate) fn set_bonded_balance(who: AccountId, bonded: Balance) {
let mut x = BondedBalanceMap::get();
x.insert(who, bonded);
BondedBalanceMap::set(&x)
}
/// Mimics a slash towards a pool specified by `pool_id`.
/// This reduces the bonded balance of a pool by `amount` and calls [`Pools::on_slash`] to
/// enact changes in the nomination-pool pallet.
///
/// Does not modify any [`SubPools`] of the pool as [`Default::default`] is passed for
/// `slashed_unlocking`.
pub fn slash_by(pool_id: PoolId, amount: Balance) {
let acc = Pools::generate_bonded_account(pool_id);
let bonded = BondedBalanceMap::get();
let pre_total = bonded.get(&acc).unwrap();
Self::set_bonded_balance(acc, pre_total - amount);
DelegateMock::on_slash(acc, amount);
Pools::on_slash(&acc, pre_total - amount, &Default::default(), amount);
}
}
impl pezsp_staking::StakingInterface for StakingMock {
type Balance = Balance;
type AccountId = AccountId;
type CurrencyToVote = ();
fn minimum_nominator_bond() -> Self::Balance {
StakingMinBond::get()
}
fn minimum_validator_bond() -> Self::Balance {
StakingMinBond::get()
}
fn desired_validator_count() -> u32 {
unimplemented!("method currently not used in testing")
}
fn current_era() -> EraIndex {
CurrentEra::get()
}
fn bonding_duration() -> EraIndex {
BondingDuration::get()
}
fn status(
_: &Self::AccountId,
) -> Result<pezsp_staking::StakerStatus<Self::AccountId>, DispatchError> {
Nominations::get()
.map(|noms| pezsp_staking::StakerStatus::Nominator(noms))
.ok_or(DispatchError::Other("NotStash"))
}
fn is_virtual_staker(who: &Self::AccountId) -> bool {
AgentBalanceMap::get().contains_key(who)
}
fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult {
let mut x = BondedBalanceMap::get();
x.get_mut(who).map(|v| *v += extra);
BondedBalanceMap::set(&x);
Ok(())
}
fn unbond(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
let mut x = BondedBalanceMap::get();
*x.get_mut(who).unwrap() = x.get_mut(who).unwrap().saturating_sub(amount);
BondedBalanceMap::set(&x);
let era = Self::current_era();
let unlocking_at = era + Self::bonding_duration();
let mut y = UnbondingBalanceMap::get();
y.entry(*who).or_insert(Default::default()).push((unlocking_at, amount));
UnbondingBalanceMap::set(&y);
Ok(())
}
fn set_payee(_stash: &Self::AccountId, _reward_acc: &Self::AccountId) -> DispatchResult {
unimplemented!("method currently not used in testing")
}
fn chill(_: &Self::AccountId) -> pezsp_runtime::DispatchResult {
Ok(())
}
fn withdraw_unbonded(who: Self::AccountId, _: u32) -> Result<bool, DispatchError> {
let mut unbonding_map = UnbondingBalanceMap::get();
// closure to calculate the current unlocking funds across all eras/accounts.
let unlocking = |pair: &Vec<(EraIndex, Balance)>| -> Balance {
pair.iter()
.try_fold(Zero::zero(), |acc: Balance, (_at, amount)| acc.checked_add(*amount))
.unwrap()
};
let staker_map = unbonding_map.get_mut(&who).ok_or("Nothing to unbond")?;
let unlocking_before = unlocking(&staker_map);
let current_era = Self::current_era();
staker_map.retain(|(unlocking_at, _amount)| *unlocking_at > current_era);
// if there was a withdrawal, notify the pallet.
let withdraw_amount = unlocking_before.saturating_sub(unlocking(&staker_map));
Pools::on_withdraw(&who, withdraw_amount);
DelegateMock::on_withdraw(who, withdraw_amount);
UnbondingBalanceMap::set(&unbonding_map);
Ok(UnbondingBalanceMap::get().get(&who).unwrap().is_empty() &&
BondedBalanceMap::get().get(&who).unwrap().is_zero())
}
fn bond(stash: &Self::AccountId, value: Self::Balance, _: &Self::AccountId) -> DispatchResult {
StakingMock::set_bonded_balance(*stash, value);
Ok(())
}
fn nominate(_: &Self::AccountId, nominations: Vec<Self::AccountId>) -> DispatchResult {
Nominations::set(&Some(nominations));
Ok(())
}
#[cfg(feature = "runtime-benchmarks")]
fn nominations(_: &Self::AccountId) -> Option<Vec<Self::AccountId>> {
Nominations::get()
}
fn stash_by_ctrl(_controller: &Self::AccountId) -> Result<Self::AccountId, DispatchError> {
unimplemented!("method currently not used in testing")
}
fn stake(who: &Self::AccountId) -> Result<Stake<Balance>, DispatchError> {
match (UnbondingBalanceMap::get().get(who), BondedBalanceMap::get().get(who).copied()) {
(None, None) => Err(DispatchError::Other("balance not found")),
(Some(v), None) => Ok(Stake {
total: v.into_iter().fold(0u128, |acc, &x| acc.saturating_add(x.1)),
active: 0,
}),
(None, Some(v)) => Ok(Stake { total: v, active: v }),
(Some(a), Some(b)) => Ok(Stake {
total: a.into_iter().fold(0u128, |acc, &x| acc.saturating_add(x.1)) + b,
active: b,
}),
}
}
fn election_ongoing() -> bool {
unimplemented!("method currently not used in testing")
}
fn force_unstake(_who: Self::AccountId) -> pezsp_runtime::DispatchResult {
unimplemented!("method currently not used in testing")
}
fn is_exposed_in_era(_who: &Self::AccountId, _era: &EraIndex) -> bool {
unimplemented!("method currently not used in testing")
}
#[cfg(feature = "runtime-benchmarks")]
fn add_era_stakers(
_current_era: &EraIndex,
_stash: &Self::AccountId,
_exposures: Vec<(Self::AccountId, Self::Balance)>,
) {
unimplemented!("method currently not used in testing")
}
#[cfg(feature = "runtime-benchmarks")]
fn set_current_era(_era: EraIndex) {
unimplemented!("method currently not used in testing")
}
#[cfg(feature = "runtime-benchmarks")]
fn max_exposure_page_size() -> pezsp_staking::Page {
unimplemented!("method currently not used in testing")
}
fn slash_reward_fraction() -> Perbill {
unimplemented!("method currently not used in testing")
}
}
parameter_types! {
// Map of agent to their (delegated balance, unclaimed withdrawal, pending slash).
pub storage AgentBalanceMap: BTreeMap<AccountId, (Balance, Balance, Balance)> = Default::default();
pub storage DelegatorBalanceMap: BTreeMap<AccountId, Balance> = Default::default();
}
pub struct DelegateMock;
impl DelegationInterface for DelegateMock {
type Balance = Balance;
type AccountId = AccountId;
fn agent_balance(agent: Agent<Self::AccountId>) -> Option<Self::Balance> {
AgentBalanceMap::get()
.get(&agent.get())
.copied()
.map(|(delegated, _, pending)| delegated - pending)
}
fn agent_transferable_balance(agent: Agent<Self::AccountId>) -> Option<Self::Balance> {
AgentBalanceMap::get()
.get(&agent.get())
.copied()
.map(|(_, unclaimed_withdrawals, _)| unclaimed_withdrawals)
}
fn delegator_balance(delegator: Delegator<Self::AccountId>) -> Option<Self::Balance> {
DelegatorBalanceMap::get().get(&delegator.get()).copied()
}
fn register_agent(
agent: Agent<Self::AccountId>,
_reward_account: &Self::AccountId,
) -> DispatchResult {
let mut agents = AgentBalanceMap::get();
agents.insert(agent.get(), (0, 0, 0));
AgentBalanceMap::set(&agents);
Ok(())
}
fn remove_agent(agent: Agent<Self::AccountId>) -> DispatchResult {
let mut agents = AgentBalanceMap::get();
let agent = agent.get();
assert!(agents.contains_key(&agent));
agents.remove(&agent);
AgentBalanceMap::set(&agents);
Ok(())
}
fn delegate(
delegator: Delegator<Self::AccountId>,
agent: Agent<Self::AccountId>,
amount: Self::Balance,
) -> DispatchResult {
let delegator = delegator.get();
let mut delegators = DelegatorBalanceMap::get();
delegators.entry(delegator).and_modify(|b| *b += amount).or_insert(amount);
DelegatorBalanceMap::set(&delegators);
let agent = agent.get();
let mut agents = AgentBalanceMap::get();
agents
.get_mut(&agent)
.map(|(d, _, _)| *d += amount)
.ok_or(DispatchError::Other("agent not registered"))?;
AgentBalanceMap::set(&agents);
if BondedBalanceMap::get().contains_key(&agent) {
StakingMock::bond_extra(&agent, amount)
} else {
// reward account does not matter in this context.
StakingMock::bond(&agent, amount, &999)
}
}
fn withdraw_delegation(
delegator: Delegator<Self::AccountId>,
agent: Agent<Self::AccountId>,
amount: Self::Balance,
_num_slashing_spans: u32,
) -> DispatchResult {
let mut delegators = DelegatorBalanceMap::get();
delegators.get_mut(&delegator.get()).map(|b| *b -= amount);
DelegatorBalanceMap::set(&delegators);
let mut agents = AgentBalanceMap::get();
agents.get_mut(&agent.get()).map(|(d, u, _)| {
*d -= amount;
*u -= amount;
});
AgentBalanceMap::set(&agents);
Ok(())
}
fn pending_slash(agent: Agent<Self::AccountId>) -> Option<Self::Balance> {
AgentBalanceMap::get()
.get(&agent.get())
.copied()
.map(|(_, _, pending_slash)| pending_slash)
}
fn delegator_slash(
agent: Agent<Self::AccountId>,
delegator: Delegator<Self::AccountId>,
value: Self::Balance,
_maybe_reporter: Option<Self::AccountId>,
) -> DispatchResult {
let mut delegators = DelegatorBalanceMap::get();
delegators.get_mut(&delegator.get()).map(|b| *b -= value);
DelegatorBalanceMap::set(&delegators);
let mut agents = AgentBalanceMap::get();
agents.get_mut(&agent.get()).map(|(_, _, p)| {
p.saturating_reduce(value);
});
AgentBalanceMap::set(&agents);
Ok(())
}
}
impl DelegateMock {
pub fn set_agent_balance(who: AccountId, delegated: Balance) {
let mut agents = AgentBalanceMap::get();
agents.insert(who, (delegated, 0, 0));
AgentBalanceMap::set(&agents);
}
pub fn set_delegator_balance(who: AccountId, amount: Balance) {
let mut delegators = DelegatorBalanceMap::get();
delegators.insert(who, amount);
DelegatorBalanceMap::set(&delegators);
}
pub fn on_slash(agent: AccountId, amount: Balance) {
let mut agents = AgentBalanceMap::get();
agents.get_mut(&agent).map(|(_, _, p)| *p += amount);
AgentBalanceMap::set(&agents);
}
fn on_withdraw(agent: AccountId, amount: Balance) {
let mut agents = AgentBalanceMap::get();
// if agent exists, add the amount to unclaimed withdrawals.
agents.get_mut(&agent).map(|(_, u, _)| *u += amount);
AgentBalanceMap::set(&agents);
}
}
impl DelegationMigrator for DelegateMock {
type Balance = Balance;
type AccountId = AccountId;
fn migrate_nominator_to_agent(
_agent: Agent<Self::AccountId>,
_reward_account: &Self::AccountId,
) -> DispatchResult {
unimplemented!("not used in current unit tests")
}
fn migrate_delegation(
_agent: Agent<Self::AccountId>,
_delegator: Delegator<Self::AccountId>,
_value: Self::Balance,
) -> DispatchResult {
unimplemented!("not used in current unit tests")
}
#[cfg(feature = "runtime-benchmarks")]
fn force_kill_agent(_agent: Agent<Self::AccountId>) {
unimplemented!("not used in current unit tests")
}
}
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
impl pezframe_system::Config for Runtime {
type Nonce = u64;
type AccountId = AccountId;
type Lookup = pezsp_runtime::traits::IdentityLookup<Self::AccountId>;
type Block = Block;
type AccountData = pezpallet_balances::AccountData<Balance>;
}
parameter_types! {
pub static ExistentialDeposit: Balance = 5;
}
#[derive_impl(pezpallet_balances::config_preludes::TestDefaultConfig)]
impl pezpallet_balances::Config for Runtime {
type Balance = Balance;
type ExistentialDeposit = ExistentialDeposit;
type AccountStore = System;
type FreezeIdentifier = RuntimeFreezeReason;
type MaxFreezes = VariantCountOf<RuntimeFreezeReason>;
type RuntimeFreezeReason = RuntimeFreezeReason;
}
pub struct BalanceToU256;
impl Convert<Balance, U256> for BalanceToU256 {
fn convert(n: Balance) -> U256 {
n.into()
}
}
pub struct U256ToBalance;
impl Convert<U256, Balance> for U256ToBalance {
fn convert(n: U256) -> Balance {
n.try_into().unwrap()
}
}
pub struct RestrictMock;
impl Contains<AccountId> for RestrictMock {
fn contains(who: &AccountId) -> bool {
RestrictedAccounts::get().contains(who)
}
}
parameter_types! {
pub static PostUnbondingPoolsWindow: u32 = 2;
pub static MaxMetadataLen: u32 = 2;
pub static CheckLevel: u8 = 255;
pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls");
}
ord_parameter_types! {
pub const Admin: u128 = 42;
}
impl pools::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type WeightInfo = ();
type Currency = Balances;
type RuntimeFreezeReason = RuntimeFreezeReason;
type RewardCounter = RewardCounter;
type BalanceToU256 = BalanceToU256;
type U256ToBalance = U256ToBalance;
type StakeAdapter = adapter::DelegateStake<Self, StakingMock, DelegateMock>;
type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow;
type PalletId = PoolsPalletId;
type MaxMetadataLen = MaxMetadataLen;
type MaxUnbonding = MaxUnbonding;
type MaxPointsToBalance = pezframe_support::traits::ConstU8<10>;
type AdminOrigin = EnsureSignedBy<Admin, AccountId>;
type BlockNumberProvider = System;
type Filter = RestrictMock;
}
type Block = pezframe_system::mocking::MockBlock<Runtime>;
pezframe_support::construct_runtime!(
pub enum Runtime {
System: pezframe_system,
Balances: pezpallet_balances,
Pools: pools,
}
);
pub struct ExtBuilder {
members: Vec<(AccountId, Balance)>,
max_members: Option<u32>,
max_members_per_pool: Option<u32>,
global_max_commission: Option<Perbill>,
}
impl Default for ExtBuilder {
fn default() -> Self {
Self {
members: Default::default(),
max_members: Some(4),
max_members_per_pool: Some(3),
global_max_commission: Some(Perbill::from_percent(90)),
}
}
}
#[cfg_attr(feature = "fuzzing", allow(dead_code))]
impl ExtBuilder {
// Add members to pool 0.
pub fn add_members(mut self, members: Vec<(AccountId, Balance)>) -> Self {
self.members = members;
self
}
pub fn ed(self, ed: Balance) -> Self {
ExistentialDeposit::set(ed);
self
}
pub fn min_bond(self, min: Balance) -> Self {
StakingMinBond::set(min);
self
}
pub fn min_join_bond(self, min: Balance) -> Self {
MinJoinBondConfig::set(min);
self
}
pub fn with_check(self, level: u8) -> Self {
CheckLevel::set(level);
self
}
pub fn max_members(mut self, max: Option<u32>) -> Self {
self.max_members = max;
self
}
pub fn max_members_per_pool(mut self, max: Option<u32>) -> Self {
self.max_members_per_pool = max;
self
}
pub fn global_max_commission(mut self, commission: Option<Perbill>) -> Self {
self.global_max_commission = commission;
self
}
pub fn build(self) -> pezsp_io::TestExternalities {
pezsp_tracing::try_init_simple();
let mut storage =
pezframe_system::GenesisConfig::<Runtime>::default().build_storage().unwrap();
let _ = crate::GenesisConfig::<Runtime> {
min_join_bond: MinJoinBondConfig::get(),
min_create_bond: 2,
max_pools: Some(2),
max_members_per_pool: self.max_members_per_pool,
max_members: self.max_members,
global_max_commission: self.global_max_commission,
}
.assimilate_storage(&mut storage);
let mut ext = pezsp_io::TestExternalities::from(storage);
ext.execute_with(|| {
// for events to be deposited.
pezframe_system::Pallet::<Runtime>::set_block_number(1);
// make a pool
let amount_to_bond = Pools::depositor_min_bond();
Currency::set_balance(&10, amount_to_bond * 5);
assert_ok!(Pools::create(RawOrigin::Signed(10).into(), amount_to_bond, 900, 901, 902));
assert_ok!(Pools::set_metadata(RuntimeOrigin::signed(900), 1, vec![1, 1]));
let last_pool = LastPoolId::<Runtime>::get();
for (account_id, bonded) in self.members {
<Runtime as Config>::Currency::set_balance(&account_id, bonded * 2);
assert_ok!(Pools::join(RawOrigin::Signed(account_id).into(), bonded, last_pool));
}
});
ext
}
pub fn build_and_execute(self, test: impl FnOnce()) {
self.build().execute_with(|| {
test();
Pools::do_try_state(CheckLevel::get()).unwrap();
})
}
}
pub fn unsafe_set_state(pool_id: PoolId, state: PoolState) {
BondedPools::<Runtime>::try_mutate(pool_id, |maybe_bonded_pool| {
maybe_bonded_pool.as_mut().ok_or(()).map(|bonded_pool| {
bonded_pool.state = state;
})
})
.unwrap()
}
parameter_types! {
storage PoolsEvents: u32 = 0;
storage BalancesEvents: u32 = 0;
}
/// Helper to run a specified amount of blocks.
pub fn run_blocks(n: u64) {
let current_block = System::block_number();
System::run_to_block::<AllPalletsWithSystem>(n + current_block);
}
/// All events of this pallet.
pub fn pool_events_since_last_call() -> Vec<super::Event<Runtime>> {
let events = System::events()
.into_iter()
.map(|r| r.event)
.filter_map(|e| if let RuntimeEvent::Pools(inner) = e { Some(inner) } else { None })
.collect::<Vec<_>>();
let already_seen = PoolsEvents::get();
PoolsEvents::set(&(events.len() as u32));
events.into_iter().skip(already_seen as usize).collect()
}
/// All events of the `Balances` pallet.
pub fn balances_events_since_last_call() -> Vec<pezpallet_balances::Event<Runtime>> {
let events = System::events()
.into_iter()
.map(|r| r.event)
.filter_map(|e| if let RuntimeEvent::Balances(inner) = e { Some(inner) } else { None })
.collect::<Vec<_>>();
let already_seen = BalancesEvents::get();
BalancesEvents::set(&(events.len() as u32));
events.into_iter().skip(already_seen as usize).collect()
}
/// Same as `fully_unbond`, in permissioned setting.
pub fn fully_unbond_permissioned(member: AccountId) -> DispatchResult {
let points = PoolMembers::<Runtime>::get(member)
.map(|d| d.active_points())
.unwrap_or_default();
Pools::unbond(RuntimeOrigin::signed(member), member, points)
}
pub fn pending_rewards_for_delegator(delegator: AccountId) -> Balance {
let member = PoolMembers::<T>::get(delegator).unwrap();
let bonded_pool = BondedPools::<T>::get(member.pool_id).unwrap();
let reward_pool = RewardPools::<T>::get(member.pool_id).unwrap();
assert!(!bonded_pool.points.is_zero());
let commission = bonded_pool.commission.current();
let current_rc = reward_pool
.current_reward_counter(member.pool_id, bonded_pool.points, commission)
.unwrap()
.0;
member.pending_rewards(current_rc).unwrap_or_default()
}
#[derive(PartialEq, Debug)]
pub enum RewardImbalance {
// There is no reward deficit.
Surplus(Balance),
// There is a reward deficit.
Deficit(Balance),
}
pub fn pool_pending_rewards(pool: PoolId) -> Result<BalanceOf<T>, pezsp_runtime::DispatchError> {
let bonded_pool = BondedPools::<T>::get(pool).ok_or(Error::<T>::PoolNotFound)?;
let reward_pool = RewardPools::<T>::get(pool).ok_or(Error::<T>::PoolNotFound)?;
let current_rc = if !bonded_pool.points.is_zero() {
let commission = bonded_pool.commission.current();
reward_pool.current_reward_counter(pool, bonded_pool.points, commission)?.0
} else {
Default::default()
};
Ok(PoolMembers::<T>::iter()
.filter(|(_, d)| d.pool_id == pool)
.map(|(_, d)| d.pending_rewards(current_rc).unwrap_or_default())
.fold(0u32.into(), |acc: BalanceOf<T>, x| acc.saturating_add(x)))
}
pub fn reward_imbalance(pool: PoolId) -> RewardImbalance {
let pending_rewards = pool_pending_rewards(pool).expect("pool should exist");
let current_balance = RewardPool::<Runtime>::current_balance(pool);
if pending_rewards > current_balance {
RewardImbalance::Deficit(pending_rewards - current_balance)
} else {
RewardImbalance::Surplus(current_balance - pending_rewards)
}
}
pub fn set_pool_balance(who: AccountId, amount: Balance) {
StakingMock::set_bonded_balance(who, amount);
DelegateMock::set_agent_balance(who, amount);
}
pub fn member_delegation(who: AccountId) -> Balance {
<T as Config>::StakeAdapter::member_delegation_balance(Member::from(who))
.expect("who must be a pool member")
}
pub fn pool_balance(id: PoolId) -> Balance {
<T as Config>::StakeAdapter::total_balance(Pool::from(Pools::generate_bonded_account(id)))
.expect("who must be a bonded pool account")
}
pub fn add_to_restrict_list(who: &AccountId) {
if !RestrictedAccounts::get().contains(who) {
RestrictedAccounts::mutate(|l| l.push(*who));
}
}
pub fn remove_from_restrict_list(who: &AccountId) {
RestrictedAccounts::mutate(|l| l.retain(|x| x != who));
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn u256_to_balance_convert_works() {
assert_eq!(U256ToBalance::convert(0u32.into()), Zero::zero());
assert_eq!(U256ToBalance::convert(Balance::max_value().into()), Balance::max_value())
}
#[test]
#[should_panic]
fn u256_to_balance_convert_panics_correctly() {
U256ToBalance::convert(U256::from(Balance::max_value()).saturating_add(1u32.into()));
}
#[test]
fn balance_to_u256_convert_works() {
assert_eq!(BalanceToU256::convert(0u32.into()), U256::zero());
assert_eq!(BalanceToU256::convert(Balance::max_value()), Balance::max_value().into())
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff