pallet_staking_async/pallet/
mod.rs

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