Skip to main content

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