pezpallet_staking/pezpallet/
mod.rs

1// This file is part of Bizinikiwi.
2
3// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Staking FRAME Pezpallet.
19
20use alloc::vec::Vec;
21use codec::Codec;
22use pezframe_election_provider_support::{ElectionProvider, SortedListProvider, VoteWeight};
23use pezframe_support::{
24	pezpallet_prelude::*,
25	traits::{
26		fungible::{
27			hold::{Balanced as FunHoldBalanced, Mutate as FunHoldMutate},
28			Mutate as FunMutate,
29		},
30		Contains, Defensive, EnsureOrigin, EstimateNextNewSession, Get, InspectLockableCurrency,
31		Nothing, OnUnbalanced, UnixTime,
32	},
33	weights::Weight,
34	BoundedVec,
35};
36use pezframe_system::{ensure_root, ensure_signed, pezpallet_prelude::*};
37use pezsp_runtime::{
38	traits::{SaturatedConversion, StaticLookup, Zero},
39	ArithmeticError, Perbill, Percent,
40};
41
42use pezsp_staking::{
43	EraIndex, Page, SessionIndex,
44	StakingAccount::{self, Controller, Stash},
45	StakingInterface,
46};
47
48mod impls;
49
50pub use impls::*;
51
52use crate::{
53	asset, slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, EraPayout,
54	EraRewardPoints, Exposure, ExposurePage, Forcing, LedgerIntegrityState, MaxNominationsOf,
55	NegativeImbalanceOf, Nominations, NominationsQuota, PositiveImbalanceOf, RewardDestination,
56	SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, ValidatorPrefs,
57};
58
59// The speculative number of spans are used as an input of the weight annotation of
60// [`Call::unbond`], as the post dispatch weight may depend on the number of slashing span on the
61// account which is not provided as an input. The value set should be conservative but sensible.
62pub(crate) const SPECULATIVE_NUM_SPANS: u32 = 32;
63
64#[pezframe_support::pezpallet]
65pub mod pezpallet {
66	use super::*;
67	use codec::HasCompact;
68	use pezframe_election_provider_support::ElectionDataProvider;
69
70	use crate::{BenchmarkingConfig, PagedExposureMetadata};
71
72	/// The in-code storage version.
73	const STORAGE_VERSION: StorageVersion = StorageVersion::new(16);
74
75	#[pezpallet::pezpallet]
76	#[pezpallet::storage_version(STORAGE_VERSION)]
77	pub struct Pezpallet<T>(_);
78
79	/// Possible operations on the configuration values of this pezpallet.
80	#[derive(TypeInfo, Debug, Clone, Encode, Decode, DecodeWithMemTracking, PartialEq)]
81	pub enum ConfigOp<T: Default + Codec> {
82		/// Don't change.
83		Noop,
84		/// Set the given value.
85		Set(T),
86		/// Remove from storage.
87		Remove,
88	}
89
90	#[pezpallet::config(with_default)]
91	pub trait Config: pezframe_system::Config {
92		/// The old trait for staking balance. Deprecated and only used for migrating old ledgers.
93		#[pezpallet::no_default]
94		type OldCurrency: InspectLockableCurrency<
95			Self::AccountId,
96			Moment = BlockNumberFor<Self>,
97			Balance = Self::CurrencyBalance,
98		>;
99
100		/// The staking balance.
101		#[pezpallet::no_default]
102		type Currency: FunHoldMutate<
103				Self::AccountId,
104				Reason = Self::RuntimeHoldReason,
105				Balance = Self::CurrencyBalance,
106			> + FunMutate<Self::AccountId, Balance = Self::CurrencyBalance>
107			+ FunHoldBalanced<Self::AccountId, Balance = Self::CurrencyBalance>;
108
109		/// Overarching hold reason.
110		#[pezpallet::no_default_bounds]
111		type RuntimeHoldReason: From<HoldReason>;
112
113		/// Just the `Currency::Balance` type; we have this item to allow us to constrain it to
114		/// `From<u64>`.
115		type CurrencyBalance: pezsp_runtime::traits::AtLeast32BitUnsigned
116			+ codec::FullCodec
117			+ DecodeWithMemTracking
118			+ HasCompact<Type: DecodeWithMemTracking>
119			+ Copy
120			+ MaybeSerializeDeserialize
121			+ core::fmt::Debug
122			+ Default
123			+ From<u64>
124			+ TypeInfo
125			+ Send
126			+ Sync
127			+ MaxEncodedLen;
128		/// Time used for computing era duration.
129		///
130		/// It is guaranteed to start being called from the first `on_finalize`. Thus value at
131		/// genesis is not used.
132		#[pezpallet::no_default]
133		type UnixTime: UnixTime;
134
135		/// Convert a balance into a number used for election calculation. This must fit into a
136		/// `u64` but is allowed to be sensibly lossy. The `u64` is used to communicate with the
137		/// [`pezframe_election_provider_support`] crate which accepts u64 numbers and does
138		/// operations in 128.
139		/// Consequently, the backward convert is used convert the u128s from sp-elections back to a
140		/// [`BalanceOf`].
141		#[pezpallet::no_default_bounds]
142		type CurrencyToVote: pezsp_staking::currency_to_vote::CurrencyToVote<BalanceOf<Self>>;
143
144		/// Something that provides the election functionality.
145		#[pezpallet::no_default]
146		type ElectionProvider: ElectionProvider<
147			AccountId = Self::AccountId,
148			BlockNumber = BlockNumberFor<Self>,
149			// we only accept an election provider that has staking as data provider.
150			DataProvider = Pezpallet<Self>,
151		>;
152		/// Something that provides the election functionality at genesis.
153		#[pezpallet::no_default]
154		type GenesisElectionProvider: ElectionProvider<
155			AccountId = Self::AccountId,
156			BlockNumber = BlockNumberFor<Self>,
157			DataProvider = Pezpallet<Self>,
158		>;
159
160		/// Something that defines the maximum number of nominations per nominator.
161		#[pezpallet::no_default_bounds]
162		type NominationsQuota: NominationsQuota<BalanceOf<Self>>;
163
164		/// Number of eras to keep in history.
165		///
166		/// Following information is kept for eras in `[current_era -
167		/// HistoryDepth, current_era]`: `ErasStakers`, `ErasStakersClipped`,
168		/// `ErasValidatorPrefs`, `ErasValidatorReward`, `ErasRewardPoints`,
169		/// `ErasTotalStake`, `ErasStartSessionIndex`, `ClaimedRewards`, `ErasStakersPaged`,
170		/// `ErasStakersOverview`.
171		///
172		/// Must be more than the number of eras delayed by session.
173		/// I.e. active era must always be in history. I.e. `active_era >
174		/// current_era - history_depth` must be guaranteed.
175		///
176		/// If migrating an existing pezpallet from storage value to config value,
177		/// this should be set to same value or greater as in storage.
178		///
179		/// Note: `HistoryDepth` is used as the upper bound for the `BoundedVec`
180		/// item `StakingLedger.legacy_claimed_rewards`. Setting this value lower than
181		/// the existing value can lead to inconsistencies in the
182		/// `StakingLedger` and will need to be handled properly in a migration.
183		/// The test `reducing_history_depth_abrupt` shows this effect.
184		#[pezpallet::constant]
185		type HistoryDepth: Get<u32>;
186
187		/// Tokens have been minted and are unused for validator-reward.
188		/// See [Era payout](./index.html#era-payout).
189		#[pezpallet::no_default_bounds]
190		type RewardRemainder: OnUnbalanced<NegativeImbalanceOf<Self>>;
191
192		/// The overarching event type.
193		#[pezpallet::no_default_bounds]
194		#[allow(deprecated)]
195		type RuntimeEvent: From<Event<Self>>
196			+ IsType<<Self as pezframe_system::Config>::RuntimeEvent>;
197
198		/// Handler for the unbalanced reduction when slashing a staker.
199		#[pezpallet::no_default_bounds]
200		type Slash: OnUnbalanced<NegativeImbalanceOf<Self>>;
201
202		/// Handler for the unbalanced increment when rewarding a staker.
203		/// NOTE: in most cases, the implementation of `OnUnbalanced` should modify the total
204		/// issuance.
205		#[pezpallet::no_default_bounds]
206		type Reward: OnUnbalanced<PositiveImbalanceOf<Self>>;
207
208		/// Number of sessions per era.
209		#[pezpallet::constant]
210		type SessionsPerEra: Get<SessionIndex>;
211
212		/// Number of eras that staked funds must remain bonded for.
213		#[pezpallet::constant]
214		type BondingDuration: Get<EraIndex>;
215
216		/// Number of eras that slashes are deferred by, after computation.
217		///
218		/// This should be less than the bonding duration. Set to 0 if slashes
219		/// should be applied immediately, without opportunity for intervention.
220		#[pezpallet::constant]
221		type SlashDeferDuration: Get<EraIndex>;
222
223		/// The origin which can manage less critical staking parameters that does not require root.
224		///
225		/// Supported actions: (1) cancel deferred slash, (2) set minimum commission.
226		#[pezpallet::no_default]
227		type AdminOrigin: EnsureOrigin<Self::RuntimeOrigin>;
228
229		/// Interface for interacting with a session pezpallet.
230		type SessionInterface: SessionInterface<Self::AccountId>;
231
232		/// The payout for validators and the system for the current era.
233		/// See [Era payout](./index.html#era-payout).
234		#[pezpallet::no_default]
235		type EraPayout: EraPayout<BalanceOf<Self>>;
236
237		/// Something that can estimate the next session change, accurately or as a best effort
238		/// guess.
239		#[pezpallet::no_default_bounds]
240		type NextNewSession: EstimateNextNewSession<BlockNumberFor<Self>>;
241
242		/// The maximum size of each `T::ExposurePage`.
243		///
244		/// An `ExposurePage` is weakly bounded to a maximum of `MaxExposurePageSize`
245		/// nominators.
246		///
247		/// For older non-paged exposure, a reward payout was restricted to the top
248		/// `MaxExposurePageSize` nominators. This is to limit the i/o cost for the
249		/// nominator payout.
250		///
251		/// Note: `MaxExposurePageSize` is used to bound `ClaimedRewards` and is unsafe to reduce
252		/// without handling it in a migration.
253		#[pezpallet::constant]
254		type MaxExposurePageSize: Get<u32>;
255
256		/// The absolute maximum of winner validators this pezpallet should return.
257		#[pezpallet::constant]
258		type MaxValidatorSet: Get<u32>;
259
260		/// Something that provides a best-effort sorted list of voters aka electing nominators,
261		/// used for NPoS election.
262		///
263		/// The changes to nominators are reported to this. Moreover, each validator's self-vote is
264		/// also reported as one independent vote.
265		///
266		/// To keep the load off the chain as much as possible, changes made to the staked amount
267		/// via rewards and slashes are not reported and thus need to be manually fixed by the
268		/// staker. In case of `bags-list`, this always means using `rebag` and `putInFrontOf`.
269		///
270		/// Invariant: what comes out of this list will always be a nominator.
271		#[pezpallet::no_default]
272		type VoterList: SortedListProvider<Self::AccountId, Score = VoteWeight>;
273
274		/// WIP: This is a noop as of now, the actual business logic that's described below is going
275		/// to be introduced in a follow-up PR.
276		///
277		/// Something that provides a best-effort sorted list of targets aka electable validators,
278		/// used for NPoS election.
279		///
280		/// The changes to the approval stake of each validator are reported to this. This means any
281		/// change to:
282		/// 1. The stake of any validator or nominator.
283		/// 2. The targets of any nominator
284		/// 3. The role of any staker (e.g. validator -> chilled, nominator -> validator, etc)
285		///
286		/// Unlike `VoterList`, the values in this list are always kept up to date with reward and
287		/// slash as well, and thus represent the accurate approval stake of all account being
288		/// nominated by nominators.
289		///
290		/// Note that while at the time of nomination, all targets are checked to be real
291		/// validators, they can chill at any point, and their approval stakes will still be
292		/// recorded. This implies that what comes out of iterating this list MIGHT NOT BE AN ACTIVE
293		/// VALIDATOR.
294		#[pezpallet::no_default]
295		type TargetList: SortedListProvider<Self::AccountId, Score = BalanceOf<Self>>;
296
297		/// The maximum number of `unlocking` chunks a [`StakingLedger`] can
298		/// have. Effectively determines how many unique eras a staker may be
299		/// unbonding in.
300		///
301		/// Note: `MaxUnlockingChunks` is used as the upper bound for the
302		/// `BoundedVec` item `StakingLedger.unlocking`. Setting this value
303		/// lower than the existing value can lead to inconsistencies in the
304		/// `StakingLedger` and will need to be handled properly in a runtime
305		/// migration. The test `reducing_max_unlocking_chunks_abrupt` shows
306		/// this effect.
307		#[pezpallet::constant]
308		type MaxUnlockingChunks: Get<u32>;
309
310		/// The maximum amount of controller accounts that can be deprecated in one call.
311		type MaxControllersInDeprecationBatch: Get<u32>;
312
313		/// Something that listens to staking updates and performs actions based on the data it
314		/// receives.
315		///
316		/// WARNING: this only reports slashing and withdraw events for the time being.
317		#[pezpallet::no_default_bounds]
318		type EventListeners: pezsp_staking::OnStakingUpdate<Self::AccountId, BalanceOf<Self>>;
319
320		#[pezpallet::no_default_bounds]
321		/// Filter some accounts from participating in staking.
322		///
323		/// This is useful for example to blacklist an account that is participating in staking in
324		/// another way (such as pools).
325		type Filter: Contains<Self::AccountId>;
326
327		/// Some parameters of the benchmarking.
328		#[cfg(feature = "std")]
329		type BenchmarkingConfig: BenchmarkingConfig;
330
331		#[cfg(not(feature = "std"))]
332		#[pezpallet::no_default]
333		type BenchmarkingConfig: BenchmarkingConfig;
334
335		/// Weight information for extrinsics in this pezpallet.
336		type WeightInfo: WeightInfo;
337	}
338
339	/// A reason for placing a hold on funds.
340	#[pezpallet::composite_enum]
341	pub enum HoldReason {
342		/// Funds on stake by a nominator or a validator.
343		#[codec(index = 0)]
344		Staking,
345	}
346
347	/// Default implementations of [`DefaultConfig`], which can be used to implement [`Config`].
348	pub mod config_preludes {
349		use super::*;
350		use pezframe_support::{derive_impl, parameter_types, traits::ConstU32};
351		pub struct TestDefaultConfig;
352
353		#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
354		impl pezframe_system::DefaultConfig for TestDefaultConfig {}
355
356		parameter_types! {
357			pub const SessionsPerEra: SessionIndex = 3;
358			pub const BondingDuration: EraIndex = 3;
359		}
360
361		#[pezframe_support::register_default_impl(TestDefaultConfig)]
362		impl DefaultConfig for TestDefaultConfig {
363			#[inject_runtime_type]
364			type RuntimeEvent = ();
365			#[inject_runtime_type]
366			type RuntimeHoldReason = ();
367			type CurrencyBalance = u128;
368			type CurrencyToVote = ();
369			type NominationsQuota = crate::FixedNominationsQuota<16>;
370			type HistoryDepth = ConstU32<84>;
371			type RewardRemainder = ();
372			type Slash = ();
373			type Reward = ();
374			type SessionsPerEra = SessionsPerEra;
375			type BondingDuration = BondingDuration;
376			type SlashDeferDuration = ();
377			type SessionInterface = ();
378			type NextNewSession = ();
379			type MaxExposurePageSize = ConstU32<64>;
380			type MaxUnlockingChunks = ConstU32<32>;
381			type MaxValidatorSet = ConstU32<100>;
382			type MaxControllersInDeprecationBatch = ConstU32<100>;
383			type EventListeners = ();
384			type Filter = Nothing;
385			#[cfg(feature = "std")]
386			type BenchmarkingConfig = crate::TestBenchmarkingConfig;
387			type WeightInfo = ();
388		}
389	}
390
391	/// The ideal number of active validators.
392	#[pezpallet::storage]
393	pub type ValidatorCount<T> = StorageValue<_, u32, ValueQuery>;
394
395	/// Minimum number of staking participants before emergency conditions are imposed.
396	#[pezpallet::storage]
397	pub type MinimumValidatorCount<T> = StorageValue<_, u32, ValueQuery>;
398
399	/// Any validators that may never be slashed or forcibly kicked. It's a Vec since they're
400	/// easy to initialize and the performance hit is minimal (we expect no more than four
401	/// invulnerables) and restricted to testnets.
402	#[pezpallet::storage]
403	#[pezpallet::unbounded]
404	pub type Invulnerables<T: Config> = StorageValue<_, Vec<T::AccountId>, ValueQuery>;
405
406	/// Map from all locked "stash" accounts to the controller account.
407	///
408	/// TWOX-NOTE: SAFE since `AccountId` is a secure hash.
409	#[pezpallet::storage]
410	pub type Bonded<T: Config> = StorageMap<_, Twox64Concat, T::AccountId, T::AccountId>;
411
412	/// The minimum active bond to become and maintain the role of a nominator.
413	#[pezpallet::storage]
414	pub type MinNominatorBond<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;
415
416	/// The minimum active bond to become and maintain the role of a validator.
417	#[pezpallet::storage]
418	pub type MinValidatorBond<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;
419
420	/// The minimum active nominator stake of the last successful election.
421	#[pezpallet::storage]
422	pub type MinimumActiveStake<T> = StorageValue<_, BalanceOf<T>, ValueQuery>;
423
424	/// The minimum amount of commission that validators can set.
425	///
426	/// If set to `0`, no limit exists.
427	#[pezpallet::storage]
428	pub type MinCommission<T: Config> = StorageValue<_, Perbill, ValueQuery>;
429
430	/// Map from all (unlocked) "controller" accounts to the info regarding the staking.
431	///
432	/// Note: All the reads and mutations to this storage *MUST* be done through the methods exposed
433	/// by [`StakingLedger`] to ensure data and lock consistency.
434	#[pezpallet::storage]
435	pub type Ledger<T: Config> = StorageMap<_, Blake2_128Concat, T::AccountId, StakingLedger<T>>;
436
437	/// Where the reward payment should be made. Keyed by stash.
438	///
439	/// TWOX-NOTE: SAFE since `AccountId` is a secure hash.
440	#[pezpallet::storage]
441	pub type Payee<T: Config> =
442		StorageMap<_, Twox64Concat, T::AccountId, RewardDestination<T::AccountId>, OptionQuery>;
443
444	/// The map from (wannabe) validator stash key to the preferences of that validator.
445	///
446	/// TWOX-NOTE: SAFE since `AccountId` is a secure hash.
447	#[pezpallet::storage]
448	pub type Validators<T: Config> =
449		CountedStorageMap<_, Twox64Concat, T::AccountId, ValidatorPrefs, ValueQuery>;
450
451	/// The maximum validator count before we stop allowing new validators to join.
452	///
453	/// When this value is not set, no limits are enforced.
454	#[pezpallet::storage]
455	pub type MaxValidatorsCount<T> = StorageValue<_, u32, OptionQuery>;
456
457	/// The map from nominator stash key to their nomination preferences, namely the validators that
458	/// they wish to support.
459	///
460	/// Note that the keys of this storage map might become non-decodable in case the
461	/// account's [`NominationsQuota::MaxNominations`] configuration is decreased.
462	/// In this rare case, these nominators
463	/// are still existent in storage, their key is correct and retrievable (i.e. `contains_key`
464	/// indicates that they exist), but their value cannot be decoded. Therefore, the non-decodable
465	/// nominators will effectively not-exist, until they re-submit their preferences such that it
466	/// is within the bounds of the newly set `Config::MaxNominations`.
467	///
468	/// This implies that `::iter_keys().count()` and `::iter().count()` might return different
469	/// values for this map. Moreover, the main `::count()` is aligned with the former, namely the
470	/// number of keys that exist.
471	///
472	/// Lastly, if any of the nominators become non-decodable, they can be chilled immediately via
473	/// [`Call::chill_other`] dispatchable by anyone.
474	///
475	/// TWOX-NOTE: SAFE since `AccountId` is a secure hash.
476	#[pezpallet::storage]
477	pub type Nominators<T: Config> =
478		CountedStorageMap<_, Twox64Concat, T::AccountId, Nominations<T>>;
479
480	/// Stakers whose funds are managed by other pallets.
481	///
482	/// This pezpallet does not apply any locks on them, therefore they are only virtually bonded.
483	/// They are expected to be keyless accounts and hence should not be allowed to mutate their
484	/// ledger directly via this pezpallet. Instead, these accounts are managed by other pallets
485	/// and accessed via low level apis. We keep track of them to do minimal integrity checks.
486	#[pezpallet::storage]
487	pub type VirtualStakers<T: Config> = CountedStorageMap<_, Twox64Concat, T::AccountId, ()>;
488
489	/// The maximum nominator count before we stop allowing new validators to join.
490	///
491	/// When this value is not set, no limits are enforced.
492	#[pezpallet::storage]
493	pub type MaxNominatorsCount<T> = StorageValue<_, u32, OptionQuery>;
494
495	/// The current era index.
496	///
497	/// This is the latest planned era, depending on how the Session pezpallet queues the validator
498	/// set, it might be active or not.
499	#[pezpallet::storage]
500	pub type CurrentEra<T> = StorageValue<_, EraIndex>;
501
502	/// The active era information, it holds index and start.
503	///
504	/// The active era is the era being currently rewarded. Validator set of this era must be
505	/// equal to [`SessionInterface::validators`].
506	#[pezpallet::storage]
507	pub type ActiveEra<T> = StorageValue<_, ActiveEraInfo>;
508
509	/// The session index at which the era start for the last [`Config::HistoryDepth`] eras.
510	///
511	/// Note: This tracks the starting session (i.e. session index when era start being active)
512	/// for the eras in `[CurrentEra - HISTORY_DEPTH, CurrentEra]`.
513	#[pezpallet::storage]
514	pub type ErasStartSessionIndex<T> = StorageMap<_, Twox64Concat, EraIndex, SessionIndex>;
515
516	/// Exposure of validator at era.
517	///
518	/// This is keyed first by the era index to allow bulk deletion and then the stash account.
519	///
520	/// Is it removed after [`Config::HistoryDepth`] eras.
521	/// If stakers hasn't been set or has been removed then empty exposure is returned.
522	///
523	/// Note: Deprecated since v14. Use `EraInfo` instead to work with exposures.
524	#[pezpallet::storage]
525	#[pezpallet::unbounded]
526	pub type ErasStakers<T: Config> = StorageDoubleMap<
527		_,
528		Twox64Concat,
529		EraIndex,
530		Twox64Concat,
531		T::AccountId,
532		Exposure<T::AccountId, BalanceOf<T>>,
533		ValueQuery,
534	>;
535
536	/// Summary of validator exposure at a given era.
537	///
538	/// This contains the total stake in support of the validator and their own stake. In addition,
539	/// it can also be used to get the number of nominators backing this validator and the number of
540	/// exposure pages they are divided into. The page count is useful to determine the number of
541	/// pages of rewards that needs to be claimed.
542	///
543	/// This is keyed first by the era index to allow bulk deletion and then the stash account.
544	/// Should only be accessed through `EraInfo`.
545	///
546	/// Is it removed after [`Config::HistoryDepth`] eras.
547	/// If stakers hasn't been set or has been removed then empty overview is returned.
548	#[pezpallet::storage]
549	pub type ErasStakersOverview<T: Config> = StorageDoubleMap<
550		_,
551		Twox64Concat,
552		EraIndex,
553		Twox64Concat,
554		T::AccountId,
555		PagedExposureMetadata<BalanceOf<T>>,
556		OptionQuery,
557	>;
558
559	/// Clipped Exposure of validator at era.
560	///
561	/// Note: This is deprecated, should be used as read-only and will be removed in the future.
562	/// New `Exposure`s are stored in a paged manner in `ErasStakersPaged` instead.
563	///
564	/// This is similar to [`ErasStakers`] but number of nominators exposed is reduced to the
565	/// `T::MaxExposurePageSize` biggest stakers.
566	/// (Note: the field `total` and `own` of the exposure remains unchanged).
567	/// This is used to limit the i/o cost for the nominator payout.
568	///
569	/// This is keyed fist by the era index to allow bulk deletion and then the stash account.
570	///
571	/// It is removed after [`Config::HistoryDepth`] eras.
572	/// If stakers hasn't been set or has been removed then empty exposure is returned.
573	///
574	/// Note: Deprecated since v14. Use `EraInfo` instead to work with exposures.
575	#[pezpallet::storage]
576	#[pezpallet::unbounded]
577	pub type ErasStakersClipped<T: Config> = StorageDoubleMap<
578		_,
579		Twox64Concat,
580		EraIndex,
581		Twox64Concat,
582		T::AccountId,
583		Exposure<T::AccountId, BalanceOf<T>>,
584		ValueQuery,
585	>;
586
587	/// Paginated exposure of a validator at given era.
588	///
589	/// This is keyed first by the era index to allow bulk deletion, then stash account and finally
590	/// the page. Should only be accessed through `EraInfo`.
591	///
592	/// This is cleared after [`Config::HistoryDepth`] eras.
593	#[pezpallet::storage]
594	#[pezpallet::unbounded]
595	pub type ErasStakersPaged<T: Config> = StorageNMap<
596		_,
597		(
598			NMapKey<Twox64Concat, EraIndex>,
599			NMapKey<Twox64Concat, T::AccountId>,
600			NMapKey<Twox64Concat, Page>,
601		),
602		ExposurePage<T::AccountId, BalanceOf<T>>,
603		OptionQuery,
604	>;
605
606	/// History of claimed paged rewards by era and validator.
607	///
608	/// This is keyed by era and validator stash which maps to the set of page indexes which have
609	/// been claimed.
610	///
611	/// It is removed after [`Config::HistoryDepth`] eras.
612	#[pezpallet::storage]
613	#[pezpallet::unbounded]
614	pub type ClaimedRewards<T: Config> = StorageDoubleMap<
615		_,
616		Twox64Concat,
617		EraIndex,
618		Twox64Concat,
619		T::AccountId,
620		Vec<Page>,
621		ValueQuery,
622	>;
623
624	/// Similar to `ErasStakers`, this holds the preferences of validators.
625	///
626	/// This is keyed first by the era index to allow bulk deletion and then the stash account.
627	///
628	/// Is it removed after [`Config::HistoryDepth`] eras.
629	// If prefs hasn't been set or has been removed then 0 commission is returned.
630	#[pezpallet::storage]
631	pub type ErasValidatorPrefs<T: Config> = StorageDoubleMap<
632		_,
633		Twox64Concat,
634		EraIndex,
635		Twox64Concat,
636		T::AccountId,
637		ValidatorPrefs,
638		ValueQuery,
639	>;
640
641	/// The total validator era payout for the last [`Config::HistoryDepth`] eras.
642	///
643	/// Eras that haven't finished yet or has been removed doesn't have reward.
644	#[pezpallet::storage]
645	pub type ErasValidatorReward<T: Config> = StorageMap<_, Twox64Concat, EraIndex, BalanceOf<T>>;
646
647	/// Rewards for the last [`Config::HistoryDepth`] eras.
648	/// If reward hasn't been set or has been removed then 0 reward is returned.
649	#[pezpallet::storage]
650	#[pezpallet::unbounded]
651	pub type ErasRewardPoints<T: Config> =
652		StorageMap<_, Twox64Concat, EraIndex, EraRewardPoints<T::AccountId>, ValueQuery>;
653
654	/// The total amount staked for the last [`Config::HistoryDepth`] eras.
655	/// If total hasn't been set or has been removed then 0 stake is returned.
656	#[pezpallet::storage]
657	pub type ErasTotalStake<T: Config> =
658		StorageMap<_, Twox64Concat, EraIndex, BalanceOf<T>, ValueQuery>;
659
660	/// Mode of era forcing.
661	#[pezpallet::storage]
662	pub type ForceEra<T> = StorageValue<_, Forcing, ValueQuery>;
663
664	/// Maximum staked rewards, i.e. the percentage of the era inflation that
665	/// is used for stake rewards.
666	/// See [Era payout](./index.html#era-payout).
667	#[pezpallet::storage]
668	pub type MaxStakedRewards<T> = StorageValue<_, Percent, OptionQuery>;
669
670	/// The percentage of the slash that is distributed to reporters.
671	///
672	/// The rest of the slashed value is handled by the `Slash`.
673	#[pezpallet::storage]
674	pub type SlashRewardFraction<T> = StorageValue<_, Perbill, ValueQuery>;
675
676	/// The amount of currency given to reporters of a slash event which was
677	/// canceled by extraordinary circumstances (e.g. governance).
678	#[pezpallet::storage]
679	pub type CanceledSlashPayout<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;
680
681	/// All unapplied slashes that are queued for later.
682	#[pezpallet::storage]
683	#[pezpallet::unbounded]
684	pub type UnappliedSlashes<T: Config> = StorageMap<
685		_,
686		Twox64Concat,
687		EraIndex,
688		Vec<UnappliedSlash<T::AccountId, BalanceOf<T>>>,
689		ValueQuery,
690	>;
691
692	/// A mapping from still-bonded eras to the first session index of that era.
693	///
694	/// Must contains information for eras for the range:
695	/// `[active_era - bounding_duration; active_era]`
696	#[pezpallet::storage]
697	#[pezpallet::unbounded]
698	pub type BondedEras<T: Config> = StorageValue<_, Vec<(EraIndex, SessionIndex)>, ValueQuery>;
699
700	/// All slashing events on validators, mapped by era to the highest slash proportion
701	/// and slash value of the era.
702	#[pezpallet::storage]
703	pub type ValidatorSlashInEra<T: Config> = StorageDoubleMap<
704		_,
705		Twox64Concat,
706		EraIndex,
707		Twox64Concat,
708		T::AccountId,
709		(Perbill, BalanceOf<T>),
710	>;
711
712	/// All slashing events on nominators, mapped by era to the highest slash value of the era.
713	#[pezpallet::storage]
714	pub type NominatorSlashInEra<T: Config> =
715		StorageDoubleMap<_, Twox64Concat, EraIndex, Twox64Concat, T::AccountId, BalanceOf<T>>;
716
717	/// Slashing spans for stash accounts.
718	#[pezpallet::storage]
719	#[pezpallet::unbounded]
720	pub type SlashingSpans<T: Config> =
721		StorageMap<_, Twox64Concat, T::AccountId, slashing::SlashingSpans>;
722
723	/// Records information about the maximum slash of a stash within a slashing span,
724	/// as well as how much reward has been paid out.
725	#[pezpallet::storage]
726	pub type SpanSlash<T: Config> = StorageMap<
727		_,
728		Twox64Concat,
729		(T::AccountId, slashing::SpanIndex),
730		slashing::SpanRecord<BalanceOf<T>>,
731		ValueQuery,
732	>;
733
734	/// The last planned session scheduled by the session pezpallet.
735	///
736	/// This is basically in sync with the call to
737	/// [`pezpallet_session::SessionManager::new_session`].
738	#[pezpallet::storage]
739	pub type CurrentPlannedSession<T> = StorageValue<_, SessionIndex, ValueQuery>;
740
741	/// The threshold for when users can start calling `chill_other` for other validators /
742	/// nominators. The threshold is compared to the actual number of validators / nominators
743	/// (`CountFor*`) in the system compared to the configured max (`Max*Count`).
744	#[pezpallet::storage]
745	pub type ChillThreshold<T: Config> = StorageValue<_, Percent, OptionQuery>;
746
747	#[pezpallet::genesis_config]
748	#[derive(pezframe_support::DefaultNoBound)]
749	pub struct GenesisConfig<T: Config> {
750		pub validator_count: u32,
751		pub minimum_validator_count: u32,
752		pub invulnerables: Vec<T::AccountId>,
753		pub force_era: Forcing,
754		pub slash_reward_fraction: Perbill,
755		pub canceled_payout: BalanceOf<T>,
756		pub stakers:
757			Vec<(T::AccountId, T::AccountId, BalanceOf<T>, crate::StakerStatus<T::AccountId>)>,
758		pub min_nominator_bond: BalanceOf<T>,
759		pub min_validator_bond: BalanceOf<T>,
760		pub max_validator_count: Option<u32>,
761		pub max_nominator_count: Option<u32>,
762	}
763
764	#[pezpallet::genesis_build]
765	impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
766		fn build(&self) {
767			ValidatorCount::<T>::put(self.validator_count);
768			MinimumValidatorCount::<T>::put(self.minimum_validator_count);
769			Invulnerables::<T>::put(&self.invulnerables);
770			ForceEra::<T>::put(self.force_era);
771			CanceledSlashPayout::<T>::put(self.canceled_payout);
772			SlashRewardFraction::<T>::put(self.slash_reward_fraction);
773			MinNominatorBond::<T>::put(self.min_nominator_bond);
774			MinValidatorBond::<T>::put(self.min_validator_bond);
775			if let Some(x) = self.max_validator_count {
776				MaxValidatorsCount::<T>::put(x);
777			}
778			if let Some(x) = self.max_nominator_count {
779				MaxNominatorsCount::<T>::put(x);
780			}
781
782			for &(ref stash, _, balance, ref status) in &self.stakers {
783				crate::log!(
784					trace,
785					"inserting genesis staker: {:?} => {:?} => {:?}",
786					stash,
787					balance,
788					status
789				);
790				assert!(
791					asset::free_to_stake::<T>(stash) >= balance,
792					"Stash does not have enough balance to bond."
793				);
794				pezframe_support::assert_ok!(<Pezpallet<T>>::bond(
795					T::RuntimeOrigin::from(Some(stash.clone()).into()),
796					balance,
797					RewardDestination::Staked,
798				));
799				pezframe_support::assert_ok!(match status {
800					crate::StakerStatus::Validator => <Pezpallet<T>>::validate(
801						T::RuntimeOrigin::from(Some(stash.clone()).into()),
802						Default::default(),
803					),
804					crate::StakerStatus::Nominator(votes) => <Pezpallet<T>>::nominate(
805						T::RuntimeOrigin::from(Some(stash.clone()).into()),
806						votes.iter().map(|l| T::Lookup::unlookup(l.clone())).collect(),
807					),
808					_ => Ok(()),
809				});
810				assert!(
811					ValidatorCount::<T>::get()
812						<= <T::ElectionProvider as ElectionProvider>::MaxWinnersPerPage::get()
813							* <T::ElectionProvider as ElectionProvider>::Pages::get()
814				);
815			}
816
817			// all voters are reported to the `VoterList`.
818			assert_eq!(
819				T::VoterList::count(),
820				Nominators::<T>::count() + Validators::<T>::count(),
821				"not all genesis stakers were inserted into sorted list provider, something is wrong."
822			);
823		}
824	}
825
826	#[pezpallet::event]
827	#[pezpallet::generate_deposit(pub(crate) fn deposit_event)]
828	pub enum Event<T: Config> {
829		/// The era payout has been set; the first balance is the validator-payout; the second is
830		/// the remainder from the maximum amount of reward.
831		EraPaid { era_index: EraIndex, validator_payout: BalanceOf<T>, remainder: BalanceOf<T> },
832		/// The nominator has been rewarded by this amount to this destination.
833		Rewarded {
834			stash: T::AccountId,
835			dest: RewardDestination<T::AccountId>,
836			amount: BalanceOf<T>,
837		},
838		/// A staker (validator or nominator) has been slashed by the given amount.
839		Slashed { staker: T::AccountId, amount: BalanceOf<T> },
840		/// A slash for the given validator, for the given percentage of their stake, at the given
841		/// era as been reported.
842		SlashReported { validator: T::AccountId, fraction: Perbill, slash_era: EraIndex },
843		/// An old slashing report from a prior era was discarded because it could
844		/// not be processed.
845		OldSlashingReportDiscarded { session_index: SessionIndex },
846		/// A new set of stakers was elected.
847		StakersElected,
848		/// An account has bonded this amount. \[stash, amount\]
849		///
850		/// NOTE: This event is only emitted when funds are bonded via a dispatchable. Notably,
851		/// it will not be emitted for staking rewards when they are added to stake.
852		Bonded { stash: T::AccountId, amount: BalanceOf<T> },
853		/// An account has unbonded this amount.
854		Unbonded { stash: T::AccountId, amount: BalanceOf<T> },
855		/// An account has called `withdraw_unbonded` and removed unbonding chunks worth `Balance`
856		/// from the unlocking queue.
857		Withdrawn { stash: T::AccountId, amount: BalanceOf<T> },
858		/// A nominator has been kicked from a validator.
859		Kicked { nominator: T::AccountId, stash: T::AccountId },
860		/// The election failed. No new era is planned.
861		StakingElectionFailed,
862		/// An account has stopped participating as either a validator or nominator.
863		Chilled { stash: T::AccountId },
864		/// A Page of stakers rewards are getting paid. `next` is `None` if all pages are claimed.
865		PayoutStarted {
866			era_index: EraIndex,
867			validator_stash: T::AccountId,
868			page: Page,
869			next: Option<Page>,
870		},
871		/// A validator has set their preferences.
872		ValidatorPrefsSet { stash: T::AccountId, prefs: ValidatorPrefs },
873		/// Voters size limit reached.
874		SnapshotVotersSizeExceeded { size: u32 },
875		/// Targets size limit reached.
876		SnapshotTargetsSizeExceeded { size: u32 },
877		/// A new force era mode was set.
878		ForceEra { mode: Forcing },
879		/// Report of a controller batch deprecation.
880		ControllerBatchDeprecated { failures: u32 },
881		/// Staking balance migrated from locks to holds, with any balance that could not be held
882		/// is force withdrawn.
883		CurrencyMigrated { stash: T::AccountId, force_withdraw: BalanceOf<T> },
884	}
885
886	#[pezpallet::error]
887	#[derive(PartialEq)]
888	pub enum Error<T> {
889		/// Not a controller account.
890		NotController,
891		/// Not a stash account.
892		NotStash,
893		/// Stash is already bonded.
894		AlreadyBonded,
895		/// Controller is already paired.
896		AlreadyPaired,
897		/// Targets cannot be empty.
898		EmptyTargets,
899		/// Duplicate index.
900		DuplicateIndex,
901		/// Slash record index out of bounds.
902		InvalidSlashIndex,
903		/// Cannot have a validator or nominator role, with value less than the minimum defined by
904		/// governance (see `MinValidatorBond` and `MinNominatorBond`). If unbonding is the
905		/// intention, `chill` first to remove one's role as validator/nominator.
906		InsufficientBond,
907		/// Can not schedule more unlock chunks.
908		NoMoreChunks,
909		/// Can not rebond without unlocking chunks.
910		NoUnlockChunk,
911		/// Attempting to target a stash that still has funds.
912		FundedTarget,
913		/// Invalid era to reward.
914		InvalidEraToReward,
915		/// Invalid number of nominations.
916		InvalidNumberOfNominations,
917		/// Items are not sorted and unique.
918		NotSortedAndUnique,
919		/// Rewards for this era have already been claimed for this validator.
920		AlreadyClaimed,
921		/// No nominators exist on this page.
922		InvalidPage,
923		/// Incorrect previous history depth input provided.
924		IncorrectHistoryDepth,
925		/// Incorrect number of slashing spans provided.
926		IncorrectSlashingSpans,
927		/// Internal state has become somehow corrupted and the operation cannot continue.
928		BadState,
929		/// Too many nomination targets supplied.
930		TooManyTargets,
931		/// A nomination target was supplied that was blocked or otherwise not a validator.
932		BadTarget,
933		/// The user has enough bond and thus cannot be chilled forcefully by an external person.
934		CannotChillOther,
935		/// There are too many nominators in the system. Governance needs to adjust the staking
936		/// settings to keep things safe for the runtime.
937		TooManyNominators,
938		/// There are too many validator candidates in the system. Governance needs to adjust the
939		/// staking settings to keep things safe for the runtime.
940		TooManyValidators,
941		/// Commission is too low. Must be at least `MinCommission`.
942		CommissionTooLow,
943		/// Some bound is not met.
944		BoundNotMet,
945		/// Used when attempting to use deprecated controller account logic.
946		ControllerDeprecated,
947		/// Cannot reset a ledger.
948		CannotRestoreLedger,
949		/// Provided reward destination is not allowed.
950		RewardDestinationRestricted,
951		/// Not enough funds available to withdraw.
952		NotEnoughFunds,
953		/// Operation not allowed for virtual stakers.
954		VirtualStakerNotAllowed,
955		/// Stash could not be reaped as other pezpallet might depend on it.
956		CannotReapStash,
957		/// The stake of this account is already migrated to `Fungible` holds.
958		AlreadyMigrated,
959		/// Account is restricted from participation in staking. This may happen if the account is
960		/// staking in another way already, such as via pool.
961		Restricted,
962	}
963
964	#[pezpallet::hooks]
965	impl<T: Config> Hooks<BlockNumberFor<T>> for Pezpallet<T> {
966		fn on_initialize(_now: BlockNumberFor<T>) -> Weight {
967			// just return the weight of the on_finalize.
968			T::DbWeight::get().reads(1)
969		}
970
971		fn on_finalize(_n: BlockNumberFor<T>) {
972			// Set the start of the first era.
973			if let Some(mut active_era) = ActiveEra::<T>::get() {
974				if active_era.start.is_none() {
975					let now_as_millis_u64 = T::UnixTime::now().as_millis().saturated_into::<u64>();
976					active_era.start = Some(now_as_millis_u64);
977					// This write only ever happens once, we don't include it in the weight in
978					// general
979					ActiveEra::<T>::put(active_era);
980				}
981			}
982			// `on_finalize` weight is tracked in `on_initialize`
983		}
984
985		fn integrity_test() {
986			// ensure that we funnel the correct value to the `DataProvider::MaxVotesPerVoter`;
987			assert_eq!(
988				MaxNominationsOf::<T>::get(),
989				<Self as ElectionDataProvider>::MaxVotesPerVoter::get()
990			);
991			// and that MaxNominations is always greater than 1, since we count on this.
992			assert!(!MaxNominationsOf::<T>::get().is_zero());
993
994			// ensure election results are always bounded with the same value
995			assert!(
996				<T::ElectionProvider as ElectionProvider>::MaxWinnersPerPage::get()
997					== <T::GenesisElectionProvider as ElectionProvider>::MaxWinnersPerPage::get()
998			);
999
1000			assert!(
1001				T::SlashDeferDuration::get() < T::BondingDuration::get() || T::BondingDuration::get() == 0,
1002				"As per documentation, slash defer duration ({}) should be less than bonding duration ({}).",
1003				T::SlashDeferDuration::get(),
1004				T::BondingDuration::get(),
1005			)
1006		}
1007
1008		#[cfg(feature = "try-runtime")]
1009		fn try_state(n: BlockNumberFor<T>) -> Result<(), pezsp_runtime::TryRuntimeError> {
1010			Self::do_try_state(n)
1011		}
1012	}
1013
1014	impl<T: Config> Pezpallet<T> {
1015		/// Get the ideal number of active validators.
1016		pub fn validator_count() -> u32 {
1017			ValidatorCount::<T>::get()
1018		}
1019
1020		/// Get the minimum number of staking participants before emergency conditions are imposed.
1021		pub fn minimum_validator_count() -> u32 {
1022			MinimumValidatorCount::<T>::get()
1023		}
1024
1025		/// Get the validators that may never be slashed or forcibly kicked out.
1026		pub fn invulnerables() -> Vec<T::AccountId> {
1027			Invulnerables::<T>::get()
1028		}
1029
1030		/// Get the preferences of a given validator.
1031		pub fn validators<EncodeLikeAccountId>(account_id: EncodeLikeAccountId) -> ValidatorPrefs
1032		where
1033			EncodeLikeAccountId: codec::EncodeLike<T::AccountId>,
1034		{
1035			Validators::<T>::get(account_id)
1036		}
1037
1038		/// Get the nomination preferences of a given nominator.
1039		pub fn nominators<EncodeLikeAccountId>(
1040			account_id: EncodeLikeAccountId,
1041		) -> Option<Nominations<T>>
1042		where
1043			EncodeLikeAccountId: codec::EncodeLike<T::AccountId>,
1044		{
1045			Nominators::<T>::get(account_id)
1046		}
1047
1048		/// Get the current era index.
1049		pub fn current_era() -> Option<EraIndex> {
1050			CurrentEra::<T>::get()
1051		}
1052
1053		/// Get the active era information.
1054		pub fn active_era() -> Option<ActiveEraInfo> {
1055			ActiveEra::<T>::get()
1056		}
1057
1058		/// Get the session index at which the era starts for the last [`Config::HistoryDepth`]
1059		/// eras.
1060		pub fn eras_start_session_index<EncodeLikeEraIndex>(
1061			era_index: EncodeLikeEraIndex,
1062		) -> Option<SessionIndex>
1063		where
1064			EncodeLikeEraIndex: codec::EncodeLike<EraIndex>,
1065		{
1066			ErasStartSessionIndex::<T>::get(era_index)
1067		}
1068
1069		/// Get the clipped exposure of a given validator at an era.
1070		pub fn eras_stakers_clipped<EncodeLikeEraIndex, EncodeLikeAccountId>(
1071			era_index: EncodeLikeEraIndex,
1072			account_id: EncodeLikeAccountId,
1073		) -> Exposure<T::AccountId, BalanceOf<T>>
1074		where
1075			EncodeLikeEraIndex: codec::EncodeLike<EraIndex>,
1076			EncodeLikeAccountId: codec::EncodeLike<T::AccountId>,
1077		{
1078			ErasStakersClipped::<T>::get(era_index, account_id)
1079		}
1080
1081		/// Get the paged history of claimed rewards by era for given validator.
1082		pub fn claimed_rewards<EncodeLikeEraIndex, EncodeLikeAccountId>(
1083			era_index: EncodeLikeEraIndex,
1084			account_id: EncodeLikeAccountId,
1085		) -> Vec<Page>
1086		where
1087			EncodeLikeEraIndex: codec::EncodeLike<EraIndex>,
1088			EncodeLikeAccountId: codec::EncodeLike<T::AccountId>,
1089		{
1090			ClaimedRewards::<T>::get(era_index, account_id)
1091		}
1092
1093		/// Get the preferences of given validator at given era.
1094		pub fn eras_validator_prefs<EncodeLikeEraIndex, EncodeLikeAccountId>(
1095			era_index: EncodeLikeEraIndex,
1096			account_id: EncodeLikeAccountId,
1097		) -> ValidatorPrefs
1098		where
1099			EncodeLikeEraIndex: codec::EncodeLike<EraIndex>,
1100			EncodeLikeAccountId: codec::EncodeLike<T::AccountId>,
1101		{
1102			ErasValidatorPrefs::<T>::get(era_index, account_id)
1103		}
1104
1105		/// Get the total validator era payout for the last [`Config::HistoryDepth`] eras.
1106		pub fn eras_validator_reward<EncodeLikeEraIndex>(
1107			era_index: EncodeLikeEraIndex,
1108		) -> Option<BalanceOf<T>>
1109		where
1110			EncodeLikeEraIndex: codec::EncodeLike<EraIndex>,
1111		{
1112			ErasValidatorReward::<T>::get(era_index)
1113		}
1114
1115		/// Get the rewards for the last [`Config::HistoryDepth`] eras.
1116		pub fn eras_reward_points<EncodeLikeEraIndex>(
1117			era_index: EncodeLikeEraIndex,
1118		) -> EraRewardPoints<T::AccountId>
1119		where
1120			EncodeLikeEraIndex: codec::EncodeLike<EraIndex>,
1121		{
1122			ErasRewardPoints::<T>::get(era_index)
1123		}
1124
1125		/// Get the total amount staked for the last [`Config::HistoryDepth`] eras.
1126		pub fn eras_total_stake<EncodeLikeEraIndex>(era_index: EncodeLikeEraIndex) -> BalanceOf<T>
1127		where
1128			EncodeLikeEraIndex: codec::EncodeLike<EraIndex>,
1129		{
1130			ErasTotalStake::<T>::get(era_index)
1131		}
1132
1133		/// Get the mode of era forcing.
1134		pub fn force_era() -> Forcing {
1135			ForceEra::<T>::get()
1136		}
1137
1138		/// Get the percentage of the slash that is distributed to reporters.
1139		pub fn slash_reward_fraction() -> Perbill {
1140			SlashRewardFraction::<T>::get()
1141		}
1142
1143		/// Get the amount of canceled slash payout.
1144		pub fn canceled_payout() -> BalanceOf<T> {
1145			CanceledSlashPayout::<T>::get()
1146		}
1147
1148		/// Get the slashing spans for given account.
1149		pub fn slashing_spans<EncodeLikeAccountId>(
1150			account_id: EncodeLikeAccountId,
1151		) -> Option<slashing::SlashingSpans>
1152		where
1153			EncodeLikeAccountId: codec::EncodeLike<T::AccountId>,
1154		{
1155			SlashingSpans::<T>::get(account_id)
1156		}
1157
1158		/// Get the last planned session scheduled by the session pezpallet.
1159		pub fn current_planned_session() -> SessionIndex {
1160			CurrentPlannedSession::<T>::get()
1161		}
1162	}
1163
1164	#[pezpallet::call]
1165	impl<T: Config> Pezpallet<T> {
1166		/// Take the origin account as a stash and lock up `value` of its balance. `controller` will
1167		/// be the account that controls it.
1168		///
1169		/// `value` must be more than the `minimum_balance` specified by `T::Currency`.
1170		///
1171		/// The dispatch origin for this call must be _Signed_ by the stash account.
1172		///
1173		/// Emits `Bonded`.
1174		/// ## Complexity
1175		/// - Independent of the arguments. Moderate complexity.
1176		/// - O(1).
1177		/// - Three extra DB entries.
1178		///
1179		/// NOTE: Two of the storage writes (`Self::bonded`, `Self::payee`) are _never_ cleaned
1180		/// unless the `origin` falls below _existential deposit_ (or equal to 0) and gets removed
1181		/// as dust.
1182		#[pezpallet::call_index(0)]
1183		#[pezpallet::weight(T::WeightInfo::bond())]
1184		pub fn bond(
1185			origin: OriginFor<T>,
1186			#[pezpallet::compact] value: BalanceOf<T>,
1187			payee: RewardDestination<T::AccountId>,
1188		) -> DispatchResult {
1189			let stash = ensure_signed(origin)?;
1190
1191			ensure!(!T::Filter::contains(&stash), Error::<T>::Restricted);
1192
1193			if StakingLedger::<T>::is_bonded(StakingAccount::Stash(stash.clone())) {
1194				return Err(Error::<T>::AlreadyBonded.into());
1195			}
1196
1197			// An existing controller cannot become a stash.
1198			if StakingLedger::<T>::is_bonded(StakingAccount::Controller(stash.clone())) {
1199				return Err(Error::<T>::AlreadyPaired.into());
1200			}
1201
1202			// Reject a bond which is considered to be _dust_.
1203			if value < asset::existential_deposit::<T>() {
1204				return Err(Error::<T>::InsufficientBond.into());
1205			}
1206
1207			let stash_balance = asset::free_to_stake::<T>(&stash);
1208			let value = value.min(stash_balance);
1209			Self::deposit_event(Event::<T>::Bonded { stash: stash.clone(), amount: value });
1210			let ledger = StakingLedger::<T>::new(stash.clone(), value);
1211
1212			// You're auto-bonded forever, here. We might improve this by only bonding when
1213			// you actually validate/nominate and remove once you unbond __everything__.
1214			ledger.bond(payee)?;
1215
1216			Ok(())
1217		}
1218
1219		/// Add some extra amount that have appeared in the stash `free_balance` into the balance up
1220		/// for staking.
1221		///
1222		/// The dispatch origin for this call must be _Signed_ by the stash, not the controller.
1223		///
1224		/// Use this if there are additional funds in your stash account that you wish to bond.
1225		/// Unlike [`bond`](Self::bond) or [`unbond`](Self::unbond) this function does not impose
1226		/// any limitation on the amount that can be added.
1227		///
1228		/// Emits `Bonded`.
1229		///
1230		/// ## Complexity
1231		/// - Independent of the arguments. Insignificant complexity.
1232		/// - O(1).
1233		#[pezpallet::call_index(1)]
1234		#[pezpallet::weight(T::WeightInfo::bond_extra())]
1235		pub fn bond_extra(
1236			origin: OriginFor<T>,
1237			#[pezpallet::compact] max_additional: BalanceOf<T>,
1238		) -> DispatchResult {
1239			let stash = ensure_signed(origin)?;
1240			ensure!(!T::Filter::contains(&stash), Error::<T>::Restricted);
1241			Self::do_bond_extra(&stash, max_additional)
1242		}
1243
1244		/// Schedule a portion of the stash to be unlocked ready for transfer out after the bond
1245		/// period ends. If this leaves an amount actively bonded less than
1246		/// [`asset::existential_deposit`], then it is increased to the full amount.
1247		///
1248		/// The stash may be chilled if the ledger total amount falls to 0 after unbonding.
1249		///
1250		/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
1251		///
1252		/// Once the unlock period is done, you can call `withdraw_unbonded` to actually move
1253		/// the funds out of management ready for transfer.
1254		///
1255		/// No more than a limited number of unlocking chunks (see `MaxUnlockingChunks`)
1256		/// can co-exists at the same time. If there are no unlocking chunks slots available
1257		/// [`Call::withdraw_unbonded`] is called to remove some of the chunks (if possible).
1258		///
1259		/// If a user encounters the `InsufficientBond` error when calling this extrinsic,
1260		/// they should call `chill` first in order to free up their bonded funds.
1261		///
1262		/// Emits `Unbonded`.
1263		///
1264		/// See also [`Call::withdraw_unbonded`].
1265		#[pezpallet::call_index(2)]
1266		#[pezpallet::weight(
1267            T::WeightInfo::withdraw_unbonded_kill(SPECULATIVE_NUM_SPANS).saturating_add(T::WeightInfo::unbond()).saturating_add(T::WeightInfo::chill()))
1268        ]
1269		pub fn unbond(
1270			origin: OriginFor<T>,
1271			#[pezpallet::compact] value: BalanceOf<T>,
1272		) -> DispatchResultWithPostInfo {
1273			let controller = ensure_signed(origin)?;
1274
1275			let ledger = Self::ledger(StakingAccount::Controller(controller.clone()))?;
1276
1277			let mut total_weight = if value >= ledger.total {
1278				Self::chill_stash(&ledger.stash);
1279				T::WeightInfo::chill()
1280			} else {
1281				Zero::zero()
1282			};
1283
1284			if let Some(withdraw_weight) = Self::do_unbond(controller, value)? {
1285				total_weight.saturating_accrue(withdraw_weight);
1286			}
1287
1288			Ok(Some(total_weight).into())
1289		}
1290
1291		/// Remove any unlocked chunks from the `unlocking` queue from our management.
1292		///
1293		/// This essentially frees up that balance to be used by the stash account to do whatever
1294		/// it wants.
1295		///
1296		/// The dispatch origin for this call must be _Signed_ by the controller.
1297		///
1298		/// Emits `Withdrawn`.
1299		///
1300		/// See also [`Call::unbond`].
1301		///
1302		/// ## Parameters
1303		///
1304		/// - `num_slashing_spans` indicates the number of metadata slashing spans to clear when
1305		/// this call results in a complete removal of all the data related to the stash account.
1306		/// In this case, the `num_slashing_spans` must be larger or equal to the number of
1307		/// slashing spans associated with the stash account in the [`SlashingSpans`] storage type,
1308		/// otherwise the call will fail. The call weight is directly proportional to
1309		/// `num_slashing_spans`.
1310		///
1311		/// ## Complexity
1312		/// O(S) where S is the number of slashing spans to remove
1313		/// NOTE: Weight annotation is the kill scenario, we refund otherwise.
1314		#[pezpallet::call_index(3)]
1315		#[pezpallet::weight(T::WeightInfo::withdraw_unbonded_kill(*num_slashing_spans))]
1316		pub fn withdraw_unbonded(
1317			origin: OriginFor<T>,
1318			num_slashing_spans: u32,
1319		) -> DispatchResultWithPostInfo {
1320			let controller = ensure_signed(origin)?;
1321
1322			let actual_weight = Self::do_withdraw_unbonded(&controller, num_slashing_spans)?;
1323			Ok(Some(actual_weight).into())
1324		}
1325
1326		/// Declare the desire to validate for the origin controller.
1327		///
1328		/// Effects will be felt at the beginning of the next era.
1329		///
1330		/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
1331		#[pezpallet::call_index(4)]
1332		#[pezpallet::weight(T::WeightInfo::validate())]
1333		pub fn validate(origin: OriginFor<T>, prefs: ValidatorPrefs) -> DispatchResult {
1334			let controller = ensure_signed(origin)?;
1335
1336			let ledger = Self::ledger(Controller(controller))?;
1337
1338			ensure!(ledger.active >= MinValidatorBond::<T>::get(), Error::<T>::InsufficientBond);
1339			let stash = &ledger.stash;
1340
1341			// ensure their commission is correct.
1342			ensure!(prefs.commission >= MinCommission::<T>::get(), Error::<T>::CommissionTooLow);
1343
1344			// Only check limits if they are not already a validator.
1345			if !Validators::<T>::contains_key(stash) {
1346				// If this error is reached, we need to adjust the `MinValidatorBond` and start
1347				// calling `chill_other`. Until then, we explicitly block new validators to protect
1348				// the runtime.
1349				if let Some(max_validators) = MaxValidatorsCount::<T>::get() {
1350					ensure!(
1351						Validators::<T>::count() < max_validators,
1352						Error::<T>::TooManyValidators
1353					);
1354				}
1355			}
1356
1357			Self::do_remove_nominator(stash);
1358			Self::do_add_validator(stash, prefs.clone());
1359			Self::deposit_event(Event::<T>::ValidatorPrefsSet { stash: ledger.stash, prefs });
1360
1361			Ok(())
1362		}
1363
1364		/// Declare the desire to nominate `targets` for the origin controller.
1365		///
1366		/// Effects will be felt at the beginning of the next era.
1367		///
1368		/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
1369		///
1370		/// ## Complexity
1371		/// - The transaction's complexity is proportional to the size of `targets` (N)
1372		/// which is capped at CompactAssignments::LIMIT (T::MaxNominations).
1373		/// - Both the reads and writes follow a similar pattern.
1374		#[pezpallet::call_index(5)]
1375		#[pezpallet::weight(T::WeightInfo::nominate(targets.len() as u32))]
1376		pub fn nominate(
1377			origin: OriginFor<T>,
1378			targets: Vec<AccountIdLookupOf<T>>,
1379		) -> DispatchResult {
1380			let controller = ensure_signed(origin)?;
1381
1382			let ledger = Self::ledger(StakingAccount::Controller(controller.clone()))?;
1383
1384			ensure!(ledger.active >= MinNominatorBond::<T>::get(), Error::<T>::InsufficientBond);
1385			let stash = &ledger.stash;
1386
1387			// Only check limits if they are not already a nominator.
1388			if !Nominators::<T>::contains_key(stash) {
1389				// If this error is reached, we need to adjust the `MinNominatorBond` and start
1390				// calling `chill_other`. Until then, we explicitly block new nominators to protect
1391				// the runtime.
1392				if let Some(max_nominators) = MaxNominatorsCount::<T>::get() {
1393					ensure!(
1394						Nominators::<T>::count() < max_nominators,
1395						Error::<T>::TooManyNominators
1396					);
1397				}
1398			}
1399
1400			ensure!(!targets.is_empty(), Error::<T>::EmptyTargets);
1401			ensure!(
1402				targets.len() <= T::NominationsQuota::get_quota(ledger.active) as usize,
1403				Error::<T>::TooManyTargets
1404			);
1405
1406			let old = Nominators::<T>::get(stash).map_or_else(Vec::new, |x| x.targets.into_inner());
1407
1408			let targets: BoundedVec<_, _> = targets
1409				.into_iter()
1410				.map(|t| T::Lookup::lookup(t).map_err(DispatchError::from))
1411				.map(|n| {
1412					n.and_then(|n| {
1413						if old.contains(&n) || !Validators::<T>::get(&n).blocked {
1414							Ok(n)
1415						} else {
1416							Err(Error::<T>::BadTarget.into())
1417						}
1418					})
1419				})
1420				.collect::<Result<Vec<_>, _>>()?
1421				.try_into()
1422				.map_err(|_| Error::<T>::TooManyNominators)?;
1423
1424			let nominations = Nominations {
1425				targets,
1426				// Initial nominations are considered submitted at era 0. See `Nominations` doc.
1427				submitted_in: CurrentEra::<T>::get().unwrap_or(0),
1428				suppressed: false,
1429			};
1430
1431			Self::do_remove_validator(stash);
1432			Self::do_add_nominator(stash, nominations);
1433			Ok(())
1434		}
1435
1436		/// Declare no desire to either validate or nominate.
1437		///
1438		/// Effects will be felt at the beginning of the next era.
1439		///
1440		/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
1441		///
1442		/// ## Complexity
1443		/// - Independent of the arguments. Insignificant complexity.
1444		/// - Contains one read.
1445		/// - Writes are limited to the `origin` account key.
1446		#[pezpallet::call_index(6)]
1447		#[pezpallet::weight(T::WeightInfo::chill())]
1448		pub fn chill(origin: OriginFor<T>) -> DispatchResult {
1449			let controller = ensure_signed(origin)?;
1450
1451			let ledger = Self::ledger(StakingAccount::Controller(controller))?;
1452
1453			Self::chill_stash(&ledger.stash);
1454			Ok(())
1455		}
1456
1457		/// (Re-)set the payment target for a controller.
1458		///
1459		/// Effects will be felt instantly (as soon as this function is completed successfully).
1460		///
1461		/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
1462		///
1463		/// ## Complexity
1464		/// - O(1)
1465		/// - Independent of the arguments. Insignificant complexity.
1466		/// - Contains a limited number of reads.
1467		/// - Writes are limited to the `origin` account key.
1468		/// ---------
1469		#[pezpallet::call_index(7)]
1470		#[pezpallet::weight(T::WeightInfo::set_payee())]
1471		pub fn set_payee(
1472			origin: OriginFor<T>,
1473			payee: RewardDestination<T::AccountId>,
1474		) -> DispatchResult {
1475			let controller = ensure_signed(origin)?;
1476			let ledger = Self::ledger(Controller(controller.clone()))?;
1477
1478			ensure!(
1479				(payee != {
1480					#[allow(deprecated)]
1481					RewardDestination::Controller
1482				}),
1483				Error::<T>::ControllerDeprecated
1484			);
1485
1486			ledger
1487				.set_payee(payee)
1488				.defensive_proof("ledger was retrieved from storage, thus it's bonded; qed.")?;
1489
1490			Ok(())
1491		}
1492
1493		/// (Re-)sets the controller of a stash to the stash itself. This function previously
1494		/// accepted a `controller` argument to set the controller to an account other than the
1495		/// stash itself. This functionality has now been removed, now only setting the controller
1496		/// to the stash, if it is not already.
1497		///
1498		/// Effects will be felt instantly (as soon as this function is completed successfully).
1499		///
1500		/// The dispatch origin for this call must be _Signed_ by the stash, not the controller.
1501		///
1502		/// ## Complexity
1503		/// O(1)
1504		/// - Independent of the arguments. Insignificant complexity.
1505		/// - Contains a limited number of reads.
1506		/// - Writes are limited to the `origin` account key.
1507		#[pezpallet::call_index(8)]
1508		#[pezpallet::weight(T::WeightInfo::set_controller())]
1509		pub fn set_controller(origin: OriginFor<T>) -> DispatchResult {
1510			let stash = ensure_signed(origin)?;
1511
1512			Self::ledger(StakingAccount::Stash(stash.clone())).map(|ledger| {
1513				let controller = ledger.controller()
1514                    .defensive_proof("Ledger's controller field didn't exist. The controller should have been fetched using StakingLedger.")
1515                    .ok_or(Error::<T>::NotController)?;
1516
1517				if controller == stash {
1518					// Stash is already its own controller.
1519					return Err(Error::<T>::AlreadyPaired.into())
1520				}
1521
1522				ledger.set_controller_to_stash()?;
1523				Ok(())
1524			})?
1525		}
1526
1527		/// Sets the ideal number of validators.
1528		///
1529		/// The dispatch origin must be Root.
1530		///
1531		/// ## Complexity
1532		/// O(1)
1533		#[pezpallet::call_index(9)]
1534		#[pezpallet::weight(T::WeightInfo::set_validator_count())]
1535		pub fn set_validator_count(
1536			origin: OriginFor<T>,
1537			#[pezpallet::compact] new: u32,
1538		) -> DispatchResult {
1539			ensure_root(origin)?;
1540			// ensure new validator count does not exceed maximum winners
1541			// support by election provider.
1542			ensure!(new <= T::MaxValidatorSet::get(), Error::<T>::TooManyValidators);
1543
1544			ValidatorCount::<T>::put(new);
1545			Ok(())
1546		}
1547
1548		/// Increments the ideal number of validators up to maximum of
1549		/// `ElectionProviderBase::MaxWinners`.
1550		///
1551		/// The dispatch origin must be Root.
1552		///
1553		/// ## Complexity
1554		/// Same as [`Self::set_validator_count`].
1555		#[pezpallet::call_index(10)]
1556		#[pezpallet::weight(T::WeightInfo::set_validator_count())]
1557		pub fn increase_validator_count(
1558			origin: OriginFor<T>,
1559			#[pezpallet::compact] additional: u32,
1560		) -> DispatchResult {
1561			ensure_root(origin)?;
1562			let old = ValidatorCount::<T>::get();
1563			let new = old.checked_add(additional).ok_or(ArithmeticError::Overflow)?;
1564			ensure!(new <= T::MaxValidatorSet::get(), Error::<T>::TooManyValidators);
1565
1566			ValidatorCount::<T>::put(new);
1567			Ok(())
1568		}
1569
1570		/// Scale up the ideal number of validators by a factor up to maximum of
1571		/// `ElectionProviderBase::MaxWinners`.
1572		///
1573		/// The dispatch origin must be Root.
1574		///
1575		/// ## Complexity
1576		/// Same as [`Self::set_validator_count`].
1577		#[pezpallet::call_index(11)]
1578		#[pezpallet::weight(T::WeightInfo::set_validator_count())]
1579		pub fn scale_validator_count(origin: OriginFor<T>, factor: Percent) -> DispatchResult {
1580			ensure_root(origin)?;
1581			let old = ValidatorCount::<T>::get();
1582			let new = old.checked_add(factor.mul_floor(old)).ok_or(ArithmeticError::Overflow)?;
1583
1584			ensure!(new <= T::MaxValidatorSet::get(), Error::<T>::TooManyValidators);
1585
1586			ValidatorCount::<T>::put(new);
1587			Ok(())
1588		}
1589
1590		/// Force there to be no new eras indefinitely.
1591		///
1592		/// The dispatch origin must be Root.
1593		///
1594		/// # Warning
1595		///
1596		/// The election process starts multiple blocks before the end of the era.
1597		/// Thus the election process may be ongoing when this is called. In this case the
1598		/// election will continue until the next era is triggered.
1599		///
1600		/// ## Complexity
1601		/// - No arguments.
1602		/// - Weight: O(1)
1603		#[pezpallet::call_index(12)]
1604		#[pezpallet::weight(T::WeightInfo::force_no_eras())]
1605		pub fn force_no_eras(origin: OriginFor<T>) -> DispatchResult {
1606			ensure_root(origin)?;
1607			Self::set_force_era(Forcing::ForceNone);
1608			Ok(())
1609		}
1610
1611		/// Force there to be a new era at the end of the next session. After this, it will be
1612		/// reset to normal (non-forced) behaviour.
1613		///
1614		/// The dispatch origin must be Root.
1615		///
1616		/// # Warning
1617		///
1618		/// The election process starts multiple blocks before the end of the era.
1619		/// If this is called just before a new era is triggered, the election process may not
1620		/// have enough blocks to get a result.
1621		///
1622		/// ## Complexity
1623		/// - No arguments.
1624		/// - Weight: O(1)
1625		#[pezpallet::call_index(13)]
1626		#[pezpallet::weight(T::WeightInfo::force_new_era())]
1627		pub fn force_new_era(origin: OriginFor<T>) -> DispatchResult {
1628			ensure_root(origin)?;
1629			Self::set_force_era(Forcing::ForceNew);
1630			Ok(())
1631		}
1632
1633		/// Set the validators who cannot be slashed (if any).
1634		///
1635		/// The dispatch origin must be Root.
1636		#[pezpallet::call_index(14)]
1637		#[pezpallet::weight(T::WeightInfo::set_invulnerables(invulnerables.len() as u32))]
1638		pub fn set_invulnerables(
1639			origin: OriginFor<T>,
1640			invulnerables: Vec<T::AccountId>,
1641		) -> DispatchResult {
1642			ensure_root(origin)?;
1643			<Invulnerables<T>>::put(invulnerables);
1644			Ok(())
1645		}
1646
1647		/// Force a current staker to become completely unstaked, immediately.
1648		///
1649		/// The dispatch origin must be Root.
1650		///
1651		/// ## Parameters
1652		///
1653		/// - `num_slashing_spans`: Refer to comments on [`Call::withdraw_unbonded`] for more
1654		/// details.
1655		#[pezpallet::call_index(15)]
1656		#[pezpallet::weight(T::WeightInfo::force_unstake(*num_slashing_spans))]
1657		pub fn force_unstake(
1658			origin: OriginFor<T>,
1659			stash: T::AccountId,
1660			num_slashing_spans: u32,
1661		) -> DispatchResult {
1662			ensure_root(origin)?;
1663
1664			// Remove all staking-related information and lock.
1665			Self::kill_stash(&stash, num_slashing_spans)?;
1666
1667			Ok(())
1668		}
1669
1670		/// Force there to be a new era at the end of sessions indefinitely.
1671		///
1672		/// The dispatch origin must be Root.
1673		///
1674		/// # Warning
1675		///
1676		/// The election process starts multiple blocks before the end of the era.
1677		/// If this is called just before a new era is triggered, the election process may not
1678		/// have enough blocks to get a result.
1679		#[pezpallet::call_index(16)]
1680		#[pezpallet::weight(T::WeightInfo::force_new_era_always())]
1681		pub fn force_new_era_always(origin: OriginFor<T>) -> DispatchResult {
1682			ensure_root(origin)?;
1683			Self::set_force_era(Forcing::ForceAlways);
1684			Ok(())
1685		}
1686
1687		/// Cancel enactment of a deferred slash.
1688		///
1689		/// Can be called by the `T::AdminOrigin`.
1690		///
1691		/// Parameters: era and indices of the slashes for that era to kill.
1692		/// They **must** be sorted in ascending order, *and* unique.
1693		#[pezpallet::call_index(17)]
1694		#[pezpallet::weight(T::WeightInfo::cancel_deferred_slash(slash_indices.len() as u32))]
1695		pub fn cancel_deferred_slash(
1696			origin: OriginFor<T>,
1697			era: EraIndex,
1698			slash_indices: Vec<u32>,
1699		) -> DispatchResult {
1700			T::AdminOrigin::ensure_origin(origin)?;
1701
1702			ensure!(!slash_indices.is_empty(), Error::<T>::EmptyTargets);
1703			ensure!(is_sorted_and_unique(&slash_indices), Error::<T>::NotSortedAndUnique);
1704
1705			let mut unapplied = UnappliedSlashes::<T>::get(&era);
1706			let last_item = slash_indices[slash_indices.len() - 1];
1707			ensure!((last_item as usize) < unapplied.len(), Error::<T>::InvalidSlashIndex);
1708
1709			for (removed, index) in slash_indices.into_iter().enumerate() {
1710				let index = (index as usize) - removed;
1711				unapplied.remove(index);
1712			}
1713
1714			UnappliedSlashes::<T>::insert(&era, &unapplied);
1715			Ok(())
1716		}
1717
1718		/// Pay out next page of the stakers behind a validator for the given era.
1719		///
1720		/// - `validator_stash` is the stash account of the validator.
1721		/// - `era` may be any era between `[current_era - history_depth; current_era]`.
1722		///
1723		/// The origin of this call must be _Signed_. Any account can call this function, even if
1724		/// it is not one of the stakers.
1725		///
1726		/// The reward payout could be paged in case there are too many nominators backing the
1727		/// `validator_stash`. This call will payout unpaid pages in an ascending order. To claim a
1728		/// specific page, use `payout_stakers_by_page`.`
1729		///
1730		/// If all pages are claimed, it returns an error `InvalidPage`.
1731		#[pezpallet::call_index(18)]
1732		#[pezpallet::weight(T::WeightInfo::payout_stakers_alive_staked(
1733			T::MaxExposurePageSize::get()
1734		))]
1735		pub fn payout_stakers(
1736			origin: OriginFor<T>,
1737			validator_stash: T::AccountId,
1738			era: EraIndex,
1739		) -> DispatchResultWithPostInfo {
1740			ensure_signed(origin)?;
1741			Self::do_payout_stakers(validator_stash, era)
1742		}
1743
1744		/// Rebond a portion of the stash scheduled to be unlocked.
1745		///
1746		/// The dispatch origin must be signed by the controller.
1747		///
1748		/// ## Complexity
1749		/// - Time complexity: O(L), where L is unlocking chunks
1750		/// - Bounded by `MaxUnlockingChunks`.
1751		#[pezpallet::call_index(19)]
1752		#[pezpallet::weight(T::WeightInfo::rebond(T::MaxUnlockingChunks::get() as u32))]
1753		pub fn rebond(
1754			origin: OriginFor<T>,
1755			#[pezpallet::compact] value: BalanceOf<T>,
1756		) -> DispatchResultWithPostInfo {
1757			let controller = ensure_signed(origin)?;
1758			let ledger = Self::ledger(Controller(controller))?;
1759
1760			ensure!(!T::Filter::contains(&ledger.stash), Error::<T>::Restricted);
1761			ensure!(!ledger.unlocking.is_empty(), Error::<T>::NoUnlockChunk);
1762
1763			let initial_unlocking = ledger.unlocking.len() as u32;
1764			let (ledger, rebonded_value) = ledger.rebond(value);
1765			// Last check: the new active amount of ledger must be more than ED.
1766			ensure!(
1767				ledger.active >= asset::existential_deposit::<T>(),
1768				Error::<T>::InsufficientBond
1769			);
1770
1771			Self::deposit_event(Event::<T>::Bonded {
1772				stash: ledger.stash.clone(),
1773				amount: rebonded_value,
1774			});
1775
1776			let stash = ledger.stash.clone();
1777			let final_unlocking = ledger.unlocking.len();
1778
1779			// NOTE: ledger must be updated prior to calling `Self::weight_of`.
1780			ledger.update()?;
1781			if T::VoterList::contains(&stash) {
1782				let _ = T::VoterList::on_update(&stash, Self::weight_of(&stash)).defensive();
1783			}
1784
1785			let removed_chunks = 1u32 // for the case where the last iterated chunk is not removed
1786				.saturating_add(initial_unlocking)
1787				.saturating_sub(final_unlocking as u32);
1788			Ok(Some(T::WeightInfo::rebond(removed_chunks)).into())
1789		}
1790
1791		/// Remove all data structures concerning a staker/stash once it is at a state where it can
1792		/// be considered `dust` in the staking system. The requirements are:
1793		///
1794		/// 1. the `total_balance` of the stash is below existential deposit.
1795		/// 2. or, the `ledger.total` of the stash is below existential deposit.
1796		/// 3. or, existential deposit is zero and either `total_balance` or `ledger.total` is zero.
1797		///
1798		/// The former can happen in cases like a slash; the latter when a fully unbonded account
1799		/// is still receiving staking rewards in `RewardDestination::Staked`.
1800		///
1801		/// It can be called by anyone, as long as `stash` meets the above requirements.
1802		///
1803		/// Refunds the transaction fees upon successful execution.
1804		///
1805		/// ## Parameters
1806		///
1807		/// - `num_slashing_spans`: Refer to comments on [`Call::withdraw_unbonded`] for more
1808		/// details.
1809		#[pezpallet::call_index(20)]
1810		#[pezpallet::weight(T::WeightInfo::reap_stash(*num_slashing_spans))]
1811		pub fn reap_stash(
1812			origin: OriginFor<T>,
1813			stash: T::AccountId,
1814			num_slashing_spans: u32,
1815		) -> DispatchResultWithPostInfo {
1816			ensure_signed(origin)?;
1817
1818			// virtual stakers should not be allowed to be reaped.
1819			ensure!(!Self::is_virtual_staker(&stash), Error::<T>::VirtualStakerNotAllowed);
1820
1821			let ed = asset::existential_deposit::<T>();
1822			let origin_balance = asset::total_balance::<T>(&stash);
1823			let ledger_total =
1824				Self::ledger(Stash(stash.clone())).map(|l| l.total).unwrap_or_default();
1825			let reapable = origin_balance < ed
1826				|| origin_balance.is_zero()
1827				|| ledger_total < ed
1828				|| ledger_total.is_zero();
1829			ensure!(reapable, Error::<T>::FundedTarget);
1830
1831			// Remove all staking-related information and lock.
1832			Self::kill_stash(&stash, num_slashing_spans)?;
1833
1834			Ok(Pays::No.into())
1835		}
1836
1837		/// Remove the given nominations from the calling validator.
1838		///
1839		/// Effects will be felt at the beginning of the next era.
1840		///
1841		/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
1842		///
1843		/// - `who`: A list of nominator stash accounts who are nominating this validator which
1844		///   should no longer be nominating this validator.
1845		///
1846		/// Note: Making this call only makes sense if you first set the validator preferences to
1847		/// block any further nominations.
1848		#[pezpallet::call_index(21)]
1849		#[pezpallet::weight(T::WeightInfo::kick(who.len() as u32))]
1850		pub fn kick(origin: OriginFor<T>, who: Vec<AccountIdLookupOf<T>>) -> DispatchResult {
1851			let controller = ensure_signed(origin)?;
1852			let ledger = Self::ledger(Controller(controller))?;
1853			let stash = &ledger.stash;
1854
1855			for nom_stash in who
1856				.into_iter()
1857				.map(T::Lookup::lookup)
1858				.collect::<Result<Vec<T::AccountId>, _>>()?
1859				.into_iter()
1860			{
1861				Nominators::<T>::mutate(&nom_stash, |maybe_nom| {
1862					if let Some(ref mut nom) = maybe_nom {
1863						if let Some(pos) = nom.targets.iter().position(|v| v == stash) {
1864							nom.targets.swap_remove(pos);
1865							Self::deposit_event(Event::<T>::Kicked {
1866								nominator: nom_stash.clone(),
1867								stash: stash.clone(),
1868							});
1869						}
1870					}
1871				});
1872			}
1873
1874			Ok(())
1875		}
1876
1877		/// Update the various staking configurations .
1878		///
1879		/// * `min_nominator_bond`: The minimum active bond needed to be a nominator.
1880		/// * `min_validator_bond`: The minimum active bond needed to be a validator.
1881		/// * `max_nominator_count`: The max number of users who can be a nominator at once. When
1882		///   set to `None`, no limit is enforced.
1883		/// * `max_validator_count`: The max number of users who can be a validator at once. When
1884		///   set to `None`, no limit is enforced.
1885		/// * `chill_threshold`: The ratio of `max_nominator_count` or `max_validator_count` which
1886		///   should be filled in order for the `chill_other` transaction to work.
1887		/// * `min_commission`: The minimum amount of commission that each validators must maintain.
1888		///   This is checked only upon calling `validate`. Existing validators are not affected.
1889		///
1890		/// RuntimeOrigin must be Root to call this function.
1891		///
1892		/// NOTE: Existing nominators and validators will not be affected by this update.
1893		/// to kick people under the new limits, `chill_other` should be called.
1894		// We assume the worst case for this call is either: all items are set or all items are
1895		// removed.
1896		#[pezpallet::call_index(22)]
1897		#[pezpallet::weight(
1898			T::WeightInfo::set_staking_configs_all_set()
1899				.max(T::WeightInfo::set_staking_configs_all_remove())
1900		)]
1901		pub fn set_staking_configs(
1902			origin: OriginFor<T>,
1903			min_nominator_bond: ConfigOp<BalanceOf<T>>,
1904			min_validator_bond: ConfigOp<BalanceOf<T>>,
1905			max_nominator_count: ConfigOp<u32>,
1906			max_validator_count: ConfigOp<u32>,
1907			chill_threshold: ConfigOp<Percent>,
1908			min_commission: ConfigOp<Perbill>,
1909			max_staked_rewards: ConfigOp<Percent>,
1910		) -> DispatchResult {
1911			ensure_root(origin)?;
1912
1913			macro_rules! config_op_exp {
1914				($storage:ty, $op:ident) => {
1915					match $op {
1916						ConfigOp::Noop => (),
1917						ConfigOp::Set(v) => <$storage>::put(v),
1918						ConfigOp::Remove => <$storage>::kill(),
1919					}
1920				};
1921			}
1922
1923			config_op_exp!(MinNominatorBond<T>, min_nominator_bond);
1924			config_op_exp!(MinValidatorBond<T>, min_validator_bond);
1925			config_op_exp!(MaxNominatorsCount<T>, max_nominator_count);
1926			config_op_exp!(MaxValidatorsCount<T>, max_validator_count);
1927			config_op_exp!(ChillThreshold<T>, chill_threshold);
1928			config_op_exp!(MinCommission<T>, min_commission);
1929			config_op_exp!(MaxStakedRewards<T>, max_staked_rewards);
1930			Ok(())
1931		}
1932		/// Declare a `controller` to stop participating as either a validator or nominator.
1933		///
1934		/// Effects will be felt at the beginning of the next era.
1935		///
1936		/// The dispatch origin for this call must be _Signed_, but can be called by anyone.
1937		///
1938		/// If the caller is the same as the controller being targeted, then no further checks are
1939		/// enforced, and this function behaves just like `chill`.
1940		///
1941		/// If the caller is different than the controller being targeted, the following conditions
1942		/// must be met:
1943		///
1944		/// * `controller` must belong to a nominator who has become non-decodable,
1945		///
1946		/// Or:
1947		///
1948		/// * A `ChillThreshold` must be set and checked which defines how close to the max
1949		///   nominators or validators we must reach before users can start chilling one-another.
1950		/// * A `MaxNominatorCount` and `MaxValidatorCount` must be set which is used to determine
1951		///   how close we are to the threshold.
1952		/// * A `MinNominatorBond` and `MinValidatorBond` must be set and checked, which determines
1953		///   if this is a person that should be chilled because they have not met the threshold
1954		///   bond required.
1955		///
1956		/// This can be helpful if bond requirements are updated, and we need to remove old users
1957		/// who do not satisfy these requirements.
1958		#[pezpallet::call_index(23)]
1959		#[pezpallet::weight(T::WeightInfo::chill_other())]
1960		pub fn chill_other(origin: OriginFor<T>, stash: T::AccountId) -> DispatchResult {
1961			// Anyone can call this function.
1962			let caller = ensure_signed(origin)?;
1963			let ledger = Self::ledger(Stash(stash.clone()))?;
1964			let controller = ledger
1965				.controller()
1966				.defensive_proof(
1967					"Ledger's controller field didn't exist. The controller should have been fetched using StakingLedger.",
1968				)
1969				.ok_or(Error::<T>::NotController)?;
1970
1971			// In order for one user to chill another user, the following conditions must be met:
1972			//
1973			// * `controller` belongs to a nominator who has become non-decodable,
1974			//
1975			// Or
1976			//
1977			// * A `ChillThreshold` is set which defines how close to the max nominators or
1978			//   validators we must reach before users can start chilling one-another.
1979			// * A `MaxNominatorCount` and `MaxValidatorCount` which is used to determine how close
1980			//   we are to the threshold.
1981			// * A `MinNominatorBond` and `MinValidatorBond` which is the final condition checked to
1982			//   determine this is a person that should be chilled because they have not met the
1983			//   threshold bond required.
1984			//
1985			// Otherwise, if caller is the same as the controller, this is just like `chill`.
1986
1987			if Nominators::<T>::contains_key(&stash) && Nominators::<T>::get(&stash).is_none() {
1988				Self::chill_stash(&stash);
1989				return Ok(());
1990			}
1991
1992			if caller != controller {
1993				let threshold = ChillThreshold::<T>::get().ok_or(Error::<T>::CannotChillOther)?;
1994				let min_active_bond = if Nominators::<T>::contains_key(&stash) {
1995					let max_nominator_count =
1996						MaxNominatorsCount::<T>::get().ok_or(Error::<T>::CannotChillOther)?;
1997					let current_nominator_count = Nominators::<T>::count();
1998					ensure!(
1999						threshold * max_nominator_count < current_nominator_count,
2000						Error::<T>::CannotChillOther
2001					);
2002					MinNominatorBond::<T>::get()
2003				} else if Validators::<T>::contains_key(&stash) {
2004					let max_validator_count =
2005						MaxValidatorsCount::<T>::get().ok_or(Error::<T>::CannotChillOther)?;
2006					let current_validator_count = Validators::<T>::count();
2007					ensure!(
2008						threshold * max_validator_count < current_validator_count,
2009						Error::<T>::CannotChillOther
2010					);
2011					MinValidatorBond::<T>::get()
2012				} else {
2013					Zero::zero()
2014				};
2015
2016				ensure!(ledger.active < min_active_bond, Error::<T>::CannotChillOther);
2017			}
2018
2019			Self::chill_stash(&stash);
2020			Ok(())
2021		}
2022
2023		/// Force a validator to have at least the minimum commission. This will not affect a
2024		/// validator who already has a commission greater than or equal to the minimum. Any account
2025		/// can call this.
2026		#[pezpallet::call_index(24)]
2027		#[pezpallet::weight(T::WeightInfo::force_apply_min_commission())]
2028		pub fn force_apply_min_commission(
2029			origin: OriginFor<T>,
2030			validator_stash: T::AccountId,
2031		) -> DispatchResult {
2032			ensure_signed(origin)?;
2033			let min_commission = MinCommission::<T>::get();
2034			Validators::<T>::try_mutate_exists(validator_stash, |maybe_prefs| {
2035				maybe_prefs
2036					.as_mut()
2037					.map(|prefs| {
2038						(prefs.commission < min_commission)
2039							.then(|| prefs.commission = min_commission)
2040					})
2041					.ok_or(Error::<T>::NotStash)
2042			})?;
2043			Ok(())
2044		}
2045
2046		/// Sets the minimum amount of commission that each validators must maintain.
2047		///
2048		/// This call has lower privilege requirements than `set_staking_config` and can be called
2049		/// by the `T::AdminOrigin`. Root can always call this.
2050		#[pezpallet::call_index(25)]
2051		#[pezpallet::weight(T::WeightInfo::set_min_commission())]
2052		pub fn set_min_commission(origin: OriginFor<T>, new: Perbill) -> DispatchResult {
2053			T::AdminOrigin::ensure_origin(origin)?;
2054			MinCommission::<T>::put(new);
2055			Ok(())
2056		}
2057
2058		/// Pay out a page of the stakers behind a validator for the given era and page.
2059		///
2060		/// - `validator_stash` is the stash account of the validator.
2061		/// - `era` may be any era between `[current_era - history_depth; current_era]`.
2062		/// - `page` is the page index of nominators to pay out with value between 0 and
2063		///   `num_nominators / T::MaxExposurePageSize`.
2064		///
2065		/// The origin of this call must be _Signed_. Any account can call this function, even if
2066		/// it is not one of the stakers.
2067		///
2068		/// If a validator has more than [`Config::MaxExposurePageSize`] nominators backing
2069		/// them, then the list of nominators is paged, with each page being capped at
2070		/// [`Config::MaxExposurePageSize`.] If a validator has more than one page of nominators,
2071		/// the call needs to be made for each page separately in order for all the nominators
2072		/// backing a validator to receive the reward. The nominators are not sorted across pages
2073		/// and so it should not be assumed the highest staker would be on the topmost page and vice
2074		/// versa. If rewards are not claimed in [`Config::HistoryDepth`] eras, they are lost.
2075		#[pezpallet::call_index(26)]
2076		#[pezpallet::weight(T::WeightInfo::payout_stakers_alive_staked(
2077			T::MaxExposurePageSize::get()
2078		))]
2079		pub fn payout_stakers_by_page(
2080			origin: OriginFor<T>,
2081			validator_stash: T::AccountId,
2082			era: EraIndex,
2083			page: Page,
2084		) -> DispatchResultWithPostInfo {
2085			ensure_signed(origin)?;
2086			Self::do_payout_stakers_by_page(validator_stash, era, page)
2087		}
2088
2089		/// Migrates an account's `RewardDestination::Controller` to
2090		/// `RewardDestination::Account(controller)`.
2091		///
2092		/// Effects will be felt instantly (as soon as this function is completed successfully).
2093		///
2094		/// This will waive the transaction fee if the `payee` is successfully migrated.
2095		#[pezpallet::call_index(27)]
2096		#[pezpallet::weight(T::WeightInfo::update_payee())]
2097		pub fn update_payee(
2098			origin: OriginFor<T>,
2099			controller: T::AccountId,
2100		) -> DispatchResultWithPostInfo {
2101			ensure_signed(origin)?;
2102			let ledger = Self::ledger(StakingAccount::Controller(controller.clone()))?;
2103
2104			ensure!(
2105				(Payee::<T>::get(&ledger.stash) == {
2106					#[allow(deprecated)]
2107					Some(RewardDestination::Controller)
2108				}),
2109				Error::<T>::NotController
2110			);
2111
2112			ledger
2113				.set_payee(RewardDestination::Account(controller))
2114				.defensive_proof("ledger should have been previously retrieved from storage.")?;
2115
2116			Ok(Pays::No.into())
2117		}
2118
2119		/// Updates a batch of controller accounts to their corresponding stash account if they are
2120		/// not the same. Ignores any controller accounts that do not exist, and does not operate if
2121		/// the stash and controller are already the same.
2122		///
2123		/// Effects will be felt instantly (as soon as this function is completed successfully).
2124		///
2125		/// The dispatch origin must be `T::AdminOrigin`.
2126		#[pezpallet::call_index(28)]
2127		#[pezpallet::weight(T::WeightInfo::deprecate_controller_batch(controllers.len() as u32))]
2128		pub fn deprecate_controller_batch(
2129			origin: OriginFor<T>,
2130			controllers: BoundedVec<T::AccountId, T::MaxControllersInDeprecationBatch>,
2131		) -> DispatchResultWithPostInfo {
2132			T::AdminOrigin::ensure_origin(origin)?;
2133
2134			// Ignore controllers that do not exist or are already the same as stash.
2135			let filtered_batch_with_ledger: Vec<_> = controllers
2136				.iter()
2137				.filter_map(|controller| {
2138					let ledger = Self::ledger(StakingAccount::Controller(controller.clone()));
2139					ledger.ok().map_or(None, |ledger| {
2140						// If the controller `RewardDestination` is still the deprecated
2141						// `Controller` variant, skip deprecating this account.
2142						let payee_deprecated = Payee::<T>::get(&ledger.stash) == {
2143							#[allow(deprecated)]
2144							Some(RewardDestination::Controller)
2145						};
2146
2147						if ledger.stash != *controller && !payee_deprecated {
2148							Some(ledger)
2149						} else {
2150							None
2151						}
2152					})
2153				})
2154				.collect();
2155
2156			// Update unique pairs.
2157			let mut failures = 0;
2158			for ledger in filtered_batch_with_ledger {
2159				let _ = ledger.clone().set_controller_to_stash().map_err(|_| failures += 1);
2160			}
2161			Self::deposit_event(Event::<T>::ControllerBatchDeprecated { failures });
2162
2163			Ok(Some(T::WeightInfo::deprecate_controller_batch(controllers.len() as u32)).into())
2164		}
2165
2166		/// Restores the state of a ledger which is in an inconsistent state.
2167		///
2168		/// The requirements to restore a ledger are the following:
2169		/// * The stash is bonded; or
2170		/// * The stash is not bonded but it has a staking lock left behind; or
2171		/// * If the stash has an associated ledger and its state is inconsistent; or
2172		/// * If the ledger is not corrupted *but* its staking lock is out of sync.
2173		///
2174		/// The `maybe_*` input parameters will overwrite the corresponding data and metadata of the
2175		/// ledger associated with the stash. If the input parameters are not set, the ledger will
2176		/// be reset values from on-chain state.
2177		#[pezpallet::call_index(29)]
2178		#[pezpallet::weight(T::WeightInfo::restore_ledger())]
2179		pub fn restore_ledger(
2180			origin: OriginFor<T>,
2181			stash: T::AccountId,
2182			maybe_controller: Option<T::AccountId>,
2183			maybe_total: Option<BalanceOf<T>>,
2184			maybe_unlocking: Option<BoundedVec<UnlockChunk<BalanceOf<T>>, T::MaxUnlockingChunks>>,
2185		) -> DispatchResult {
2186			T::AdminOrigin::ensure_origin(origin)?;
2187
2188			// cannot restore ledger for virtual stakers.
2189			ensure!(!Self::is_virtual_staker(&stash), Error::<T>::VirtualStakerNotAllowed);
2190
2191			let current_lock = asset::staked::<T>(&stash);
2192			let stash_balance = asset::stakeable_balance::<T>(&stash);
2193
2194			let (new_controller, new_total) = match Self::inspect_bond_state(&stash) {
2195				Ok(LedgerIntegrityState::Corrupted) => {
2196					let new_controller = maybe_controller.unwrap_or(stash.clone());
2197
2198					let new_total = if let Some(total) = maybe_total {
2199						let new_total = total.min(stash_balance);
2200						// enforce hold == ledger.amount.
2201						asset::update_stake::<T>(&stash, new_total)?;
2202						new_total
2203					} else {
2204						current_lock
2205					};
2206
2207					Ok((new_controller, new_total))
2208				},
2209				Ok(LedgerIntegrityState::CorruptedKilled) => {
2210					if current_lock == Zero::zero() {
2211						// this case needs to restore both lock and ledger, so the new total needs
2212						// to be given by the called since there's no way to restore the total
2213						// on-chain.
2214						ensure!(maybe_total.is_some(), Error::<T>::CannotRestoreLedger);
2215						Ok((
2216							stash.clone(),
2217							maybe_total.expect("total exists as per the check above; qed."),
2218						))
2219					} else {
2220						Ok((stash.clone(), current_lock))
2221					}
2222				},
2223				Ok(LedgerIntegrityState::LockCorrupted) => {
2224					// ledger is not corrupted but its locks are out of sync. In this case, we need
2225					// to enforce a new ledger.total and staking lock for this stash.
2226					let new_total =
2227						maybe_total.ok_or(Error::<T>::CannotRestoreLedger)?.min(stash_balance);
2228					asset::update_stake::<T>(&stash, new_total)?;
2229
2230					Ok((stash.clone(), new_total))
2231				},
2232				Err(Error::<T>::BadState) => {
2233					// the stash and ledger do not exist but lock is lingering.
2234					asset::kill_stake::<T>(&stash)?;
2235					ensure!(
2236						Self::inspect_bond_state(&stash) == Err(Error::<T>::NotStash),
2237						Error::<T>::BadState
2238					);
2239
2240					return Ok(());
2241				},
2242				Ok(LedgerIntegrityState::Ok) | Err(_) => Err(Error::<T>::CannotRestoreLedger),
2243			}?;
2244
2245			// re-bond stash and controller tuple.
2246			Bonded::<T>::insert(&stash, &new_controller);
2247
2248			// resoter ledger state.
2249			let mut ledger = StakingLedger::<T>::new(stash.clone(), new_total);
2250			ledger.controller = Some(new_controller);
2251			ledger.unlocking = maybe_unlocking.unwrap_or_default();
2252			ledger.update()?;
2253
2254			ensure!(
2255				Self::inspect_bond_state(&stash) == Ok(LedgerIntegrityState::Ok),
2256				Error::<T>::BadState
2257			);
2258			Ok(())
2259		}
2260
2261		/// Removes the legacy Staking locks if they exist.
2262		///
2263		/// This removes the legacy lock on the stake with [`Config::OldCurrency`] and creates a
2264		/// hold on it if needed. If all stake cannot be held, the best effort is made to hold as
2265		/// much as possible. The remaining stake is forced withdrawn from the ledger.
2266		///
2267		/// The fee is waived if the migration is successful.
2268		#[pezpallet::call_index(30)]
2269		#[pezpallet::weight(T::WeightInfo::migrate_currency())]
2270		pub fn migrate_currency(
2271			origin: OriginFor<T>,
2272			stash: T::AccountId,
2273		) -> DispatchResultWithPostInfo {
2274			ensure_signed(origin)?;
2275			Self::do_migrate_currency(&stash)?;
2276
2277			// Refund the transaction fee if successful.
2278			Ok(Pays::No.into())
2279		}
2280
2281		/// This function allows governance to manually slash a validator and is a
2282		/// **fallback mechanism**.
2283		///
2284		/// The dispatch origin must be `T::AdminOrigin`.
2285		///
2286		/// ## Parameters
2287		/// - `validator_stash` - The stash account of the validator to slash.
2288		/// - `era` - The era in which the validator was in the active set.
2289		/// - `slash_fraction` - The percentage of the stake to slash, expressed as a Perbill.
2290		///
2291		/// ## Behavior
2292		///
2293		/// The slash will be applied using the standard slashing mechanics, respecting the
2294		/// configured `SlashDeferDuration`.
2295		///
2296		/// This means:
2297		/// - If the validator was already slashed by a higher percentage for the same era, this
2298		///   slash will have no additional effect.
2299		/// - If the validator was previously slashed by a lower percentage, only the difference
2300		///   will be applied.
2301		/// - The slash will be deferred by `SlashDeferDuration` eras before being enacted.
2302		#[pezpallet::call_index(33)]
2303		#[pezpallet::weight(T::WeightInfo::manual_slash())]
2304		pub fn manual_slash(
2305			origin: OriginFor<T>,
2306			validator_stash: T::AccountId,
2307			era: EraIndex,
2308			slash_fraction: Perbill,
2309		) -> DispatchResult {
2310			T::AdminOrigin::ensure_origin(origin)?;
2311
2312			// Check era is valid
2313			let current_era = CurrentEra::<T>::get().ok_or(Error::<T>::InvalidEraToReward)?;
2314			let history_depth = T::HistoryDepth::get();
2315			ensure!(
2316				era <= current_era && era >= current_era.saturating_sub(history_depth),
2317				Error::<T>::InvalidEraToReward
2318			);
2319
2320			let offence_details = pezsp_staking::offence::OffenceDetails {
2321				offender: validator_stash.clone(),
2322				reporters: Vec::new(),
2323			};
2324
2325			// Get the session index for the era
2326			let session_index =
2327				ErasStartSessionIndex::<T>::get(era).ok_or(Error::<T>::InvalidEraToReward)?;
2328
2329			// Create the offence and report it through on_offence system
2330			let _ = Self::on_offence(
2331				core::iter::once(offence_details),
2332				&[slash_fraction],
2333				session_index,
2334			);
2335
2336			Ok(())
2337		}
2338	}
2339}
2340
2341/// Check that list is sorted and has no duplicates.
2342fn is_sorted_and_unique(list: &[u32]) -> bool {
2343	list.windows(2).all(|w| w[0] < w[1])
2344}