pallet_staking_async/pallet/
mod.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
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//! `pallet-staking-async`'s main `pallet` module.
19
20use crate::{
21	asset, slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, EraPayout,
22	EraRewardPoints, ExposurePage, Forcing, LedgerIntegrityState, MaxNominationsOf,
23	NegativeImbalanceOf, Nominations, NominationsQuota, PositiveImbalanceOf, RewardDestination,
24	StakingLedger, UnappliedSlash, UnlockChunk, ValidatorPrefs,
25};
26use alloc::{format, vec::Vec};
27use codec::Codec;
28use frame_election_provider_support::{ElectionProvider, SortedListProvider, VoteWeight};
29use frame_support::{
30	assert_ok,
31	pallet_prelude::*,
32	traits::{
33		fungible::{
34			hold::{Balanced as FunHoldBalanced, Mutate as FunHoldMutate},
35			Mutate, Mutate as FunMutate,
36		},
37		Contains, Defensive, DefensiveSaturating, EnsureOrigin, Get, InspectLockableCurrency,
38		Nothing, OnUnbalanced,
39	},
40	weights::Weight,
41	BoundedBTreeSet, BoundedVec,
42};
43use frame_system::{ensure_root, ensure_signed, pallet_prelude::*};
44pub use impls::*;
45use rand::seq::SliceRandom;
46use rand_chacha::{
47	rand_core::{RngCore, SeedableRng},
48	ChaChaRng,
49};
50use sp_core::{sr25519::Pair as SrPair, Pair};
51use sp_runtime::{
52	traits::{StaticLookup, Zero},
53	ArithmeticError, Perbill, Percent,
54};
55use sp_staking::{
56	EraIndex, Page, SessionIndex,
57	StakingAccount::{self, Controller, Stash},
58	StakingInterface,
59};
60
61mod impls;
62
63#[frame_support::pallet]
64pub mod pallet {
65	use core::ops::Deref;
66
67	use super::*;
68	use crate::{session_rotation, PagedExposureMetadata, SnapshotStatus};
69	use codec::HasCompact;
70	use frame_election_provider_support::{ElectionDataProvider, PageIndex};
71	use frame_support::DefaultNoBound;
72
73	/// Represents the current step in the era pruning process
74	#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
75	pub enum PruningStep {
76		/// Pruning ErasStakersPaged storage
77		ErasStakersPaged,
78		/// Pruning ErasStakersOverview storage
79		ErasStakersOverview,
80		/// Pruning ErasValidatorPrefs storage
81		ErasValidatorPrefs,
82		/// Pruning ClaimedRewards storage
83		ClaimedRewards,
84		/// Pruning ErasValidatorReward storage
85		ErasValidatorReward,
86		/// Pruning ErasRewardPoints storage
87		ErasRewardPoints,
88		/// Pruning ErasTotalStake storage
89		ErasTotalStake,
90	}
91
92	/// The in-code storage version.
93	const STORAGE_VERSION: StorageVersion = StorageVersion::new(17);
94
95	#[pallet::pallet]
96	#[pallet::storage_version(STORAGE_VERSION)]
97	pub struct Pallet<T>(_);
98
99	/// Possible operations on the configuration values of this pallet.
100	#[derive(TypeInfo, Debug, Clone, Encode, Decode, DecodeWithMemTracking, PartialEq)]
101	pub enum ConfigOp<T: Default + Codec> {
102		/// Don't change.
103		Noop,
104		/// Set the given value.
105		Set(T),
106		/// Remove from storage.
107		Remove,
108	}
109
110	#[pallet::config(with_default)]
111	pub trait Config: frame_system::Config {
112		/// The old trait for staking balance. Deprecated and only used for migrating old ledgers.
113		#[pallet::no_default]
114		type OldCurrency: InspectLockableCurrency<
115			Self::AccountId,
116			Moment = BlockNumberFor<Self>,
117			Balance = Self::CurrencyBalance,
118		>;
119
120		/// The staking balance.
121		#[pallet::no_default]
122		type Currency: FunHoldMutate<
123				Self::AccountId,
124				Reason = Self::RuntimeHoldReason,
125				Balance = Self::CurrencyBalance,
126			> + FunMutate<Self::AccountId, Balance = Self::CurrencyBalance>
127			+ FunHoldBalanced<Self::AccountId, Balance = Self::CurrencyBalance>;
128
129		/// Overarching hold reason.
130		#[pallet::no_default_bounds]
131		type RuntimeHoldReason: From<HoldReason>;
132
133		/// Just the `Currency::Balance` type; we have this item to allow us to constrain it to
134		/// `From<u64>`.
135		type CurrencyBalance: sp_runtime::traits::AtLeast32BitUnsigned
136			+ codec::FullCodec
137			+ DecodeWithMemTracking
138			+ HasCompact<Type: DecodeWithMemTracking>
139			+ Copy
140			+ MaybeSerializeDeserialize
141			+ core::fmt::Debug
142			+ Default
143			+ From<u64>
144			+ TypeInfo
145			+ Send
146			+ Sync
147			+ MaxEncodedLen;
148
149		/// Convert a balance into a number used for election calculation. This must fit into a
150		/// `u64` but is allowed to be sensibly lossy. The `u64` is used to communicate with the
151		/// [`frame_election_provider_support`] crate which accepts u64 numbers and does operations
152		/// in 128.
153		/// Consequently, the backward convert is used convert the u128s from sp-elections back to a
154		/// [`BalanceOf`].
155		#[pallet::no_default_bounds]
156		type CurrencyToVote: sp_staking::currency_to_vote::CurrencyToVote<BalanceOf<Self>>;
157
158		/// Something that provides the election functionality.
159		#[pallet::no_default]
160		type ElectionProvider: ElectionProvider<
161			AccountId = Self::AccountId,
162			BlockNumber = BlockNumberFor<Self>,
163			// we only accept an election provider that has staking as data provider.
164			DataProvider = Pallet<Self>,
165		>;
166
167		/// Something that defines the maximum number of nominations per nominator.
168		#[pallet::no_default_bounds]
169		type NominationsQuota: NominationsQuota<BalanceOf<Self>>;
170
171		/// Number of eras to keep in history.
172		///
173		/// Following information is kept for eras in `[current_era -
174		/// HistoryDepth, current_era]`: `ErasValidatorPrefs`, `ErasValidatorReward`,
175		/// `ErasRewardPoints`, `ErasTotalStake`, `ClaimedRewards`,
176		/// `ErasStakersPaged`, `ErasStakersOverview`.
177		///
178		/// Must be more than the number of eras delayed by session.
179		/// I.e. active era must always be in history. I.e. `active_era >
180		/// current_era - history_depth` must be guaranteed.
181		///
182		/// If migrating an existing pallet from storage value to config value,
183		/// this should be set to same value or greater as in storage.
184		#[pallet::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		#[pallet::no_default_bounds]
190		type RewardRemainder: OnUnbalanced<NegativeImbalanceOf<Self>>;
191
192		/// Handler for the unbalanced reduction when slashing a staker.
193		#[pallet::no_default_bounds]
194		type Slash: OnUnbalanced<NegativeImbalanceOf<Self>>;
195
196		/// Handler for the unbalanced increment when rewarding a staker.
197		/// NOTE: in most cases, the implementation of `OnUnbalanced` should modify the total
198		/// issuance.
199		#[pallet::no_default_bounds]
200		type Reward: OnUnbalanced<PositiveImbalanceOf<Self>>;
201
202		/// Number of sessions per era, as per the preferences of the **relay chain**.
203		#[pallet::constant]
204		type SessionsPerEra: Get<SessionIndex>;
205
206		/// Number of sessions before the end of an era when the election for the next era will
207		/// start.
208		///
209		/// - This determines how many sessions **before** the last session of the era the staking
210		///   election process should begin.
211		/// - The value is bounded between **1** (election starts at the beginning of the last
212		///   session) and `SessionsPerEra` (election starts at the beginning of the first session
213		///   of the era).
214		///
215		/// ### Example:
216		/// - If `SessionsPerEra = 6` and `PlanningEraOffset = 1`, the election starts at the
217		///   beginning of session `6 - 1 = 5`.
218		/// - If `PlanningEraOffset = 6`, the election starts at the beginning of session `6 - 6 =
219		///   0`, meaning it starts at the very beginning of the era.
220		#[pallet::constant]
221		type PlanningEraOffset: Get<SessionIndex>;
222
223		/// Number of eras that staked funds must remain bonded for.
224		#[pallet::constant]
225		type BondingDuration: Get<EraIndex>;
226
227		/// Number of eras that slashes are deferred by, after computation.
228		///
229		/// This should be less than the bonding duration. Set to 0 if slashes
230		/// should be applied immediately, without opportunity for intervention.
231		#[pallet::constant]
232		type SlashDeferDuration: Get<EraIndex>;
233
234		/// The origin which can manage less critical staking parameters that does not require root.
235		///
236		/// Supported actions: (1) cancel deferred slash, (2) set minimum commission.
237		#[pallet::no_default]
238		type AdminOrigin: EnsureOrigin<Self::RuntimeOrigin>;
239
240		/// The payout for validators and the system for the current era.
241		/// See [Era payout](./index.html#era-payout).
242		#[pallet::no_default]
243		type EraPayout: EraPayout<BalanceOf<Self>>;
244
245		/// The maximum size of each `T::ExposurePage`.
246		///
247		/// An `ExposurePage` is weakly bounded to a maximum of `MaxExposurePageSize`
248		/// nominators.
249		///
250		/// For older non-paged exposure, a reward payout was restricted to the top
251		/// `MaxExposurePageSize` nominators. This is to limit the i/o cost for the
252		/// nominator payout.
253		///
254		/// Note: `MaxExposurePageSize` is used to bound `ClaimedRewards` and is unsafe to
255		/// reduce without handling it in a migration.
256		#[pallet::constant]
257		type MaxExposurePageSize: Get<u32>;
258
259		/// The absolute maximum of winner validators this pallet should return.
260		///
261		/// As this pallet supports multi-block election, the set of winner validators *per
262		/// election* is bounded by this type.
263		#[pallet::constant]
264		type MaxValidatorSet: Get<u32>;
265
266		/// Something that provides a best-effort sorted list of voters aka electing nominators,
267		/// used for NPoS election.
268		///
269		/// The changes to nominators are reported to this. Moreover, each validator's self-vote is
270		/// also reported as one independent vote.
271		///
272		/// To keep the load off the chain as much as possible, changes made to the staked amount
273		/// via rewards and slashes are not reported and thus need to be manually fixed by the
274		/// staker. In case of `bags-list`, this always means using `rebag` and `putInFrontOf`.
275		///
276		/// Invariant: what comes out of this list will always be a nominator.
277		#[pallet::no_default]
278		type VoterList: SortedListProvider<Self::AccountId, Score = VoteWeight>;
279
280		/// WIP: This is a noop as of now, the actual business logic that's described below is going
281		/// to be introduced in a follow-up PR.
282		///
283		/// Something that provides a best-effort sorted list of targets aka electable validators,
284		/// used for NPoS election.
285		///
286		/// The changes to the approval stake of each validator are reported to this. This means any
287		/// change to:
288		/// 1. The stake of any validator or nominator.
289		/// 2. The targets of any nominator
290		/// 3. The role of any staker (e.g. validator -> chilled, nominator -> validator, etc)
291		///
292		/// Unlike `VoterList`, the values in this list are always kept up to date with reward and
293		/// slash as well, and thus represent the accurate approval stake of all account being
294		/// nominated by nominators.
295		///
296		/// Note that while at the time of nomination, all targets are checked to be real
297		/// validators, they can chill at any point, and their approval stakes will still be
298		/// recorded. This implies that what comes out of iterating this list MIGHT NOT BE AN ACTIVE
299		/// VALIDATOR.
300		#[pallet::no_default]
301		type TargetList: SortedListProvider<Self::AccountId, Score = BalanceOf<Self>>;
302
303		/// The maximum number of `unlocking` chunks a [`StakingLedger`] can
304		/// have. Effectively determines how many unique eras a staker may be
305		/// unbonding in.
306		///
307		/// Note: `MaxUnlockingChunks` is used as the upper bound for the
308		/// `BoundedVec` item `StakingLedger.unlocking`. Setting this value
309		/// lower than the existing value can lead to inconsistencies in the
310		/// `StakingLedger` and will need to be handled properly in a runtime
311		/// migration. The test `reducing_max_unlocking_chunks_abrupt` shows
312		/// this effect.
313		#[pallet::constant]
314		type MaxUnlockingChunks: Get<u32>;
315
316		/// The maximum amount of controller accounts that can be deprecated in one call.
317		type MaxControllersInDeprecationBatch: Get<u32>;
318
319		/// Something that listens to staking updates and performs actions based on the data it
320		/// receives.
321		///
322		/// WARNING: this only reports slashing and withdraw events for the time being.
323		#[pallet::no_default_bounds]
324		type EventListeners: sp_staking::OnStakingUpdate<Self::AccountId, BalanceOf<Self>>;
325
326		/// Maximum number of invulnerable validators.
327		#[pallet::constant]
328		type MaxInvulnerables: Get<u32>;
329
330		/// Maximum allowed era duration in milliseconds.
331		///
332		/// This provides a defensive upper bound to cap the effective era duration, preventing
333		/// excessively long eras from causing runaway inflation (e.g., due to bugs). If the actual
334		/// era duration exceeds this value, it will be clamped to this maximum.
335		///
336		/// Example: For an ideal era duration of 24 hours (86,400,000 ms),
337		/// this can be set to 604,800,000 ms (7 days).
338		#[pallet::constant]
339		type MaxEraDuration: Get<u64>;
340
341		/// Maximum number of storage items that can be pruned in a single call.
342		///
343		/// This controls how many storage items can be deleted in each call to `prune_era_step`.
344		/// This should be set to a conservative value (e.g., 100-500 items) to ensure pruning
345		/// doesn't consume too much block space. The actual weight is determined by benchmarks.
346		#[pallet::constant]
347		type MaxPruningItems: Get<u32>;
348
349		/// Interface to talk to the RC-Client pallet, possibly sending election results to the
350		/// relay chain.
351		#[pallet::no_default]
352		type RcClientInterface: pallet_staking_async_rc_client::RcClientInterface<
353			AccountId = Self::AccountId,
354		>;
355
356		#[pallet::no_default_bounds]
357		/// Filter some accounts from participating in staking.
358		///
359		/// This is useful for example to blacklist an account that is participating in staking in
360		/// another way (such as pools).
361		type Filter: Contains<Self::AccountId>;
362
363		/// Weight information for extrinsics in this pallet.
364		type WeightInfo: WeightInfo;
365	}
366
367	/// A reason for placing a hold on funds.
368	#[pallet::composite_enum]
369	pub enum HoldReason {
370		/// Funds on stake by a nominator or a validator.
371		#[codec(index = 0)]
372		Staking,
373	}
374
375	/// Default implementations of [`DefaultConfig`], which can be used to implement [`Config`].
376	pub mod config_preludes {
377		use super::*;
378		use frame_support::{derive_impl, parameter_types, traits::ConstU32};
379		pub struct TestDefaultConfig;
380
381		#[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
382		impl frame_system::DefaultConfig for TestDefaultConfig {}
383
384		parameter_types! {
385			pub const SessionsPerEra: SessionIndex = 3;
386			pub const BondingDuration: EraIndex = 3;
387			pub const MaxPruningItems: u32 = 100;
388		}
389
390		#[frame_support::register_default_impl(TestDefaultConfig)]
391		impl DefaultConfig for TestDefaultConfig {
392			#[inject_runtime_type]
393			type RuntimeHoldReason = ();
394			type CurrencyBalance = u128;
395			type CurrencyToVote = ();
396			type NominationsQuota = crate::FixedNominationsQuota<16>;
397			type HistoryDepth = ConstU32<84>;
398			type RewardRemainder = ();
399			type Slash = ();
400			type Reward = ();
401			type SessionsPerEra = SessionsPerEra;
402			type BondingDuration = BondingDuration;
403			type PlanningEraOffset = ConstU32<1>;
404			type SlashDeferDuration = ();
405			type MaxExposurePageSize = ConstU32<64>;
406			type MaxUnlockingChunks = ConstU32<32>;
407			type MaxValidatorSet = ConstU32<100>;
408			type MaxControllersInDeprecationBatch = ConstU32<100>;
409			type MaxInvulnerables = ConstU32<20>;
410			type MaxEraDuration = ();
411			type MaxPruningItems = MaxPruningItems;
412			type EventListeners = ();
413			type Filter = Nothing;
414			type WeightInfo = ();
415		}
416	}
417
418	/// The ideal number of active validators.
419	#[pallet::storage]
420	pub type ValidatorCount<T> = StorageValue<_, u32, ValueQuery>;
421
422	/// Any validators that may never be slashed or forcibly kicked. It's a Vec since they're
423	/// easy to initialize and the performance hit is minimal (we expect no more than four
424	/// invulnerables) and restricted to testnets.
425	#[pallet::storage]
426	pub type Invulnerables<T: Config> =
427		StorageValue<_, BoundedVec<T::AccountId, T::MaxInvulnerables>, ValueQuery>;
428
429	/// Map from all locked "stash" accounts to the controller account.
430	///
431	/// TWOX-NOTE: SAFE since `AccountId` is a secure hash.
432	#[pallet::storage]
433	pub type Bonded<T: Config> = StorageMap<_, Twox64Concat, T::AccountId, T::AccountId>;
434
435	/// The minimum active bond to become and maintain the role of a nominator.
436	#[pallet::storage]
437	pub type MinNominatorBond<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;
438
439	/// The minimum active bond to become and maintain the role of a validator.
440	#[pallet::storage]
441	pub type MinValidatorBond<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;
442
443	/// The minimum active nominator stake of the last successful election.
444	#[pallet::storage]
445	pub type MinimumActiveStake<T> = StorageValue<_, BalanceOf<T>, ValueQuery>;
446
447	/// The minimum amount of commission that validators can set.
448	///
449	/// If set to `0`, no limit exists.
450	#[pallet::storage]
451	pub type MinCommission<T: Config> = StorageValue<_, Perbill, ValueQuery>;
452
453	/// Map from all (unlocked) "controller" accounts to the info regarding the staking.
454	///
455	/// Note: All the reads and mutations to this storage *MUST* be done through the methods exposed
456	/// by [`StakingLedger`] to ensure data and lock consistency.
457	#[pallet::storage]
458	pub type Ledger<T: Config> = StorageMap<_, Blake2_128Concat, T::AccountId, StakingLedger<T>>;
459
460	/// Where the reward payment should be made. Keyed by stash.
461	///
462	/// TWOX-NOTE: SAFE since `AccountId` is a secure hash.
463	#[pallet::storage]
464	pub type Payee<T: Config> =
465		StorageMap<_, Twox64Concat, T::AccountId, RewardDestination<T::AccountId>, OptionQuery>;
466
467	/// The map from (wannabe) validator stash key to the preferences of that validator.
468	///
469	/// TWOX-NOTE: SAFE since `AccountId` is a secure hash.
470	#[pallet::storage]
471	pub type Validators<T: Config> =
472		CountedStorageMap<_, Twox64Concat, T::AccountId, ValidatorPrefs, ValueQuery>;
473
474	/// The maximum validator count before we stop allowing new validators to join.
475	///
476	/// When this value is not set, no limits are enforced.
477	#[pallet::storage]
478	pub type MaxValidatorsCount<T> = StorageValue<_, u32, OptionQuery>;
479
480	/// The map from nominator stash key to their nomination preferences, namely the validators that
481	/// they wish to support.
482	///
483	/// Note that the keys of this storage map might become non-decodable in case the
484	/// account's [`NominationsQuota::MaxNominations`] configuration is decreased.
485	/// In this rare case, these nominators
486	/// are still existent in storage, their key is correct and retrievable (i.e. `contains_key`
487	/// indicates that they exist), but their value cannot be decoded. Therefore, the non-decodable
488	/// nominators will effectively not-exist, until they re-submit their preferences such that it
489	/// is within the bounds of the newly set `Config::MaxNominations`.
490	///
491	/// This implies that `::iter_keys().count()` and `::iter().count()` might return different
492	/// values for this map. Moreover, the main `::count()` is aligned with the former, namely the
493	/// number of keys that exist.
494	///
495	/// Lastly, if any of the nominators become non-decodable, they can be chilled immediately via
496	/// [`Call::chill_other`] dispatchable by anyone.
497	///
498	/// TWOX-NOTE: SAFE since `AccountId` is a secure hash.
499	#[pallet::storage]
500	pub type Nominators<T: Config> =
501		CountedStorageMap<_, Twox64Concat, T::AccountId, Nominations<T>>;
502
503	/// Stakers whose funds are managed by other pallets.
504	///
505	/// This pallet does not apply any locks on them, therefore they are only virtually bonded. They
506	/// are expected to be keyless accounts and hence should not be allowed to mutate their ledger
507	/// directly via this pallet. Instead, these accounts are managed by other pallets and accessed
508	/// via low level apis. We keep track of them to do minimal integrity checks.
509	#[pallet::storage]
510	pub type VirtualStakers<T: Config> = CountedStorageMap<_, Twox64Concat, T::AccountId, ()>;
511
512	/// The maximum nominator count before we stop allowing new validators to join.
513	///
514	/// When this value is not set, no limits are enforced.
515	#[pallet::storage]
516	pub type MaxNominatorsCount<T> = StorageValue<_, u32, OptionQuery>;
517
518	// --- AUDIT NOTE: the following storage items should only be controlled by `Rotator`
519
520	/// The current planned era index.
521	///
522	/// This is the latest planned era, depending on how the Session pallet queues the validator
523	/// set, it might be active or not.
524	#[pallet::storage]
525	pub type CurrentEra<T> = StorageValue<_, EraIndex>;
526
527	/// The active era information, it holds index and start.
528	///
529	/// The active era is the era being currently rewarded. Validator set of this era must be
530	/// equal to what is RC's session pallet.
531	#[pallet::storage]
532	pub type ActiveEra<T> = StorageValue<_, ActiveEraInfo>;
533
534	/// Custom bound for [`BondedEras`] which is equal to [`Config::BondingDuration`] + 1.
535	pub struct BondedErasBound<T>(core::marker::PhantomData<T>);
536	impl<T: Config> Get<u32> for BondedErasBound<T> {
537		fn get() -> u32 {
538			T::BondingDuration::get().saturating_add(1)
539		}
540	}
541
542	/// A mapping from still-bonded eras to the first session index of that era.
543	///
544	/// Must contains information for eras for the range:
545	/// `[active_era - bounding_duration; active_era]`
546	#[pallet::storage]
547	pub type BondedEras<T: Config> =
548		StorageValue<_, BoundedVec<(EraIndex, SessionIndex), BondedErasBound<T>>, ValueQuery>;
549
550	// --- AUDIT Note: end of storage items controlled by `Rotator`.
551
552	/// Summary of validator exposure at a given era.
553	///
554	/// This contains the total stake in support of the validator and their own stake. In addition,
555	/// it can also be used to get the number of nominators backing this validator and the number of
556	/// exposure pages they are divided into. The page count is useful to determine the number of
557	/// pages of rewards that needs to be claimed.
558	///
559	/// This is keyed first by the era index to allow bulk deletion and then the stash account.
560	/// Should only be accessed through `Eras`.
561	///
562	/// Is it removed after [`Config::HistoryDepth`] eras.
563	/// If stakers hasn't been set or has been removed then empty overview is returned.
564	#[pallet::storage]
565	pub type ErasStakersOverview<T: Config> = StorageDoubleMap<
566		_,
567		Twox64Concat,
568		EraIndex,
569		Twox64Concat,
570		T::AccountId,
571		PagedExposureMetadata<BalanceOf<T>>,
572		OptionQuery,
573	>;
574
575	/// A bounded wrapper for [`sp_staking::ExposurePage`].
576	///
577	/// It has `Deref` and `DerefMut` impls that map it back [`sp_staking::ExposurePage`] for all
578	/// purposes. This is done in such a way because we prefer to keep the types in [`sp_staking`]
579	/// pure, and not polluted by pallet-specific bounding logic.
580	///
581	/// It encoded and decodes exactly the same as [`sp_staking::ExposurePage`], and provides a
582	/// manual `MaxEncodedLen` implementation, to be used in benchmarking
583	#[derive(PartialEqNoBound, Encode, Decode, DebugNoBound, TypeInfo, DefaultNoBound)]
584	#[scale_info(skip_type_params(T))]
585	pub struct BoundedExposurePage<T: Config>(pub ExposurePage<T::AccountId, BalanceOf<T>>);
586	impl<T: Config> Deref for BoundedExposurePage<T> {
587		type Target = ExposurePage<T::AccountId, BalanceOf<T>>;
588
589		fn deref(&self) -> &Self::Target {
590			&self.0
591		}
592	}
593
594	impl<T: Config> core::ops::DerefMut for BoundedExposurePage<T> {
595		fn deref_mut(&mut self) -> &mut Self::Target {
596			&mut self.0
597		}
598	}
599
600	impl<T: Config> codec::MaxEncodedLen for BoundedExposurePage<T> {
601		fn max_encoded_len() -> usize {
602			let max_exposure_page_size = T::MaxExposurePageSize::get() as usize;
603			let individual_size =
604				T::AccountId::max_encoded_len() + BalanceOf::<T>::max_encoded_len();
605
606			// 1 balance for `total`
607			BalanceOf::<T>::max_encoded_len() +
608			// individual_size multiplied by page size
609				max_exposure_page_size.saturating_mul(individual_size)
610		}
611	}
612
613	impl<T: Config> From<ExposurePage<T::AccountId, BalanceOf<T>>> for BoundedExposurePage<T> {
614		fn from(value: ExposurePage<T::AccountId, BalanceOf<T>>) -> Self {
615			Self(value)
616		}
617	}
618
619	impl<T: Config> From<BoundedExposurePage<T>> for ExposurePage<T::AccountId, BalanceOf<T>> {
620		fn from(value: BoundedExposurePage<T>) -> Self {
621			value.0
622		}
623	}
624
625	impl<T: Config> codec::EncodeLike<BoundedExposurePage<T>>
626		for ExposurePage<T::AccountId, BalanceOf<T>>
627	{
628	}
629
630	/// Paginated exposure of a validator at given era.
631	///
632	/// This is keyed first by the era index to allow bulk deletion, then stash account and finally
633	/// the page. Should only be accessed through `Eras`.
634	///
635	/// This is cleared after [`Config::HistoryDepth`] eras.
636	#[pallet::storage]
637	pub type ErasStakersPaged<T: Config> = StorageNMap<
638		_,
639		(
640			NMapKey<Twox64Concat, EraIndex>,
641			NMapKey<Twox64Concat, T::AccountId>,
642			NMapKey<Twox64Concat, Page>,
643		),
644		BoundedExposurePage<T>,
645		OptionQuery,
646	>;
647
648	pub struct ClaimedRewardsBound<T>(core::marker::PhantomData<T>);
649	impl<T: Config> Get<u32> for ClaimedRewardsBound<T> {
650		fn get() -> u32 {
651			let max_total_nominators_per_validator =
652				<T::ElectionProvider as ElectionProvider>::MaxBackersPerWinnerFinal::get();
653			let exposure_page_size = T::MaxExposurePageSize::get();
654			max_total_nominators_per_validator
655				.saturating_div(exposure_page_size)
656				.saturating_add(1)
657		}
658	}
659
660	/// History of claimed paged rewards by era and validator.
661	///
662	/// This is keyed by era and validator stash which maps to the set of page indexes which have
663	/// been claimed.
664	///
665	/// It is removed after [`Config::HistoryDepth`] eras.
666	#[pallet::storage]
667	pub type ClaimedRewards<T: Config> = StorageDoubleMap<
668		_,
669		Twox64Concat,
670		EraIndex,
671		Twox64Concat,
672		T::AccountId,
673		WeakBoundedVec<Page, ClaimedRewardsBound<T>>,
674		ValueQuery,
675	>;
676
677	/// Exposure of validator at era with the preferences of validators.
678	///
679	/// This is keyed first by the era index to allow bulk deletion and then the stash account.
680	///
681	/// Is it removed after [`Config::HistoryDepth`] eras.
682	// If prefs hasn't been set or has been removed then 0 commission is returned.
683	#[pallet::storage]
684	pub type ErasValidatorPrefs<T: Config> = StorageDoubleMap<
685		_,
686		Twox64Concat,
687		EraIndex,
688		Twox64Concat,
689		T::AccountId,
690		ValidatorPrefs,
691		ValueQuery,
692	>;
693
694	/// The total validator era payout for the last [`Config::HistoryDepth`] eras.
695	///
696	/// Eras that haven't finished yet or has been removed doesn't have reward.
697	#[pallet::storage]
698	pub type ErasValidatorReward<T: Config> = StorageMap<_, Twox64Concat, EraIndex, BalanceOf<T>>;
699
700	/// Rewards for the last [`Config::HistoryDepth`] eras.
701	/// If reward hasn't been set or has been removed then 0 reward is returned.
702	#[pallet::storage]
703	pub type ErasRewardPoints<T: Config> =
704		StorageMap<_, Twox64Concat, EraIndex, EraRewardPoints<T>, ValueQuery>;
705
706	/// The total amount staked for the last [`Config::HistoryDepth`] eras.
707	/// If total hasn't been set or has been removed then 0 stake is returned.
708	#[pallet::storage]
709	pub type ErasTotalStake<T: Config> =
710		StorageMap<_, Twox64Concat, EraIndex, BalanceOf<T>, ValueQuery>;
711
712	/// Mode of era forcing.
713	#[pallet::storage]
714	pub type ForceEra<T> = StorageValue<_, Forcing, ValueQuery>;
715
716	/// Maximum staked rewards, i.e. the percentage of the era inflation that
717	/// is used for stake rewards.
718	/// See [Era payout](./index.html#era-payout).
719	#[pallet::storage]
720	pub type MaxStakedRewards<T> = StorageValue<_, Percent, OptionQuery>;
721
722	/// The percentage of the slash that is distributed to reporters.
723	///
724	/// The rest of the slashed value is handled by the `Slash`.
725	#[pallet::storage]
726	pub type SlashRewardFraction<T> = StorageValue<_, Perbill, ValueQuery>;
727
728	/// The amount of currency given to reporters of a slash event which was
729	/// canceled by extraordinary circumstances (e.g. governance).
730	#[pallet::storage]
731	pub type CanceledSlashPayout<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;
732
733	/// Stores reported offences in a queue until they are processed in subsequent blocks.
734	///
735	/// Each offence is recorded under the corresponding era index and the offending validator's
736	/// account. If an offence spans multiple pages, only one page is processed at a time. Offences
737	/// are handled sequentially, with their associated slashes computed and stored in
738	/// `UnappliedSlashes`. These slashes are then applied in a future era as determined by
739	/// `SlashDeferDuration`.
740	///
741	/// Any offences tied to an era older than `BondingDuration` are automatically dropped.
742	/// Processing always prioritizes the oldest era first.
743	#[pallet::storage]
744	pub type OffenceQueue<T: Config> = StorageDoubleMap<
745		_,
746		Twox64Concat,
747		EraIndex,
748		Twox64Concat,
749		T::AccountId,
750		slashing::OffenceRecord<T::AccountId>,
751	>;
752
753	/// Tracks the eras that contain offences in `OffenceQueue`, sorted from **earliest to latest**.
754	///
755	/// - This ensures efficient retrieval of the oldest offence without iterating through
756	/// `OffenceQueue`.
757	/// - When a new offence is added to `OffenceQueue`, its era is **inserted in sorted order**
758	/// if not already present.
759	/// - When all offences for an era are processed, it is **removed** from this list.
760	/// - The maximum length of this vector is bounded by `BondingDuration`.
761	///
762	/// This eliminates the need for expensive iteration and sorting when fetching the next offence
763	/// to process.
764	#[pallet::storage]
765	pub type OffenceQueueEras<T: Config> = StorageValue<_, WeakBoundedVec<u32, T::BondingDuration>>;
766
767	/// Tracks the currently processed offence record from the `OffenceQueue`.
768	///
769	/// - When processing offences, an offence record is **popped** from the oldest era in
770	///   `OffenceQueue` and stored here.
771	/// - The function `process_offence` reads from this storage, processing one page of exposure at
772	///   a time.
773	/// - After processing a page, the `exposure_page` count is **decremented** until it reaches
774	///   zero.
775	/// - Once fully processed, the offence record is removed from this storage.
776	///
777	/// This ensures that offences are processed incrementally, preventing excessive computation
778	/// in a single block while maintaining correct slashing behavior.
779	#[pallet::storage]
780	pub type ProcessingOffence<T: Config> =
781		StorageValue<_, (EraIndex, T::AccountId, slashing::OffenceRecord<T::AccountId>)>;
782
783	/// All unapplied slashes that are queued for later.
784	#[pallet::storage]
785	pub type UnappliedSlashes<T: Config> = StorageDoubleMap<
786		_,
787		Twox64Concat,
788		EraIndex,
789		Twox64Concat,
790		// Unique key for unapplied slashes: (validator, slash fraction, page index).
791		(T::AccountId, Perbill, u32),
792		UnappliedSlash<T>,
793		OptionQuery,
794	>;
795
796	/// Cancelled slashes by era and validator with maximum slash fraction to be cancelled.
797	///
798	/// When slashes are cancelled by governance, this stores the era and the validators
799	/// whose slashes should be cancelled, along with the maximum slash fraction that should
800	/// be cancelled for each validator.
801	#[pallet::storage]
802	pub type CancelledSlashes<T: Config> = StorageMap<
803		_,
804		Twox64Concat,
805		EraIndex,
806		BoundedVec<(T::AccountId, Perbill), T::MaxValidatorSet>,
807		ValueQuery,
808	>;
809
810	/// All slashing events on validators, mapped by era to the highest slash proportion
811	/// and slash value of the era.
812	#[pallet::storage]
813	pub type ValidatorSlashInEra<T: Config> = StorageDoubleMap<
814		_,
815		Twox64Concat,
816		EraIndex,
817		Twox64Concat,
818		T::AccountId,
819		(Perbill, BalanceOf<T>),
820	>;
821
822	/// The threshold for when users can start calling `chill_other` for other validators /
823	/// nominators. The threshold is compared to the actual number of validators / nominators
824	/// (`CountFor*`) in the system compared to the configured max (`Max*Count`).
825	#[pallet::storage]
826	pub type ChillThreshold<T: Config> = StorageValue<_, Percent, OptionQuery>;
827
828	/// Voter snapshot progress status.
829	///
830	/// If the status is `Ongoing`, it keeps a cursor of the last voter retrieved to proceed when
831	/// creating the next snapshot page.
832	#[pallet::storage]
833	pub type VoterSnapshotStatus<T: Config> =
834		StorageValue<_, SnapshotStatus<T::AccountId>, ValueQuery>;
835
836	/// Keeps track of an ongoing multi-page election solution request.
837	///
838	/// If `Some(_)``, it is the next page that we intend to elect. If `None`, we are not in the
839	/// election process.
840	///
841	/// This is only set in multi-block elections. Should always be `None` otherwise.
842	#[pallet::storage]
843	pub type NextElectionPage<T: Config> = StorageValue<_, PageIndex, OptionQuery>;
844
845	/// A bounded list of the "electable" stashes that resulted from a successful election.
846	#[pallet::storage]
847	pub type ElectableStashes<T: Config> =
848		StorageValue<_, BoundedBTreeSet<T::AccountId, T::MaxValidatorSet>, ValueQuery>;
849
850	/// Tracks the current step of era pruning process for each era being lazily pruned.
851	#[pallet::storage]
852	pub type EraPruningState<T: Config> = StorageMap<_, Twox64Concat, EraIndex, PruningStep>;
853
854	#[pallet::genesis_config]
855	#[derive(frame_support::DefaultNoBound, frame_support::DebugNoBound)]
856	pub struct GenesisConfig<T: Config> {
857		pub validator_count: u32,
858		pub invulnerables: BoundedVec<T::AccountId, T::MaxInvulnerables>,
859		pub force_era: Forcing,
860		pub slash_reward_fraction: Perbill,
861		pub canceled_payout: BalanceOf<T>,
862		pub stakers: Vec<(T::AccountId, BalanceOf<T>, crate::StakerStatus<T::AccountId>)>,
863		pub min_nominator_bond: BalanceOf<T>,
864		pub min_validator_bond: BalanceOf<T>,
865		pub max_validator_count: Option<u32>,
866		pub max_nominator_count: Option<u32>,
867		/// Create the given number of validators and nominators.
868		///
869		/// These account need not be in the endowment list of balances, and are auto-topped up
870		/// here.
871		///
872		/// Useful for testing genesis config.
873		pub dev_stakers: Option<(u32, u32)>,
874		/// initial active era, corresponding session index and start timestamp.
875		pub active_era: (u32, u32, u64),
876	}
877
878	impl<T: Config> GenesisConfig<T> {
879		fn generate_endowed_bonded_account(derivation: &str, rng: &mut ChaChaRng) -> T::AccountId {
880			let pair: SrPair = Pair::from_string(&derivation, None)
881				.expect(&format!("Failed to parse derivation string: {derivation}"));
882			let who = T::AccountId::decode(&mut &pair.public().encode()[..])
883				.expect(&format!("Failed to decode public key from pair: {:?}", pair.public()));
884
885			let (min, max) = T::VoterList::range();
886			let stake = BalanceOf::<T>::from(rng.next_u64().min(max).max(min));
887			let two: BalanceOf<T> = 2u32.into();
888
889			assert_ok!(T::Currency::mint_into(&who, stake * two));
890			assert_ok!(<Pallet<T>>::bond(
891				T::RuntimeOrigin::from(Some(who.clone()).into()),
892				stake,
893				RewardDestination::Staked,
894			));
895			who
896		}
897	}
898
899	#[pallet::genesis_build]
900	impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
901		fn build(&self) {
902			crate::log!(trace, "initializing with {:?}", self);
903			assert!(
904				self.validator_count <=
905					<T::ElectionProvider as ElectionProvider>::MaxWinnersPerPage::get() *
906						<T::ElectionProvider as ElectionProvider>::Pages::get(),
907				"validator count is too high, `ElectionProvider` can never fulfill this"
908			);
909			ValidatorCount::<T>::put(self.validator_count);
910
911			assert!(
912				self.invulnerables.len() as u32 <= T::MaxInvulnerables::get(),
913				"Too many invulnerable validators at genesis."
914			);
915			<Invulnerables<T>>::put(&self.invulnerables);
916
917			ForceEra::<T>::put(self.force_era);
918			CanceledSlashPayout::<T>::put(self.canceled_payout);
919			SlashRewardFraction::<T>::put(self.slash_reward_fraction);
920			MinNominatorBond::<T>::put(self.min_nominator_bond);
921			MinValidatorBond::<T>::put(self.min_validator_bond);
922			if let Some(x) = self.max_validator_count {
923				MaxValidatorsCount::<T>::put(x);
924			}
925			if let Some(x) = self.max_nominator_count {
926				MaxNominatorsCount::<T>::put(x);
927			}
928
929			// First pass: set up all validators and idle stakers
930			for &(ref stash, balance, ref status) in &self.stakers {
931				match status {
932					crate::StakerStatus::Validator => {
933						crate::log!(
934							trace,
935							"inserting genesis validator: {:?} => {:?} => {:?}",
936							stash,
937							balance,
938							status
939						);
940						assert!(
941							asset::free_to_stake::<T>(stash) >= balance,
942							"Stash does not have enough balance to bond."
943						);
944						assert_ok!(<Pallet<T>>::bond(
945							T::RuntimeOrigin::from(Some(stash.clone()).into()),
946							balance,
947							RewardDestination::Staked,
948						));
949						assert_ok!(<Pallet<T>>::validate(
950							T::RuntimeOrigin::from(Some(stash.clone()).into()),
951							Default::default(),
952						));
953					},
954					crate::StakerStatus::Idle => {
955						crate::log!(
956							trace,
957							"inserting genesis idle staker: {:?} => {:?} => {:?}",
958							stash,
959							balance,
960							status
961						);
962						assert!(
963							asset::free_to_stake::<T>(stash) >= balance,
964							"Stash does not have enough balance to bond."
965						);
966						assert_ok!(<Pallet<T>>::bond(
967							T::RuntimeOrigin::from(Some(stash.clone()).into()),
968							balance,
969							RewardDestination::Staked,
970						));
971					},
972					_ => {},
973				}
974			}
975
976			// Second pass: set up all nominators (now that validators exist)
977			for &(ref stash, balance, ref status) in &self.stakers {
978				match status {
979					crate::StakerStatus::Nominator(votes) => {
980						crate::log!(
981							trace,
982							"inserting genesis nominator: {:?} => {:?} => {:?}",
983							stash,
984							balance,
985							status
986						);
987						assert!(
988							asset::free_to_stake::<T>(stash) >= balance,
989							"Stash does not have enough balance to bond."
990						);
991						assert_ok!(<Pallet<T>>::bond(
992							T::RuntimeOrigin::from(Some(stash.clone()).into()),
993							balance,
994							RewardDestination::Staked,
995						));
996						assert_ok!(<Pallet<T>>::nominate(
997							T::RuntimeOrigin::from(Some(stash.clone()).into()),
998							votes.iter().map(|l| T::Lookup::unlookup(l.clone())).collect(),
999						));
1000					},
1001					_ => {},
1002				}
1003			}
1004
1005			// all voters are reported to the `VoterList`.
1006			assert_eq!(
1007				T::VoterList::count(),
1008				Nominators::<T>::count() + Validators::<T>::count(),
1009				"not all genesis stakers were inserted into sorted list provider, something is wrong."
1010			);
1011
1012			// now generate the dev stakers, after all else is setup
1013			if let Some((validators, nominators)) = self.dev_stakers {
1014				crate::log!(
1015					debug,
1016					"generating dev stakers: validators: {}, nominators: {}",
1017					validators,
1018					nominators
1019				);
1020				let base_derivation = "//staker//{}";
1021
1022				// it is okay for the randomness to be the same on every call. If we want different,
1023				// we can make `base_derivation` configurable.
1024				let mut rng =
1025					ChaChaRng::from_seed(base_derivation.using_encoded(sp_core::blake2_256));
1026
1027				(0..validators).for_each(|index| {
1028					let derivation = base_derivation.replace("{}", &format!("validator{}", index));
1029					let who = Self::generate_endowed_bonded_account(&derivation, &mut rng);
1030					assert_ok!(<Pallet<T>>::validate(
1031						T::RuntimeOrigin::from(Some(who.clone()).into()),
1032						Default::default(),
1033					));
1034				});
1035
1036				let all_validators = Validators::<T>::iter_keys().collect::<Vec<_>>();
1037
1038				(0..nominators).for_each(|index| {
1039					let derivation = base_derivation.replace("{}", &format!("nominator{}", index));
1040					let who = Self::generate_endowed_bonded_account(&derivation, &mut rng);
1041
1042					let random_nominations = all_validators
1043						.choose_multiple(&mut rng, MaxNominationsOf::<T>::get() as usize)
1044						.map(|v| v.clone())
1045						.collect::<Vec<_>>();
1046
1047					assert_ok!(<Pallet<T>>::nominate(
1048						T::RuntimeOrigin::from(Some(who.clone()).into()),
1049						random_nominations.iter().map(|l| T::Lookup::unlookup(l.clone())).collect(),
1050					));
1051				})
1052			}
1053
1054			let (active_era, session_index, timestamp) = self.active_era;
1055			ActiveEra::<T>::put(ActiveEraInfo { index: active_era, start: Some(timestamp) });
1056			// at genesis, we do not have any new planned era.
1057			CurrentEra::<T>::put(active_era);
1058			// set the bonded genesis era
1059			BondedEras::<T>::put(
1060				BoundedVec::<_, BondedErasBound<T>>::try_from(
1061					alloc::vec![(active_era, session_index)]
1062				)
1063				.expect("bound for BondedEras is BondingDuration + 1; can contain at least one element; qed")
1064			);
1065		}
1066	}
1067
1068	#[pallet::event]
1069	#[pallet::generate_deposit(pub fn deposit_event)]
1070	pub enum Event<T: Config> {
1071		/// The era payout has been set; the first balance is the validator-payout; the second is
1072		/// the remainder from the maximum amount of reward.
1073		EraPaid {
1074			era_index: EraIndex,
1075			validator_payout: BalanceOf<T>,
1076			remainder: BalanceOf<T>,
1077		},
1078		/// The nominator has been rewarded by this amount to this destination.
1079		Rewarded {
1080			stash: T::AccountId,
1081			dest: RewardDestination<T::AccountId>,
1082			amount: BalanceOf<T>,
1083		},
1084		/// A staker (validator or nominator) has been slashed by the given amount.
1085		Slashed {
1086			staker: T::AccountId,
1087			amount: BalanceOf<T>,
1088		},
1089		/// An old slashing report from a prior era was discarded because it could
1090		/// not be processed.
1091		OldSlashingReportDiscarded {
1092			session_index: SessionIndex,
1093		},
1094		/// An account has bonded this amount. \[stash, amount\]
1095		///
1096		/// NOTE: This event is only emitted when funds are bonded via a dispatchable. Notably,
1097		/// it will not be emitted for staking rewards when they are added to stake.
1098		Bonded {
1099			stash: T::AccountId,
1100			amount: BalanceOf<T>,
1101		},
1102		/// An account has unbonded this amount.
1103		Unbonded {
1104			stash: T::AccountId,
1105			amount: BalanceOf<T>,
1106		},
1107		/// An account has called `withdraw_unbonded` and removed unbonding chunks worth `Balance`
1108		/// from the unlocking queue.
1109		Withdrawn {
1110			stash: T::AccountId,
1111			amount: BalanceOf<T>,
1112		},
1113		/// A subsequent event of `Withdrawn`, indicating that `stash` was fully removed from the
1114		/// system.
1115		StakerRemoved {
1116			stash: T::AccountId,
1117		},
1118		/// A nominator has been kicked from a validator.
1119		Kicked {
1120			nominator: T::AccountId,
1121			stash: T::AccountId,
1122		},
1123		/// An account has stopped participating as either a validator or nominator.
1124		Chilled {
1125			stash: T::AccountId,
1126		},
1127		/// A Page of stakers rewards are getting paid. `next` is `None` if all pages are claimed.
1128		PayoutStarted {
1129			era_index: EraIndex,
1130			validator_stash: T::AccountId,
1131			page: Page,
1132			next: Option<Page>,
1133		},
1134		/// A validator has set their preferences.
1135		ValidatorPrefsSet {
1136			stash: T::AccountId,
1137			prefs: ValidatorPrefs,
1138		},
1139		/// Voters size limit reached.
1140		SnapshotVotersSizeExceeded {
1141			size: u32,
1142		},
1143		/// Targets size limit reached.
1144		SnapshotTargetsSizeExceeded {
1145			size: u32,
1146		},
1147		ForceEra {
1148			mode: Forcing,
1149		},
1150		/// Report of a controller batch deprecation.
1151		ControllerBatchDeprecated {
1152			failures: u32,
1153		},
1154		/// Staking balance migrated from locks to holds, with any balance that could not be held
1155		/// is force withdrawn.
1156		CurrencyMigrated {
1157			stash: T::AccountId,
1158			force_withdraw: BalanceOf<T>,
1159		},
1160		/// A page from a multi-page election was fetched. A number of these are followed by
1161		/// `StakersElected`.
1162		///
1163		/// `Ok(count)` indicates the give number of stashes were added.
1164		/// `Err(index)` indicates that the stashes after index were dropped.
1165		/// `Err(0)` indicates that an error happened but no stashes were dropped nor added.
1166		///
1167		/// The error indicates that a number of validators were dropped due to excess size, but
1168		/// the overall election will continue.
1169		PagedElectionProceeded {
1170			page: PageIndex,
1171			result: Result<u32, u32>,
1172		},
1173		/// An offence for the given validator, for the given percentage of their stake, at the
1174		/// given era as been reported.
1175		OffenceReported {
1176			offence_era: EraIndex,
1177			validator: T::AccountId,
1178			fraction: Perbill,
1179		},
1180		/// An offence has been processed and the corresponding slash has been computed.
1181		SlashComputed {
1182			offence_era: EraIndex,
1183			slash_era: EraIndex,
1184			offender: T::AccountId,
1185			page: u32,
1186		},
1187		/// An unapplied slash has been cancelled.
1188		SlashCancelled {
1189			slash_era: EraIndex,
1190			validator: T::AccountId,
1191		},
1192		/// Session change has been triggered.
1193		///
1194		/// If planned_era is one era ahead of active_era, it implies new era is being planned and
1195		/// election is ongoing.
1196		SessionRotated {
1197			starting_session: SessionIndex,
1198			active_era: EraIndex,
1199			planned_era: EraIndex,
1200		},
1201		/// Something occurred that should never happen under normal operation.
1202		/// Logged as an event for fail-safe observability.
1203		Unexpected(UnexpectedKind),
1204		/// An offence was reported that was too old to be processed, and thus was dropped.
1205		OffenceTooOld {
1206			offence_era: EraIndex,
1207			validator: T::AccountId,
1208			fraction: Perbill,
1209		},
1210		/// An old era with the given index was pruned.
1211		EraPruned {
1212			index: EraIndex,
1213		},
1214	}
1215
1216	/// Represents unexpected or invariant-breaking conditions encountered during execution.
1217	///
1218	/// These variants are emitted as [`Event::Unexpected`] and indicate a defensive check has
1219	/// failed. While these should never occur under normal operation, they are useful for
1220	/// diagnosing issues in production or test environments.
1221	#[derive(Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, TypeInfo, RuntimeDebug)]
1222	pub enum UnexpectedKind {
1223		/// Emitted when calculated era duration exceeds the configured maximum.
1224		EraDurationBoundExceeded,
1225		/// Received a validator activation event that is not recognized.
1226		UnknownValidatorActivation,
1227	}
1228
1229	#[pallet::error]
1230	#[derive(PartialEq)]
1231	pub enum Error<T> {
1232		/// Not a controller account.
1233		NotController,
1234		/// Not a stash account.
1235		NotStash,
1236		/// Stash is already bonded.
1237		AlreadyBonded,
1238		/// Controller is already paired.
1239		AlreadyPaired,
1240		/// Targets cannot be empty.
1241		EmptyTargets,
1242		/// Duplicate index.
1243		DuplicateIndex,
1244		/// Slash record not found.
1245		InvalidSlashRecord,
1246		/// Cannot bond, nominate or validate with value less than the minimum defined by
1247		/// governance (see `MinValidatorBond` and `MinNominatorBond`). If unbonding is the
1248		/// intention, `chill` first to remove one's role as validator/nominator.
1249		InsufficientBond,
1250		/// Can not schedule more unlock chunks.
1251		NoMoreChunks,
1252		/// Can not rebond without unlocking chunks.
1253		NoUnlockChunk,
1254		/// Attempting to target a stash that still has funds.
1255		FundedTarget,
1256		/// Invalid era to reward.
1257		InvalidEraToReward,
1258		/// Invalid number of nominations.
1259		InvalidNumberOfNominations,
1260		/// Rewards for this era have already been claimed for this validator.
1261		AlreadyClaimed,
1262		/// No nominators exist on this page.
1263		InvalidPage,
1264		/// Incorrect previous history depth input provided.
1265		IncorrectHistoryDepth,
1266		/// Internal state has become somehow corrupted and the operation cannot continue.
1267		BadState,
1268		/// Too many nomination targets supplied.
1269		TooManyTargets,
1270		/// A nomination target was supplied that was blocked or otherwise not a validator.
1271		BadTarget,
1272		/// The user has enough bond and thus cannot be chilled forcefully by an external person.
1273		CannotChillOther,
1274		/// There are too many nominators in the system. Governance needs to adjust the staking
1275		/// settings to keep things safe for the runtime.
1276		TooManyNominators,
1277		/// There are too many validator candidates in the system. Governance needs to adjust the
1278		/// staking settings to keep things safe for the runtime.
1279		TooManyValidators,
1280		/// Commission is too low. Must be at least `MinCommission`.
1281		CommissionTooLow,
1282		/// Some bound is not met.
1283		BoundNotMet,
1284		/// Used when attempting to use deprecated controller account logic.
1285		ControllerDeprecated,
1286		/// Cannot reset a ledger.
1287		CannotRestoreLedger,
1288		/// Provided reward destination is not allowed.
1289		RewardDestinationRestricted,
1290		/// Not enough funds available to withdraw.
1291		NotEnoughFunds,
1292		/// Operation not allowed for virtual stakers.
1293		VirtualStakerNotAllowed,
1294		/// Stash could not be reaped as other pallet might depend on it.
1295		CannotReapStash,
1296		/// The stake of this account is already migrated to `Fungible` holds.
1297		AlreadyMigrated,
1298		/// Era not yet started.
1299		EraNotStarted,
1300		/// Account is restricted from participation in staking. This may happen if the account is
1301		/// staking in another way already, such as via pool.
1302		Restricted,
1303		/// Unapplied slashes in the recently concluded era is blocking this operation.
1304		/// See `Call::apply_slash` to apply them.
1305		UnappliedSlashesInPreviousEra,
1306		/// The era is not eligible for pruning.
1307		EraNotPrunable,
1308		/// The slash has been cancelled and cannot be applied.
1309		CancelledSlash,
1310	}
1311
1312	impl<T: Config> Pallet<T> {
1313		/// Apply previously-unapplied slashes on the beginning of a new era, after a delay.
1314		pub fn apply_unapplied_slashes(active_era: EraIndex) -> Weight {
1315			let mut slashes = UnappliedSlashes::<T>::iter_prefix(&active_era).take(1);
1316			if let Some((key, slash)) = slashes.next() {
1317				crate::log!(
1318					debug,
1319					"🦹 found slash {:?} scheduled to be executed in era {:?}",
1320					slash,
1321					active_era,
1322				);
1323
1324				// Check if this slash has been cancelled
1325				if Self::check_slash_cancelled(active_era, &key.0, key.1) {
1326					crate::log!(
1327						debug,
1328						"🦹 slash for {:?} in era {:?} was cancelled, skipping",
1329						key.0,
1330						active_era,
1331					);
1332				} else {
1333					let offence_era = active_era.saturating_sub(T::SlashDeferDuration::get());
1334					slashing::apply_slash::<T>(slash, offence_era);
1335				}
1336
1337				// Always remove the slash from UnappliedSlashes
1338				UnappliedSlashes::<T>::remove(&active_era, &key);
1339
1340				// Check if there are more slashes for this era
1341				if UnappliedSlashes::<T>::iter_prefix(&active_era).next().is_none() {
1342					// No more slashes for this era, clear CancelledSlashes
1343					CancelledSlashes::<T>::remove(&active_era);
1344				}
1345
1346				T::WeightInfo::apply_slash()
1347			} else {
1348				// No slashes found for this era
1349				T::DbWeight::get().reads(1)
1350			}
1351		}
1352
1353		/// Execute one step of era pruning and get actual weight used
1354		fn do_prune_era_step(era: EraIndex) -> Result<Weight, DispatchError> {
1355			// Get current pruning state. If EraPruningState doesn't exist, it means:
1356			// - Era was never marked for pruning, OR
1357			// - Era was already fully pruned (pruning state was removed on final step)
1358			// In either case, this is an error - user should not call prune on non-prunable eras
1359			let current_step = EraPruningState::<T>::get(era).ok_or(Error::<T>::EraNotPrunable)?;
1360
1361			// Limit items to prevent deleting more than we can safely account for in weight
1362			// calculations
1363			let items_limit = T::MaxPruningItems::get().min(T::MaxValidatorSet::get());
1364
1365			let actual_weight = match current_step {
1366				PruningStep::ErasStakersPaged => {
1367					let result = ErasStakersPaged::<T>::clear_prefix((era,), items_limit, None);
1368					let items_deleted = result.backend as u32;
1369					result.maybe_cursor.is_none().then(|| {
1370						EraPruningState::<T>::insert(era, PruningStep::ErasStakersOverview)
1371					});
1372					T::WeightInfo::prune_era_stakers_paged(items_deleted)
1373				},
1374				PruningStep::ErasStakersOverview => {
1375					let result = ErasStakersOverview::<T>::clear_prefix(era, items_limit, None);
1376					let items_deleted = result.backend as u32;
1377					result.maybe_cursor.is_none().then(|| {
1378						EraPruningState::<T>::insert(era, PruningStep::ErasValidatorPrefs)
1379					});
1380					T::WeightInfo::prune_era_stakers_overview(items_deleted)
1381				},
1382				PruningStep::ErasValidatorPrefs => {
1383					let result = ErasValidatorPrefs::<T>::clear_prefix(era, items_limit, None);
1384					let items_deleted = result.backend as u32;
1385					result
1386						.maybe_cursor
1387						.is_none()
1388						.then(|| EraPruningState::<T>::insert(era, PruningStep::ClaimedRewards));
1389					T::WeightInfo::prune_era_validator_prefs(items_deleted)
1390				},
1391				PruningStep::ClaimedRewards => {
1392					let result = ClaimedRewards::<T>::clear_prefix(era, items_limit, None);
1393					let items_deleted = result.backend as u32;
1394					result.maybe_cursor.is_none().then(|| {
1395						EraPruningState::<T>::insert(era, PruningStep::ErasValidatorReward)
1396					});
1397					T::WeightInfo::prune_era_claimed_rewards(items_deleted)
1398				},
1399				PruningStep::ErasValidatorReward => {
1400					ErasValidatorReward::<T>::remove(era);
1401					EraPruningState::<T>::insert(era, PruningStep::ErasRewardPoints);
1402					T::WeightInfo::prune_era_validator_reward()
1403				},
1404				PruningStep::ErasRewardPoints => {
1405					ErasRewardPoints::<T>::remove(era);
1406					EraPruningState::<T>::insert(era, PruningStep::ErasTotalStake);
1407					T::WeightInfo::prune_era_reward_points()
1408				},
1409				PruningStep::ErasTotalStake => {
1410					ErasTotalStake::<T>::remove(era);
1411					// This is the final step - remove the pruning state
1412					EraPruningState::<T>::remove(era);
1413					T::WeightInfo::prune_era_total_stake()
1414				},
1415			};
1416
1417			// Check if era is fully pruned (pruning state removed) and emit event
1418			if EraPruningState::<T>::get(era).is_none() {
1419				Self::deposit_event(Event::<T>::EraPruned { index: era });
1420			}
1421
1422			Ok(actual_weight)
1423		}
1424	}
1425
1426	#[pallet::hooks]
1427	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
1428		fn on_initialize(_now: BlockNumberFor<T>) -> Weight {
1429			// process our queue.
1430			let mut consumed_weight = slashing::process_offence::<T>();
1431
1432			// apply any pending slashes after `SlashDeferDuration`.
1433			consumed_weight.saturating_accrue(T::DbWeight::get().reads(1));
1434			if let Some(active_era) = ActiveEra::<T>::get() {
1435				let slash_weight = Self::apply_unapplied_slashes(active_era.index);
1436				consumed_weight.saturating_accrue(slash_weight);
1437			}
1438
1439			// maybe plan eras and stuff. Note that this is benchmark as a part of the
1440			// election-provider's benchmarks.
1441			session_rotation::EraElectionPlanner::<T>::maybe_fetch_election_results();
1442			consumed_weight
1443		}
1444
1445		fn integrity_test() {
1446			// ensure that we funnel the correct value to the `DataProvider::MaxVotesPerVoter`;
1447			assert_eq!(
1448				MaxNominationsOf::<T>::get(),
1449				<Self as ElectionDataProvider>::MaxVotesPerVoter::get()
1450			);
1451
1452			// and that MaxNominations is always greater than 1, since we count on this.
1453			assert!(!MaxNominationsOf::<T>::get().is_zero());
1454
1455			assert!(
1456				T::SlashDeferDuration::get() < T::BondingDuration::get() || T::BondingDuration::get() == 0,
1457				"As per documentation, slash defer duration ({}) should be less than bonding duration ({}).",
1458				T::SlashDeferDuration::get(),
1459				T::BondingDuration::get(),
1460			);
1461
1462			// Ensure MaxPruningItems is reasonable (minimum 100 for efficiency)
1463			assert!(
1464				T::MaxPruningItems::get() >= 100,
1465				"MaxPruningItems must be at least 100 for efficient pruning, got: {}",
1466				T::MaxPruningItems::get()
1467			);
1468		}
1469
1470		#[cfg(feature = "try-runtime")]
1471		fn try_state(n: BlockNumberFor<T>) -> Result<(), sp_runtime::TryRuntimeError> {
1472			Self::do_try_state(n)
1473		}
1474	}
1475
1476	#[pallet::call]
1477	impl<T: Config> Pallet<T> {
1478		/// Take the origin account as a stash and lock up `value` of its balance. `controller` will
1479		/// be the account that controls it.
1480		///
1481		/// `value` must be more than the `minimum_balance` specified by `T::Currency`.
1482		///
1483		/// The dispatch origin for this call must be _Signed_ by the stash account.
1484		///
1485		/// Emits `Bonded`.
1486		///
1487		/// NOTE: Two of the storage writes (`Self::bonded`, `Self::payee`) are _never_ cleaned
1488		/// unless the `origin` falls below _existential deposit_ (or equal to 0) and gets removed
1489		/// as dust.
1490		#[pallet::call_index(0)]
1491		#[pallet::weight(T::WeightInfo::bond())]
1492		pub fn bond(
1493			origin: OriginFor<T>,
1494			#[pallet::compact] value: BalanceOf<T>,
1495			payee: RewardDestination<T::AccountId>,
1496		) -> DispatchResult {
1497			let stash = ensure_signed(origin)?;
1498
1499			ensure!(!T::Filter::contains(&stash), Error::<T>::Restricted);
1500
1501			if StakingLedger::<T>::is_bonded(StakingAccount::Stash(stash.clone())) {
1502				return Err(Error::<T>::AlreadyBonded.into());
1503			}
1504
1505			// An existing controller cannot become a stash.
1506			if StakingLedger::<T>::is_bonded(StakingAccount::Controller(stash.clone())) {
1507				return Err(Error::<T>::AlreadyPaired.into());
1508			}
1509
1510			// Reject a bond which is lower than the minimum bond.
1511			if value < Self::min_chilled_bond() {
1512				return Err(Error::<T>::InsufficientBond.into());
1513			}
1514
1515			let stash_balance = asset::free_to_stake::<T>(&stash);
1516			let value = value.min(stash_balance);
1517			Self::deposit_event(Event::<T>::Bonded { stash: stash.clone(), amount: value });
1518			let ledger = StakingLedger::<T>::new(stash.clone(), value);
1519
1520			// You're auto-bonded forever, here. We might improve this by only bonding when
1521			// you actually validate/nominate and remove once you unbond __everything__.
1522			ledger.bond(payee)?;
1523
1524			Ok(())
1525		}
1526
1527		/// Add some extra amount that have appeared in the stash `free_balance` into the balance up
1528		/// for staking.
1529		///
1530		/// The dispatch origin for this call must be _Signed_ by the stash, not the controller.
1531		///
1532		/// Use this if there are additional funds in your stash account that you wish to bond.
1533		/// Unlike [`bond`](Self::bond) or [`unbond`](Self::unbond) this function does not impose
1534		/// any limitation on the amount that can be added.
1535		///
1536		/// Emits `Bonded`.
1537		#[pallet::call_index(1)]
1538		#[pallet::weight(T::WeightInfo::bond_extra())]
1539		pub fn bond_extra(
1540			origin: OriginFor<T>,
1541			#[pallet::compact] max_additional: BalanceOf<T>,
1542		) -> DispatchResult {
1543			let stash = ensure_signed(origin)?;
1544			ensure!(!T::Filter::contains(&stash), Error::<T>::Restricted);
1545			Self::do_bond_extra(&stash, max_additional)
1546		}
1547
1548		/// Schedule a portion of the stash to be unlocked ready for transfer out after the bond
1549		/// period ends. If this leaves an amount actively bonded less than
1550		/// [`asset::existential_deposit`], then it is increased to the full amount.
1551		///
1552		/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
1553		///
1554		/// Once the unlock period is done, you can call `withdraw_unbonded` to actually move
1555		/// the funds out of management ready for transfer.
1556		///
1557		/// No more than a limited number of unlocking chunks (see `MaxUnlockingChunks`)
1558		/// can co-exists at the same time. If there are no unlocking chunks slots available
1559		/// [`Call::withdraw_unbonded`] is called to remove some of the chunks (if possible).
1560		///
1561		/// If a user encounters the `InsufficientBond` error when calling this extrinsic,
1562		/// they should call `chill` first in order to free up their bonded funds.
1563		///
1564		/// Emits `Unbonded`.
1565		///
1566		/// See also [`Call::withdraw_unbonded`].
1567		#[pallet::call_index(2)]
1568		#[pallet::weight(
1569            T::WeightInfo::withdraw_unbonded_kill().saturating_add(T::WeightInfo::unbond()))
1570        ]
1571		pub fn unbond(
1572			origin: OriginFor<T>,
1573			#[pallet::compact] value: BalanceOf<T>,
1574		) -> DispatchResultWithPostInfo {
1575			let controller = ensure_signed(origin)?;
1576			let unlocking =
1577				Self::ledger(Controller(controller.clone())).map(|l| l.unlocking.len())?;
1578
1579			// if there are no unlocking chunks available, try to remove any chunks by withdrawing
1580			// funds that have fully unbonded.
1581			let maybe_withdraw_weight = {
1582				if unlocking == T::MaxUnlockingChunks::get() as usize {
1583					Some(Self::do_withdraw_unbonded(&controller)?)
1584				} else {
1585					None
1586				}
1587			};
1588
1589			// we need to fetch the ledger again because it may have been mutated in the call
1590			// to `Self::do_withdraw_unbonded` above.
1591			let mut ledger = Self::ledger(Controller(controller))?;
1592			let mut value = value.min(ledger.active);
1593			let stash = ledger.stash.clone();
1594
1595			ensure!(
1596				ledger.unlocking.len() < T::MaxUnlockingChunks::get() as usize,
1597				Error::<T>::NoMoreChunks,
1598			);
1599
1600			if !value.is_zero() {
1601				ledger.active -= value;
1602
1603				// Avoid there being a dust balance left in the staking system.
1604				if ledger.active < asset::existential_deposit::<T>() {
1605					value += ledger.active;
1606					ledger.active = Zero::zero();
1607				}
1608
1609				let min_active_bond = if Nominators::<T>::contains_key(&stash) {
1610					Self::min_nominator_bond()
1611				} else if Validators::<T>::contains_key(&stash) {
1612					Self::min_validator_bond()
1613				} else {
1614					// staker is chilled, no min bond.
1615					Zero::zero()
1616				};
1617
1618				// Make sure that the user maintains enough active bond for their role.
1619				// If a user runs into this error, they should chill first.
1620				ensure!(ledger.active >= min_active_bond, Error::<T>::InsufficientBond);
1621
1622				// Note: we used current era before, but that is meant to be used for only election.
1623				// The right value to use here is the active era.
1624
1625				let era = session_rotation::Rotator::<T>::active_era()
1626					.saturating_add(T::BondingDuration::get());
1627				if let Some(chunk) = ledger.unlocking.last_mut().filter(|chunk| chunk.era == era) {
1628					// To keep the chunk count down, we only keep one chunk per era. Since
1629					// `unlocking` is a FiFo queue, if a chunk exists for `era` we know that it will
1630					// be the last one.
1631					chunk.value = chunk.value.defensive_saturating_add(value)
1632				} else {
1633					ledger
1634						.unlocking
1635						.try_push(UnlockChunk { value, era })
1636						.map_err(|_| Error::<T>::NoMoreChunks)?;
1637				};
1638				// NOTE: ledger must be updated prior to calling `Self::weight_of`.
1639				ledger.update()?;
1640
1641				// update this staker in the sorted list, if they exist in it.
1642				if T::VoterList::contains(&stash) {
1643					let _ = T::VoterList::on_update(&stash, Self::weight_of(&stash));
1644				}
1645
1646				Self::deposit_event(Event::<T>::Unbonded { stash, amount: value });
1647			}
1648
1649			let actual_weight = if let Some(withdraw_weight) = maybe_withdraw_weight {
1650				Some(T::WeightInfo::unbond().saturating_add(withdraw_weight))
1651			} else {
1652				Some(T::WeightInfo::unbond())
1653			};
1654
1655			Ok(actual_weight.into())
1656		}
1657
1658		/// Remove any stake that has been fully unbonded and is ready for withdrawal.
1659		///
1660		/// Stake is considered fully unbonded once [`Config::BondingDuration`] has elapsed since
1661		/// the unbonding was initiated. In rare cases—such as when offences for the unbonded era
1662		/// have been reported but not yet processed—withdrawal is restricted to eras for which
1663		/// all offences have been processed.
1664		///
1665		/// The unlocked stake will be returned as free balance in the stash account.
1666		///
1667		/// The dispatch origin for this call must be _Signed_ by the controller.
1668		///
1669		/// Emits `Withdrawn`.
1670		///
1671		/// See also [`Call::unbond`].
1672		///
1673		/// ## Parameters
1674		///
1675		/// - `num_slashing_spans`: **Deprecated**. Retained only for backward compatibility; this
1676		///   parameter has no effect.
1677		#[pallet::call_index(3)]
1678		#[pallet::weight(T::WeightInfo::withdraw_unbonded_kill())]
1679		pub fn withdraw_unbonded(
1680			origin: OriginFor<T>,
1681			_num_slashing_spans: u32,
1682		) -> DispatchResultWithPostInfo {
1683			let controller = ensure_signed(origin)?;
1684
1685			let actual_weight = Self::do_withdraw_unbonded(&controller)?;
1686			Ok(Some(actual_weight).into())
1687		}
1688
1689		/// Declare the desire to validate for the origin controller.
1690		///
1691		/// Effects will be felt at the beginning of the next era.
1692		///
1693		/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
1694		#[pallet::call_index(4)]
1695		#[pallet::weight(T::WeightInfo::validate())]
1696		pub fn validate(origin: OriginFor<T>, prefs: ValidatorPrefs) -> DispatchResult {
1697			let controller = ensure_signed(origin)?;
1698
1699			let ledger = Self::ledger(Controller(controller))?;
1700
1701			ensure!(ledger.active >= Self::min_validator_bond(), Error::<T>::InsufficientBond);
1702			let stash = &ledger.stash;
1703
1704			// ensure their commission is correct.
1705			ensure!(prefs.commission >= MinCommission::<T>::get(), Error::<T>::CommissionTooLow);
1706
1707			// Only check limits if they are not already a validator.
1708			if !Validators::<T>::contains_key(stash) {
1709				// If this error is reached, we need to adjust the `MinValidatorBond` and start
1710				// calling `chill_other`. Until then, we explicitly block new validators to protect
1711				// the runtime.
1712				if let Some(max_validators) = MaxValidatorsCount::<T>::get() {
1713					ensure!(
1714						Validators::<T>::count() < max_validators,
1715						Error::<T>::TooManyValidators
1716					);
1717				}
1718			}
1719
1720			Self::do_remove_nominator(stash);
1721			Self::do_add_validator(stash, prefs.clone());
1722			Self::deposit_event(Event::<T>::ValidatorPrefsSet { stash: ledger.stash, prefs });
1723
1724			Ok(())
1725		}
1726
1727		/// Declare the desire to nominate `targets` for the origin controller.
1728		///
1729		/// Effects will be felt at the beginning of the next era.
1730		///
1731		/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
1732		#[pallet::call_index(5)]
1733		#[pallet::weight(T::WeightInfo::nominate(targets.len() as u32))]
1734		pub fn nominate(
1735			origin: OriginFor<T>,
1736			targets: Vec<AccountIdLookupOf<T>>,
1737		) -> DispatchResult {
1738			let controller = ensure_signed(origin)?;
1739
1740			let ledger = Self::ledger(StakingAccount::Controller(controller.clone()))?;
1741
1742			ensure!(ledger.active >= Self::min_nominator_bond(), Error::<T>::InsufficientBond);
1743			let stash = &ledger.stash;
1744
1745			// Only check limits if they are not already a nominator.
1746			if !Nominators::<T>::contains_key(stash) {
1747				// If this error is reached, we need to adjust the `MinNominatorBond` and start
1748				// calling `chill_other`. Until then, we explicitly block new nominators to protect
1749				// the runtime.
1750				if let Some(max_nominators) = MaxNominatorsCount::<T>::get() {
1751					ensure!(
1752						Nominators::<T>::count() < max_nominators,
1753						Error::<T>::TooManyNominators
1754					);
1755				}
1756			}
1757
1758			// dedup targets
1759			let mut targets = targets
1760				.into_iter()
1761				.map(|t| T::Lookup::lookup(t).map_err(DispatchError::from))
1762				.collect::<Result<Vec<_>, _>>()?;
1763			targets.sort();
1764			targets.dedup();
1765
1766			ensure!(!targets.is_empty(), Error::<T>::EmptyTargets);
1767			ensure!(
1768				targets.len() <= T::NominationsQuota::get_quota(ledger.active) as usize,
1769				Error::<T>::TooManyTargets
1770			);
1771
1772			let old = Nominators::<T>::get(stash).map_or_else(Vec::new, |x| x.targets.into_inner());
1773
1774			let targets: BoundedVec<_, _> = targets
1775				.into_iter()
1776				.map(|n| {
1777					if old.contains(&n) ||
1778						(Validators::<T>::contains_key(&n) && !Validators::<T>::get(&n).blocked)
1779					{
1780						Ok(n)
1781					} else {
1782						Err(Error::<T>::BadTarget.into())
1783					}
1784				})
1785				.collect::<Result<Vec<_>, DispatchError>>()?
1786				.try_into()
1787				.map_err(|_| Error::<T>::TooManyNominators)?;
1788
1789			let nominations = Nominations {
1790				targets,
1791				// Initial nominations are considered submitted at era 0. See `Nominations` doc.
1792				submitted_in: CurrentEra::<T>::get().unwrap_or(0),
1793				suppressed: false,
1794			};
1795
1796			Self::do_remove_validator(stash);
1797			Self::do_add_nominator(stash, nominations);
1798			Ok(())
1799		}
1800
1801		/// Declare no desire to either validate or nominate.
1802		///
1803		/// Effects will be felt at the beginning of the next era.
1804		///
1805		/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
1806		///
1807		/// ## Complexity
1808		/// - Independent of the arguments. Insignificant complexity.
1809		/// - Contains one read.
1810		/// - Writes are limited to the `origin` account key.
1811		#[pallet::call_index(6)]
1812		#[pallet::weight(T::WeightInfo::chill())]
1813		pub fn chill(origin: OriginFor<T>) -> DispatchResult {
1814			let controller = ensure_signed(origin)?;
1815
1816			let ledger = Self::ledger(StakingAccount::Controller(controller))?;
1817
1818			Self::chill_stash(&ledger.stash);
1819			Ok(())
1820		}
1821
1822		/// (Re-)set the payment target for a controller.
1823		///
1824		/// Effects will be felt instantly (as soon as this function is completed successfully).
1825		///
1826		/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
1827		#[pallet::call_index(7)]
1828		#[pallet::weight(T::WeightInfo::set_payee())]
1829		pub fn set_payee(
1830			origin: OriginFor<T>,
1831			payee: RewardDestination<T::AccountId>,
1832		) -> DispatchResult {
1833			let controller = ensure_signed(origin)?;
1834			let ledger = Self::ledger(Controller(controller.clone()))?;
1835
1836			ensure!(
1837				(payee != {
1838					#[allow(deprecated)]
1839					RewardDestination::Controller
1840				}),
1841				Error::<T>::ControllerDeprecated
1842			);
1843
1844			let _ = ledger
1845				.set_payee(payee)
1846				.defensive_proof("ledger was retrieved from storage, thus it's bonded; qed.")?;
1847
1848			Ok(())
1849		}
1850
1851		/// (Re-)sets the controller of a stash to the stash itself. This function previously
1852		/// accepted a `controller` argument to set the controller to an account other than the
1853		/// stash itself. This functionality has now been removed, now only setting the controller
1854		/// to the stash, if it is not already.
1855		///
1856		/// Effects will be felt instantly (as soon as this function is completed successfully).
1857		///
1858		/// The dispatch origin for this call must be _Signed_ by the stash, not the controller.
1859		#[pallet::call_index(8)]
1860		#[pallet::weight(T::WeightInfo::set_controller())]
1861		pub fn set_controller(origin: OriginFor<T>) -> DispatchResult {
1862			let stash = ensure_signed(origin)?;
1863
1864			Self::ledger(StakingAccount::Stash(stash.clone())).map(|ledger| {
1865				let controller = ledger.controller()
1866                    .defensive_proof("Ledger's controller field didn't exist. The controller should have been fetched using StakingLedger.")
1867                    .ok_or(Error::<T>::NotController)?;
1868
1869				if controller == stash {
1870					// Stash is already its own controller.
1871					return Err(Error::<T>::AlreadyPaired.into())
1872				}
1873
1874				let _ = ledger.set_controller_to_stash()?;
1875				Ok(())
1876			})?
1877		}
1878
1879		/// Sets the ideal number of validators.
1880		///
1881		/// The dispatch origin must be Root.
1882		#[pallet::call_index(9)]
1883		#[pallet::weight(T::WeightInfo::set_validator_count())]
1884		pub fn set_validator_count(
1885			origin: OriginFor<T>,
1886			#[pallet::compact] new: u32,
1887		) -> DispatchResult {
1888			ensure_root(origin)?;
1889
1890			ensure!(new <= T::MaxValidatorSet::get(), Error::<T>::TooManyValidators);
1891
1892			ValidatorCount::<T>::put(new);
1893			Ok(())
1894		}
1895
1896		/// Increments the ideal number of validators up to maximum of
1897		/// `T::MaxValidatorSet`.
1898		///
1899		/// The dispatch origin must be Root.
1900		#[pallet::call_index(10)]
1901		#[pallet::weight(T::WeightInfo::set_validator_count())]
1902		pub fn increase_validator_count(
1903			origin: OriginFor<T>,
1904			#[pallet::compact] additional: u32,
1905		) -> DispatchResult {
1906			ensure_root(origin)?;
1907			let old = ValidatorCount::<T>::get();
1908			let new = old.checked_add(additional).ok_or(ArithmeticError::Overflow)?;
1909
1910			ensure!(new <= T::MaxValidatorSet::get(), Error::<T>::TooManyValidators);
1911
1912			ValidatorCount::<T>::put(new);
1913			Ok(())
1914		}
1915
1916		/// Scale up the ideal number of validators by a factor up to maximum of
1917		/// `T::MaxValidatorSet`.
1918		///
1919		/// The dispatch origin must be Root.
1920		#[pallet::call_index(11)]
1921		#[pallet::weight(T::WeightInfo::set_validator_count())]
1922		pub fn scale_validator_count(origin: OriginFor<T>, factor: Percent) -> DispatchResult {
1923			ensure_root(origin)?;
1924			let old = ValidatorCount::<T>::get();
1925			let new = old.checked_add(factor.mul_floor(old)).ok_or(ArithmeticError::Overflow)?;
1926
1927			ensure!(new <= T::MaxValidatorSet::get(), Error::<T>::TooManyValidators);
1928
1929			ValidatorCount::<T>::put(new);
1930			Ok(())
1931		}
1932
1933		/// Force there to be no new eras indefinitely.
1934		///
1935		/// The dispatch origin must be Root.
1936		///
1937		/// # Warning
1938		///
1939		/// The election process starts multiple blocks before the end of the era.
1940		/// Thus the election process may be ongoing when this is called. In this case the
1941		/// election will continue until the next era is triggered.
1942		#[pallet::call_index(12)]
1943		#[pallet::weight(T::WeightInfo::force_no_eras())]
1944		pub fn force_no_eras(origin: OriginFor<T>) -> DispatchResult {
1945			ensure_root(origin)?;
1946			Self::set_force_era(Forcing::ForceNone);
1947			Ok(())
1948		}
1949
1950		/// Force there to be a new era at the end of the next session. After this, it will be
1951		/// reset to normal (non-forced) behaviour.
1952		///
1953		/// The dispatch origin must be Root.
1954		///
1955		/// # Warning
1956		///
1957		/// The election process starts multiple blocks before the end of the era.
1958		/// If this is called just before a new era is triggered, the election process may not
1959		/// have enough blocks to get a result.
1960		#[pallet::call_index(13)]
1961		#[pallet::weight(T::WeightInfo::force_new_era())]
1962		pub fn force_new_era(origin: OriginFor<T>) -> DispatchResult {
1963			ensure_root(origin)?;
1964			Self::set_force_era(Forcing::ForceNew);
1965			Ok(())
1966		}
1967
1968		/// Set the validators who cannot be slashed (if any).
1969		///
1970		/// The dispatch origin must be Root.
1971		#[pallet::call_index(14)]
1972		#[pallet::weight(T::WeightInfo::set_invulnerables(invulnerables.len() as u32))]
1973		pub fn set_invulnerables(
1974			origin: OriginFor<T>,
1975			invulnerables: Vec<T::AccountId>,
1976		) -> DispatchResult {
1977			ensure_root(origin)?;
1978			let invulnerables =
1979				BoundedVec::try_from(invulnerables).map_err(|_| Error::<T>::BoundNotMet)?;
1980			<Invulnerables<T>>::put(invulnerables);
1981			Ok(())
1982		}
1983
1984		/// Force a current staker to become completely unstaked, immediately.
1985		///
1986		/// The dispatch origin must be Root.
1987		/// ## Parameters
1988		///
1989		/// - `stash`: The stash account to be unstaked.
1990		/// - `num_slashing_spans`: **Deprecated**. This parameter is retained for backward
1991		/// compatibility. It no longer has any effect.
1992		#[pallet::call_index(15)]
1993		#[pallet::weight(T::WeightInfo::force_unstake())]
1994		pub fn force_unstake(
1995			origin: OriginFor<T>,
1996			stash: T::AccountId,
1997			_num_slashing_spans: u32,
1998		) -> DispatchResult {
1999			ensure_root(origin)?;
2000
2001			// Remove all staking-related information and lock.
2002			Self::kill_stash(&stash)?;
2003
2004			Ok(())
2005		}
2006
2007		/// Force there to be a new era at the end of sessions indefinitely.
2008		///
2009		/// The dispatch origin must be Root.
2010		///
2011		/// # Warning
2012		///
2013		/// The election process starts multiple blocks before the end of the era.
2014		/// If this is called just before a new era is triggered, the election process may not
2015		/// have enough blocks to get a result.
2016		#[pallet::call_index(16)]
2017		#[pallet::weight(T::WeightInfo::force_new_era_always())]
2018		pub fn force_new_era_always(origin: OriginFor<T>) -> DispatchResult {
2019			ensure_root(origin)?;
2020			Self::set_force_era(Forcing::ForceAlways);
2021			Ok(())
2022		}
2023
2024		/// Cancels scheduled slashes for a given era before they are applied.
2025		///
2026		/// This function allows `T::AdminOrigin` to cancel pending slashes for specified validators
2027		/// in a given era. The cancelled slashes are stored and will be checked when applying
2028		/// slashes.
2029		///
2030		/// ## Parameters
2031		/// - `era`: The staking era for which slashes should be cancelled. This is the era where
2032		///   the slash would be applied, not the era in which the offence was committed.
2033		/// - `validator_slashes`: A list of validator stash accounts and their slash fractions to
2034		///   be cancelled.
2035		#[pallet::call_index(17)]
2036		#[pallet::weight(T::WeightInfo::cancel_deferred_slash(validator_slashes.len() as u32))]
2037		pub fn cancel_deferred_slash(
2038			origin: OriginFor<T>,
2039			era: EraIndex,
2040			validator_slashes: Vec<(T::AccountId, Perbill)>,
2041		) -> DispatchResult {
2042			T::AdminOrigin::ensure_origin(origin)?;
2043			ensure!(!validator_slashes.is_empty(), Error::<T>::EmptyTargets);
2044
2045			// Get current cancelled slashes for this era
2046			let mut cancelled_slashes = CancelledSlashes::<T>::get(&era);
2047
2048			// Process each validator slash
2049			for (validator, slash_fraction) in validator_slashes {
2050				// Since this is gated by admin origin, we don't need to check if they are really
2051				// validators and trust governance to correctly set the parameters.
2052
2053				// Remove any existing entry for this validator
2054				cancelled_slashes.retain(|(v, _)| v != &validator);
2055
2056				// Add the validator with the specified slash fraction
2057				cancelled_slashes
2058					.try_push((validator.clone(), slash_fraction))
2059					.map_err(|_| Error::<T>::BoundNotMet)
2060					.defensive_proof("cancelled_slashes should have capacity for all validators")?;
2061
2062				Self::deposit_event(Event::<T>::SlashCancelled { slash_era: era, validator });
2063			}
2064
2065			// Update storage
2066			CancelledSlashes::<T>::insert(&era, cancelled_slashes);
2067
2068			Ok(())
2069		}
2070
2071		/// Pay out next page of the stakers behind a validator for the given era.
2072		///
2073		/// - `validator_stash` is the stash account of the validator.
2074		/// - `era` may be any era between `[current_era - history_depth; current_era]`.
2075		///
2076		/// The origin of this call must be _Signed_. Any account can call this function, even if
2077		/// it is not one of the stakers.
2078		///
2079		/// The reward payout could be paged in case there are too many nominators backing the
2080		/// `validator_stash`. This call will payout unpaid pages in an ascending order. To claim a
2081		/// specific page, use `payout_stakers_by_page`.`
2082		///
2083		/// If all pages are claimed, it returns an error `InvalidPage`.
2084		#[pallet::call_index(18)]
2085		#[pallet::weight(T::WeightInfo::payout_stakers_alive_staked(T::MaxExposurePageSize::get()))]
2086		pub fn payout_stakers(
2087			origin: OriginFor<T>,
2088			validator_stash: T::AccountId,
2089			era: EraIndex,
2090		) -> DispatchResultWithPostInfo {
2091			ensure_signed(origin)?;
2092
2093			Self::do_payout_stakers(validator_stash, era)
2094		}
2095
2096		/// Rebond a portion of the stash scheduled to be unlocked.
2097		///
2098		/// The dispatch origin must be signed by the controller.
2099		#[pallet::call_index(19)]
2100		#[pallet::weight(T::WeightInfo::rebond(T::MaxUnlockingChunks::get() as u32))]
2101		pub fn rebond(
2102			origin: OriginFor<T>,
2103			#[pallet::compact] value: BalanceOf<T>,
2104		) -> DispatchResultWithPostInfo {
2105			let controller = ensure_signed(origin)?;
2106			let ledger = Self::ledger(Controller(controller))?;
2107
2108			ensure!(!T::Filter::contains(&ledger.stash), Error::<T>::Restricted);
2109			ensure!(!ledger.unlocking.is_empty(), Error::<T>::NoUnlockChunk);
2110
2111			let initial_unlocking = ledger.unlocking.len() as u32;
2112			let (ledger, rebonded_value) = ledger.rebond(value);
2113			// Last check: the new active amount of ledger must be more than min bond.
2114			ensure!(ledger.active >= Self::min_chilled_bond(), Error::<T>::InsufficientBond);
2115
2116			Self::deposit_event(Event::<T>::Bonded {
2117				stash: ledger.stash.clone(),
2118				amount: rebonded_value,
2119			});
2120
2121			let stash = ledger.stash.clone();
2122			let final_unlocking = ledger.unlocking.len();
2123
2124			// NOTE: ledger must be updated prior to calling `Self::weight_of`.
2125			ledger.update()?;
2126			if T::VoterList::contains(&stash) {
2127				let _ = T::VoterList::on_update(&stash, Self::weight_of(&stash));
2128			}
2129
2130			let removed_chunks = 1u32 // for the case where the last iterated chunk is not removed
2131				.saturating_add(initial_unlocking)
2132				.saturating_sub(final_unlocking as u32);
2133			Ok(Some(T::WeightInfo::rebond(removed_chunks)).into())
2134		}
2135
2136		/// Remove all data structures concerning a staker/stash once it is at a state where it can
2137		/// be considered `dust` in the staking system. The requirements are:
2138		///
2139		/// 1. the `total_balance` of the stash is below minimum bond.
2140		/// 2. or, the `ledger.total` of the stash is below minimum bond.
2141		/// 3. or, existential deposit is zero and either `total_balance` or `ledger.total` is zero.
2142		///
2143		/// The former can happen in cases like a slash; the latter when a fully unbonded account
2144		/// is still receiving staking rewards in `RewardDestination::Staked`.
2145		///
2146		/// It can be called by anyone, as long as `stash` meets the above requirements.
2147		///
2148		/// Refunds the transaction fees upon successful execution.
2149		///
2150		/// ## Parameters
2151		///
2152		/// - `stash`: The stash account to be reaped.
2153		/// - `num_slashing_spans`: **Deprecated**. This parameter is retained for backward
2154		/// compatibility. It no longer has any effect.
2155		#[pallet::call_index(20)]
2156		#[pallet::weight(T::WeightInfo::reap_stash())]
2157		pub fn reap_stash(
2158			origin: OriginFor<T>,
2159			stash: T::AccountId,
2160			_num_slashing_spans: u32,
2161		) -> DispatchResultWithPostInfo {
2162			let _ = ensure_signed(origin)?;
2163
2164			// virtual stakers should not be allowed to be reaped.
2165			ensure!(!Self::is_virtual_staker(&stash), Error::<T>::VirtualStakerNotAllowed);
2166
2167			let min_chilled_bond = Self::min_chilled_bond();
2168			let origin_balance = asset::total_balance::<T>(&stash);
2169			let ledger_total =
2170				Self::ledger(Stash(stash.clone())).map(|l| l.total).unwrap_or_default();
2171			let reapable = origin_balance < min_chilled_bond ||
2172				origin_balance.is_zero() ||
2173				ledger_total < min_chilled_bond ||
2174				ledger_total.is_zero();
2175			ensure!(reapable, Error::<T>::FundedTarget);
2176
2177			// Remove all staking-related information and lock.
2178			Self::kill_stash(&stash)?;
2179
2180			Ok(Pays::No.into())
2181		}
2182
2183		/// Remove the given nominations from the calling validator.
2184		///
2185		/// Effects will be felt at the beginning of the next era.
2186		///
2187		/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
2188		///
2189		/// - `who`: A list of nominator stash accounts who are nominating this validator which
2190		///   should no longer be nominating this validator.
2191		///
2192		/// Note: Making this call only makes sense if you first set the validator preferences to
2193		/// block any further nominations.
2194		#[pallet::call_index(21)]
2195		#[pallet::weight(T::WeightInfo::kick(who.len() as u32))]
2196		pub fn kick(origin: OriginFor<T>, who: Vec<AccountIdLookupOf<T>>) -> DispatchResult {
2197			let controller = ensure_signed(origin)?;
2198			let ledger = Self::ledger(Controller(controller))?;
2199			let stash = &ledger.stash;
2200
2201			for nom_stash in who
2202				.into_iter()
2203				.map(T::Lookup::lookup)
2204				.collect::<Result<Vec<T::AccountId>, _>>()?
2205				.into_iter()
2206			{
2207				Nominators::<T>::mutate(&nom_stash, |maybe_nom| {
2208					if let Some(ref mut nom) = maybe_nom {
2209						if let Some(pos) = nom.targets.iter().position(|v| v == stash) {
2210							nom.targets.swap_remove(pos);
2211							Self::deposit_event(Event::<T>::Kicked {
2212								nominator: nom_stash.clone(),
2213								stash: stash.clone(),
2214							});
2215						}
2216					}
2217				});
2218			}
2219
2220			Ok(())
2221		}
2222
2223		/// Update the various staking configurations .
2224		///
2225		/// * `min_nominator_bond`: The minimum active bond needed to be a nominator.
2226		/// * `min_validator_bond`: The minimum active bond needed to be a validator.
2227		/// * `max_nominator_count`: The max number of users who can be a nominator at once. When
2228		///   set to `None`, no limit is enforced.
2229		/// * `max_validator_count`: The max number of users who can be a validator at once. When
2230		///   set to `None`, no limit is enforced.
2231		/// * `chill_threshold`: The ratio of `max_nominator_count` or `max_validator_count` which
2232		///   should be filled in order for the `chill_other` transaction to work.
2233		/// * `min_commission`: The minimum amount of commission that each validators must maintain.
2234		///   This is checked only upon calling `validate`. Existing validators are not affected.
2235		///
2236		/// RuntimeOrigin must be Root to call this function.
2237		///
2238		/// NOTE: Existing nominators and validators will not be affected by this update.
2239		/// to kick people under the new limits, `chill_other` should be called.
2240		// We assume the worst case for this call is either: all items are set or all items are
2241		// removed.
2242		#[pallet::call_index(22)]
2243		#[pallet::weight(
2244			T::WeightInfo::set_staking_configs_all_set()
2245				.max(T::WeightInfo::set_staking_configs_all_remove())
2246		)]
2247		pub fn set_staking_configs(
2248			origin: OriginFor<T>,
2249			min_nominator_bond: ConfigOp<BalanceOf<T>>,
2250			min_validator_bond: ConfigOp<BalanceOf<T>>,
2251			max_nominator_count: ConfigOp<u32>,
2252			max_validator_count: ConfigOp<u32>,
2253			chill_threshold: ConfigOp<Percent>,
2254			min_commission: ConfigOp<Perbill>,
2255			max_staked_rewards: ConfigOp<Percent>,
2256		) -> DispatchResult {
2257			ensure_root(origin)?;
2258
2259			macro_rules! config_op_exp {
2260				($storage:ty, $op:ident) => {
2261					match $op {
2262						ConfigOp::Noop => (),
2263						ConfigOp::Set(v) => <$storage>::put(v),
2264						ConfigOp::Remove => <$storage>::kill(),
2265					}
2266				};
2267			}
2268
2269			config_op_exp!(MinNominatorBond<T>, min_nominator_bond);
2270			config_op_exp!(MinValidatorBond<T>, min_validator_bond);
2271			config_op_exp!(MaxNominatorsCount<T>, max_nominator_count);
2272			config_op_exp!(MaxValidatorsCount<T>, max_validator_count);
2273			config_op_exp!(ChillThreshold<T>, chill_threshold);
2274			config_op_exp!(MinCommission<T>, min_commission);
2275			config_op_exp!(MaxStakedRewards<T>, max_staked_rewards);
2276			Ok(())
2277		}
2278		/// Declare a `controller` to stop participating as either a validator or nominator.
2279		///
2280		/// Effects will be felt at the beginning of the next era.
2281		///
2282		/// The dispatch origin for this call must be _Signed_, but can be called by anyone.
2283		///
2284		/// If the caller is the same as the controller being targeted, then no further checks are
2285		/// enforced, and this function behaves just like `chill`.
2286		///
2287		/// If the caller is different than the controller being targeted, the following conditions
2288		/// must be met:
2289		///
2290		/// * `controller` must belong to a nominator who has become non-decodable,
2291		///
2292		/// Or:
2293		///
2294		/// * A `ChillThreshold` must be set and checked which defines how close to the max
2295		///   nominators or validators we must reach before users can start chilling one-another.
2296		/// * A `MaxNominatorCount` and `MaxValidatorCount` must be set which is used to determine
2297		///   how close we are to the threshold.
2298		/// * A `MinNominatorBond` and `MinValidatorBond` must be set and checked, which determines
2299		///   if this is a person that should be chilled because they have not met the threshold
2300		///   bond required.
2301		///
2302		/// This can be helpful if bond requirements are updated, and we need to remove old users
2303		/// who do not satisfy these requirements.
2304		#[pallet::call_index(23)]
2305		#[pallet::weight(T::WeightInfo::chill_other())]
2306		pub fn chill_other(origin: OriginFor<T>, stash: T::AccountId) -> DispatchResult {
2307			// Anyone can call this function.
2308			let caller = ensure_signed(origin)?;
2309			let ledger = Self::ledger(Stash(stash.clone()))?;
2310			let controller = ledger
2311				.controller()
2312				.defensive_proof(
2313					"Ledger's controller field didn't exist. The controller should have been fetched using StakingLedger.",
2314				)
2315				.ok_or(Error::<T>::NotController)?;
2316
2317			// In order for one user to chill another user, the following conditions must be met:
2318			//
2319			// * `controller` belongs to a nominator who has become non-decodable,
2320			//
2321			// Or
2322			//
2323			// * A `ChillThreshold` is set which defines how close to the max nominators or
2324			//   validators we must reach before users can start chilling one-another.
2325			// * A `MaxNominatorCount` and `MaxValidatorCount` which is used to determine how close
2326			//   we are to the threshold.
2327			// * A `MinNominatorBond` and `MinValidatorBond` which is the final condition checked to
2328			//   determine this is a person that should be chilled because they have not met the
2329			//   threshold bond required.
2330			//
2331			// Otherwise, if caller is the same as the controller, this is just like `chill`.
2332
2333			if Nominators::<T>::contains_key(&stash) && Nominators::<T>::get(&stash).is_none() {
2334				Self::chill_stash(&stash);
2335				return Ok(());
2336			}
2337
2338			if caller != controller {
2339				let threshold = ChillThreshold::<T>::get().ok_or(Error::<T>::CannotChillOther)?;
2340				let min_active_bond = if Nominators::<T>::contains_key(&stash) {
2341					let max_nominator_count =
2342						MaxNominatorsCount::<T>::get().ok_or(Error::<T>::CannotChillOther)?;
2343					let current_nominator_count = Nominators::<T>::count();
2344					ensure!(
2345						threshold * max_nominator_count < current_nominator_count,
2346						Error::<T>::CannotChillOther
2347					);
2348					Self::min_nominator_bond()
2349				} else if Validators::<T>::contains_key(&stash) {
2350					let max_validator_count =
2351						MaxValidatorsCount::<T>::get().ok_or(Error::<T>::CannotChillOther)?;
2352					let current_validator_count = Validators::<T>::count();
2353					ensure!(
2354						threshold * max_validator_count < current_validator_count,
2355						Error::<T>::CannotChillOther
2356					);
2357					Self::min_validator_bond()
2358				} else {
2359					Zero::zero()
2360				};
2361
2362				ensure!(ledger.active < min_active_bond, Error::<T>::CannotChillOther);
2363			}
2364
2365			Self::chill_stash(&stash);
2366			Ok(())
2367		}
2368
2369		/// Force a validator to have at least the minimum commission. This will not affect a
2370		/// validator who already has a commission greater than or equal to the minimum. Any account
2371		/// can call this.
2372		#[pallet::call_index(24)]
2373		#[pallet::weight(T::WeightInfo::force_apply_min_commission())]
2374		pub fn force_apply_min_commission(
2375			origin: OriginFor<T>,
2376			validator_stash: T::AccountId,
2377		) -> DispatchResult {
2378			ensure_signed(origin)?;
2379			let min_commission = MinCommission::<T>::get();
2380			Validators::<T>::try_mutate_exists(validator_stash, |maybe_prefs| {
2381				maybe_prefs
2382					.as_mut()
2383					.map(|prefs| {
2384						(prefs.commission < min_commission)
2385							.then(|| prefs.commission = min_commission)
2386					})
2387					.ok_or(Error::<T>::NotStash)
2388			})?;
2389			Ok(())
2390		}
2391
2392		/// Sets the minimum amount of commission that each validators must maintain.
2393		///
2394		/// This call has lower privilege requirements than `set_staking_config` and can be called
2395		/// by the `T::AdminOrigin`. Root can always call this.
2396		#[pallet::call_index(25)]
2397		#[pallet::weight(T::WeightInfo::set_min_commission())]
2398		pub fn set_min_commission(origin: OriginFor<T>, new: Perbill) -> DispatchResult {
2399			T::AdminOrigin::ensure_origin(origin)?;
2400			MinCommission::<T>::put(new);
2401			Ok(())
2402		}
2403
2404		/// Pay out a page of the stakers behind a validator for the given era and page.
2405		///
2406		/// - `validator_stash` is the stash account of the validator.
2407		/// - `era` may be any era between `[current_era - history_depth; current_era]`.
2408		/// - `page` is the page index of nominators to pay out with value between 0 and
2409		///   `num_nominators / T::MaxExposurePageSize`.
2410		///
2411		/// The origin of this call must be _Signed_. Any account can call this function, even if
2412		/// it is not one of the stakers.
2413		///
2414		/// If a validator has more than [`Config::MaxExposurePageSize`] nominators backing
2415		/// them, then the list of nominators is paged, with each page being capped at
2416		/// [`Config::MaxExposurePageSize`.] If a validator has more than one page of nominators,
2417		/// the call needs to be made for each page separately in order for all the nominators
2418		/// backing a validator to receive the reward. The nominators are not sorted across pages
2419		/// and so it should not be assumed the highest staker would be on the topmost page and vice
2420		/// versa. If rewards are not claimed in [`Config::HistoryDepth`] eras, they are lost.
2421		#[pallet::call_index(26)]
2422		#[pallet::weight(T::WeightInfo::payout_stakers_alive_staked(T::MaxExposurePageSize::get()))]
2423		pub fn payout_stakers_by_page(
2424			origin: OriginFor<T>,
2425			validator_stash: T::AccountId,
2426			era: EraIndex,
2427			page: Page,
2428		) -> DispatchResultWithPostInfo {
2429			ensure_signed(origin)?;
2430			Self::do_payout_stakers_by_page(validator_stash, era, page)
2431		}
2432
2433		/// Migrates an account's `RewardDestination::Controller` to
2434		/// `RewardDestination::Account(controller)`.
2435		///
2436		/// Effects will be felt instantly (as soon as this function is completed successfully).
2437		///
2438		/// This will waive the transaction fee if the `payee` is successfully migrated.
2439		#[pallet::call_index(27)]
2440		#[pallet::weight(T::WeightInfo::update_payee())]
2441		pub fn update_payee(
2442			origin: OriginFor<T>,
2443			controller: T::AccountId,
2444		) -> DispatchResultWithPostInfo {
2445			let _ = ensure_signed(origin)?;
2446			let ledger = Self::ledger(StakingAccount::Controller(controller.clone()))?;
2447
2448			ensure!(
2449				(Payee::<T>::get(&ledger.stash) == {
2450					#[allow(deprecated)]
2451					Some(RewardDestination::Controller)
2452				}),
2453				Error::<T>::NotController
2454			);
2455
2456			let _ = ledger
2457				.set_payee(RewardDestination::Account(controller))
2458				.defensive_proof("ledger should have been previously retrieved from storage.")?;
2459
2460			Ok(Pays::No.into())
2461		}
2462
2463		/// Updates a batch of controller accounts to their corresponding stash account if they are
2464		/// not the same. Ignores any controller accounts that do not exist, and does not operate if
2465		/// the stash and controller are already the same.
2466		///
2467		/// Effects will be felt instantly (as soon as this function is completed successfully).
2468		///
2469		/// The dispatch origin must be `T::AdminOrigin`.
2470		#[pallet::call_index(28)]
2471		#[pallet::weight(T::WeightInfo::deprecate_controller_batch(controllers.len() as u32))]
2472		pub fn deprecate_controller_batch(
2473			origin: OriginFor<T>,
2474			controllers: BoundedVec<T::AccountId, T::MaxControllersInDeprecationBatch>,
2475		) -> DispatchResultWithPostInfo {
2476			T::AdminOrigin::ensure_origin(origin)?;
2477
2478			// Ignore controllers that do not exist or are already the same as stash.
2479			let filtered_batch_with_ledger: Vec<_> = controllers
2480				.iter()
2481				.filter_map(|controller| {
2482					let ledger = Self::ledger(StakingAccount::Controller(controller.clone()));
2483					ledger.ok().map_or(None, |ledger| {
2484						// If the controller `RewardDestination` is still the deprecated
2485						// `Controller` variant, skip deprecating this account.
2486						let payee_deprecated = Payee::<T>::get(&ledger.stash) == {
2487							#[allow(deprecated)]
2488							Some(RewardDestination::Controller)
2489						};
2490
2491						if ledger.stash != *controller && !payee_deprecated {
2492							Some(ledger)
2493						} else {
2494							None
2495						}
2496					})
2497				})
2498				.collect();
2499
2500			// Update unique pairs.
2501			let mut failures = 0;
2502			for ledger in filtered_batch_with_ledger {
2503				let _ = ledger.clone().set_controller_to_stash().map_err(|_| failures += 1);
2504			}
2505			Self::deposit_event(Event::<T>::ControllerBatchDeprecated { failures });
2506
2507			Ok(Some(T::WeightInfo::deprecate_controller_batch(controllers.len() as u32)).into())
2508		}
2509
2510		/// Restores the state of a ledger which is in an inconsistent state.
2511		///
2512		/// The requirements to restore a ledger are the following:
2513		/// * The stash is bonded; or
2514		/// * The stash is not bonded but it has a staking lock left behind; or
2515		/// * If the stash has an associated ledger and its state is inconsistent; or
2516		/// * If the ledger is not corrupted *but* its staking lock is out of sync.
2517		///
2518		/// The `maybe_*` input parameters will overwrite the corresponding data and metadata of the
2519		/// ledger associated with the stash. If the input parameters are not set, the ledger will
2520		/// be reset values from on-chain state.
2521		#[pallet::call_index(29)]
2522		#[pallet::weight(T::WeightInfo::restore_ledger())]
2523		pub fn restore_ledger(
2524			origin: OriginFor<T>,
2525			stash: T::AccountId,
2526			maybe_controller: Option<T::AccountId>,
2527			maybe_total: Option<BalanceOf<T>>,
2528			maybe_unlocking: Option<BoundedVec<UnlockChunk<BalanceOf<T>>, T::MaxUnlockingChunks>>,
2529		) -> DispatchResult {
2530			T::AdminOrigin::ensure_origin(origin)?;
2531
2532			// cannot restore ledger for virtual stakers.
2533			ensure!(!Self::is_virtual_staker(&stash), Error::<T>::VirtualStakerNotAllowed);
2534
2535			let current_lock = asset::staked::<T>(&stash);
2536			let stash_balance = asset::stakeable_balance::<T>(&stash);
2537
2538			let (new_controller, new_total) = match Self::inspect_bond_state(&stash) {
2539				Ok(LedgerIntegrityState::Corrupted) => {
2540					let new_controller = maybe_controller.unwrap_or(stash.clone());
2541
2542					let new_total = if let Some(total) = maybe_total {
2543						let new_total = total.min(stash_balance);
2544						// enforce hold == ledger.amount.
2545						asset::update_stake::<T>(&stash, new_total)?;
2546						new_total
2547					} else {
2548						current_lock
2549					};
2550
2551					Ok((new_controller, new_total))
2552				},
2553				Ok(LedgerIntegrityState::CorruptedKilled) => {
2554					if current_lock == Zero::zero() {
2555						// this case needs to restore both lock and ledger, so the new total needs
2556						// to be given by the called since there's no way to restore the total
2557						// on-chain.
2558						ensure!(maybe_total.is_some(), Error::<T>::CannotRestoreLedger);
2559						Ok((
2560							stash.clone(),
2561							maybe_total.expect("total exists as per the check above; qed."),
2562						))
2563					} else {
2564						Ok((stash.clone(), current_lock))
2565					}
2566				},
2567				Ok(LedgerIntegrityState::LockCorrupted) => {
2568					// ledger is not corrupted but its locks are out of sync. In this case, we need
2569					// to enforce a new ledger.total and staking lock for this stash.
2570					let new_total =
2571						maybe_total.ok_or(Error::<T>::CannotRestoreLedger)?.min(stash_balance);
2572					asset::update_stake::<T>(&stash, new_total)?;
2573
2574					Ok((stash.clone(), new_total))
2575				},
2576				Err(Error::<T>::BadState) => {
2577					// the stash and ledger do not exist but lock is lingering.
2578					asset::kill_stake::<T>(&stash)?;
2579					ensure!(
2580						Self::inspect_bond_state(&stash) == Err(Error::<T>::NotStash),
2581						Error::<T>::BadState
2582					);
2583
2584					return Ok(());
2585				},
2586				Ok(LedgerIntegrityState::Ok) | Err(_) => Err(Error::<T>::CannotRestoreLedger),
2587			}?;
2588
2589			// re-bond stash and controller tuple.
2590			Bonded::<T>::insert(&stash, &new_controller);
2591
2592			// resoter ledger state.
2593			let mut ledger = StakingLedger::<T>::new(stash.clone(), new_total);
2594			ledger.controller = Some(new_controller);
2595			ledger.unlocking = maybe_unlocking.unwrap_or_default();
2596			ledger.update()?;
2597
2598			ensure!(
2599				Self::inspect_bond_state(&stash) == Ok(LedgerIntegrityState::Ok),
2600				Error::<T>::BadState
2601			);
2602			Ok(())
2603		}
2604
2605		/// Migrates permissionlessly a stash from locks to holds.
2606		///
2607		/// This removes the old lock on the stake and creates a hold on it atomically. If all
2608		/// stake cannot be held, the best effort is made to hold as much as possible. The remaining
2609		/// stake is removed from the ledger.
2610		///
2611		/// The fee is waived if the migration is successful.
2612		#[pallet::call_index(30)]
2613		#[pallet::weight(T::WeightInfo::migrate_currency())]
2614		pub fn migrate_currency(
2615			origin: OriginFor<T>,
2616			stash: T::AccountId,
2617		) -> DispatchResultWithPostInfo {
2618			let _ = ensure_signed(origin)?;
2619			Self::do_migrate_currency(&stash)?;
2620
2621			// Refund the transaction fee if successful.
2622			Ok(Pays::No.into())
2623		}
2624
2625		/// Manually and permissionlessly applies a deferred slash for a given era.
2626		///
2627		/// Normally, slashes are automatically applied shortly after the start of the `slash_era`.
2628		/// The automatic application of slashes is handled by the pallet's internal logic, and it
2629		/// tries to apply one slash page per block of the era.
2630		/// If for some reason, one era is not enough for applying all slash pages, the remaining
2631		/// slashes need to be manually (permissionlessly) applied.
2632		///
2633		/// For a given era x, if at era x+1, slashes are still unapplied, all withdrawals get
2634		/// blocked, and these need to be manually applied by calling this function.
2635		/// This function exists as a **fallback mechanism** for this extreme situation, but we
2636		/// never expect to encounter this in normal scenarios.
2637		///
2638		/// The parameters for this call can be queried by looking at the `UnappliedSlashes` storage
2639		/// for eras older than the active era.
2640		///
2641		/// ## Parameters
2642		/// - `slash_era`: The staking era in which the slash was originally scheduled.
2643		/// - `slash_key`: A unique identifier for the slash, represented as a tuple:
2644		///   - `stash`: The stash account of the validator being slashed.
2645		///   - `slash_fraction`: The fraction of the stake that was slashed.
2646		///   - `page_index`: The index of the exposure page being processed.
2647		///
2648		/// ## Behavior
2649		/// - The function is **permissionless**—anyone can call it.
2650		/// - The `slash_era` **must be the current era or a past era**.
2651		/// If it is in the future, the
2652		///   call fails with `EraNotStarted`.
2653		/// - The fee is waived if the slash is successfully applied.
2654		///
2655		/// ## Future Improvement
2656		/// - Implement an **off-chain worker (OCW) task** to automatically apply slashes when there
2657		///   is unused block space, improving efficiency.
2658		#[pallet::call_index(31)]
2659		#[pallet::weight(T::WeightInfo::apply_slash())]
2660		pub fn apply_slash(
2661			origin: OriginFor<T>,
2662			slash_era: EraIndex,
2663			slash_key: (T::AccountId, Perbill, u32),
2664		) -> DispatchResultWithPostInfo {
2665			let _ = ensure_signed(origin)?;
2666			let active_era = ActiveEra::<T>::get().map(|a| a.index).unwrap_or_default();
2667			ensure!(slash_era <= active_era, Error::<T>::EraNotStarted);
2668
2669			// Check if this slash has been cancelled
2670			ensure!(
2671				!Self::check_slash_cancelled(slash_era, &slash_key.0, slash_key.1),
2672				Error::<T>::CancelledSlash
2673			);
2674
2675			let unapplied_slash = UnappliedSlashes::<T>::take(&slash_era, &slash_key)
2676				.ok_or(Error::<T>::InvalidSlashRecord)?;
2677			slashing::apply_slash::<T>(unapplied_slash, slash_era);
2678
2679			Ok(Pays::No.into())
2680		}
2681
2682		/// Perform one step of era pruning to prevent PoV size exhaustion from unbounded deletions.
2683		///
2684		/// This extrinsic enables permissionless lazy pruning of era data by performing
2685		/// incremental deletion of storage items. Each call processes a limited number
2686		/// of items based on available block weight to avoid exceeding block limits.
2687		///
2688		/// Returns `Pays::No` when work is performed to incentivize regular maintenance.
2689		/// Anyone can call this to help maintain the chain's storage health.
2690		///
2691		/// The era must be eligible for pruning (older than HistoryDepth + 1).
2692		/// Check `EraPruningState` storage to see if an era needs pruning before calling.
2693		#[pallet::call_index(32)]
2694		// NOTE: as pre-dispatch weight, use the maximum of all possible pruning step weights
2695		#[pallet::weight({
2696			let v = T::MaxValidatorSet::get();
2697			T::WeightInfo::prune_era_stakers_paged(v)
2698				.max(T::WeightInfo::prune_era_stakers_overview(v))
2699				.max(T::WeightInfo::prune_era_validator_prefs(v))
2700				.max(T::WeightInfo::prune_era_claimed_rewards(v))
2701				.max(T::WeightInfo::prune_era_validator_reward())
2702				.max(T::WeightInfo::prune_era_reward_points())
2703				.max(T::WeightInfo::prune_era_total_stake())
2704		})]
2705		pub fn prune_era_step(origin: OriginFor<T>, era: EraIndex) -> DispatchResultWithPostInfo {
2706			let _ = ensure_signed(origin)?;
2707
2708			// Verify era is eligible for pruning: era <= active_era - history_depth - 1
2709			let active_era = crate::session_rotation::Rotator::<T>::active_era();
2710			let history_depth = T::HistoryDepth::get();
2711			let earliest_prunable_era = active_era.saturating_sub(history_depth).saturating_sub(1);
2712			ensure!(era <= earliest_prunable_era, Error::<T>::EraNotPrunable);
2713
2714			let actual_weight = Self::do_prune_era_step(era)?;
2715
2716			Ok(frame_support::dispatch::PostDispatchInfo {
2717				actual_weight: Some(actual_weight),
2718				pays_fee: frame_support::dispatch::Pays::No,
2719			})
2720		}
2721	}
2722}