From 90d158634a57853ee53a4afd9c2a3659a29e4fcb Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 23 Nov 2023 02:06:07 +0100
Subject: [PATCH 001/202] traits for delegation based staking

---
 .../primitives/staking/src/delegation.rs      | 138 ++++++++++++++++++
 substrate/primitives/staking/src/lib.rs       |   1 +
 2 files changed, 139 insertions(+)
 create mode 100644 substrate/primitives/staking/src/delegation.rs

diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
new file mode 100644
index 0000000000000..2b6b34211e563
--- /dev/null
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -0,0 +1,138 @@
+// This file is part of Substrate.
+
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use codec::{FullCodec, MaxEncodedLen};
+use scale_info::TypeInfo;
+use sp_runtime::{
+	DispatchResult, Saturating,
+};
+use sp_std::{ops::Sub};
+
+/// Allows an account to accept stake delegations and manage its operations.
+pub trait StakeDelegatee {
+	/// Balance type used by the staking system.
+	type Balance: Sub<Output = Self::Balance>
+	+ Ord
+	+ PartialEq
+	+ Default
+	+ Copy
+	+ MaxEncodedLen
+	+ FullCodec
+	+ TypeInfo
+	+ Saturating;
+
+	/// AccountId type used by the staking system.
+	type AccountId: Clone + sp_std::fmt::Debug;
+
+	/// Total delegated balance to this account.
+	fn balance(who: Self::AccountId) -> Self::Balance;
+
+	/// Set intention to accept delegations.
+	fn accept_delegations(delegatee: &Self::AccountId, payee: &Self::AccountId) -> DispatchResult;
+
+	/// Stop accepting new delegations on this account.
+	///
+	/// The account would continue to be a delegatee until all delegations to this account has been
+	/// withdrawn.
+	fn block_delegations(delegatee: &Self::AccountId) -> DispatchResult;
+
+	/// Remove oneself as Delegatee.
+	///
+	/// This will only succeed if all delegations to this delegatee are withdrawn.
+	fn kill_delegatee(delegatee: &Self::AccountId) -> DispatchResult;
+
+	/// Update bond whenever there is a new delegate funds that are not staked.
+	fn update_bond(delegatee: &Self::AccountId) -> DispatchResult;
+
+	/// Applies a pending slash on delegatee by passing a delegator account who should be slashed
+	/// and the value to be slashed. Optionally also takes a reporter account who will be rewarded
+	/// from part of the slash imbalance.
+	fn apply_slash(
+		delegatee: &Self::AccountId,
+		delegator: &Self::AccountId,
+		value: Self::Balance,
+		reporter: Option<Self::AccountId>,
+	) -> DispatchResult;
+
+	/// Migrate a nominator account into a delegatee by moving its funds to delegator account and
+	/// delegating these funds back to delegatee.
+	///
+	/// Also takes input a payee which will be the new reward destination for the new delegatee.
+	///
+	/// This is useful for migrating old pool accounts to use delegation by providing a pool
+	/// delegator account. This pool delegator account funds can then lazily move funds to actual
+	/// delegators using [`Self::delegator_migrate`].
+	///
+	/// Note: Potentially unsafe and should be only called by trusted runtime code.
+	fn delegatee_migrate(
+		new_delegatee: &Self::AccountId,
+		proxy_delegator: &Self::AccountId,
+		payee: &Self::AccountId,
+	) -> DispatchResult;
+
+	/// Swap a delegated `value` from `delegator_from` to `delegator_to`, with delegatee remaining
+	/// the same.
+	///
+	/// This is useful for migrating old pool accounts using direct staking to lazily move
+	/// delegators to the new delegated pool account.
+	///
+	/// Note: Potentially unsafe and should be only called by trusted runtime code.
+	fn delegator_migrate(
+		delegator_from: &Self::AccountId,
+		delegator_to: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		value: Self::Balance,
+	) -> DispatchResult;
+
+}
+
+/// Allows an account to delegate their stakes to a delegatee.
+pub trait StakeDelegator {
+	type Balance: Sub<Output = Self::Balance>
+	+ Ord
+	+ PartialEq
+	+ Default
+	+ Copy
+	+ MaxEncodedLen
+	+ FullCodec
+	+ TypeInfo
+	+ Saturating;
+
+	/// AccountId type used by the staking system.
+	type AccountId: Clone + sp_std::fmt::Debug;
+
+	/// Delegate some funds to a Delegatee
+	fn delegate(
+		delegator: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		value: Self::Balance,
+	) -> DispatchResult;
+
+	/// Request removal of delegated stake.
+	fn request_undelegate(
+		delegator: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		value: Self::Balance,
+	) -> DispatchResult;
+
+	/// Request removal of delegated stake.
+	fn withdraw (
+		delegator: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		value: Self::Balance,
+	) -> DispatchResult;
+}
\ No newline at end of file
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index c2ac5ae004b1b..b4fe09b5aeb15 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -32,6 +32,7 @@ use sp_std::{collections::btree_map::BTreeMap, ops::Sub, vec, vec::Vec};
 pub mod offence;
 
 pub mod currency_to_vote;
+mod delegation;
 
 /// Simple index type with which we can count sessions.
 pub type SessionIndex = u32;

From e3baa64eaca698aa3bddb36f0feae9c6bf1dd730 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 23 Nov 2023 02:48:18 +0100
Subject: [PATCH 002/202] pallet init

---
 Cargo.lock                                  | 13 ++++
 Cargo.toml                                  |  1 +
 substrate/frame/staking-delegate/Cargo.toml | 43 +++++++++++
 substrate/frame/staking-delegate/src/lib.rs | 80 +++++++++++++++++++++
 4 files changed, 137 insertions(+)
 create mode 100644 substrate/frame/staking-delegate/Cargo.toml
 create mode 100644 substrate/frame/staking-delegate/src/lib.rs

diff --git a/Cargo.lock b/Cargo.lock
index 6d976452e4c3d..83d8ea617a6f5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -10765,6 +10765,19 @@ dependencies = [
  "substrate-test-utils",
 ]
 
+[[package]]
+name = "pallet-staking-delegate"
+version = "4.0.0-dev"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "parity-scale-codec",
+ "scale-info",
+ "sp-core",
+ "sp-io",
+ "sp-std 8.0.0",
+]
+
 [[package]]
 name = "pallet-staking-reward-curve"
 version = "4.0.0-dev"
diff --git a/Cargo.toml b/Cargo.toml
index 0091c2d7c8beb..98d41bb99e173 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -359,6 +359,7 @@ members = [
 	"substrate/frame/staking/reward-curve",
 	"substrate/frame/staking/reward-fn",
 	"substrate/frame/staking/runtime-api",
+	"substrate/frame/staking-delegate",
 	"substrate/frame/state-trie-migration",
 	"substrate/frame/statement",
 	"substrate/frame/sudo",
diff --git a/substrate/frame/staking-delegate/Cargo.toml b/substrate/frame/staking-delegate/Cargo.toml
new file mode 100644
index 0000000000000..f9fff42ff10df
--- /dev/null
+++ b/substrate/frame/staking-delegate/Cargo.toml
@@ -0,0 +1,43 @@
+[package]
+name = "pallet-staking-delegate"
+version = "4.0.0-dev"
+authors.workspace = true
+edition.workspace = true
+license = "Apache-2.0"
+homepage = "https://substrate.io"
+repository.workspace = true
+description = "FRAME safe-mode pallet"
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
+
+[dependencies]
+codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] }
+frame-support = { path = "../support", default-features = false}
+frame-system = { path = "../system", default-features = false}
+scale-info = { version = "2.10.0", default-features = false, features = ["derive"] }
+sp-std = { path = "../../primitives/std", default-features = false}
+
+[dev-dependencies]
+sp-core = { path = "../../primitives/core" }
+sp-io = { path = "../../primitives/io" }
+
+[features]
+default = [ "std" ]
+std = [
+    "codec/std",
+    "frame-support/std",
+    "frame-system/std",
+    "scale-info/std",
+    "sp-core/std",
+    "sp-io/std",
+    "sp-std/std",
+]
+runtime-benchmarks = [
+    "frame-support/runtime-benchmarks",
+    "frame-system/runtime-benchmarks",
+]
+try-runtime = [
+    "frame-support/try-runtime",
+    "frame-system/try-runtime",
+]
diff --git a/substrate/frame/staking-delegate/src/lib.rs b/substrate/frame/staking-delegate/src/lib.rs
new file mode 100644
index 0000000000000..703e9b3cd7082
--- /dev/null
+++ b/substrate/frame/staking-delegate/src/lib.rs
@@ -0,0 +1,80 @@
+// This file is part of Substrate.
+
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+use frame_support::{
+	pallet_prelude::*,
+	traits::fungible::{hold::Mutate as FunHoldMutate, Inspect as FunInspect},
+};
+use frame_system::pallet_prelude::*;
+use sp_std::{convert::TryInto, prelude::*};
+use pallet::*;
+
+pub type BalanceOf<T> = <<T as Config>::Currency as FunInspect<<T as frame_system::Config>::AccountId>>::Balance;
+
+#[frame_support::pallet]
+pub mod pallet {
+	use super::*;
+
+	#[pallet::pallet]
+	pub struct Pallet<T>(PhantomData<T>);
+
+	#[pallet::config]
+	pub trait Config: frame_system::Config {
+		/// The overarching event type.
+		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
+
+		type Currency: FunHoldMutate<
+			Self::AccountId,
+			Reason = Self::RuntimeHoldReason
+		>;
+		/// Overarching hold reason.
+		type RuntimeHoldReason: From<HoldReason>;
+	}
+
+	#[pallet::error]
+	pub enum Error<T> {
+		/// The account cannot perform this operation.
+		NotAllowed,
+		/// Delegation conditions are not met.
+		///
+		/// Possible issues are
+		/// 1) Account does not accept or has blocked delegation.
+		/// 2) Cannot delegate to self,
+		/// 3) Cannot delegate to multiple Delegatees,
+		InvalidDelegation,
+		/// The account does not have enough funds to perform the operation.
+		NotEnoughFunds,
+	}
+
+	/// A reason for placing a hold on funds.
+	#[pallet::composite_enum]
+	pub enum HoldReason {
+		/// Funds held for stake delegation to another account.
+		#[codec(index = 0)]
+		Delegating,
+	}
+
+	#[pallet::event]
+	#[pallet::generate_deposit(pub(super) fn deposit_event)]
+	pub enum Event<T: Config> {
+		Delegated { delegatee: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
+		Withdrawn { delegatee: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
+	}
+}

From 874c1342d9fea36036af71ee3473c222309977eb Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 25 Nov 2023 12:34:41 +0100
Subject: [PATCH 003/202] impl interfaces with todos

---
 Cargo.lock                                  |   2 +
 substrate/frame/staking-delegate/Cargo.toml |   7 ++
 substrate/frame/staking-delegate/src/lib.rs | 100 ++++++++++++++++++++
 substrate/primitives/staking/src/lib.rs     |   2 +-
 4 files changed, 110 insertions(+), 1 deletion(-)

diff --git a/Cargo.lock b/Cargo.lock
index 83d8ea617a6f5..9d8ae5e9d4825 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -10775,6 +10775,8 @@ dependencies = [
  "scale-info",
  "sp-core",
  "sp-io",
+ "sp-runtime",
+ "sp-staking",
  "sp-std 8.0.0",
 ]
 
diff --git a/substrate/frame/staking-delegate/Cargo.toml b/substrate/frame/staking-delegate/Cargo.toml
index f9fff42ff10df..ae957c9f5f669 100644
--- a/substrate/frame/staking-delegate/Cargo.toml
+++ b/substrate/frame/staking-delegate/Cargo.toml
@@ -17,6 +17,8 @@ frame-support = { path = "../support", default-features = false}
 frame-system = { path = "../system", default-features = false}
 scale-info = { version = "2.10.0", default-features = false, features = ["derive"] }
 sp-std = { path = "../../primitives/std", default-features = false}
+sp-runtime = { path = "../../primitives/runtime", default-features = false}
+sp-staking = { path = "../../primitives/staking", default-features = false }
 
 [dev-dependencies]
 sp-core = { path = "../../primitives/core" }
@@ -32,12 +34,17 @@ std = [
     "sp-core/std",
     "sp-io/std",
     "sp-std/std",
+    "sp-runtime/std",
+    "sp-staking/std",
 ]
 runtime-benchmarks = [
     "frame-support/runtime-benchmarks",
     "frame-system/runtime-benchmarks",
+    "sp-runtime/runtime-benchmarks",
+    "sp-staking/runtime-benchmarks",
 ]
 try-runtime = [
     "frame-support/try-runtime",
     "frame-system/try-runtime",
+    "sp-runtime/try-runtime",
 ]
diff --git a/substrate/frame/staking-delegate/src/lib.rs b/substrate/frame/staking-delegate/src/lib.rs
index 703e9b3cd7082..fac3847c5f022 100644
--- a/substrate/frame/staking-delegate/src/lib.rs
+++ b/substrate/frame/staking-delegate/src/lib.rs
@@ -25,6 +25,8 @@ use frame_support::{
 use frame_system::pallet_prelude::*;
 use sp_std::{convert::TryInto, prelude::*};
 use pallet::*;
+use sp_runtime::{traits::Zero, DispatchError, RuntimeDebug, Saturating};
+use sp_staking::delegation::{StakeDelegatee, StakeDelegator};
 
 pub type BalanceOf<T> = <<T as Config>::Currency as FunInspect<<T as frame_system::Config>::AccountId>>::Balance;
 
@@ -77,4 +79,102 @@ pub mod pallet {
 		Delegated { delegatee: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
 		Withdrawn { delegatee: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
 	}
+
+	/// Map of Delegators to their delegation.
+	///
+	/// Note: We are not using a double map with delegator and delegatee account as keys since we
+	/// want to restrict delegators to delegate only to one account.
+	#[pallet::storage]
+	pub(crate) type Delegators<T: Config> =
+	CountedStorageMap<_, Twox64Concat, T::AccountId, (T::AccountId, BalanceOf<T>), OptionQuery>;
+
+	/// Map of Delegatee to their Ledger.
+	#[pallet::storage]
+	pub(crate) type Delegatees<T: Config> = CountedStorageMap<
+		_,
+		Twox64Concat,
+		T::AccountId,
+		DelegationRegister<T>,
+		OptionQuery,
+	>;
+}
+
+impl<T: Config> StakeDelegatee for Pallet<T> {
+	type AccountId = T::AccountId;
+	type Balance = BalanceOf<T>;
+
+	fn balance(who: Self::AccountId) -> Self::Balance {
+		todo!()
+	}
+
+	fn accept_delegations(delegatee: &Self::AccountId, payee: &Self::AccountId) -> sp_runtime::DispatchResult {
+		todo!()
+	}
+
+	fn block_delegations(delegatee: &Self::AccountId) -> sp_runtime::DispatchResult {
+		todo!()
+	}
+
+	fn kill_delegatee(delegatee: &Self::AccountId) -> sp_runtime::DispatchResult {
+		todo!()
+	}
+
+	fn update_bond(delegatee: &Self::AccountId) -> sp_runtime::DispatchResult {
+		todo!()
+	}
+
+	fn apply_slash(delegatee: &Self::AccountId, delegator: &Self::AccountId, value: Self::Balance, reporter: Option<Self::AccountId>) -> sp_runtime::DispatchResult {
+		todo!()
+	}
+
+	fn delegatee_migrate(new_delegatee: &Self::AccountId, proxy_delegator: &Self::AccountId, payee: &Self::AccountId) -> sp_runtime::DispatchResult {
+		todo!()
+	}
+
+	fn delegator_migrate(delegator_from: &Self::AccountId, delegator_to: &Self::AccountId, delegatee: &Self::AccountId, value: Self::Balance) -> sp_runtime::DispatchResult {
+		todo!()
+	}
+}
+
+impl<T: Config> StakeDelegator for Pallet<T> {
+	type AccountId = T::AccountId;
+	type Balance = BalanceOf<T>;
+
+	fn delegate(delegator: &Self::AccountId, delegatee: &Self::AccountId, value: Self::Balance) -> sp_runtime::DispatchResult {
+		todo!()
+	}
+
+	fn request_undelegate(delegator: &Self::AccountId, delegatee: &Self::AccountId, value: Self::Balance) -> sp_runtime::DispatchResult {
+		todo!()
+	}
+
+	fn withdraw(delegator: &Self::AccountId, delegatee: &Self::AccountId, value: Self::Balance) -> sp_runtime::DispatchResult {
+		todo!()
+	}
+}
+
+/// Register of all delegations to a `Delegatee`.
+///
+/// This keeps track of the active balance of the delegatee that is made up from the funds that are
+/// currently delegated to this delegatee. It also tracks the pending slashes yet to be applied
+/// among other things.
+#[derive(Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
+#[scale_info(skip_type_params(T))]
+pub struct DelegationRegister<T: Config> {
+	/// Where the reward should be paid out.
+	pub payee: T::AccountId,
+	/// Sum of all delegated funds to this delegatee.
+	#[codec(compact)]
+	pub balance: BalanceOf<T>,
+	/// Slashes that are not yet applied.
+	#[codec(compact)]
+	pub pending_slash: BalanceOf<T>,
+	/// Whether this delegatee is blocked from receiving new delegations.
+	pub blocked: bool,
+}
+
+impl<T: Config> DelegationRegister<T> {
+	pub fn effective_balance(&self) -> BalanceOf<T> {
+		self.balance.saturating_sub(self.pending_slash)
+	}
 }
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index b4fe09b5aeb15..74fbbc7419f45 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -32,7 +32,7 @@ use sp_std::{collections::btree_map::BTreeMap, ops::Sub, vec, vec::Vec};
 pub mod offence;
 
 pub mod currency_to_vote;
-mod delegation;
+pub mod delegation;
 
 /// Simple index type with which we can count sessions.
 pub type SessionIndex = u32;

From af14ddf37ef9b5b8359dd7703165cdac6060a465 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 25 Nov 2023 12:51:56 +0100
Subject: [PATCH 004/202] compiles with copy impl from old branch

---
 Cargo.lock                                    |  30 ++---
 Cargo.toml                                    |   2 +-
 .../Cargo.toml                                |   2 +-
 .../src/lib.rs                                | 110 ++++++++++++++++--
 .../primitives/staking/src/delegation.rs      |   2 +-
 5 files changed, 120 insertions(+), 26 deletions(-)
 rename substrate/frame/{staking-delegate => delegated-staking}/Cargo.toml (97%)
 rename substrate/frame/{staking-delegate => delegated-staking}/src/lib.rs (62%)

diff --git a/Cargo.lock b/Cargo.lock
index 9d8ae5e9d4825..fb275c8988908 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -9676,6 +9676,21 @@ dependencies = [
  "sp-std 8.0.0",
 ]
 
+[[package]]
+name = "pallet-delegated-staking"
+version = "4.0.0-dev"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "parity-scale-codec",
+ "scale-info",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-staking",
+ "sp-std 8.0.0",
+]
+
 [[package]]
 name = "pallet-democracy"
 version = "4.0.0-dev"
@@ -10765,21 +10780,6 @@ dependencies = [
  "substrate-test-utils",
 ]
 
-[[package]]
-name = "pallet-staking-delegate"
-version = "4.0.0-dev"
-dependencies = [
- "frame-support",
- "frame-system",
- "parity-scale-codec",
- "scale-info",
- "sp-core",
- "sp-io",
- "sp-runtime",
- "sp-staking",
- "sp-std 8.0.0",
-]
-
 [[package]]
 name = "pallet-staking-reward-curve"
 version = "4.0.0-dev"
diff --git a/Cargo.toml b/Cargo.toml
index 98d41bb99e173..285a6349fffa9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -359,7 +359,7 @@ members = [
 	"substrate/frame/staking/reward-curve",
 	"substrate/frame/staking/reward-fn",
 	"substrate/frame/staking/runtime-api",
-	"substrate/frame/staking-delegate",
+	"substrate/frame/delegated-staking",
 	"substrate/frame/state-trie-migration",
 	"substrate/frame/statement",
 	"substrate/frame/sudo",
diff --git a/substrate/frame/staking-delegate/Cargo.toml b/substrate/frame/delegated-staking/Cargo.toml
similarity index 97%
rename from substrate/frame/staking-delegate/Cargo.toml
rename to substrate/frame/delegated-staking/Cargo.toml
index ae957c9f5f669..cb2d571844eab 100644
--- a/substrate/frame/staking-delegate/Cargo.toml
+++ b/substrate/frame/delegated-staking/Cargo.toml
@@ -1,5 +1,5 @@
 [package]
-name = "pallet-staking-delegate"
+name = "pallet-delegated-staking"
 version = "4.0.0-dev"
 authors.workspace = true
 edition.workspace = true
diff --git a/substrate/frame/staking-delegate/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
similarity index 62%
rename from substrate/frame/staking-delegate/src/lib.rs
rename to substrate/frame/delegated-staking/src/lib.rs
index fac3847c5f022..177bd57ea632d 100644
--- a/substrate/frame/staking-delegate/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -20,8 +20,9 @@
 
 use frame_support::{
 	pallet_prelude::*,
-	traits::fungible::{hold::Mutate as FunHoldMutate, Inspect as FunInspect},
+	traits::{fungible::{hold::Mutate as FunHoldMutate, Inspect as FunInspect}, tokens::Precision},
 };
+use frame_support::traits::tokens::{Fortitude, Preservation};
 use frame_system::pallet_prelude::*;
 use sp_std::{convert::TryInto, prelude::*};
 use pallet::*;
@@ -63,6 +64,8 @@ pub mod pallet {
 		InvalidDelegation,
 		/// The account does not have enough funds to perform the operation.
 		NotEnoughFunds,
+		/// Not an existing delegatee account.
+		NotDelegatee,
 	}
 
 	/// A reason for placing a hold on funds.
@@ -100,19 +103,44 @@ pub mod pallet {
 }
 
 impl<T: Config> StakeDelegatee for Pallet<T> {
-	type AccountId = T::AccountId;
 	type Balance = BalanceOf<T>;
+	type AccountId = T::AccountId;
 
-	fn balance(who: Self::AccountId) -> Self::Balance {
-		todo!()
+	fn delegate_balance(who: Self::AccountId) -> Self::Balance {
+		<Delegatees<T>>::get(who)
+			.map_or_else(|| 0u32.into(), |register| register.effective_balance())
 	}
 
 	fn accept_delegations(delegatee: &Self::AccountId, payee: &Self::AccountId) -> sp_runtime::DispatchResult {
-		todo!()
+		// fail if already delegatee
+		ensure!(!<Delegatees<T>>::contains_key(delegatee), Error::<T>::NotAllowed);
+		// a delegator cannot be delegatee
+		ensure!(!<Delegators<T>>::contains_key(delegatee), Error::<T>::NotAllowed);
+		// payee account cannot be same as delegatee
+		ensure!(payee != delegatee, Error::<T>::InvalidDelegation);
+
+		<Delegatees<T>>::insert(
+			delegatee,
+			DelegationRegister {
+				payee: payee.clone(),
+				balance: Zero::zero(),
+				pending_slash: Zero::zero(),
+				blocked: false,
+			},
+		);
+
+		Ok(())
 	}
 
 	fn block_delegations(delegatee: &Self::AccountId) -> sp_runtime::DispatchResult {
-		todo!()
+		<Delegatees<T>>::mutate(delegatee, |maybe_register| {
+			if let Some(register) = maybe_register {
+				register.blocked = true;
+				Ok(())
+			} else {
+				Err(Error::<T>::NotDelegatee.into())
+			}
+		})
 	}
 
 	fn kill_delegatee(delegatee: &Self::AccountId) -> sp_runtime::DispatchResult {
@@ -141,7 +169,35 @@ impl<T: Config> StakeDelegator for Pallet<T> {
 	type Balance = BalanceOf<T>;
 
 	fn delegate(delegator: &Self::AccountId, delegatee: &Self::AccountId, value: Self::Balance) -> sp_runtime::DispatchResult {
-		todo!()
+		let delegator_balance = T::Currency::reducible_balance(&delegator, Preservation::Expendable, Fortitude::Polite);
+		ensure!(value >= T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
+		ensure!(delegator_balance >= value, Error::<T>::NotEnoughFunds);
+		ensure!(delegatee != delegator, Error::<T>::InvalidDelegation);
+		ensure!(<Delegatees<T>>::contains_key(delegatee), Error::<T>::NotDelegatee);
+
+		// cannot delegate to another delegatee.
+		if <Delegatees<T>>::contains_key(delegator) {
+			return Err(Error::<T>::InvalidDelegation.into())
+		}
+
+		let new_delegation_amount =
+			if let Some((current_delegatee, current_delegation)) = <Delegators<T>>::get(delegator) {
+				ensure!(&current_delegatee == delegatee, Error::<T>::InvalidDelegation);
+				value.saturating_add(current_delegation)
+			} else {
+				value
+			};
+
+		<Delegators<T>>::insert(delegator, (delegatee, new_delegation_amount));
+		<Delegatees<T>>::mutate(delegatee, |maybe_register| {
+			if let Some(register) = maybe_register {
+				register.balance.saturating_accrue(value);
+			}
+		});
+
+		T::Currency::hold(&HoldReason::Delegating.into(), &delegator, value)?;
+
+		Ok(())
 	}
 
 	fn request_undelegate(delegator: &Self::AccountId, delegatee: &Self::AccountId, value: Self::Balance) -> sp_runtime::DispatchResult {
@@ -149,7 +205,45 @@ impl<T: Config> StakeDelegator for Pallet<T> {
 	}
 
 	fn withdraw(delegator: &Self::AccountId, delegatee: &Self::AccountId, value: Self::Balance) -> sp_runtime::DispatchResult {
-		todo!()
+		<Delegators<T>>::mutate_exists(delegator, |maybe_delegate| match maybe_delegate {
+			Some((current_delegatee, delegate_balance)) => {
+				ensure!(&current_delegatee.clone() == delegatee, Error::<T>::InvalidDelegation);
+				ensure!(*delegate_balance >= value, Error::<T>::InvalidDelegation);
+
+				delegate_balance.saturating_reduce(value);
+
+				if *delegate_balance == BalanceOf::<T>::zero() {
+					*maybe_delegate = None;
+				}
+				Ok(())
+			},
+			None => {
+				// this should never happen
+				return Err(Error::<T>::InvalidDelegation)
+			},
+		})?;
+
+		<Delegatees<T>>::mutate(delegatee, |maybe_register| match maybe_register {
+			Some(ledger) => {
+				ledger.balance.saturating_reduce(value);
+				Ok(())
+			},
+			None => {
+				// this should never happen
+				return Err(Error::<T>::InvalidDelegation)
+			},
+		})?;
+
+		let released = T::Currency::release(
+			&HoldReason::Delegating.into(),
+			&delegator,
+			value,
+			Precision::BestEffort,
+		)?;
+
+		defensive_assert!(released == value, "hold should have been released fully");
+
+		Ok(())
 	}
 }
 
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 2b6b34211e563..1837b2cc2bb19 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -39,7 +39,7 @@ pub trait StakeDelegatee {
 	type AccountId: Clone + sp_std::fmt::Debug;
 
 	/// Total delegated balance to this account.
-	fn balance(who: Self::AccountId) -> Self::Balance;
+	fn delegate_balance(who: Self::AccountId) -> Self::Balance;
 
 	/// Set intention to accept delegations.
 	fn accept_delegations(delegatee: &Self::AccountId, payee: &Self::AccountId) -> DispatchResult;

From e1ec9b20bf84611cb207ee3265637ef1f3e0a9a4 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 25 Nov 2023 13:22:55 +0100
Subject: [PATCH 005/202] build it as a wrapper over core staking

---
 substrate/frame/delegated-staking/src/lib.rs | 162 ++++++++++++++++---
 1 file changed, 139 insertions(+), 23 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 177bd57ea632d..f734c74cb4332 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -28,6 +28,7 @@ use sp_std::{convert::TryInto, prelude::*};
 use pallet::*;
 use sp_runtime::{traits::Zero, DispatchError, RuntimeDebug, Saturating};
 use sp_staking::delegation::{StakeDelegatee, StakeDelegator};
+use sp_staking::{EraIndex, Stake, StakerStatus, StakingInterface};
 
 pub type BalanceOf<T> = <<T as Config>::Currency as FunInspect<<T as frame_system::Config>::AccountId>>::Balance;
 
@@ -49,6 +50,9 @@ pub mod pallet {
 		>;
 		/// Overarching hold reason.
 		type RuntimeHoldReason: From<HoldReason>;
+
+		/// Core staking implementation.
+		type Staking: StakingInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
 	}
 
 	#[pallet::error]
@@ -102,6 +106,32 @@ pub mod pallet {
 	>;
 }
 
+/// Register of all delegations to a `Delegatee`.
+///
+/// This keeps track of the active balance of the delegatee that is made up from the funds that are
+/// currently delegated to this delegatee. It also tracks the pending slashes yet to be applied
+/// among other things.
+#[derive(Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
+#[scale_info(skip_type_params(T))]
+pub struct DelegationRegister<T: Config> {
+	/// Where the reward should be paid out.
+	pub payee: T::AccountId,
+	/// Sum of all delegated funds to this delegatee.
+	#[codec(compact)]
+	pub balance: BalanceOf<T>,
+	/// Slashes that are not yet applied.
+	#[codec(compact)]
+	pub pending_slash: BalanceOf<T>,
+	/// Whether this delegatee is blocked from receiving new delegations.
+	pub blocked: bool,
+}
+
+impl<T: Config> DelegationRegister<T> {
+	pub fn effective_balance(&self) -> BalanceOf<T> {
+		self.balance.saturating_sub(self.pending_slash)
+	}
+}
+
 impl<T: Config> StakeDelegatee for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
@@ -247,28 +277,114 @@ impl<T: Config> StakeDelegator for Pallet<T> {
 	}
 }
 
-/// Register of all delegations to a `Delegatee`.
-///
-/// This keeps track of the active balance of the delegatee that is made up from the funds that are
-/// currently delegated to this delegatee. It also tracks the pending slashes yet to be applied
-/// among other things.
-#[derive(Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
-#[scale_info(skip_type_params(T))]
-pub struct DelegationRegister<T: Config> {
-	/// Where the reward should be paid out.
-	pub payee: T::AccountId,
-	/// Sum of all delegated funds to this delegatee.
-	#[codec(compact)]
-	pub balance: BalanceOf<T>,
-	/// Slashes that are not yet applied.
-	#[codec(compact)]
-	pub pending_slash: BalanceOf<T>,
-	/// Whether this delegatee is blocked from receiving new delegations.
-	pub blocked: bool,
-}
+impl<T: Config> StakingInterface for Pallet<T> {
+	type Balance = BalanceOf<T>;
+	type AccountId = T::AccountId;
+	type CurrencyToVote = <T::Staking as StakingInterface>::CurrencyToVote;
 
-impl<T: Config> DelegationRegister<T> {
-	pub fn effective_balance(&self) -> BalanceOf<T> {
-		self.balance.saturating_sub(self.pending_slash)
+	fn minimum_nominator_bond() -> Self::Balance {
+		T::Staking::minimum_nominator_bond()
 	}
-}
+
+	fn minimum_validator_bond() -> Self::Balance {
+		T::Staking::minimum_validator_bond()
+	}
+
+	fn stash_by_ctrl(controller: &Self::AccountId) -> Result<Self::AccountId, DispatchError> {
+		T::Staking::stash_by_ctrl(controller)
+	}
+
+	fn bonding_duration() -> EraIndex {
+		T::Staking::bonding_duration()
+	}
+
+	fn current_era() -> EraIndex {
+		T::Staking::current_era()
+	}
+
+	fn stake(who: &Self::AccountId) -> Result<Stake<Self::Balance>, DispatchError> {
+		T::Staking::stake(who)
+	}
+
+	fn total_stake(who: &Self::AccountId) -> Result<Self::Balance, DispatchError> {
+		T::Staking::total_stake(who)
+	}
+
+	fn active_stake(who: &Self::AccountId) -> Result<Self::Balance, DispatchError> {
+		T::Staking::active_stake(who)
+	}
+
+	fn is_unbonding(who: &Self::AccountId) -> Result<bool, DispatchError> {
+		T::Staking::is_unbonding(who)
+	}
+
+	fn fully_unbond(who: &Self::AccountId) -> sp_runtime::DispatchResult {
+		T::Staking::fully_unbond(who)
+	}
+
+	fn bond(who: &Self::AccountId, value: Self::Balance, payee: &Self::AccountId) -> sp_runtime::DispatchResult {
+		T::Staking::bond(who, value, payee)
+	}
+
+	fn nominate(who: &Self::AccountId, validators: Vec<Self::AccountId>) -> sp_runtime::DispatchResult {
+		T::Staking::nominate(who, validators)
+	}
+
+	fn chill(who: &Self::AccountId) -> sp_runtime::DispatchResult {
+		T::Staking::chill(who)
+	}
+
+	fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> sp_runtime::DispatchResult {
+		T::Staking::bond_extra(who, extra)
+	}
+
+	fn unbond(stash: &Self::AccountId, value: Self::Balance) -> sp_runtime::DispatchResult {
+		T::Staking::unbond(stash, value)
+	}
+
+	fn withdraw_unbonded(stash: Self::AccountId, num_slashing_spans: u32) -> Result<bool, DispatchError> {
+		T::Staking::withdraw_unbonded(stash, num_slashing_spans)
+	}
+
+	fn desired_validator_count() -> u32 {
+		T::Staking::desired_validator_count()
+	}
+
+	fn election_ongoing() -> bool {
+		T::Staking::election_ongoing()
+	}
+
+	fn force_unstake(who: Self::AccountId) -> sp_runtime::DispatchResult {
+		T::Staking::force_unstake(who)
+	}
+
+	fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool {
+		T::Staking::is_exposed_in_era(who, era)
+	}
+
+	fn status(who: &Self::AccountId) -> Result<StakerStatus<Self::AccountId>, DispatchError> {
+		T::Staking::status(who)
+	}
+
+	fn is_validator(who: &Self::AccountId) -> bool {
+		T::Staking::is_validator(who)
+	}
+
+	fn nominations(who: &Self::AccountId) -> Option<Vec<Self::AccountId>> {
+		T::Staking::nominations(who)
+	}
+
+	#[cfg(feature = "runtime-benchmarks")]
+	fn max_exposure_page_size() -> sp_staking::Page {
+		T::Staking::max_exposure_page_size()
+	}
+
+	#[cfg(feature = "runtime-benchmarks")]
+	fn add_era_stakers(current_era: &EraIndex, stash: &Self::AccountId, exposures: Vec<(Self::AccountId, Self::Balance)>) {
+		T::Staking::add_era_stakers(current_era, stash, exposures)
+	}
+	#[cfg(feature = "runtime-benchmarks")]
+	fn set_current_era(era: EraIndex) {
+		T::Staking::set_current_era(era)
+	}
+}
\ No newline at end of file

From 7f9186910d7cc0de4fb27806ff321a24560cf99a Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 25 Nov 2023 16:38:47 +0100
Subject: [PATCH 006/202] refactor

---
 substrate/frame/delegated-staking/src/lib.rs  | 162 +++++++++++-------
 .../primitives/staking/src/delegation.rs      |  32 ++--
 2 files changed, 120 insertions(+), 74 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index f734c74cb4332..813443fcb06ff 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -20,17 +20,22 @@
 
 use frame_support::{
 	pallet_prelude::*,
-	traits::{fungible::{hold::Mutate as FunHoldMutate, Inspect as FunInspect}, tokens::Precision},
+	traits::{
+		fungible::{hold::Mutate as FunHoldMutate, Inspect as FunInspect},
+		tokens::{Fortitude, Precision, Preservation},
+	},
 };
-use frame_support::traits::tokens::{Fortitude, Preservation};
 use frame_system::pallet_prelude::*;
-use sp_std::{convert::TryInto, prelude::*};
 use pallet::*;
 use sp_runtime::{traits::Zero, DispatchError, RuntimeDebug, Saturating};
-use sp_staking::delegation::{StakeDelegatee, StakeDelegator};
-use sp_staking::{EraIndex, Stake, StakerStatus, StakingInterface};
+use sp_staking::{
+	delegation::{Delegatee, Delegator},
+	EraIndex, Stake, StakerStatus, StakingInterface,
+};
+use sp_std::{convert::TryInto, prelude::*};
 
-pub type BalanceOf<T> = <<T as Config>::Currency as FunInspect<<T as frame_system::Config>::AccountId>>::Balance;
+pub type BalanceOf<T> =
+	<<T as Config>::Currency as FunInspect<<T as frame_system::Config>::AccountId>>::Balance;
 
 #[frame_support::pallet]
 pub mod pallet {
@@ -44,10 +49,7 @@ pub mod pallet {
 		/// The overarching event type.
 		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
 
-		type Currency: FunHoldMutate<
-			Self::AccountId,
-			Reason = Self::RuntimeHoldReason
-		>;
+		type Currency: FunHoldMutate<Self::AccountId, Reason = Self::RuntimeHoldReason>;
 		/// Overarching hold reason.
 		type RuntimeHoldReason: From<HoldReason>;
 
@@ -93,17 +95,12 @@ pub mod pallet {
 	/// want to restrict delegators to delegate only to one account.
 	#[pallet::storage]
 	pub(crate) type Delegators<T: Config> =
-	CountedStorageMap<_, Twox64Concat, T::AccountId, (T::AccountId, BalanceOf<T>), OptionQuery>;
+		CountedStorageMap<_, Twox64Concat, T::AccountId, (T::AccountId, BalanceOf<T>), OptionQuery>;
 
 	/// Map of Delegatee to their Ledger.
 	#[pallet::storage]
-	pub(crate) type Delegatees<T: Config> = CountedStorageMap<
-		_,
-		Twox64Concat,
-		T::AccountId,
-		DelegationRegister<T>,
-		OptionQuery,
-	>;
+	pub(crate) type Delegatees<T: Config> =
+		CountedStorageMap<_, Twox64Concat, T::AccountId, DelegationRegister<T>, OptionQuery>;
 }
 
 /// Register of all delegations to a `Delegatee`.
@@ -132,7 +129,7 @@ impl<T: Config> DelegationRegister<T> {
 	}
 }
 
-impl<T: Config> StakeDelegatee for Pallet<T> {
+impl<T: Config> Delegatee for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
@@ -141,23 +138,30 @@ impl<T: Config> StakeDelegatee for Pallet<T> {
 			.map_or_else(|| 0u32.into(), |register| register.effective_balance())
 	}
 
-	fn accept_delegations(delegatee: &Self::AccountId, payee: &Self::AccountId) -> sp_runtime::DispatchResult {
-		// fail if already delegatee
-		ensure!(!<Delegatees<T>>::contains_key(delegatee), Error::<T>::NotAllowed);
-		// a delegator cannot be delegatee
-		ensure!(!<Delegators<T>>::contains_key(delegatee), Error::<T>::NotAllowed);
+	fn accept_delegations(
+		who: &Self::AccountId,
+		payee: &Self::AccountId,
+	) -> sp_runtime::DispatchResult {
+		// Existing delegatee cannot accept delegation
+		ensure!(!<Delegatees<T>>::contains_key(who), Error::<T>::NotAllowed);
+
 		// payee account cannot be same as delegatee
-		ensure!(payee != delegatee, Error::<T>::InvalidDelegation);
-
-		<Delegatees<T>>::insert(
-			delegatee,
-			DelegationRegister {
-				payee: payee.clone(),
-				balance: Zero::zero(),
-				pending_slash: Zero::zero(),
-				blocked: false,
-			},
-		);
+		ensure!(payee != who, Error::<T>::InvalidDelegation);
+
+		// if already a delegator, unblock and return success
+		<Delegatees<T>>::mutate(who, |maybe_register| {
+			if let Some(register) = maybe_register {
+				register.blocked = false;
+				register.payee = payee.clone();
+			} else {
+				*maybe_register = Some(DelegationRegister {
+					payee: payee.clone(),
+					balance: Zero::zero(),
+					pending_slash: Zero::zero(),
+					blocked: false,
+				});
+			}
+		});
 
 		Ok(())
 	}
@@ -181,25 +185,35 @@ impl<T: Config> StakeDelegatee for Pallet<T> {
 		todo!()
 	}
 
-	fn apply_slash(delegatee: &Self::AccountId, delegator: &Self::AccountId, value: Self::Balance, reporter: Option<Self::AccountId>) -> sp_runtime::DispatchResult {
+	fn apply_slash(
+		delegatee: &Self::AccountId,
+		delegator: &Self::AccountId,
+		value: Self::Balance,
+		reporter: Option<Self::AccountId>,
+	) -> sp_runtime::DispatchResult {
 		todo!()
 	}
 
-	fn delegatee_migrate(new_delegatee: &Self::AccountId, proxy_delegator: &Self::AccountId, payee: &Self::AccountId) -> sp_runtime::DispatchResult {
-		todo!()
-	}
-
-	fn delegator_migrate(delegator_from: &Self::AccountId, delegator_to: &Self::AccountId, delegatee: &Self::AccountId, value: Self::Balance) -> sp_runtime::DispatchResult {
+	fn delegatee_migrate(
+		new_delegatee: &Self::AccountId,
+		proxy_delegator: &Self::AccountId,
+		payee: &Self::AccountId,
+	) -> sp_runtime::DispatchResult {
 		todo!()
 	}
 }
 
-impl<T: Config> StakeDelegator for Pallet<T> {
+impl<T: Config> Delegator for Pallet<T> {
 	type AccountId = T::AccountId;
 	type Balance = BalanceOf<T>;
 
-	fn delegate(delegator: &Self::AccountId, delegatee: &Self::AccountId, value: Self::Balance) -> sp_runtime::DispatchResult {
-		let delegator_balance = T::Currency::reducible_balance(&delegator, Preservation::Expendable, Fortitude::Polite);
+	fn delegate(
+		delegator: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		value: Self::Balance,
+	) -> sp_runtime::DispatchResult {
+		let delegator_balance =
+			T::Currency::reducible_balance(&delegator, Preservation::Expendable, Fortitude::Polite);
 		ensure!(value >= T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
 		ensure!(delegator_balance >= value, Error::<T>::NotEnoughFunds);
 		ensure!(delegatee != delegator, Error::<T>::InvalidDelegation);
@@ -210,13 +224,14 @@ impl<T: Config> StakeDelegator for Pallet<T> {
 			return Err(Error::<T>::InvalidDelegation.into())
 		}
 
-		let new_delegation_amount =
-			if let Some((current_delegatee, current_delegation)) = <Delegators<T>>::get(delegator) {
-				ensure!(&current_delegatee == delegatee, Error::<T>::InvalidDelegation);
-				value.saturating_add(current_delegation)
-			} else {
-				value
-			};
+		let new_delegation_amount = if let Some((current_delegatee, current_delegation)) =
+			<Delegators<T>>::get(delegator)
+		{
+			ensure!(&current_delegatee == delegatee, Error::<T>::InvalidDelegation);
+			value.saturating_add(current_delegation)
+		} else {
+			value
+		};
 
 		<Delegators<T>>::insert(delegator, (delegatee, new_delegation_amount));
 		<Delegatees<T>>::mutate(delegatee, |maybe_register| {
@@ -230,11 +245,19 @@ impl<T: Config> StakeDelegator for Pallet<T> {
 		Ok(())
 	}
 
-	fn request_undelegate(delegator: &Self::AccountId, delegatee: &Self::AccountId, value: Self::Balance) -> sp_runtime::DispatchResult {
+	fn request_undelegate(
+		delegator: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		value: Self::Balance,
+	) -> sp_runtime::DispatchResult {
 		todo!()
 	}
 
-	fn withdraw(delegator: &Self::AccountId, delegatee: &Self::AccountId, value: Self::Balance) -> sp_runtime::DispatchResult {
+	fn withdraw(
+		delegator: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		value: Self::Balance,
+	) -> sp_runtime::DispatchResult {
 		<Delegators<T>>::mutate_exists(delegator, |maybe_delegate| match maybe_delegate {
 			Some((current_delegatee, delegate_balance)) => {
 				ensure!(&current_delegatee.clone() == delegatee, Error::<T>::InvalidDelegation);
@@ -275,6 +298,15 @@ impl<T: Config> StakeDelegator for Pallet<T> {
 
 		Ok(())
 	}
+
+	fn delegator_migrate(
+		delegator_from: &Self::AccountId,
+		delegator_to: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		value: Self::Balance,
+	) -> sp_runtime::DispatchResult {
+		todo!()
+	}
 }
 
 impl<T: Config> StakingInterface for Pallet<T> {
@@ -322,11 +354,18 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		T::Staking::fully_unbond(who)
 	}
 
-	fn bond(who: &Self::AccountId, value: Self::Balance, payee: &Self::AccountId) -> sp_runtime::DispatchResult {
+	fn bond(
+		who: &Self::AccountId,
+		value: Self::Balance,
+		payee: &Self::AccountId,
+	) -> sp_runtime::DispatchResult {
 		T::Staking::bond(who, value, payee)
 	}
 
-	fn nominate(who: &Self::AccountId, validators: Vec<Self::AccountId>) -> sp_runtime::DispatchResult {
+	fn nominate(
+		who: &Self::AccountId,
+		validators: Vec<Self::AccountId>,
+	) -> sp_runtime::DispatchResult {
 		T::Staking::nominate(who, validators)
 	}
 
@@ -342,7 +381,10 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		T::Staking::unbond(stash, value)
 	}
 
-	fn withdraw_unbonded(stash: Self::AccountId, num_slashing_spans: u32) -> Result<bool, DispatchError> {
+	fn withdraw_unbonded(
+		stash: Self::AccountId,
+		num_slashing_spans: u32,
+	) -> Result<bool, DispatchError> {
 		T::Staking::withdraw_unbonded(stash, num_slashing_spans)
 	}
 
@@ -380,11 +422,15 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	#[cfg(feature = "runtime-benchmarks")]
-	fn add_era_stakers(current_era: &EraIndex, stash: &Self::AccountId, exposures: Vec<(Self::AccountId, Self::Balance)>) {
+	fn add_era_stakers(
+		current_era: &EraIndex,
+		stash: &Self::AccountId,
+		exposures: Vec<(Self::AccountId, Self::Balance)>,
+	) {
 		T::Staking::add_era_stakers(current_era, stash, exposures)
 	}
 	#[cfg(feature = "runtime-benchmarks")]
 	fn set_current_era(era: EraIndex) {
 		T::Staking::set_current_era(era)
 	}
-}
\ No newline at end of file
+}
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 1837b2cc2bb19..7154d2c8c6675 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -23,7 +23,7 @@ use sp_runtime::{
 use sp_std::{ops::Sub};
 
 /// Allows an account to accept stake delegations and manage its operations.
-pub trait StakeDelegatee {
+pub trait Delegatee {
 	/// Balance type used by the staking system.
 	type Balance: Sub<Output = Self::Balance>
 	+ Ord
@@ -84,24 +84,10 @@ pub trait StakeDelegatee {
 		payee: &Self::AccountId,
 	) -> DispatchResult;
 
-	/// Swap a delegated `value` from `delegator_from` to `delegator_to`, with delegatee remaining
-	/// the same.
-	///
-	/// This is useful for migrating old pool accounts using direct staking to lazily move
-	/// delegators to the new delegated pool account.
-	///
-	/// Note: Potentially unsafe and should be only called by trusted runtime code.
-	fn delegator_migrate(
-		delegator_from: &Self::AccountId,
-		delegator_to: &Self::AccountId,
-		delegatee: &Self::AccountId,
-		value: Self::Balance,
-	) -> DispatchResult;
-
 }
 
 /// Allows an account to delegate their stakes to a delegatee.
-pub trait StakeDelegator {
+pub trait Delegator {
 	type Balance: Sub<Output = Self::Balance>
 	+ Ord
 	+ PartialEq
@@ -135,4 +121,18 @@ pub trait StakeDelegator {
 		delegatee: &Self::AccountId,
 		value: Self::Balance,
 	) -> DispatchResult;
+
+	/// Swap a delegated `value` from `delegator_from` to `delegator_to`, with delegatee remaining
+	/// the same.
+	///
+	/// This is useful for migrating old pool accounts using direct staking to lazily move
+	/// delegators to the new delegated pool account.
+	///
+	/// Note: Potentially unsafe and should be only called by trusted runtime code.
+	fn delegator_migrate(
+		delegator_from: &Self::AccountId,
+		delegator_to: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		value: Self::Balance,
+	) -> DispatchResult;
 }
\ No newline at end of file

From 7a9f4de28a6d1edfb4eb049d3d8759e39bb81e06 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 25 Nov 2023 17:26:10 +0100
Subject: [PATCH 007/202] finish refactoring delegatee

---
 substrate/frame/delegated-staking/src/lib.rs | 187 ++++++-------------
 substrate/frame/staking/src/pallet/impls.rs  |   5 +
 substrate/primitives/staking/src/lib.rs      |   3 +
 3 files changed, 63 insertions(+), 132 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 813443fcb06ff..24d528f237f2d 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -21,8 +21,9 @@
 use frame_support::{
 	pallet_prelude::*,
 	traits::{
-		fungible::{hold::Mutate as FunHoldMutate, Inspect as FunInspect},
+		fungible::{hold::Mutate as FunHoldMutate, Inspect as FunInspect, Mutate as FunMutate},
 		tokens::{Fortitude, Precision, Preservation},
+		ExistenceRequirement,
 	},
 };
 use frame_system::pallet_prelude::*;
@@ -49,7 +50,8 @@ pub mod pallet {
 		/// The overarching event type.
 		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
 
-		type Currency: FunHoldMutate<Self::AccountId, Reason = Self::RuntimeHoldReason>;
+		type Currency: FunHoldMutate<Self::AccountId, Reason = Self::RuntimeHoldReason>
+			+ FunMutate<Self::AccountId>;
 		/// Overarching hold reason.
 		type RuntimeHoldReason: From<HoldReason>;
 
@@ -72,6 +74,8 @@ pub mod pallet {
 		NotEnoughFunds,
 		/// Not an existing delegatee account.
 		NotDelegatee,
+		/// Some corruption in internal state.
+		BadState,
 	}
 
 	/// A reason for placing a hold on funds.
@@ -181,8 +185,20 @@ impl<T: Config> Delegatee for Pallet<T> {
 		todo!()
 	}
 
-	fn update_bond(delegatee: &Self::AccountId) -> sp_runtime::DispatchResult {
-		todo!()
+	fn update_bond(who: &Self::AccountId) -> sp_runtime::DispatchResult {
+		let delegatee = <Delegatees<T>>::get(who).ok_or(Error::<T>::NotDelegatee)?;
+		let delegated_balance = delegatee.effective_balance();
+
+		match T::Staking::stake(who) {
+			Ok(stake) => {
+				let unstaked_delegated_balance = delegated_balance.saturating_sub(stake.total);
+				T::Staking::bond_extra(who, unstaked_delegated_balance)
+			},
+			Err(_) => {
+				// If stake not found, it means this is the first bond
+				T::Staking::bond(who, delegated_balance, &delegatee.payee)
+			},
+		}
 	}
 
 	fn apply_slash(
@@ -194,18 +210,51 @@ impl<T: Config> Delegatee for Pallet<T> {
 		todo!()
 	}
 
+	/// Transfers funds from current staked account to `proxy_delegator`. Current staked account
+	/// becomes a delegatee with `proxy_delegator` delegating stakes to it.
 	fn delegatee_migrate(
 		new_delegatee: &Self::AccountId,
 		proxy_delegator: &Self::AccountId,
 		payee: &Self::AccountId,
 	) -> sp_runtime::DispatchResult {
-		todo!()
+		ensure!(new_delegatee != proxy_delegator, Error::<T>::InvalidDelegation);
+
+		// ensure proxy delegator has at least minimum balance to keep the account alive.
+		ensure!(
+			T::Currency::reducible_balance(
+				proxy_delegator,
+				Preservation::Expendable,
+				Fortitude::Polite
+			) > Zero::zero(),
+			Error::<T>::NotEnoughFunds
+		);
+
+		// ensure staker is a nominator
+		let status = T::Staking::status(new_delegatee)?;
+		match status {
+			StakerStatus::Nominator(_) => (),
+			_ => return Err(Error::<T>::InvalidDelegation.into()),
+		}
+
+		let stake = T::Staking::stake(new_delegatee)?;
+
+		// unlock funds from staker
+		T::Staking::force_unlock(new_delegatee)?;
+
+		// try transferring the staked amount. This should never fail but if it does, it indicates
+		// bad state and we abort.
+		T::Currency::transfer(new_delegatee, proxy_delegator, stake.total, Preservation::Expendable)
+			.map_err(|_| Error::<T>::BadState)?;
+
+		// delegate from new delegator to staker.
+		Self::accept_delegations(new_delegatee, payee)?;
+		Self::delegate(proxy_delegator, new_delegatee, stake.total)
 	}
 }
 
 impl<T: Config> Delegator for Pallet<T> {
-	type AccountId = T::AccountId;
 	type Balance = BalanceOf<T>;
+	type AccountId = T::AccountId;
 
 	fn delegate(
 		delegator: &Self::AccountId,
@@ -308,129 +357,3 @@ impl<T: Config> Delegator for Pallet<T> {
 		todo!()
 	}
 }
-
-impl<T: Config> StakingInterface for Pallet<T> {
-	type Balance = BalanceOf<T>;
-	type AccountId = T::AccountId;
-	type CurrencyToVote = <T::Staking as StakingInterface>::CurrencyToVote;
-
-	fn minimum_nominator_bond() -> Self::Balance {
-		T::Staking::minimum_nominator_bond()
-	}
-
-	fn minimum_validator_bond() -> Self::Balance {
-		T::Staking::minimum_validator_bond()
-	}
-
-	fn stash_by_ctrl(controller: &Self::AccountId) -> Result<Self::AccountId, DispatchError> {
-		T::Staking::stash_by_ctrl(controller)
-	}
-
-	fn bonding_duration() -> EraIndex {
-		T::Staking::bonding_duration()
-	}
-
-	fn current_era() -> EraIndex {
-		T::Staking::current_era()
-	}
-
-	fn stake(who: &Self::AccountId) -> Result<Stake<Self::Balance>, DispatchError> {
-		T::Staking::stake(who)
-	}
-
-	fn total_stake(who: &Self::AccountId) -> Result<Self::Balance, DispatchError> {
-		T::Staking::total_stake(who)
-	}
-
-	fn active_stake(who: &Self::AccountId) -> Result<Self::Balance, DispatchError> {
-		T::Staking::active_stake(who)
-	}
-
-	fn is_unbonding(who: &Self::AccountId) -> Result<bool, DispatchError> {
-		T::Staking::is_unbonding(who)
-	}
-
-	fn fully_unbond(who: &Self::AccountId) -> sp_runtime::DispatchResult {
-		T::Staking::fully_unbond(who)
-	}
-
-	fn bond(
-		who: &Self::AccountId,
-		value: Self::Balance,
-		payee: &Self::AccountId,
-	) -> sp_runtime::DispatchResult {
-		T::Staking::bond(who, value, payee)
-	}
-
-	fn nominate(
-		who: &Self::AccountId,
-		validators: Vec<Self::AccountId>,
-	) -> sp_runtime::DispatchResult {
-		T::Staking::nominate(who, validators)
-	}
-
-	fn chill(who: &Self::AccountId) -> sp_runtime::DispatchResult {
-		T::Staking::chill(who)
-	}
-
-	fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> sp_runtime::DispatchResult {
-		T::Staking::bond_extra(who, extra)
-	}
-
-	fn unbond(stash: &Self::AccountId, value: Self::Balance) -> sp_runtime::DispatchResult {
-		T::Staking::unbond(stash, value)
-	}
-
-	fn withdraw_unbonded(
-		stash: Self::AccountId,
-		num_slashing_spans: u32,
-	) -> Result<bool, DispatchError> {
-		T::Staking::withdraw_unbonded(stash, num_slashing_spans)
-	}
-
-	fn desired_validator_count() -> u32 {
-		T::Staking::desired_validator_count()
-	}
-
-	fn election_ongoing() -> bool {
-		T::Staking::election_ongoing()
-	}
-
-	fn force_unstake(who: Self::AccountId) -> sp_runtime::DispatchResult {
-		T::Staking::force_unstake(who)
-	}
-
-	fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool {
-		T::Staking::is_exposed_in_era(who, era)
-	}
-
-	fn status(who: &Self::AccountId) -> Result<StakerStatus<Self::AccountId>, DispatchError> {
-		T::Staking::status(who)
-	}
-
-	fn is_validator(who: &Self::AccountId) -> bool {
-		T::Staking::is_validator(who)
-	}
-
-	fn nominations(who: &Self::AccountId) -> Option<Vec<Self::AccountId>> {
-		T::Staking::nominations(who)
-	}
-
-	#[cfg(feature = "runtime-benchmarks")]
-	fn max_exposure_page_size() -> sp_staking::Page {
-		T::Staking::max_exposure_page_size()
-	}
-
-	#[cfg(feature = "runtime-benchmarks")]
-	fn add_era_stakers(
-		current_era: &EraIndex,
-		stash: &Self::AccountId,
-		exposures: Vec<(Self::AccountId, Self::Balance)>,
-	) {
-		T::Staking::add_era_stakers(current_era, stash, exposures)
-	}
-	#[cfg(feature = "runtime-benchmarks")]
-	fn set_current_era(era: EraIndex) {
-		T::Staking::set_current_era(era)
-	}
-}
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index d294686751cd0..26af96dd54e03 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1815,6 +1815,11 @@ impl<T: Config> StakingInterface for Pallet<T> {
 			T::MaxExposurePageSize::get()
 		}
 	}
+
+	fn force_unlock(who: &Self::AccountId) -> sp_runtime::DispatchResult {
+		T::Currency::remove_lock(crate::STAKING_ID, who);
+		Ok(())
+	}
 }
 
 #[cfg(any(test, feature = "try-runtime"))]
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 74fbbc7419f45..9be0e338af334 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -285,6 +285,9 @@ pub trait StakingInterface {
 		}
 	}
 
+	/// Used for migration of locks.
+	fn force_unlock(who: &Self::AccountId) -> DispatchResult;
+
 	#[cfg(feature = "runtime-benchmarks")]
 	fn max_exposure_page_size() -> Page;
 

From 4f52e4916a3a9c5eb8b0abb8abdd193160dbc678 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 25 Nov 2023 17:42:38 +0100
Subject: [PATCH 008/202] refactor migrate functions

---
 substrate/frame/delegated-staking/src/lib.rs  | 116 ++++++++++--------
 .../primitives/staking/src/delegation.rs      |  58 ++++-----
 2 files changed, 94 insertions(+), 80 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 24d528f237f2d..e3a1b48df4509 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -201,6 +201,52 @@ impl<T: Config> Delegatee for Pallet<T> {
 		}
 	}
 
+	fn withdraw(
+		delegator: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		value: Self::Balance,
+	) -> sp_runtime::DispatchResult {
+		<Delegators<T>>::mutate_exists(delegator, |maybe_delegate| match maybe_delegate {
+			Some((current_delegatee, delegate_balance)) => {
+				ensure!(&current_delegatee.clone() == delegatee, Error::<T>::NotDelegatee);
+				ensure!(*delegate_balance >= value, Error::<T>::NotAllowed);
+
+				delegate_balance.saturating_reduce(value);
+
+				if *delegate_balance == BalanceOf::<T>::zero() {
+					*maybe_delegate = None;
+				}
+				Ok(())
+			},
+			None => {
+				// delegator does not exist
+				return Err(Error::<T>::NotAllowed)
+			},
+		})?;
+
+		<Delegatees<T>>::mutate(delegatee, |maybe_register| match maybe_register {
+			Some(ledger) => {
+				ledger.balance.saturating_reduce(value);
+				Ok(())
+			},
+			None => {
+				// Delegatee not found
+				return Err(Error::<T>::NotDelegatee)
+			},
+		})?;
+
+		let released = T::Currency::release(
+			&HoldReason::Delegating.into(),
+			&delegator,
+			value,
+			Precision::BestEffort,
+		)?;
+
+		defensive_assert!(released == value, "hold should have been released fully");
+
+		Ok(())
+	}
+
 	fn apply_slash(
 		delegatee: &Self::AccountId,
 		delegator: &Self::AccountId,
@@ -243,8 +289,13 @@ impl<T: Config> Delegatee for Pallet<T> {
 
 		// try transferring the staked amount. This should never fail but if it does, it indicates
 		// bad state and we abort.
-		T::Currency::transfer(new_delegatee, proxy_delegator, stake.total, Preservation::Expendable)
-			.map_err(|_| Error::<T>::BadState)?;
+		T::Currency::transfer(
+			new_delegatee,
+			proxy_delegator,
+			stake.total,
+			Preservation::Expendable,
+		)
+		.map_err(|_| Error::<T>::BadState)?;
 
 		// delegate from new delegator to staker.
 		Self::accept_delegations(new_delegatee, payee)?;
@@ -302,58 +353,27 @@ impl<T: Config> Delegator for Pallet<T> {
 		todo!()
 	}
 
-	fn withdraw(
-		delegator: &Self::AccountId,
+	/// Move funds from proxy delegator to actual delegator.
+	// TODO: Keep track of proxy delegator and only allow movement from proxy -> new delegator
+	fn delegator_migrate(
+		existing_delegator: &Self::AccountId,
+		new_delegator: &Self::AccountId,
 		delegatee: &Self::AccountId,
 		value: Self::Balance,
 	) -> sp_runtime::DispatchResult {
-		<Delegators<T>>::mutate_exists(delegator, |maybe_delegate| match maybe_delegate {
-			Some((current_delegatee, delegate_balance)) => {
-				ensure!(&current_delegatee.clone() == delegatee, Error::<T>::InvalidDelegation);
-				ensure!(*delegate_balance >= value, Error::<T>::InvalidDelegation);
-
-				delegate_balance.saturating_reduce(value);
-
-				if *delegate_balance == BalanceOf::<T>::zero() {
-					*maybe_delegate = None;
-				}
-				Ok(())
-			},
-			None => {
-				// this should never happen
-				return Err(Error::<T>::InvalidDelegation)
-			},
-		})?;
-
-		<Delegatees<T>>::mutate(delegatee, |maybe_register| match maybe_register {
-			Some(ledger) => {
-				ledger.balance.saturating_reduce(value);
-				Ok(())
-			},
-			None => {
-				// this should never happen
-				return Err(Error::<T>::InvalidDelegation)
-			},
-		})?;
+		ensure!(value >= T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
 
-		let released = T::Currency::release(
-			&HoldReason::Delegating.into(),
-			&delegator,
-			value,
-			Precision::BestEffort,
-		)?;
+		// ensure delegatee exists.
+		ensure!(!<Delegatees<T>>::contains_key(delegatee), Error::<T>::NotDelegatee);
 
-		defensive_assert!(released == value, "hold should have been released fully");
+		// remove delegation of `value` from `existing_delegator`.
+		Self::withdraw(existing_delegator, delegatee, value)?;
 
-		Ok(())
-	}
+		// transfer the withdrawn value to `new_delegator`.
+		T::Currency::transfer(existing_delegator, new_delegator, value, Preservation::Expendable)
+			.map_err(|_| Error::<T>::BadState)?;
 
-	fn delegator_migrate(
-		delegator_from: &Self::AccountId,
-		delegator_to: &Self::AccountId,
-		delegatee: &Self::AccountId,
-		value: Self::Balance,
-	) -> sp_runtime::DispatchResult {
-		todo!()
+		// add the above removed delegation to `new_delegator`.
+		Self::delegate(new_delegator, delegatee, value)
 	}
 }
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 7154d2c8c6675..6ee556bbcb75f 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -17,23 +17,21 @@
 
 use codec::{FullCodec, MaxEncodedLen};
 use scale_info::TypeInfo;
-use sp_runtime::{
-	DispatchResult, Saturating,
-};
-use sp_std::{ops::Sub};
+use sp_runtime::{DispatchResult, Saturating};
+use sp_std::ops::Sub;
 
 /// Allows an account to accept stake delegations and manage its operations.
 pub trait Delegatee {
 	/// Balance type used by the staking system.
 	type Balance: Sub<Output = Self::Balance>
-	+ Ord
-	+ PartialEq
-	+ Default
-	+ Copy
-	+ MaxEncodedLen
-	+ FullCodec
-	+ TypeInfo
-	+ Saturating;
+		+ Ord
+		+ PartialEq
+		+ Default
+		+ Copy
+		+ MaxEncodedLen
+		+ FullCodec
+		+ TypeInfo
+		+ Saturating;
 
 	/// AccountId type used by the staking system.
 	type AccountId: Clone + sp_std::fmt::Debug;
@@ -45,9 +43,6 @@ pub trait Delegatee {
 	fn accept_delegations(delegatee: &Self::AccountId, payee: &Self::AccountId) -> DispatchResult;
 
 	/// Stop accepting new delegations on this account.
-	///
-	/// The account would continue to be a delegatee until all delegations to this account has been
-	/// withdrawn.
 	fn block_delegations(delegatee: &Self::AccountId) -> DispatchResult;
 
 	/// Remove oneself as Delegatee.
@@ -58,6 +53,13 @@ pub trait Delegatee {
 	/// Update bond whenever there is a new delegate funds that are not staked.
 	fn update_bond(delegatee: &Self::AccountId) -> DispatchResult;
 
+	/// Request removal of delegated stake.
+	fn withdraw(
+		delegatee: &Self::AccountId,
+		delegator: &Self::AccountId,
+		value: Self::Balance,
+	) -> DispatchResult;
+
 	/// Applies a pending slash on delegatee by passing a delegator account who should be slashed
 	/// and the value to be slashed. Optionally also takes a reporter account who will be rewarded
 	/// from part of the slash imbalance.
@@ -83,20 +85,19 @@ pub trait Delegatee {
 		proxy_delegator: &Self::AccountId,
 		payee: &Self::AccountId,
 	) -> DispatchResult;
-
 }
 
 /// Allows an account to delegate their stakes to a delegatee.
 pub trait Delegator {
 	type Balance: Sub<Output = Self::Balance>
-	+ Ord
-	+ PartialEq
-	+ Default
-	+ Copy
-	+ MaxEncodedLen
-	+ FullCodec
-	+ TypeInfo
-	+ Saturating;
+		+ Ord
+		+ PartialEq
+		+ Default
+		+ Copy
+		+ MaxEncodedLen
+		+ FullCodec
+		+ TypeInfo
+		+ Saturating;
 
 	/// AccountId type used by the staking system.
 	type AccountId: Clone + sp_std::fmt::Debug;
@@ -115,13 +116,6 @@ pub trait Delegator {
 		value: Self::Balance,
 	) -> DispatchResult;
 
-	/// Request removal of delegated stake.
-	fn withdraw (
-		delegator: &Self::AccountId,
-		delegatee: &Self::AccountId,
-		value: Self::Balance,
-	) -> DispatchResult;
-
 	/// Swap a delegated `value` from `delegator_from` to `delegator_to`, with delegatee remaining
 	/// the same.
 	///
@@ -135,4 +129,4 @@ pub trait Delegator {
 		delegatee: &Self::AccountId,
 		value: Self::Balance,
 	) -> DispatchResult;
-}
\ No newline at end of file
+}

From 666c50abdde75288a111c415471698fd9b5423a1 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 25 Nov 2023 17:43:48 +0100
Subject: [PATCH 009/202] fmt

---
 substrate/frame/delegated-staking/src/lib.rs | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index e3a1b48df4509..2e3a9ecc7c244 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -23,15 +23,13 @@ use frame_support::{
 	traits::{
 		fungible::{hold::Mutate as FunHoldMutate, Inspect as FunInspect, Mutate as FunMutate},
 		tokens::{Fortitude, Precision, Preservation},
-		ExistenceRequirement,
 	},
 };
-use frame_system::pallet_prelude::*;
 use pallet::*;
-use sp_runtime::{traits::Zero, DispatchError, RuntimeDebug, Saturating};
+use sp_runtime::{traits::Zero, RuntimeDebug, Saturating};
 use sp_staking::{
 	delegation::{Delegatee, Delegator},
-	EraIndex, Stake, StakerStatus, StakingInterface,
+	StakerStatus, StakingInterface,
 };
 use sp_std::{convert::TryInto, prelude::*};
 

From ba5b06e3779ad80c208b870edc1e13e2d1c9f33f Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 25 Nov 2023 19:04:45 +0100
Subject: [PATCH 010/202] bootstrap mock

---
 Cargo.lock                                    |   7 +
 substrate/frame/delegated-staking/Cargo.toml  |  19 +++
 .../delegated-staking/src/benchmarking.rs     |  20 +++
 substrate/frame/delegated-staking/src/lib.rs  |   9 ++
 substrate/frame/delegated-staking/src/mock.rs | 151 ++++++++++++++++++
 .../frame/delegated-staking/src/tests.rs      |  18 +++
 substrate/frame/staking/src/pallet/impls.rs   |   2 +-
 7 files changed, 225 insertions(+), 1 deletion(-)
 create mode 100644 substrate/frame/delegated-staking/src/benchmarking.rs
 create mode 100644 substrate/frame/delegated-staking/src/mock.rs
 create mode 100644 substrate/frame/delegated-staking/src/tests.rs

diff --git a/Cargo.lock b/Cargo.lock
index fb275c8988908..b6356a491be68 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -9680,8 +9680,13 @@ dependencies = [
 name = "pallet-delegated-staking"
 version = "4.0.0-dev"
 dependencies = [
+ "frame-election-provider-support",
  "frame-support",
  "frame-system",
+ "pallet-balances",
+ "pallet-staking",
+ "pallet-staking-reward-curve",
+ "pallet-timestamp",
  "parity-scale-codec",
  "scale-info",
  "sp-core",
@@ -9689,6 +9694,8 @@ dependencies = [
  "sp-runtime",
  "sp-staking",
  "sp-std 8.0.0",
+ "sp-tracing 10.0.0",
+ "substrate-test-utils",
 ]
 
 [[package]]
diff --git a/substrate/frame/delegated-staking/Cargo.toml b/substrate/frame/delegated-staking/Cargo.toml
index cb2d571844eab..735b2794d5eab 100644
--- a/substrate/frame/delegated-staking/Cargo.toml
+++ b/substrate/frame/delegated-staking/Cargo.toml
@@ -23,6 +23,13 @@ sp-staking = { path = "../../primitives/staking", default-features = false }
 [dev-dependencies]
 sp-core = { path = "../../primitives/core" }
 sp-io = { path = "../../primitives/io" }
+substrate-test-utils = { path = "../../test-utils" }
+sp-tracing = { path = "../../primitives/tracing" }
+pallet-staking = { path = "../staking" }
+pallet-balances = { path = "../balances" }
+pallet-timestamp = { path = "../timestamp" }
+pallet-staking-reward-curve = { path = "../staking/reward-curve" }
+frame-election-provider-support = { path = "../election-provider-support", default-features = false}
 
 [features]
 default = [ "std" ]
@@ -36,15 +43,27 @@ std = [
     "sp-std/std",
     "sp-runtime/std",
     "sp-staking/std",
+    "pallet-balances/std",
+    "pallet-staking/std",
+    "pallet-timestamp/std",
+    "frame-election-provider-support/std",
 ]
 runtime-benchmarks = [
     "frame-support/runtime-benchmarks",
     "frame-system/runtime-benchmarks",
     "sp-runtime/runtime-benchmarks",
     "sp-staking/runtime-benchmarks",
+    "pallet-balances/runtime-benchmarks",
+    "pallet-staking/runtime-benchmarks",
+    "pallet-timestamp/runtime-benchmarks",
+    "frame-election-provider-support/runtime-benchmarks",
 ]
 try-runtime = [
     "frame-support/try-runtime",
     "frame-system/try-runtime",
     "sp-runtime/try-runtime",
+    "pallet-balances/try-runtime",
+    "pallet-staking/try-runtime",
+    "pallet-timestamp/try-runtime",
+    "frame-election-provider-support/try-runtime",
 ]
diff --git a/substrate/frame/delegated-staking/src/benchmarking.rs b/substrate/frame/delegated-staking/src/benchmarking.rs
new file mode 100644
index 0000000000000..eeae5fa82e64c
--- /dev/null
+++ b/substrate/frame/delegated-staking/src/benchmarking.rs
@@ -0,0 +1,20 @@
+// This file is part of Substrate.
+
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Benchmarking for pallet-delegated-staking.
+
+#![cfg(feature = "runtime-benchmarks")]
\ No newline at end of file
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 2e3a9ecc7c244..3f3055fa01291 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -18,6 +18,15 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 #![deny(rustdoc::broken_intra_doc_links)]
 
+
+#[cfg(test)]
+mod mock;
+
+#[cfg(test)]
+mod tests;
+
+#[cfg(feature = "runtime-benchmarks")]
+mod benchmarking;
 use frame_support::{
 	pallet_prelude::*,
 	traits::{
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
new file mode 100644
index 0000000000000..74328a14e3e1b
--- /dev/null
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -0,0 +1,151 @@
+// This file is part of Substrate.
+
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use crate::{self as delegated_staking};
+use frame_support::{
+    assert_ok, derive_impl,
+    pallet_prelude::*,
+    parameter_types,
+    traits::{ConstU64, Currency},
+    weights::constants::WEIGHT_REF_TIME_PER_SECOND,
+};
+
+use sp_runtime::{
+    traits::{Convert, IdentityLookup},
+    BuildStorage,
+};
+
+use frame_election_provider_support::{
+    bounds::{ElectionBounds, ElectionBoundsBuilder},
+    onchain, SequentialPhragmen,
+};
+
+pub type T = Runtime;
+type Block = frame_system::mocking::MockBlock<Runtime>;
+pub type AccountId = u64;
+
+#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
+impl frame_system::Config for Runtime {
+    type Block = Block;
+    type AccountData = pallet_balances::AccountData<Balance>;
+    type AccountId = AccountId;
+    type Lookup = IdentityLookup<Self::AccountId>;
+}
+
+impl pallet_timestamp::Config for Runtime {
+    type Moment = u64;
+    type OnTimestampSet = ();
+    type MinimumPeriod = ConstU64<5>;
+    type WeightInfo = ();
+}
+
+pub type Balance = u128;
+
+parameter_types! {
+	pub static ExistentialDeposit: Balance = 1;
+}
+impl pallet_balances::Config for Runtime {
+    type MaxLocks = ConstU32<128>;
+    type MaxReserves = ();
+    type ReserveIdentifier = [u8; 8];
+    type Balance = Balance;
+    type RuntimeEvent = RuntimeEvent;
+    type DustRemoval = ();
+    type ExistentialDeposit = ExistentialDeposit;
+    type AccountStore = System;
+    type WeightInfo = ();
+    type FreezeIdentifier = ();
+    type MaxFreezes = ();
+    type RuntimeHoldReason = RuntimeHoldReason;
+    type RuntimeFreezeReason = ();
+    type MaxHolds = ConstU32<1>;
+}
+
+pallet_staking_reward_curve::build! {
+	const I_NPOS: sp_runtime::curve::PiecewiseLinear<'static> = curve!(
+		min_inflation: 0_025_000,
+		max_inflation: 0_100_000,
+		ideal_stake: 0_500_000,
+		falloff: 0_050_000,
+		max_piece_count: 40,
+		test_precision: 0_005_000,
+	);
+}
+
+parameter_types! {
+	pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS;
+	pub static BondingDuration: u32 = 3;
+	pub static CurrentEra: u32 = 0;
+    pub static ElectionsBoundsOnChain: ElectionBounds = ElectionBoundsBuilder::default().build();
+}
+pub struct OnChainSeqPhragmen;
+impl onchain::Config for OnChainSeqPhragmen {
+    type System = Runtime;
+    type Solver = SequentialPhragmen<u64, sp_runtime::Perbill>;
+    type DataProvider = Staking;
+    type WeightInfo = ();
+    type MaxWinners = ConstU32<100>;
+    type Bounds = ElectionsBoundsOnChain;
+}
+
+impl pallet_staking::Config for Runtime {
+    type Currency = Balances;
+    type CurrencyBalance = Balance;
+    type UnixTime = pallet_timestamp::Pallet<Self>;
+    type CurrencyToVote = ();
+    type RewardRemainder = ();
+    type RuntimeEvent = RuntimeEvent;
+    type Slash = ();
+    type Reward = ();
+    type SessionsPerEra = ();
+    type SlashDeferDuration = ();
+    type AdminOrigin = frame_system::EnsureRoot<Self::AccountId>;
+    type BondingDuration = BondingDuration;
+    type SessionInterface = ();
+    type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
+    type NextNewSession = ();
+    type HistoryDepth = ConstU32<84>;
+    type MaxExposurePageSize = ConstU32<64>;
+    type OffendingValidatorsThreshold = ();
+    type ElectionProvider = onchain::OnChainExecution<OnChainSeqPhragmen>;
+    type GenesisElectionProvider = Self::ElectionProvider;
+    type VoterList = pallet_staking::UseNominatorsAndValidatorsMap<Self>;
+    type TargetList = pallet_staking::UseValidatorsMap<Self>;
+    type NominationsQuota = pallet_staking::FixedNominationsQuota<16>;
+    type MaxUnlockingChunks = ConstU32<32>;
+    type EventListeners = ();
+    type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
+    type WeightInfo = ();
+}
+
+impl delegated_staking::Config for Runtime {
+    type RuntimeEvent = RuntimeEvent;
+    type Currency = Balances;
+    type RuntimeHoldReason = RuntimeHoldReason;
+    type Staking = Staking;
+}
+
+
+frame_support::construct_runtime!(
+	pub struct Runtime {
+		System: frame_system,
+		Timestamp: pallet_timestamp,
+		Balances: pallet_balances,
+		Staking: pallet_staking,
+		DelegatedStaking: delegated_staking,
+	}
+);
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
new file mode 100644
index 0000000000000..2654b670f6315
--- /dev/null
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -0,0 +1,18 @@
+// This file is part of Substrate.
+
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Tests for pallet-delegated-staking.
\ No newline at end of file
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 26af96dd54e03..5759650b4140c 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -27,7 +27,7 @@ use frame_support::{
 	dispatch::WithPostDispatchInfo,
 	pallet_prelude::*,
 	traits::{
-		Currency, Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance, Len,
+		Currency, LockableCurrency, Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance, Len,
 		OnUnbalanced, TryCollect, UnixTime,
 	},
 	weights::Weight,

From db7ede25e89bbe1b2f0c9c4b58fab43f35a3533f Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 2 Dec 2023 18:11:33 +0100
Subject: [PATCH 011/202] first test

---
 substrate/frame/delegated-staking/src/mock.rs | 34 +++++++++++++++++++
 .../frame/delegated-staking/src/tests.rs      | 12 ++++++-
 2 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 74328a14e3e1b..57828f1c8205c 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -149,3 +149,37 @@ frame_support::construct_runtime!(
 		DelegatedStaking: delegated_staking,
 	}
 );
+
+pub struct ExtBuilder {
+}
+
+impl Default for ExtBuilder {
+    fn default() -> Self {
+        Self {}
+    }
+}
+
+impl ExtBuilder {
+
+    fn build(self) -> sp_io::TestExternalities {
+        sp_tracing::try_init_simple();
+        let mut storage = frame_system::GenesisConfig::<Runtime>::default().build_storage().unwrap();
+
+        let mut ext = sp_io::TestExternalities::from(storage);
+
+        ext.execute_with(|| {
+            // for events to be deposited.
+            frame_system::Pallet::<Runtime>::set_block_number(1);
+        });
+
+        ext
+    }
+    pub fn build_and_execute(self, test: impl FnOnce() -> ()) {
+        sp_tracing::try_init_simple();
+        let mut ext = self.build();
+        ext.execute_with(test);
+        ext.execute_with(|| {
+            // DelegatedStaking::do_try_state().unwrap();
+        });
+    }
+}
\ No newline at end of file
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 2654b670f6315..fb86ac1394c8c 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -15,4 +15,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-//! Tests for pallet-delegated-staking.
\ No newline at end of file
+//! Tests for pallet-delegated-staking.
+
+use super::*;
+use crate::{mock::*, Event};
+#[test]
+fn hello_world_test() {
+    ExtBuilder::default().build_and_execute(|| {
+        assert!(true)
+    });
+
+}
\ No newline at end of file

From 7478f98e33743b5a9676824842a5ad6457a2d2d6 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 2 Dec 2023 18:14:47 +0100
Subject: [PATCH 012/202] empty genesis block

---
 substrate/frame/delegated-staking/src/lib.rs | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 3f3055fa01291..c7f9b4e6b34f5 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -93,6 +93,17 @@ pub mod pallet {
 		Delegating,
 	}
 
+	#[pallet::genesis_config]
+	#[derive(frame_support::DefaultNoBound)]
+	pub struct GenesisConfig<T: Config> {
+	}
+
+	#[pallet::genesis_build]
+	impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
+		fn build(&self) {
+		}
+	}
+
 	#[pallet::event]
 	#[pallet::generate_deposit(pub(super) fn deposit_event)]
 	pub enum Event<T: Config> {

From 990f38a0b558c12ffe6ab02bf8e53eb670195733 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 2 Dec 2023 18:15:51 +0100
Subject: [PATCH 013/202] fmt

---
 .../delegated-staking/src/benchmarking.rs     |   2 +-
 substrate/frame/delegated-staking/src/lib.rs  |   7 +-
 substrate/frame/delegated-staking/src/mock.rs | 192 +++++++++---------
 .../frame/delegated-staking/src/tests.rs      |   7 +-
 substrate/frame/staking/src/pallet/impls.rs   |   4 +-
 5 files changed, 102 insertions(+), 110 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/benchmarking.rs b/substrate/frame/delegated-staking/src/benchmarking.rs
index eeae5fa82e64c..808d19a5ce9ab 100644
--- a/substrate/frame/delegated-staking/src/benchmarking.rs
+++ b/substrate/frame/delegated-staking/src/benchmarking.rs
@@ -17,4 +17,4 @@
 
 //! Benchmarking for pallet-delegated-staking.
 
-#![cfg(feature = "runtime-benchmarks")]
\ No newline at end of file
+#![cfg(feature = "runtime-benchmarks")]
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index c7f9b4e6b34f5..50d0085e466ed 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -18,7 +18,6 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 #![deny(rustdoc::broken_intra_doc_links)]
 
-
 #[cfg(test)]
 mod mock;
 
@@ -95,13 +94,11 @@ pub mod pallet {
 
 	#[pallet::genesis_config]
 	#[derive(frame_support::DefaultNoBound)]
-	pub struct GenesisConfig<T: Config> {
-	}
+	pub struct GenesisConfig<T: Config> {}
 
 	#[pallet::genesis_build]
 	impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
-		fn build(&self) {
-		}
+		fn build(&self) {}
 	}
 
 	#[pallet::event]
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 57828f1c8205c..045c93e0c0204 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -17,21 +17,21 @@
 
 use crate::{self as delegated_staking};
 use frame_support::{
-    assert_ok, derive_impl,
-    pallet_prelude::*,
-    parameter_types,
-    traits::{ConstU64, Currency},
-    weights::constants::WEIGHT_REF_TIME_PER_SECOND,
+	assert_ok, derive_impl,
+	pallet_prelude::*,
+	parameter_types,
+	traits::{ConstU64, Currency},
+	weights::constants::WEIGHT_REF_TIME_PER_SECOND,
 };
 
 use sp_runtime::{
-    traits::{Convert, IdentityLookup},
-    BuildStorage,
+	traits::{Convert, IdentityLookup},
+	BuildStorage,
 };
 
 use frame_election_provider_support::{
-    bounds::{ElectionBounds, ElectionBoundsBuilder},
-    onchain, SequentialPhragmen,
+	bounds::{ElectionBounds, ElectionBoundsBuilder},
+	onchain, SequentialPhragmen,
 };
 
 pub type T = Runtime;
@@ -40,17 +40,17 @@ pub type AccountId = u64;
 
 #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
 impl frame_system::Config for Runtime {
-    type Block = Block;
-    type AccountData = pallet_balances::AccountData<Balance>;
-    type AccountId = AccountId;
-    type Lookup = IdentityLookup<Self::AccountId>;
+	type Block = Block;
+	type AccountData = pallet_balances::AccountData<Balance>;
+	type AccountId = AccountId;
+	type Lookup = IdentityLookup<Self::AccountId>;
 }
 
 impl pallet_timestamp::Config for Runtime {
-    type Moment = u64;
-    type OnTimestampSet = ();
-    type MinimumPeriod = ConstU64<5>;
-    type WeightInfo = ();
+	type Moment = u64;
+	type OnTimestampSet = ();
+	type MinimumPeriod = ConstU64<5>;
+	type WeightInfo = ();
 }
 
 pub type Balance = u128;
@@ -59,20 +59,20 @@ parameter_types! {
 	pub static ExistentialDeposit: Balance = 1;
 }
 impl pallet_balances::Config for Runtime {
-    type MaxLocks = ConstU32<128>;
-    type MaxReserves = ();
-    type ReserveIdentifier = [u8; 8];
-    type Balance = Balance;
-    type RuntimeEvent = RuntimeEvent;
-    type DustRemoval = ();
-    type ExistentialDeposit = ExistentialDeposit;
-    type AccountStore = System;
-    type WeightInfo = ();
-    type FreezeIdentifier = ();
-    type MaxFreezes = ();
-    type RuntimeHoldReason = RuntimeHoldReason;
-    type RuntimeFreezeReason = ();
-    type MaxHolds = ConstU32<1>;
+	type MaxLocks = ConstU32<128>;
+	type MaxReserves = ();
+	type ReserveIdentifier = [u8; 8];
+	type Balance = Balance;
+	type RuntimeEvent = RuntimeEvent;
+	type DustRemoval = ();
+	type ExistentialDeposit = ExistentialDeposit;
+	type AccountStore = System;
+	type WeightInfo = ();
+	type FreezeIdentifier = ();
+	type MaxFreezes = ();
+	type RuntimeHoldReason = RuntimeHoldReason;
+	type RuntimeFreezeReason = ();
+	type MaxHolds = ConstU32<1>;
 }
 
 pallet_staking_reward_curve::build! {
@@ -90,56 +90,55 @@ parameter_types! {
 	pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS;
 	pub static BondingDuration: u32 = 3;
 	pub static CurrentEra: u32 = 0;
-    pub static ElectionsBoundsOnChain: ElectionBounds = ElectionBoundsBuilder::default().build();
+	pub static ElectionsBoundsOnChain: ElectionBounds = ElectionBoundsBuilder::default().build();
 }
 pub struct OnChainSeqPhragmen;
 impl onchain::Config for OnChainSeqPhragmen {
-    type System = Runtime;
-    type Solver = SequentialPhragmen<u64, sp_runtime::Perbill>;
-    type DataProvider = Staking;
-    type WeightInfo = ();
-    type MaxWinners = ConstU32<100>;
-    type Bounds = ElectionsBoundsOnChain;
+	type System = Runtime;
+	type Solver = SequentialPhragmen<u64, sp_runtime::Perbill>;
+	type DataProvider = Staking;
+	type WeightInfo = ();
+	type MaxWinners = ConstU32<100>;
+	type Bounds = ElectionsBoundsOnChain;
 }
 
 impl pallet_staking::Config for Runtime {
-    type Currency = Balances;
-    type CurrencyBalance = Balance;
-    type UnixTime = pallet_timestamp::Pallet<Self>;
-    type CurrencyToVote = ();
-    type RewardRemainder = ();
-    type RuntimeEvent = RuntimeEvent;
-    type Slash = ();
-    type Reward = ();
-    type SessionsPerEra = ();
-    type SlashDeferDuration = ();
-    type AdminOrigin = frame_system::EnsureRoot<Self::AccountId>;
-    type BondingDuration = BondingDuration;
-    type SessionInterface = ();
-    type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
-    type NextNewSession = ();
-    type HistoryDepth = ConstU32<84>;
-    type MaxExposurePageSize = ConstU32<64>;
-    type OffendingValidatorsThreshold = ();
-    type ElectionProvider = onchain::OnChainExecution<OnChainSeqPhragmen>;
-    type GenesisElectionProvider = Self::ElectionProvider;
-    type VoterList = pallet_staking::UseNominatorsAndValidatorsMap<Self>;
-    type TargetList = pallet_staking::UseValidatorsMap<Self>;
-    type NominationsQuota = pallet_staking::FixedNominationsQuota<16>;
-    type MaxUnlockingChunks = ConstU32<32>;
-    type EventListeners = ();
-    type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
-    type WeightInfo = ();
+	type Currency = Balances;
+	type CurrencyBalance = Balance;
+	type UnixTime = pallet_timestamp::Pallet<Self>;
+	type CurrencyToVote = ();
+	type RewardRemainder = ();
+	type RuntimeEvent = RuntimeEvent;
+	type Slash = ();
+	type Reward = ();
+	type SessionsPerEra = ();
+	type SlashDeferDuration = ();
+	type AdminOrigin = frame_system::EnsureRoot<Self::AccountId>;
+	type BondingDuration = BondingDuration;
+	type SessionInterface = ();
+	type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
+	type NextNewSession = ();
+	type HistoryDepth = ConstU32<84>;
+	type MaxExposurePageSize = ConstU32<64>;
+	type OffendingValidatorsThreshold = ();
+	type ElectionProvider = onchain::OnChainExecution<OnChainSeqPhragmen>;
+	type GenesisElectionProvider = Self::ElectionProvider;
+	type VoterList = pallet_staking::UseNominatorsAndValidatorsMap<Self>;
+	type TargetList = pallet_staking::UseValidatorsMap<Self>;
+	type NominationsQuota = pallet_staking::FixedNominationsQuota<16>;
+	type MaxUnlockingChunks = ConstU32<32>;
+	type EventListeners = ();
+	type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
+	type WeightInfo = ();
 }
 
 impl delegated_staking::Config for Runtime {
-    type RuntimeEvent = RuntimeEvent;
-    type Currency = Balances;
-    type RuntimeHoldReason = RuntimeHoldReason;
-    type Staking = Staking;
+	type RuntimeEvent = RuntimeEvent;
+	type Currency = Balances;
+	type RuntimeHoldReason = RuntimeHoldReason;
+	type Staking = Staking;
 }
 
-
 frame_support::construct_runtime!(
 	pub struct Runtime {
 		System: frame_system,
@@ -150,36 +149,35 @@ frame_support::construct_runtime!(
 	}
 );
 
-pub struct ExtBuilder {
-}
+pub struct ExtBuilder {}
 
 impl Default for ExtBuilder {
-    fn default() -> Self {
-        Self {}
-    }
+	fn default() -> Self {
+		Self {}
+	}
 }
 
 impl ExtBuilder {
+	fn build(self) -> sp_io::TestExternalities {
+		sp_tracing::try_init_simple();
+		let mut storage =
+			frame_system::GenesisConfig::<Runtime>::default().build_storage().unwrap();
+
+		let mut ext = sp_io::TestExternalities::from(storage);
 
-    fn build(self) -> sp_io::TestExternalities {
-        sp_tracing::try_init_simple();
-        let mut storage = frame_system::GenesisConfig::<Runtime>::default().build_storage().unwrap();
-
-        let mut ext = sp_io::TestExternalities::from(storage);
-
-        ext.execute_with(|| {
-            // for events to be deposited.
-            frame_system::Pallet::<Runtime>::set_block_number(1);
-        });
-
-        ext
-    }
-    pub fn build_and_execute(self, test: impl FnOnce() -> ()) {
-        sp_tracing::try_init_simple();
-        let mut ext = self.build();
-        ext.execute_with(test);
-        ext.execute_with(|| {
-            // DelegatedStaking::do_try_state().unwrap();
-        });
-    }
-}
\ No newline at end of file
+		ext.execute_with(|| {
+			// for events to be deposited.
+			frame_system::Pallet::<Runtime>::set_block_number(1);
+		});
+
+		ext
+	}
+	pub fn build_and_execute(self, test: impl FnOnce() -> ()) {
+		sp_tracing::try_init_simple();
+		let mut ext = self.build();
+		ext.execute_with(test);
+		ext.execute_with(|| {
+			// DelegatedStaking::do_try_state().unwrap();
+		});
+	}
+}
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index fb86ac1394c8c..ebb9009bec706 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -21,8 +21,5 @@ use super::*;
 use crate::{mock::*, Event};
 #[test]
 fn hello_world_test() {
-    ExtBuilder::default().build_and_execute(|| {
-        assert!(true)
-    });
-
-}
\ No newline at end of file
+	ExtBuilder::default().build_and_execute(|| assert!(true));
+}
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 5759650b4140c..9c20e96a50c60 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -27,8 +27,8 @@ use frame_support::{
 	dispatch::WithPostDispatchInfo,
 	pallet_prelude::*,
 	traits::{
-		Currency, LockableCurrency, Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance, Len,
-		OnUnbalanced, TryCollect, UnixTime,
+		Currency, Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance, Len,
+		LockableCurrency, OnUnbalanced, TryCollect, UnixTime,
 	},
 	weights::Weight,
 };

From 11959190b30b47452156b108e4166b88b3fc4000 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 2 Dec 2023 18:37:50 +0100
Subject: [PATCH 014/202] empty tests and stake balance provider

---
 substrate/frame/delegated-staking/src/lib.rs  | 35 ++++++++++++-----
 .../frame/delegated-staking/src/tests.rs      | 39 ++++++++++++++++++-
 substrate/primitives/staking/src/lib.rs       | 21 ++++++++++
 3 files changed, 85 insertions(+), 10 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 50d0085e466ed..33391a1edeaf9 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -34,7 +34,7 @@ use frame_support::{
 	},
 };
 use pallet::*;
-use sp_runtime::{traits::Zero, RuntimeDebug, Saturating};
+use sp_runtime::{traits::Zero, DispatchResult, RuntimeDebug, Saturating};
 use sp_staking::{
 	delegation::{Delegatee, Delegator},
 	StakerStatus, StakingInterface,
@@ -92,14 +92,14 @@ pub mod pallet {
 		Delegating,
 	}
 
-	#[pallet::genesis_config]
-	#[derive(frame_support::DefaultNoBound)]
-	pub struct GenesisConfig<T: Config> {}
-
-	#[pallet::genesis_build]
-	impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
-		fn build(&self) {}
-	}
+	// #[pallet::genesis_config]
+	// #[derive(frame_support::DefaultNoBound)]
+	// pub struct GenesisConfig<T: Config> {}
+	//
+	// #[pallet::genesis_build]
+	// impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
+	// 	fn build(&self) {}
+	// }
 
 	#[pallet::event]
 	#[pallet::generate_deposit(pub(super) fn deposit_event)]
@@ -392,3 +392,20 @@ impl<T: Config> Delegator for Pallet<T> {
 		Self::delegate(new_delegator, delegatee, value)
 	}
 }
+
+impl<T: Config> sp_staking::StakeBalanceProvider for Pallet<T> {
+	type Balance = BalanceOf<T>;
+	type AccountId = T::AccountId;
+
+	fn stakeable_balance(who: Self::AccountId) -> Self::Balance {
+		todo!()
+	}
+
+	fn hold_stake(who: Self::AccountId, amount: Self::Balance) -> DispatchResult {
+		todo!()
+	}
+
+	fn release_stake(who: Self::AccountId, amount: Self::Balance) -> DispatchResult {
+		todo!()
+	}
+}
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index ebb9009bec706..c9690de90976b 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -20,6 +20,43 @@
 use super::*;
 use crate::{mock::*, Event};
 #[test]
-fn hello_world_test() {
+fn create_a_delegatee_with_first_delegator() {
+	// Similar to creating a nomination pool
+	ExtBuilder::default().build_and_execute(|| assert!(true));
+}
+
+#[test]
+fn add_delegation_to_existing_delegator() {
+	// Similar to creating a nomination pool
+	ExtBuilder::default().build_and_execute(|| assert!(true));
+}
+
+#[test]
+fn create_multiple_delegators() {
+	// Similar to creating a nomination pool
+	ExtBuilder::default().build_and_execute(|| assert!(true));
+}
+
+#[test]
+fn withdraw_delegation() {
+	// Similar to creating a nomination pool
+	ExtBuilder::default().build_and_execute(|| assert!(true));
+}
+
+#[test]
+fn apply_pending_slash() {
+	// Similar to creating a nomination pool
+	ExtBuilder::default().build_and_execute(|| assert!(true));
+}
+
+#[test]
+fn distribute_rewards() {
+	// Similar to creating a nomination pool
+	ExtBuilder::default().build_and_execute(|| assert!(true));
+}
+
+#[test]
+fn migrate_to_delegator() {
+	// Similar to creating a nomination pool
 	ExtBuilder::default().build_and_execute(|| assert!(true));
 }
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 9be0e338af334..bc9e41dd9e572 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -420,4 +420,25 @@ pub struct PagedExposureMetadata<Balance: HasCompact + codec::MaxEncodedLen> {
 	pub page_count: Page,
 }
 
+/// Something that provides stakeable balance and a mechanism to reserve this balance.
+pub trait StakeBalanceProvider {
+	/// Balance type used by the staking system.
+	type Balance: Sub<Output = Self::Balance>
+		+ Ord
+		+ PartialEq
+		+ Default
+		+ Copy
+		+ MaxEncodedLen
+		+ FullCodec
+		+ TypeInfo
+		+ Saturating;
+
+	/// AccountId type used by the staking system.
+	type AccountId: Clone + sp_std::fmt::Debug;
+
+	fn stakeable_balance(who: Self::AccountId) -> Self::Balance;
+	fn hold_stake(who: Self::AccountId, amount: Self::Balance) -> DispatchResult;
+	fn release_stake(who: Self::AccountId, amount: Self::Balance) -> DispatchResult;
+}
+
 sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $);

From beb5d1d01ac52e48ab8c63c3e8ee62d29b5a201f Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 2 Dec 2023 23:54:02 +0100
Subject: [PATCH 015/202] Staking implements StakeBalanceProvider

---
 substrate/frame/staking/src/ledger.rs       | 16 ++++++---------
 substrate/frame/staking/src/mock.rs         |  2 ++
 substrate/frame/staking/src/pallet/impls.rs | 22 +++++++++++++++++++--
 substrate/frame/staking/src/pallet/mod.rs   | 16 +++++++++++----
 substrate/primitives/staking/src/lib.rs     |  6 +++---
 5 files changed, 43 insertions(+), 19 deletions(-)

diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs
index 84bb4d167dcb0..697fa9f2257a1 100644
--- a/substrate/frame/staking/src/ledger.rs
+++ b/substrate/frame/staking/src/ledger.rs
@@ -31,16 +31,11 @@
 //! performed through the methods exposed by the [`StakingLedger`] implementation in order to ensure
 //! state consistency.
 
-use frame_support::{
-	defensive,
-	traits::{LockableCurrency, WithdrawReasons},
-};
-use sp_staking::StakingAccount;
+use frame_support::defensive;
+use sp_staking::{StakeBalanceProvider, StakingAccount};
 use sp_std::prelude::*;
 
-use crate::{
-	BalanceOf, Bonded, Config, Error, Ledger, Payee, RewardDestination, StakingLedger, STAKING_ID,
-};
+use crate::{BalanceOf, Bonded, Config, Error, Ledger, Payee, RewardDestination, StakingLedger};
 
 #[cfg(any(feature = "runtime-benchmarks", test))]
 use sp_runtime::traits::Zero;
@@ -166,7 +161,8 @@ impl<T: Config> StakingLedger<T> {
 			return Err(Error::<T>::NotStash)
 		}
 
-		T::Currency::set_lock(STAKING_ID, &self.stash, self.total, WithdrawReasons::all());
+		T::StakeBalanceProvider::update_hold(&self.stash, self.total)
+			.map_err(|_| Error::<T>::BadState)?;
 		Ledger::<T>::insert(
 			&self.controller().ok_or_else(|| {
 				defensive!("update called on a ledger that is not bonded.");
@@ -207,7 +203,7 @@ impl<T: Config> StakingLedger<T> {
 		let controller = <Bonded<T>>::get(stash).ok_or(Error::<T>::NotStash)?;
 
 		<Ledger<T>>::get(&controller).ok_or(Error::<T>::NotController).map(|ledger| {
-			T::Currency::remove_lock(STAKING_ID, &ledger.stash);
+			T::StakeBalanceProvider::release(&ledger.stash);
 			Ledger::<T>::remove(controller);
 
 			<Bonded<T>>::remove(&stash);
diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs
index 5332dbfdd5b2d..e28de7932e497 100644
--- a/substrate/frame/staking/src/mock.rs
+++ b/substrate/frame/staking/src/mock.rs
@@ -294,6 +294,8 @@ impl OnStakingUpdate<AccountId, Balance> for EventListenerMock {
 impl crate::pallet::pallet::Config for Test {
 	type Currency = Balances;
 	type CurrencyBalance = <Self as pallet_balances::Config>::Balance;
+
+	type StakeBalanceProvider = Staking;
 	type UnixTime = Timestamp;
 	type CurrencyToVote = ();
 	type RewardRemainder = RewardRemainderMock;
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 9c20e96a50c60..5332c0ba58d69 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -41,7 +41,7 @@ use sp_runtime::{
 use sp_staking::{
 	currency_to_vote::CurrencyToVote,
 	offence::{DisableStrategy, OffenceDetails, OnOffenceHandler},
-	EraIndex, Page, SessionIndex, Stake,
+	EraIndex, Page, SessionIndex, Stake, StakeBalanceProvider,
 	StakingAccount::{self, Controller, Stash},
 	StakingInterface,
 };
@@ -58,6 +58,7 @@ use super::pallet::*;
 
 #[cfg(feature = "try-runtime")]
 use frame_support::ensure;
+use frame_support::traits::WithdrawReasons;
 #[cfg(any(test, feature = "try-runtime"))]
 use sp_runtime::TryRuntimeError;
 
@@ -1817,11 +1818,28 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	fn force_unlock(who: &Self::AccountId) -> sp_runtime::DispatchResult {
-		T::Currency::remove_lock(crate::STAKING_ID, who);
+		T::StakeBalanceProvider::release(who);
 		Ok(())
 	}
 }
 
+impl<T: Config> StakeBalanceProvider for Pallet<T> {
+	type Balance = BalanceOf<T>;
+	type AccountId = T::AccountId;
+
+	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
+		T::Currency::free_balance(who)
+	}
+
+	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> sp_runtime::DispatchResult {
+		T::Currency::set_lock(crate::STAKING_ID, who, amount, WithdrawReasons::all());
+		Ok(())
+	}
+
+	fn release(who: &Self::AccountId) {
+		T::Currency::remove_lock(crate::STAKING_ID, who)
+	}
+}
 #[cfg(any(test, feature = "try-runtime"))]
 impl<T: Config> Pallet<T> {
 	pub(crate) fn do_try_state(_: BlockNumberFor<T>) -> Result<(), TryRuntimeError> {
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index b914545a76b98..508218dcfd4f8 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -37,7 +37,7 @@ use sp_runtime::{
 };
 
 use sp_staking::{
-	EraIndex, Page, SessionIndex,
+	EraIndex, Page, SessionIndex, StakeBalanceProvider,
 	StakingAccount::{self, Controller, Stash},
 };
 use sp_std::prelude::*;
@@ -103,6 +103,14 @@ pub mod pallet {
 			+ From<u64>
 			+ TypeInfo
 			+ MaxEncodedLen;
+
+		/// Something that provides stakeable balance of an account as well as a way to hold and
+		/// release this stake.
+		type StakeBalanceProvider: StakeBalanceProvider<
+			Balance = Self::CurrencyBalance,
+			AccountId = Self::AccountId,
+		>;
+
 		/// Time used for computing era duration.
 		///
 		/// It is guaranteed to start being called from the first `on_finalize`. Thus value at
@@ -703,7 +711,7 @@ pub mod pallet {
 					status
 				);
 				assert!(
-					T::Currency::free_balance(stash) >= balance,
+					T::StakeBalanceProvider::stakeable_balance(stash) >= balance,
 					"Stash does not have enough balance to bond."
 				);
 				frame_support::assert_ok!(<Pallet<T>>::bond(
@@ -936,7 +944,7 @@ pub mod pallet {
 
 			frame_system::Pallet::<T>::inc_consumers(&stash).map_err(|_| Error::<T>::BadState)?;
 
-			let stash_balance = T::Currency::free_balance(&stash);
+			let stash_balance = T::StakeBalanceProvider::stakeable_balance(&stash);
 			let value = value.min(stash_balance);
 			Self::deposit_event(Event::<T>::Bonded { stash: stash.clone(), amount: value });
 			let ledger = StakingLedger::<T>::new(stash.clone(), value);
@@ -972,7 +980,7 @@ pub mod pallet {
 
 			let mut ledger = Self::ledger(StakingAccount::Stash(stash.clone()))?;
 
-			let stash_balance = T::Currency::free_balance(&stash);
+			let stash_balance = T::StakeBalanceProvider::stakeable_balance(&stash);
 			if let Some(extra) = stash_balance.checked_sub(&ledger.total) {
 				let extra = extra.min(max_additional);
 				ledger.total += extra;
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index bc9e41dd9e572..33fcd6a84b241 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -436,9 +436,9 @@ pub trait StakeBalanceProvider {
 	/// AccountId type used by the staking system.
 	type AccountId: Clone + sp_std::fmt::Debug;
 
-	fn stakeable_balance(who: Self::AccountId) -> Self::Balance;
-	fn hold_stake(who: Self::AccountId, amount: Self::Balance) -> DispatchResult;
-	fn release_stake(who: Self::AccountId, amount: Self::Balance) -> DispatchResult;
+	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance;
+	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult;
+	fn release(who: &Self::AccountId);
 }
 
 sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $);

From 46e03fdbb56e254b273d36218456f702cdf150e9 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 00:00:18 +0100
Subject: [PATCH 016/202] refactor to allow partial withdraw from unlocking
 chunks

---
 substrate/frame/staking/src/lib.rs          | 42 +++++++++++++++++----
 substrate/frame/staking/src/pallet/impls.rs |  2 +-
 2 files changed, 35 insertions(+), 9 deletions(-)

diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs
index 41cb2a12c3a32..4e10fe787a9dd 100644
--- a/substrate/frame/staking/src/lib.rs
+++ b/substrate/frame/staking/src/lib.rs
@@ -492,19 +492,45 @@ pub struct StakingLedger<T: Config> {
 }
 
 impl<T: Config> StakingLedger<T> {
-	/// Remove entries from `unlocking` that are sufficiently old and reduce the
-	/// total by the sum of their balances.
-	fn consolidate_unlocked(self, current_era: EraIndex) -> Self {
+	/// Remove entries from `unlocking` that are sufficiently old and optionally upto a given limit.
+	/// Reduce the total by the unlocked amount.
+	fn consolidate_unlocked(
+		self,
+		current_era: EraIndex,
+		maybe_limit: Option<BalanceOf<T>>,
+	) -> Self {
 		let mut total = self.total;
+		let mut unlocked = BalanceOf::<T>::zero();
+
+		// see if there is a limit else default to total value of the ledger which implies no limit.
+		let limit = maybe_limit.unwrap_or(total);
+
+		// remove chunks that are unlocking
 		let unlocking: BoundedVec<_, _> = self
 			.unlocking
 			.into_iter()
-			.filter(|chunk| {
-				if chunk.era > current_era {
-					true
+			.filter_map(|chunk| {
+				// keep the chunks if they are from a future era or we have unlocked upto the limit
+				if chunk.era > current_era || limit == unlocked {
+					defensive_assert!(limit >= unlocked, "unlocked should never exceed limit");
+					Some(chunk)
 				} else {
-					total = total.saturating_sub(chunk.value);
-					false
+					// we remove chunks that are old enough until we reach limit.
+					let max_unlock = limit - unlocked;
+					if chunk.value <= max_unlock {
+						// unlock all and filter out
+						total = total.saturating_sub(chunk.value);
+						unlocked = unlocked.saturating_add(chunk.value);
+						None
+					} else {
+						// keep the leftover amount in the chunk
+						total = total.saturating_sub(max_unlock);
+						unlocked = unlocked.saturating_add(max_unlock);
+						Some(UnlockChunk {
+							value: chunk.value.saturating_sub(max_unlock),
+							era: chunk.era,
+						})
+					}
 				}
 			})
 			.collect::<Vec<_>>()
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 5332c0ba58d69..693a50a81aeed 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -125,7 +125,7 @@ impl<T: Config> Pallet<T> {
 		let mut ledger = Self::ledger(Controller(controller.clone()))?;
 		let (stash, old_total) = (ledger.stash.clone(), ledger.total);
 		if let Some(current_era) = Self::current_era() {
-			ledger = ledger.consolidate_unlocked(current_era)
+			ledger = ledger.consolidate_unlocked(current_era, None)
 		}
 		let new_total = ledger.total;
 

From aeca6dfb9972c5be092c3801a30ed47db4bf2c26 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 00:46:24 +0100
Subject: [PATCH 017/202] add fallback balance provider to delegated staking

---
 substrate/frame/delegated-staking/src/lib.rs  | 12 +++++++++---
 substrate/frame/delegated-staking/src/mock.rs |  6 ++++++
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 33391a1edeaf9..30663b6b3b757 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -46,6 +46,7 @@ pub type BalanceOf<T> =
 
 #[frame_support::pallet]
 pub mod pallet {
+	use sp_staking::StakeBalanceProvider;
 	use super::*;
 
 	#[pallet::pallet]
@@ -63,6 +64,11 @@ pub mod pallet {
 
 		/// Core staking implementation.
 		type Staking: StakingInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
+
+		/// Core Staking Balance Provider.
+		///
+		/// Fallback implementation when an account is not a delegatee.
+		type FallbackBalanceProvider: StakeBalanceProvider<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
 	}
 
 	#[pallet::error]
@@ -397,15 +403,15 @@ impl<T: Config> sp_staking::StakeBalanceProvider for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
-	fn stakeable_balance(who: Self::AccountId) -> Self::Balance {
+	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
 		todo!()
 	}
 
-	fn hold_stake(who: Self::AccountId, amount: Self::Balance) -> DispatchResult {
+	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
 		todo!()
 	}
 
-	fn release_stake(who: Self::AccountId, amount: Self::Balance) -> DispatchResult {
+	fn release(who: &Self::AccountId) {
 		todo!()
 	}
 }
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 045c93e0c0204..b28e899e337f2 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -38,6 +38,10 @@ pub type T = Runtime;
 type Block = frame_system::mocking::MockBlock<Runtime>;
 pub type AccountId = u64;
 
+const GENESIS_VALIDATOR: AccountId = 1;
+const GENESIS_NOMINATOR_ONE: AccountId = 101;
+const GENESIS_NOMINATOR_TWO: AccountId = 102;
+
 #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
 impl frame_system::Config for Runtime {
 	type Block = Block;
@@ -105,6 +109,7 @@ impl onchain::Config for OnChainSeqPhragmen {
 impl pallet_staking::Config for Runtime {
 	type Currency = Balances;
 	type CurrencyBalance = Balance;
+	type StakeBalanceProvider = DelegatedStaking;
 	type UnixTime = pallet_timestamp::Pallet<Self>;
 	type CurrencyToVote = ();
 	type RewardRemainder = ();
@@ -137,6 +142,7 @@ impl delegated_staking::Config for Runtime {
 	type Currency = Balances;
 	type RuntimeHoldReason = RuntimeHoldReason;
 	type Staking = Staking;
+	type FallbackBalanceProvider = Staking;
 }
 
 frame_support::construct_runtime!(

From cdbd166b231339ae836d2f4f4d1bf320ed8621ec Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 01:00:43 +0100
Subject: [PATCH 018/202] setup mocks with one validator and 2 nominators at
 genesis

---
 substrate/frame/delegated-staking/src/lib.rs  | 13 +++---
 substrate/frame/delegated-staking/src/mock.rs | 45 ++++++++++++++++++-
 2 files changed, 52 insertions(+), 6 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 30663b6b3b757..5d22c051f8225 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -46,8 +46,8 @@ pub type BalanceOf<T> =
 
 #[frame_support::pallet]
 pub mod pallet {
-	use sp_staking::StakeBalanceProvider;
 	use super::*;
+	use sp_staking::StakeBalanceProvider;
 
 	#[pallet::pallet]
 	pub struct Pallet<T>(PhantomData<T>);
@@ -68,7 +68,10 @@ pub mod pallet {
 		/// Core Staking Balance Provider.
 		///
 		/// Fallback implementation when an account is not a delegatee.
-		type FallbackBalanceProvider: StakeBalanceProvider<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
+		type FallbackBalanceProvider: StakeBalanceProvider<
+			Balance = BalanceOf<Self>,
+			AccountId = Self::AccountId,
+		>;
 	}
 
 	#[pallet::error]
@@ -404,14 +407,14 @@ impl<T: Config> sp_staking::StakeBalanceProvider for Pallet<T> {
 	type AccountId = T::AccountId;
 
 	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
-		todo!()
+		T::FallbackBalanceProvider::stakeable_balance(who)
 	}
 
 	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
-		todo!()
+		T::FallbackBalanceProvider::update_hold(who, amount)
 	}
 
 	fn release(who: &Self::AccountId) {
-		todo!()
+		T::FallbackBalanceProvider::release(who)
 	}
 }
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index b28e899e337f2..38114d1943925 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -26,7 +26,7 @@ use frame_support::{
 
 use sp_runtime::{
 	traits::{Convert, IdentityLookup},
-	BuildStorage,
+	BuildStorage, Perbill,
 };
 
 use frame_election_provider_support::{
@@ -169,6 +169,49 @@ impl ExtBuilder {
 		let mut storage =
 			frame_system::GenesisConfig::<Runtime>::default().build_storage().unwrap();
 
+		let _ = pallet_balances::GenesisConfig::<T> {
+			balances: vec![
+				(GENESIS_VALIDATOR, 10000),
+				(GENESIS_NOMINATOR_ONE, 1000),
+				(GENESIS_NOMINATOR_TWO, 2000),
+			],
+		}
+		.assimilate_storage(&mut storage);
+
+		let stakers = vec![
+			(
+				GENESIS_VALIDATOR,
+				GENESIS_VALIDATOR,
+				1000,
+				sp_staking::StakerStatus::<AccountId>::Validator,
+			),
+			(
+				GENESIS_NOMINATOR_ONE,
+				GENESIS_NOMINATOR_ONE,
+				100,
+				sp_staking::StakerStatus::<AccountId>::Nominator(vec![1]),
+			),
+			(
+				GENESIS_NOMINATOR_TWO,
+				GENESIS_NOMINATOR_TWO,
+				200,
+				sp_staking::StakerStatus::<AccountId>::Nominator(vec![1]),
+			),
+		];
+
+		let _ = pallet_staking::GenesisConfig::<T> {
+			stakers: stakers.clone(),
+			// ideal validator count
+			validator_count: 2,
+			minimum_validator_count: 1,
+			invulnerables: vec![],
+			slash_reward_fraction: Perbill::from_percent(10),
+			min_nominator_bond: ExistentialDeposit::get(),
+			min_validator_bond: ExistentialDeposit::get(),
+			..Default::default()
+		}
+		.assimilate_storage(&mut storage);
+
 		let mut ext = sp_io::TestExternalities::from(storage);
 
 		ext.execute_with(|| {

From 30a790aa26c7ea06bed4e8876ccc7b364b75350d Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 01:06:44 +0100
Subject: [PATCH 019/202] do try state for pallet-delegated-staking

---
 substrate/frame/delegated-staking/src/lib.rs  | 7 +++++++
 substrate/frame/delegated-staking/src/mock.rs | 2 +-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 5d22c051f8225..005be39096908 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -418,3 +418,10 @@ impl<T: Config> sp_staking::StakeBalanceProvider for Pallet<T> {
 		T::FallbackBalanceProvider::release(who)
 	}
 }
+
+#[cfg(any(test, feature = "try-runtime"))]
+impl<T: Config> Pallet<T> {
+	pub(crate) fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> {
+		Ok(())
+	}
+}
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 38114d1943925..f037601b1ecb3 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -226,7 +226,7 @@ impl ExtBuilder {
 		let mut ext = self.build();
 		ext.execute_with(test);
 		ext.execute_with(|| {
-			// DelegatedStaking::do_try_state().unwrap();
+			DelegatedStaking::do_try_state().unwrap();
 		});
 	}
 }

From 90b3b07e050537b4c59b600ba04410f9c882af56 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 01:50:56 +0100
Subject: [PATCH 020/202] return type of stake balance

---
 substrate/frame/delegated-staking/src/lib.rs  | 39 ++++++++++---------
 substrate/frame/delegated-staking/src/mock.rs | 11 ++++--
 .../frame/delegated-staking/src/tests.rs      | 37 +++++++++++++++++-
 substrate/frame/staking/src/pallet/impls.rs   | 12 ++----
 substrate/frame/staking/src/pallet/mod.rs     |  6 +--
 .../primitives/staking/src/delegation.rs      |  2 +-
 substrate/primitives/staking/src/lib.rs       |  8 +++-
 7 files changed, 76 insertions(+), 39 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 005be39096908..a6d20e83ae42f 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -35,10 +35,7 @@ use frame_support::{
 };
 use pallet::*;
 use sp_runtime::{traits::Zero, DispatchResult, RuntimeDebug, Saturating};
-use sp_staking::{
-	delegation::{Delegatee, Delegator},
-	StakerStatus, StakingInterface,
-};
+use sp_staking::{delegation::{Delegatee, Delegator}, StakeBalanceType, StakerStatus, StakingInterface};
 use sp_std::{convert::TryInto, prelude::*};
 
 pub type BalanceOf<T> =
@@ -78,6 +75,10 @@ pub mod pallet {
 	pub enum Error<T> {
 		/// The account cannot perform this operation.
 		NotAllowed,
+		/// An existing staker cannot become a delegatee.
+		AlreadyStaker,
+		/// Reward Destination cannot be delegatee account.
+		InvalidRewardDestination,
 		/// Delegation conditions are not met.
 		///
 		/// Possible issues are
@@ -168,22 +169,22 @@ impl<T: Config> Delegatee for Pallet<T> {
 
 	fn accept_delegations(
 		who: &Self::AccountId,
-		payee: &Self::AccountId,
-	) -> sp_runtime::DispatchResult {
+		reward_destination: &Self::AccountId,
+	) -> DispatchResult {
 		// Existing delegatee cannot accept delegation
 		ensure!(!<Delegatees<T>>::contains_key(who), Error::<T>::NotAllowed);
 
 		// payee account cannot be same as delegatee
-		ensure!(payee != who, Error::<T>::InvalidDelegation);
+		ensure!(reward_destination != who, Error::<T>::InvalidRewardDestination);
 
 		// if already a delegator, unblock and return success
 		<Delegatees<T>>::mutate(who, |maybe_register| {
 			if let Some(register) = maybe_register {
 				register.blocked = false;
-				register.payee = payee.clone();
+				register.payee = reward_destination.clone();
 			} else {
 				*maybe_register = Some(DelegationRegister {
-					payee: payee.clone(),
+					payee: reward_destination.clone(),
 					balance: Zero::zero(),
 					pending_slash: Zero::zero(),
 					blocked: false,
@@ -194,7 +195,7 @@ impl<T: Config> Delegatee for Pallet<T> {
 		Ok(())
 	}
 
-	fn block_delegations(delegatee: &Self::AccountId) -> sp_runtime::DispatchResult {
+	fn block_delegations(delegatee: &Self::AccountId) -> DispatchResult {
 		<Delegatees<T>>::mutate(delegatee, |maybe_register| {
 			if let Some(register) = maybe_register {
 				register.blocked = true;
@@ -205,11 +206,11 @@ impl<T: Config> Delegatee for Pallet<T> {
 		})
 	}
 
-	fn kill_delegatee(delegatee: &Self::AccountId) -> sp_runtime::DispatchResult {
+	fn kill_delegatee(delegatee: &Self::AccountId) -> DispatchResult {
 		todo!()
 	}
 
-	fn update_bond(who: &Self::AccountId) -> sp_runtime::DispatchResult {
+	fn update_bond(who: &Self::AccountId) -> DispatchResult {
 		let delegatee = <Delegatees<T>>::get(who).ok_or(Error::<T>::NotDelegatee)?;
 		let delegated_balance = delegatee.effective_balance();
 
@@ -229,7 +230,7 @@ impl<T: Config> Delegatee for Pallet<T> {
 		delegator: &Self::AccountId,
 		delegatee: &Self::AccountId,
 		value: Self::Balance,
-	) -> sp_runtime::DispatchResult {
+	) -> DispatchResult {
 		<Delegators<T>>::mutate_exists(delegator, |maybe_delegate| match maybe_delegate {
 			Some((current_delegatee, delegate_balance)) => {
 				ensure!(&current_delegatee.clone() == delegatee, Error::<T>::NotDelegatee);
@@ -276,7 +277,7 @@ impl<T: Config> Delegatee for Pallet<T> {
 		delegator: &Self::AccountId,
 		value: Self::Balance,
 		reporter: Option<Self::AccountId>,
-	) -> sp_runtime::DispatchResult {
+	) -> DispatchResult {
 		todo!()
 	}
 
@@ -286,7 +287,7 @@ impl<T: Config> Delegatee for Pallet<T> {
 		new_delegatee: &Self::AccountId,
 		proxy_delegator: &Self::AccountId,
 		payee: &Self::AccountId,
-	) -> sp_runtime::DispatchResult {
+	) -> DispatchResult {
 		ensure!(new_delegatee != proxy_delegator, Error::<T>::InvalidDelegation);
 
 		// ensure proxy delegator has at least minimum balance to keep the account alive.
@@ -335,7 +336,7 @@ impl<T: Config> Delegator for Pallet<T> {
 		delegator: &Self::AccountId,
 		delegatee: &Self::AccountId,
 		value: Self::Balance,
-	) -> sp_runtime::DispatchResult {
+	) -> DispatchResult {
 		let delegator_balance =
 			T::Currency::reducible_balance(&delegator, Preservation::Expendable, Fortitude::Polite);
 		ensure!(value >= T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
@@ -373,7 +374,7 @@ impl<T: Config> Delegator for Pallet<T> {
 		delegator: &Self::AccountId,
 		delegatee: &Self::AccountId,
 		value: Self::Balance,
-	) -> sp_runtime::DispatchResult {
+	) -> DispatchResult {
 		todo!()
 	}
 
@@ -384,7 +385,7 @@ impl<T: Config> Delegator for Pallet<T> {
 		new_delegator: &Self::AccountId,
 		delegatee: &Self::AccountId,
 		value: Self::Balance,
-	) -> sp_runtime::DispatchResult {
+	) -> DispatchResult {
 		ensure!(value >= T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
 
 		// ensure delegatee exists.
@@ -406,7 +407,7 @@ impl<T: Config> sp_staking::StakeBalanceProvider for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
-	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
+	fn stakeable_balance(who: &Self::AccountId) ->	(StakeBalanceType, Self::Balance)  {
 		T::FallbackBalanceProvider::stakeable_balance(who)
 	}
 
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index f037601b1ecb3..77adbdc4ea787 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -21,7 +21,6 @@ use frame_support::{
 	pallet_prelude::*,
 	parameter_types,
 	traits::{ConstU64, Currency},
-	weights::constants::WEIGHT_REF_TIME_PER_SECOND,
 };
 
 use sp_runtime::{
@@ -38,9 +37,9 @@ pub type T = Runtime;
 type Block = frame_system::mocking::MockBlock<Runtime>;
 pub type AccountId = u64;
 
-const GENESIS_VALIDATOR: AccountId = 1;
-const GENESIS_NOMINATOR_ONE: AccountId = 101;
-const GENESIS_NOMINATOR_TWO: AccountId = 102;
+pub const GENESIS_VALIDATOR: AccountId = 1;
+pub const GENESIS_NOMINATOR_ONE: AccountId = 101;
+pub const GENESIS_NOMINATOR_TWO: AccountId = 102;
 
 #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
 impl frame_system::Config for Runtime {
@@ -230,3 +229,7 @@ impl ExtBuilder {
 		});
 	}
 }
+
+pub fn fund(who: AccountId, amount: Balance) {
+	let _  = Balances::deposit_creating(&who, amount);
+}
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index c9690de90976b..94169442f6423 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -17,17 +17,50 @@
 
 //! Tests for pallet-delegated-staking.
 
+use frame_support::{assert_noop, assert_ok};
+use sp_staking::{StakeBalanceType, StakeBalanceProvider};
 use super::*;
 use crate::{mock::*, Event};
+
 #[test]
 fn create_a_delegatee_with_first_delegator() {
 	// Similar to creating a nomination pool
-	ExtBuilder::default().build_and_execute(|| assert!(true));
+	ExtBuilder::default().build_and_execute(|| {
+		let delegatee: AccountId = 200;
+		fund(delegatee, 1000);
+		let reward_account: AccountId = 201;
+		let delegator: AccountId = 202;
+		fund(delegator, 1000);
+
+		// set intention to accept delegation.
+		assert_ok!(DelegatedStaking::accept_delegations(&delegatee, &reward_account));
+
+		// delegate to this account
+		assert_ok!(DelegatedStaking::delegate(&delegator, &delegatee, 100));
+
+		// verify
+		assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), (StakeBalanceType::Delegated, 100));
+
+	});
+}
+
+#[test]
+fn cannot_become_delegatee() {
+	ExtBuilder::default().build_and_execute(|| {
+		// cannot set reward account same as delegatee account
+		assert_noop!(DelegatedStaking::accept_delegations(&100, &100), Error::<T>::InvalidRewardDestination);
+
+		// an existing validator cannot become delegatee
+		assert_noop!(DelegatedStaking::accept_delegations(&mock::GENESIS_VALIDATOR, &100), Error::<T>::AlreadyStaker);
+
+		// an existing nominator cannot become delegatee
+		assert_noop!(DelegatedStaking::accept_delegations(&mock::GENESIS_NOMINATOR_ONE, &100), Error::<T>::AlreadyStaker);
+		assert_noop!(DelegatedStaking::accept_delegations(&mock::GENESIS_NOMINATOR_TWO, &100), Error::<T>::AlreadyStaker);
+	});
 }
 
 #[test]
 fn add_delegation_to_existing_delegator() {
-	// Similar to creating a nomination pool
 	ExtBuilder::default().build_and_execute(|| assert!(true));
 }
 
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 693a50a81aeed..7ff18a6cbd841 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -38,13 +38,7 @@ use sp_runtime::{
 	traits::{Bounded, Convert, One, SaturatedConversion, Saturating, StaticLookup, Zero},
 	Perbill,
 };
-use sp_staking::{
-	currency_to_vote::CurrencyToVote,
-	offence::{DisableStrategy, OffenceDetails, OnOffenceHandler},
-	EraIndex, Page, SessionIndex, Stake, StakeBalanceProvider,
-	StakingAccount::{self, Controller, Stash},
-	StakingInterface,
-};
+use sp_staking::{currency_to_vote::CurrencyToVote, offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, EraIndex, Page, SessionIndex, Stake, StakeBalanceProvider, StakingAccount::{self, Controller, Stash}, StakingInterface, StakeBalanceType};
 use sp_std::prelude::*;
 
 use crate::{
@@ -1827,8 +1821,8 @@ impl<T: Config> StakeBalanceProvider for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
-	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
-		T::Currency::free_balance(who)
+	fn stakeable_balance(who: &Self::AccountId) -> (StakeBalanceType, Self::Balance) {
+		(StakeBalanceType::Direct, T::Currency::free_balance(who))
 	}
 
 	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> sp_runtime::DispatchResult {
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index 508218dcfd4f8..46afffe513fe7 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -711,7 +711,7 @@ pub mod pallet {
 					status
 				);
 				assert!(
-					T::StakeBalanceProvider::stakeable_balance(stash) >= balance,
+					T::StakeBalanceProvider::stakeable_balance(stash).1 >= balance,
 					"Stash does not have enough balance to bond."
 				);
 				frame_support::assert_ok!(<Pallet<T>>::bond(
@@ -944,7 +944,7 @@ pub mod pallet {
 
 			frame_system::Pallet::<T>::inc_consumers(&stash).map_err(|_| Error::<T>::BadState)?;
 
-			let stash_balance = T::StakeBalanceProvider::stakeable_balance(&stash);
+			let (_, stash_balance) = T::StakeBalanceProvider::stakeable_balance(&stash);
 			let value = value.min(stash_balance);
 			Self::deposit_event(Event::<T>::Bonded { stash: stash.clone(), amount: value });
 			let ledger = StakingLedger::<T>::new(stash.clone(), value);
@@ -980,7 +980,7 @@ pub mod pallet {
 
 			let mut ledger = Self::ledger(StakingAccount::Stash(stash.clone()))?;
 
-			let stash_balance = T::StakeBalanceProvider::stakeable_balance(&stash);
+			let (_, stash_balance) = T::StakeBalanceProvider::stakeable_balance(&stash);
 			if let Some(extra) = stash_balance.checked_sub(&ledger.total) {
 				let extra = extra.min(max_additional);
 				ledger.total += extra;
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 6ee556bbcb75f..0a77a17046ffa 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -40,7 +40,7 @@ pub trait Delegatee {
 	fn delegate_balance(who: Self::AccountId) -> Self::Balance;
 
 	/// Set intention to accept delegations.
-	fn accept_delegations(delegatee: &Self::AccountId, payee: &Self::AccountId) -> DispatchResult;
+	fn accept_delegations(delegatee: &Self::AccountId, reward_destination: &Self::AccountId) -> DispatchResult;
 
 	/// Stop accepting new delegations on this account.
 	fn block_delegations(delegatee: &Self::AccountId) -> DispatchResult;
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 33fcd6a84b241..d39f5ff53f6f3 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -436,9 +436,15 @@ pub trait StakeBalanceProvider {
 	/// AccountId type used by the staking system.
 	type AccountId: Clone + sp_std::fmt::Debug;
 
-	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance;
+	fn stakeable_balance(who: &Self::AccountId) -> (StakeBalanceType, Self::Balance);
 	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult;
 	fn release(who: &Self::AccountId);
 }
 
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum StakeBalanceType {
+	Direct,
+	Delegated,
+}
+
 sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $);

From c31c085e0f03c76233beee1266ddf53e25fd9057 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 02:01:26 +0100
Subject: [PATCH 021/202] failing tests

---
 substrate/frame/delegated-staking/src/lib.rs   | 7 ++++++-
 substrate/frame/delegated-staking/src/tests.rs | 3 ++-
 substrate/frame/staking/src/pallet/impls.rs    | 9 +++++++--
 substrate/frame/staking/src/pallet/mod.rs      | 6 +++---
 substrate/primitives/staking/src/lib.rs        | 5 ++++-
 5 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index a6d20e83ae42f..d84cc69efafed 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -407,7 +407,7 @@ impl<T: Config> sp_staking::StakeBalanceProvider for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
-	fn stakeable_balance(who: &Self::AccountId) ->	(StakeBalanceType, Self::Balance)  {
+	fn stakeable_balance(who: &Self::AccountId) ->	Self::Balance  {
 		T::FallbackBalanceProvider::stakeable_balance(who)
 	}
 
@@ -418,6 +418,11 @@ impl<T: Config> sp_staking::StakeBalanceProvider for Pallet<T> {
 	fn release(who: &Self::AccountId) {
 		T::FallbackBalanceProvider::release(who)
 	}
+
+	#[cfg(feature = "std")]
+	fn stake_type(who: &Self::AccountId) -> StakeBalanceType {
+		T::FallbackBalanceProvider::stake_type(who)
+	}
 }
 
 #[cfg(any(test, feature = "try-runtime"))]
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 94169442f6423..73c4a09f2fae8 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -39,7 +39,8 @@ fn create_a_delegatee_with_first_delegator() {
 		assert_ok!(DelegatedStaking::delegate(&delegator, &delegatee, 100));
 
 		// verify
-		assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), (StakeBalanceType::Delegated, 100));
+		assert_eq!(DelegatedStaking::stake_type(&delegatee), StakeBalanceType::Delegated);
+		assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100);
 
 	});
 }
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 7ff18a6cbd841..6185c76fbf340 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1821,8 +1821,8 @@ impl<T: Config> StakeBalanceProvider for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
-	fn stakeable_balance(who: &Self::AccountId) -> (StakeBalanceType, Self::Balance) {
-		(StakeBalanceType::Direct, T::Currency::free_balance(who))
+	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
+		T::Currency::free_balance(who)
 	}
 
 	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> sp_runtime::DispatchResult {
@@ -1833,6 +1833,11 @@ impl<T: Config> StakeBalanceProvider for Pallet<T> {
 	fn release(who: &Self::AccountId) {
 		T::Currency::remove_lock(crate::STAKING_ID, who)
 	}
+
+	#[cfg(feature = "std")]
+	fn stake_type(_: &Self::AccountId) -> StakeBalanceType {
+		StakeBalanceType::Direct
+	}
 }
 #[cfg(any(test, feature = "try-runtime"))]
 impl<T: Config> Pallet<T> {
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index 46afffe513fe7..508218dcfd4f8 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -711,7 +711,7 @@ pub mod pallet {
 					status
 				);
 				assert!(
-					T::StakeBalanceProvider::stakeable_balance(stash).1 >= balance,
+					T::StakeBalanceProvider::stakeable_balance(stash) >= balance,
 					"Stash does not have enough balance to bond."
 				);
 				frame_support::assert_ok!(<Pallet<T>>::bond(
@@ -944,7 +944,7 @@ pub mod pallet {
 
 			frame_system::Pallet::<T>::inc_consumers(&stash).map_err(|_| Error::<T>::BadState)?;
 
-			let (_, stash_balance) = T::StakeBalanceProvider::stakeable_balance(&stash);
+			let stash_balance = T::StakeBalanceProvider::stakeable_balance(&stash);
 			let value = value.min(stash_balance);
 			Self::deposit_event(Event::<T>::Bonded { stash: stash.clone(), amount: value });
 			let ledger = StakingLedger::<T>::new(stash.clone(), value);
@@ -980,7 +980,7 @@ pub mod pallet {
 
 			let mut ledger = Self::ledger(StakingAccount::Stash(stash.clone()))?;
 
-			let (_, stash_balance) = T::StakeBalanceProvider::stakeable_balance(&stash);
+			let stash_balance = T::StakeBalanceProvider::stakeable_balance(&stash);
 			if let Some(extra) = stash_balance.checked_sub(&ledger.total) {
 				let extra = extra.min(max_additional);
 				ledger.total += extra;
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index d39f5ff53f6f3..6b1cd16329437 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -436,9 +436,12 @@ pub trait StakeBalanceProvider {
 	/// AccountId type used by the staking system.
 	type AccountId: Clone + sp_std::fmt::Debug;
 
-	fn stakeable_balance(who: &Self::AccountId) -> (StakeBalanceType, Self::Balance);
+	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance;
 	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult;
 	fn release(who: &Self::AccountId);
+
+	#[cfg(feature = "std")]
+	fn stake_type(who: &Self::AccountId) -> StakeBalanceType;
 }
 
 #[derive(Clone, Debug, Eq, PartialEq)]

From 41d0ee066f86275f5848dcb4813f492cc034fd9d Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 02:01:48 +0100
Subject: [PATCH 022/202] fmt

---
 substrate/frame/delegated-staking/src/lib.rs  |  7 ++++--
 substrate/frame/delegated-staking/src/mock.rs |  2 +-
 .../frame/delegated-staking/src/tests.rs      | 25 +++++++++++++------
 substrate/frame/staking/src/pallet/impls.rs   |  8 +++++-
 .../primitives/staking/src/delegation.rs      |  5 +++-
 5 files changed, 35 insertions(+), 12 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index d84cc69efafed..760bb6c73133d 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -35,7 +35,10 @@ use frame_support::{
 };
 use pallet::*;
 use sp_runtime::{traits::Zero, DispatchResult, RuntimeDebug, Saturating};
-use sp_staking::{delegation::{Delegatee, Delegator}, StakeBalanceType, StakerStatus, StakingInterface};
+use sp_staking::{
+	delegation::{Delegatee, Delegator},
+	StakeBalanceType, StakerStatus, StakingInterface,
+};
 use sp_std::{convert::TryInto, prelude::*};
 
 pub type BalanceOf<T> =
@@ -407,7 +410,7 @@ impl<T: Config> sp_staking::StakeBalanceProvider for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
-	fn stakeable_balance(who: &Self::AccountId) ->	Self::Balance  {
+	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
 		T::FallbackBalanceProvider::stakeable_balance(who)
 	}
 
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 77adbdc4ea787..99b9a94c68ad7 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -231,5 +231,5 @@ impl ExtBuilder {
 }
 
 pub fn fund(who: AccountId, amount: Balance) {
-	let _  = Balances::deposit_creating(&who, amount);
+	let _ = Balances::deposit_creating(&who, amount);
 }
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 73c4a09f2fae8..7a0085f0033cd 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -17,10 +17,10 @@
 
 //! Tests for pallet-delegated-staking.
 
-use frame_support::{assert_noop, assert_ok};
-use sp_staking::{StakeBalanceType, StakeBalanceProvider};
 use super::*;
 use crate::{mock::*, Event};
+use frame_support::{assert_noop, assert_ok};
+use sp_staking::{StakeBalanceProvider, StakeBalanceType};
 
 #[test]
 fn create_a_delegatee_with_first_delegator() {
@@ -41,7 +41,6 @@ fn create_a_delegatee_with_first_delegator() {
 		// verify
 		assert_eq!(DelegatedStaking::stake_type(&delegatee), StakeBalanceType::Delegated);
 		assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100);
-
 	});
 }
 
@@ -49,14 +48,26 @@ fn create_a_delegatee_with_first_delegator() {
 fn cannot_become_delegatee() {
 	ExtBuilder::default().build_and_execute(|| {
 		// cannot set reward account same as delegatee account
-		assert_noop!(DelegatedStaking::accept_delegations(&100, &100), Error::<T>::InvalidRewardDestination);
+		assert_noop!(
+			DelegatedStaking::accept_delegations(&100, &100),
+			Error::<T>::InvalidRewardDestination
+		);
 
 		// an existing validator cannot become delegatee
-		assert_noop!(DelegatedStaking::accept_delegations(&mock::GENESIS_VALIDATOR, &100), Error::<T>::AlreadyStaker);
+		assert_noop!(
+			DelegatedStaking::accept_delegations(&mock::GENESIS_VALIDATOR, &100),
+			Error::<T>::AlreadyStaker
+		);
 
 		// an existing nominator cannot become delegatee
-		assert_noop!(DelegatedStaking::accept_delegations(&mock::GENESIS_NOMINATOR_ONE, &100), Error::<T>::AlreadyStaker);
-		assert_noop!(DelegatedStaking::accept_delegations(&mock::GENESIS_NOMINATOR_TWO, &100), Error::<T>::AlreadyStaker);
+		assert_noop!(
+			DelegatedStaking::accept_delegations(&mock::GENESIS_NOMINATOR_ONE, &100),
+			Error::<T>::AlreadyStaker
+		);
+		assert_noop!(
+			DelegatedStaking::accept_delegations(&mock::GENESIS_NOMINATOR_TWO, &100),
+			Error::<T>::AlreadyStaker
+		);
 	});
 }
 
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 6185c76fbf340..c0fd4fcc99371 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -38,7 +38,13 @@ use sp_runtime::{
 	traits::{Bounded, Convert, One, SaturatedConversion, Saturating, StaticLookup, Zero},
 	Perbill,
 };
-use sp_staking::{currency_to_vote::CurrencyToVote, offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, EraIndex, Page, SessionIndex, Stake, StakeBalanceProvider, StakingAccount::{self, Controller, Stash}, StakingInterface, StakeBalanceType};
+use sp_staking::{
+	currency_to_vote::CurrencyToVote,
+	offence::{DisableStrategy, OffenceDetails, OnOffenceHandler},
+	EraIndex, Page, SessionIndex, Stake, StakeBalanceProvider, StakeBalanceType,
+	StakingAccount::{self, Controller, Stash},
+	StakingInterface,
+};
 use sp_std::prelude::*;
 
 use crate::{
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 0a77a17046ffa..09e27d405fe83 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -40,7 +40,10 @@ pub trait Delegatee {
 	fn delegate_balance(who: Self::AccountId) -> Self::Balance;
 
 	/// Set intention to accept delegations.
-	fn accept_delegations(delegatee: &Self::AccountId, reward_destination: &Self::AccountId) -> DispatchResult;
+	fn accept_delegations(
+		delegatee: &Self::AccountId,
+		reward_destination: &Self::AccountId,
+	) -> DispatchResult;
 
 	/// Stop accepting new delegations on this account.
 	fn block_delegations(delegatee: &Self::AccountId) -> DispatchResult;

From c1ad5b636a65384f64e31d1ec18d1bd09001a562 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 02:49:15 +0100
Subject: [PATCH 023/202] green tests

---
 substrate/frame/delegated-staking/src/lib.rs | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 760bb6c73133d..73b4432ddc921 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -177,6 +177,9 @@ impl<T: Config> Delegatee for Pallet<T> {
 		// Existing delegatee cannot accept delegation
 		ensure!(!<Delegatees<T>>::contains_key(who), Error::<T>::NotAllowed);
 
+		// make sure they are not already a direct staker
+		ensure!(T::Staking::status(who).is_err(), Error::<T>::AlreadyStaker);
+
 		// payee account cannot be same as delegatee
 		ensure!(reward_destination != who, Error::<T>::InvalidRewardDestination);
 
@@ -411,7 +414,10 @@ impl<T: Config> sp_staking::StakeBalanceProvider for Pallet<T> {
 	type AccountId = T::AccountId;
 
 	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
-		T::FallbackBalanceProvider::stakeable_balance(who)
+		<Delegatees<T>>::get(who).map_or_else(
+			|| T::FallbackBalanceProvider::stakeable_balance(who),
+			|delegatee| delegatee.effective_balance(),
+		)
 	}
 
 	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
@@ -424,10 +430,20 @@ impl<T: Config> sp_staking::StakeBalanceProvider for Pallet<T> {
 
 	#[cfg(feature = "std")]
 	fn stake_type(who: &Self::AccountId) -> StakeBalanceType {
+		if Self::is_delegatee(who) {
+			return StakeBalanceType::Delegated;
+		}
+
 		T::FallbackBalanceProvider::stake_type(who)
 	}
 }
 
+impl<T: Config> Pallet<T> {
+	fn is_delegatee(who: &T::AccountId) -> bool {
+		<Delegatees<T>>::contains_key(who)
+	}
+}
+
 #[cfg(any(test, feature = "try-runtime"))]
 impl<T: Config> Pallet<T> {
 	pub(crate) fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> {

From 918233ef460f17cd8a883d0e5f6650f5910f75c7 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 03:09:14 +0100
Subject: [PATCH 024/202] refactor

---
 substrate/frame/delegated-staking/src/lib.rs  | 127 +++++++++---------
 .../frame/delegated-staking/src/tests.rs      |  35 ++++-
 .../primitives/staking/src/delegation.rs      |  56 ++++----
 3 files changed, 125 insertions(+), 93 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 73b4432ddc921..493d1d7a13c79 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -201,6 +201,52 @@ impl<T: Config> Delegatee for Pallet<T> {
 		Ok(())
 	}
 
+	/// Transfers funds from current staked account to `proxy_delegator`. Current staked account
+	/// becomes a delegatee with `proxy_delegator` delegating stakes to it.
+	fn migrate_accept_delegations(
+		new_delegatee: &Self::AccountId,
+		proxy_delegator: &Self::AccountId,
+		payee: &Self::AccountId,
+	) -> DispatchResult {
+		ensure!(new_delegatee != proxy_delegator, Error::<T>::InvalidDelegation);
+
+		// ensure proxy delegator has at least minimum balance to keep the account alive.
+		ensure!(
+			T::Currency::reducible_balance(
+				proxy_delegator,
+				Preservation::Expendable,
+				Fortitude::Polite
+			) > Zero::zero(),
+			Error::<T>::NotEnoughFunds
+		);
+
+		// ensure staker is a nominator
+		let status = T::Staking::status(new_delegatee)?;
+		match status {
+			StakerStatus::Nominator(_) => (),
+			_ => return Err(Error::<T>::InvalidDelegation.into()),
+		}
+
+		let stake = T::Staking::stake(new_delegatee)?;
+
+		// unlock funds from staker
+		T::Staking::force_unlock(new_delegatee)?;
+
+		// try transferring the staked amount. This should never fail but if it does, it indicates
+		// bad state and we abort.
+		T::Currency::transfer(
+			new_delegatee,
+			proxy_delegator,
+			stake.total,
+			Preservation::Expendable,
+		)
+		.map_err(|_| Error::<T>::BadState)?;
+
+		// delegate from new delegator to staker.
+		Self::accept_delegations(new_delegatee, payee)?;
+		Self::delegate(proxy_delegator, new_delegatee, stake.total)
+	}
+
 	fn block_delegations(delegatee: &Self::AccountId) -> DispatchResult {
 		<Delegatees<T>>::mutate(delegatee, |maybe_register| {
 			if let Some(register) = maybe_register {
@@ -287,51 +333,30 @@ impl<T: Config> Delegatee for Pallet<T> {
 		todo!()
 	}
 
-	/// Transfers funds from current staked account to `proxy_delegator`. Current staked account
-	/// becomes a delegatee with `proxy_delegator` delegating stakes to it.
-	fn delegatee_migrate(
-		new_delegatee: &Self::AccountId,
-		proxy_delegator: &Self::AccountId,
-		payee: &Self::AccountId,
+	/// Move funds from proxy delegator to actual delegator.
+	// TODO: Keep track of proxy delegator and only allow movement from proxy -> new delegator
+	fn migrate_delegator(
+		delegatee: &Self::AccountId,
+		existing_delegator: &Self::AccountId,
+		new_delegator: &Self::AccountId,
+		value: Self::Balance,
 	) -> DispatchResult {
-		ensure!(new_delegatee != proxy_delegator, Error::<T>::InvalidDelegation);
-
-		// ensure proxy delegator has at least minimum balance to keep the account alive.
-		ensure!(
-			T::Currency::reducible_balance(
-				proxy_delegator,
-				Preservation::Expendable,
-				Fortitude::Polite
-			) > Zero::zero(),
-			Error::<T>::NotEnoughFunds
-		);
-
-		// ensure staker is a nominator
-		let status = T::Staking::status(new_delegatee)?;
-		match status {
-			StakerStatus::Nominator(_) => (),
-			_ => return Err(Error::<T>::InvalidDelegation.into()),
-		}
+		ensure!(value >= T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
 
-		let stake = T::Staking::stake(new_delegatee)?;
+		// ensure delegatee exists.
+		ensure!(!<Delegatees<T>>::contains_key(delegatee), Error::<T>::NotDelegatee);
 
-		// unlock funds from staker
-		T::Staking::force_unlock(new_delegatee)?;
+		// remove delegation of `value` from `existing_delegator`.
+		Self::withdraw(existing_delegator, delegatee, value)?;
 
-		// try transferring the staked amount. This should never fail but if it does, it indicates
-		// bad state and we abort.
-		T::Currency::transfer(
-			new_delegatee,
-			proxy_delegator,
-			stake.total,
-			Preservation::Expendable,
-		)
-		.map_err(|_| Error::<T>::BadState)?;
+		// transfer the withdrawn value to `new_delegator`.
+		T::Currency::transfer(existing_delegator, new_delegator, value, Preservation::Expendable)
+			.map_err(|_| Error::<T>::BadState)?;
 
-		// delegate from new delegator to staker.
-		Self::accept_delegations(new_delegatee, payee)?;
-		Self::delegate(proxy_delegator, new_delegatee, stake.total)
+		// add the above removed delegation to `new_delegator`.
+		Self::delegate(new_delegator, delegatee, value)
 	}
+
 }
 
 impl<T: Config> Delegator for Pallet<T> {
@@ -383,30 +408,6 @@ impl<T: Config> Delegator for Pallet<T> {
 	) -> DispatchResult {
 		todo!()
 	}
-
-	/// Move funds from proxy delegator to actual delegator.
-	// TODO: Keep track of proxy delegator and only allow movement from proxy -> new delegator
-	fn delegator_migrate(
-		existing_delegator: &Self::AccountId,
-		new_delegator: &Self::AccountId,
-		delegatee: &Self::AccountId,
-		value: Self::Balance,
-	) -> DispatchResult {
-		ensure!(value >= T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
-
-		// ensure delegatee exists.
-		ensure!(!<Delegatees<T>>::contains_key(delegatee), Error::<T>::NotDelegatee);
-
-		// remove delegation of `value` from `existing_delegator`.
-		Self::withdraw(existing_delegator, delegatee, value)?;
-
-		// transfer the withdrawn value to `new_delegator`.
-		T::Currency::transfer(existing_delegator, new_delegator, value, Preservation::Expendable)
-			.map_err(|_| Error::<T>::BadState)?;
-
-		// add the above removed delegation to `new_delegator`.
-		Self::delegate(new_delegator, delegatee, value)
-	}
 }
 
 impl<T: Config> sp_staking::StakeBalanceProvider for Pallet<T> {
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 7a0085f0033cd..ebe1dc05da9c0 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -24,7 +24,6 @@ use sp_staking::{StakeBalanceProvider, StakeBalanceType};
 
 #[test]
 fn create_a_delegatee_with_first_delegator() {
-	// Similar to creating a nomination pool
 	ExtBuilder::default().build_and_execute(|| {
 		let delegatee: AccountId = 200;
 		fund(delegatee, 1000);
@@ -90,18 +89,46 @@ fn withdraw_delegation() {
 
 #[test]
 fn apply_pending_slash() {
-	// Similar to creating a nomination pool
 	ExtBuilder::default().build_and_execute(|| assert!(true));
 }
 
 #[test]
 fn distribute_rewards() {
-	// Similar to creating a nomination pool
 	ExtBuilder::default().build_and_execute(|| assert!(true));
 }
 
 #[test]
 fn migrate_to_delegator() {
-	// Similar to creating a nomination pool
 	ExtBuilder::default().build_and_execute(|| assert!(true));
 }
+
+/// Integration tests with pallet-staking and pallet-nomination-pools.
+mod integration {
+	use crate::mock::ExtBuilder;
+
+	#[test]
+	fn bond() {
+		ExtBuilder::default().build_and_execute(|| assert!(true));
+	}
+
+	#[test]
+	fn bond_extra() {
+		ExtBuilder::default().build_and_execute(|| assert!(true));
+	}
+
+	#[test]
+	fn partial_withdraw() {
+		ExtBuilder::default().build_and_execute(|| assert!(true));
+	}
+
+	#[test]
+	fn claim_reward() {
+		ExtBuilder::default().build_and_execute(|| assert!(true));
+	}
+
+	#[test]
+	fn slash_works() {
+		ExtBuilder::default().build_and_execute(|| assert!(true));
+	}
+
+}
\ No newline at end of file
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 09e27d405fe83..71e756e47cfd7 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -45,6 +45,25 @@ pub trait Delegatee {
 		reward_destination: &Self::AccountId,
 	) -> DispatchResult;
 
+	/// Migrate an nominator account into a delegatee.
+	///
+	/// # Arguments
+	///
+	/// * `new_delegatee`: This is the current nominator account. Funds will be moved from this
+	///   account to `proxy_delegator` and delegated back to `new_delegatee`.
+	/// * `proxy_delegator`: All existing staked funds will be moved to this account. Future
+	///   migration of funds from `proxy_delegator` to `delegator` is possible via calling
+	///   [`Self::migrate_delegator`].
+	///  * `payee`: Delegatees need to set where they want their rewards to be paid out.
+	///
+	/// This is similar to [`Self::accept_delegations`] but allows a current nominator to migrate to
+	/// a delegatee.
+	fn migrate_accept_delegations(
+		new_delegatee: &Self::AccountId,
+		proxy_delegator: &Self::AccountId,
+		payee: &Self::AccountId,
+	) -> DispatchResult;
+
 	/// Stop accepting new delegations on this account.
 	fn block_delegations(delegatee: &Self::AccountId) -> DispatchResult;
 
@@ -73,20 +92,19 @@ pub trait Delegatee {
 		reporter: Option<Self::AccountId>,
 	) -> DispatchResult;
 
-	/// Migrate a nominator account into a delegatee by moving its funds to delegator account and
-	/// delegating these funds back to delegatee.
-	///
-	/// Also takes input a payee which will be the new reward destination for the new delegatee.
+	/// Swap a delegated `value` from `delegator_from` to `delegator_to`, with delegatee remaining
+	/// the same.
 	///
-	/// This is useful for migrating old pool accounts to use delegation by providing a pool
-	/// delegator account. This pool delegator account funds can then lazily move funds to actual
-	/// delegators using [`Self::delegator_migrate`].
+	/// This is useful for migrating old pool accounts using direct staking to lazily move
+	/// delegators to the new delegated pool account.
 	///
-	/// Note: Potentially unsafe and should be only called by trusted runtime code.
-	fn delegatee_migrate(
-		new_delegatee: &Self::AccountId,
-		proxy_delegator: &Self::AccountId,
-		payee: &Self::AccountId,
+	/// FIXME(ank4n): delegator_from should be removed and be always `proxy_delegator` that was
+	/// registered while calling [`Self::migrate_accept_delegations`].
+	fn migrate_delegator(
+		delegatee: &Self::AccountId,
+		delegator_from: &Self::AccountId,
+		delegator_to: &Self::AccountId,
+		value: Self::Balance,
 	) -> DispatchResult;
 }
 
@@ -118,18 +136,4 @@ pub trait Delegator {
 		delegatee: &Self::AccountId,
 		value: Self::Balance,
 	) -> DispatchResult;
-
-	/// Swap a delegated `value` from `delegator_from` to `delegator_to`, with delegatee remaining
-	/// the same.
-	///
-	/// This is useful for migrating old pool accounts using direct staking to lazily move
-	/// delegators to the new delegated pool account.
-	///
-	/// Note: Potentially unsafe and should be only called by trusted runtime code.
-	fn delegator_migrate(
-		delegator_from: &Self::AccountId,
-		delegator_to: &Self::AccountId,
-		delegatee: &Self::AccountId,
-		value: Self::Balance,
-	) -> DispatchResult;
 }

From 883d62c33b50f4d24270dc1fc39ddbfe2c181a22 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 03:12:02 +0100
Subject: [PATCH 025/202] fmt

---
 substrate/frame/delegated-staking/src/lib.rs   | 1 -
 substrate/frame/delegated-staking/src/tests.rs | 3 +--
 2 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 493d1d7a13c79..49fb58d3779be 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -356,7 +356,6 @@ impl<T: Config> Delegatee for Pallet<T> {
 		// add the above removed delegation to `new_delegator`.
 		Self::delegate(new_delegator, delegatee, value)
 	}
-
 }
 
 impl<T: Config> Delegator for Pallet<T> {
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index ebe1dc05da9c0..c026c3e491099 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -130,5 +130,4 @@ mod integration {
 	fn slash_works() {
 		ExtBuilder::default().build_and_execute(|| assert!(true));
 	}
-
-}
\ No newline at end of file
+}

From 26da4ceb9d1501152bd9529c4597761e5ee26f88 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 03:23:29 +0100
Subject: [PATCH 026/202] green create_multiple_delegators test

---
 .../frame/delegated-staking/src/tests.rs      | 29 ++++++++++++++-----
 1 file changed, 22 insertions(+), 7 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index c026c3e491099..40c30c9ce0380 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -70,15 +70,30 @@ fn cannot_become_delegatee() {
 	});
 }
 
-#[test]
-fn add_delegation_to_existing_delegator() {
-	ExtBuilder::default().build_and_execute(|| assert!(true));
-}
-
 #[test]
 fn create_multiple_delegators() {
-	// Similar to creating a nomination pool
-	ExtBuilder::default().build_and_execute(|| assert!(true));
+	ExtBuilder::default().build_and_execute(|| {
+		let delegatee: AccountId = 200;
+		fund(delegatee, 1000);
+		let reward_account: AccountId = 201;
+
+		// before becoming a delegatee, stakeable balance is only direct balance.
+		assert_eq!(DelegatedStaking::stake_type(&delegatee), StakeBalanceType::Direct);
+		assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 1000);
+
+		// set intention to accept delegation.
+		assert_ok!(DelegatedStaking::accept_delegations(&delegatee, &reward_account));
+
+		// create 100 delegators
+		for i in 202..302 {
+			fund(i, 100 + ExistentialDeposit::get());
+			assert_ok!(DelegatedStaking::delegate(&i, &delegatee, 100));
+		}
+
+		// verify
+		assert_eq!(DelegatedStaking::stake_type(&delegatee), StakeBalanceType::Delegated);
+		assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100 * 100);
+	});
 }
 
 #[test]

From 215718df65c26ae968fb0432b4f4adf6c699c870 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 16:32:24 +0100
Subject: [PATCH 027/202] Reward destincation checker

---
 substrate/frame/delegated-staking/src/lib.rs  |  6 +--
 substrate/frame/delegated-staking/src/mock.rs |  4 +-
 .../frame/delegated-staking/src/tests.rs      | 48 +++++++++++++-----
 substrate/frame/staking/src/ledger.rs         | 49 +++++++------------
 substrate/frame/staking/src/lib.rs            | 16 ++++++
 substrate/frame/staking/src/mock.rs           |  2 +
 substrate/frame/staking/src/pallet/impls.rs   |  4 +-
 substrate/frame/staking/src/pallet/mod.rs     |  8 ++-
 substrate/primitives/staking/src/lib.rs       | 37 ++++++++------
 9 files changed, 110 insertions(+), 64 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 49fb58d3779be..c52f93448f5af 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -47,7 +47,7 @@ pub type BalanceOf<T> =
 #[frame_support::pallet]
 pub mod pallet {
 	use super::*;
-	use sp_staking::StakeBalanceProvider;
+	use sp_staking::StakingBalanceProvider;
 
 	#[pallet::pallet]
 	pub struct Pallet<T>(PhantomData<T>);
@@ -68,7 +68,7 @@ pub mod pallet {
 		/// Core Staking Balance Provider.
 		///
 		/// Fallback implementation when an account is not a delegatee.
-		type FallbackBalanceProvider: StakeBalanceProvider<
+		type FallbackBalanceProvider: StakingBalanceProvider<
 			Balance = BalanceOf<Self>,
 			AccountId = Self::AccountId,
 		>;
@@ -409,7 +409,7 @@ impl<T: Config> Delegator for Pallet<T> {
 	}
 }
 
-impl<T: Config> sp_staking::StakeBalanceProvider for Pallet<T> {
+impl<T: Config> sp_staking::StakingBalanceProvider for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 99b9a94c68ad7..e136ee56fa3a4 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -230,6 +230,8 @@ impl ExtBuilder {
 	}
 }
 
-pub fn fund(who: AccountId, amount: Balance) {
+/// fund and return who.
+pub fn fund(who: AccountId, amount: Balance) -> AccountId {
 	let _ = Balances::deposit_creating(&who, amount);
+	who
 }
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 40c30c9ce0380..0713261b5394d 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -20,26 +20,27 @@
 use super::*;
 use crate::{mock::*, Event};
 use frame_support::{assert_noop, assert_ok};
-use sp_staking::{StakeBalanceProvider, StakeBalanceType};
+use pallet_staking::Error as StakingError;
+use sp_staking::{StakingBalanceProvider, StakeBalanceType};
+use frame_support::traits::fungible::InspectHold;
 
 #[test]
 fn create_a_delegatee_with_first_delegator() {
 	ExtBuilder::default().build_and_execute(|| {
 		let delegatee: AccountId = 200;
-		fund(delegatee, 1000);
 		let reward_account: AccountId = 201;
 		let delegator: AccountId = 202;
-		fund(delegator, 1000);
 
 		// set intention to accept delegation.
-		assert_ok!(DelegatedStaking::accept_delegations(&delegatee, &reward_account));
+		assert_ok!(DelegatedStaking::accept_delegations(&fund(delegatee, 1000), &reward_account));
 
 		// delegate to this account
-		assert_ok!(DelegatedStaking::delegate(&delegator, &delegatee, 100));
+		assert_ok!(DelegatedStaking::delegate(&fund(delegator, 1000), &delegatee, 100));
 
 		// verify
 		assert_eq!(DelegatedStaking::stake_type(&delegatee), StakeBalanceType::Delegated);
 		assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100);
+		assert_eq!(Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator), 100);
 	});
 }
 
@@ -74,11 +75,10 @@ fn cannot_become_delegatee() {
 fn create_multiple_delegators() {
 	ExtBuilder::default().build_and_execute(|| {
 		let delegatee: AccountId = 200;
-		fund(delegatee, 1000);
 		let reward_account: AccountId = 201;
 
 		// before becoming a delegatee, stakeable balance is only direct balance.
-		assert_eq!(DelegatedStaking::stake_type(&delegatee), StakeBalanceType::Direct);
+		assert_eq!(DelegatedStaking::stake_type(&fund(delegatee, 1000)), StakeBalanceType::Direct);
 		assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 1000);
 
 		// set intention to accept delegation.
@@ -86,8 +86,13 @@ fn create_multiple_delegators() {
 
 		// create 100 delegators
 		for i in 202..302 {
-			fund(i, 100 + ExistentialDeposit::get());
-			assert_ok!(DelegatedStaking::delegate(&i, &delegatee, 100));
+			assert_ok!(DelegatedStaking::delegate(
+				&fund(i, 100 + ExistentialDeposit::get()),
+				&delegatee,
+				100
+			));
+			// Balance of 100 held on delegator account for delegating to the delegatee.
+			assert_eq!(Balances::balance_on_hold(&HoldReason::Delegating.into(), &i), 100);
 		}
 
 		// verify
@@ -117,13 +122,32 @@ fn migrate_to_delegator() {
 	ExtBuilder::default().build_and_execute(|| assert!(true));
 }
 
-/// Integration tests with pallet-staking and pallet-nomination-pools.
+/// Integration tests with pallet-staking.
 mod integration {
-	use crate::mock::ExtBuilder;
+	use super::*;
 
 	#[test]
 	fn bond() {
-		ExtBuilder::default().build_and_execute(|| assert!(true));
+		ExtBuilder::default().build_and_execute(|| {
+			let delegatee: AccountId = 99;
+			let reward_acc: AccountId = 100;
+			assert_eq!(Staking::status(&delegatee), Err(StakingError::<T>::NotStash.into()));
+			assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 0);
+			assert_eq!(Balances::free_balance(delegatee), 0);
+
+			// set intention to become a delegatee
+			assert_ok!(DelegatedStaking::accept_delegations(&fund(delegatee, 100), &reward_acc));
+			// set some delegations
+			for delegator in 200..250 {
+				assert_ok!(DelegatedStaking::delegate(&fund(delegator, 1000), &delegatee, 100));
+				assert_eq!(Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator), 100);
+				assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100);
+
+				assert_ok!(Staking::bond(RuntimeOrigin::signed(delegatee), ));
+			}
+
+			//
+		});
 	}
 
 	#[test]
diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs
index 697fa9f2257a1..a9d46b098aa21 100644
--- a/substrate/frame/staking/src/ledger.rs
+++ b/substrate/frame/staking/src/ledger.rs
@@ -16,26 +16,13 @@
 // limitations under the License.
 
 //! A Ledger implementation for stakers.
-//!
-//! A [`StakingLedger`] encapsulates all the state and logic related to the stake of bonded
-//! stakers, namely, it handles the following storage items:
-//! * [`Bonded`]: mutates and reads the state of the controller <> stash bond map (to be deprecated
-//! soon);
-//! * [`Ledger`]: mutates and reads the state of all the stakers. The [`Ledger`] storage item stores
-//!   instances of [`StakingLedger`] keyed by the staker's controller account and should be mutated
-//!   and read through the [`StakingLedger`] API;
-//! * [`Payee`]: mutates and reads the reward destination preferences for a bonded stash.
-//! * Staking locks: mutates the locks for staking.
-//!
-//! NOTE: All the storage operations related to the staking ledger (both reads and writes) *MUST* be
-//! performed through the methods exposed by the [`StakingLedger`] implementation in order to ensure
-//! state consistency.
 
 use frame_support::defensive;
-use sp_staking::{StakeBalanceProvider, StakingAccount};
+use sp_staking::{StakingAccount, StakingBalanceProvider};
 use sp_std::prelude::*;
 
 use crate::{BalanceOf, Bonded, Config, Error, Ledger, Payee, RewardDestination, StakingLedger};
+use sp_staking::RewardDestinationChecker;
 
 #[cfg(any(feature = "runtime-benchmarks", test))]
 use sp_runtime::traits::Zero;
@@ -54,12 +41,6 @@ impl<T: Config> StakingLedger<T> {
 	}
 
 	/// Returns a new instance of a staking ledger.
-	///
-	/// The [`Ledger`] storage is not mutated. In order to store, `StakingLedger::update` must be
-	/// called on the returned staking ledger.
-	///
-	/// Note: as the controller accounts are being deprecated, the stash account is the same as the
-	/// controller account.
 	pub fn new(stash: T::AccountId, stake: BalanceOf<T>) -> Self {
 		Self {
 			stash: stash.clone(),
@@ -179,22 +160,30 @@ impl<T: Config> StakingLedger<T> {
 	/// It sets the reward preferences for the bonded stash.
 	pub(crate) fn bond(self, payee: RewardDestination<T::AccountId>) -> Result<(), Error<T>> {
 		if <Bonded<T>>::contains_key(&self.stash) {
-			Err(Error::<T>::AlreadyBonded)
-		} else {
-			<Payee<T>>::insert(&self.stash, payee);
-			<Bonded<T>>::insert(&self.stash, &self.stash);
-			self.update()
+			return Err(Error::<T>::AlreadyBonded);
 		}
+
+		if T::RewardDestinationChecker::restrict(&self.stash, payee.clone().from(&self.stash)) {
+			return Err(Error::<T>::RewardDestinationRestricted);
+		}
+
+		<Payee<T>>::insert(&self.stash, payee);
+		<Bonded<T>>::insert(&self.stash, &self.stash);
+		self.update()
 	}
 
 	/// Sets the ledger Payee.
 	pub(crate) fn set_payee(self, payee: RewardDestination<T::AccountId>) -> Result<(), Error<T>> {
 		if !<Bonded<T>>::contains_key(&self.stash) {
-			Err(Error::<T>::NotStash)
-		} else {
-			<Payee<T>>::insert(&self.stash, payee);
-			Ok(())
+			return Err(Error::<T>::NotStash);
+		}
+
+		if T::RewardDestinationChecker::restrict(&self.stash, payee.clone().from(&self.stash)) {
+			return Err(Error::<T>::RewardDestinationRestricted);
 		}
+
+		<Payee<T>>::insert(&self.stash, payee);
+		Ok(())
 	}
 
 	/// Clears all data related to a staking ledger and its bond in both [`Ledger`] and [`Bonded`]
diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs
index 4e10fe787a9dd..97398e457cc03 100644
--- a/substrate/frame/staking/src/lib.rs
+++ b/substrate/frame/staking/src/lib.rs
@@ -413,6 +413,22 @@ impl<AccountId> Default for RewardDestination<AccountId> {
 	}
 }
 
+impl<AccountId: Clone> RewardDestination<AccountId> {
+	fn from(self, stash: &AccountId) -> Option<AccountId> {
+		match self {
+			// FIXME(ank4n): Figure out later how to handle Controller
+			RewardDestination::Staked | RewardDestination::Stash => Some(stash.clone()),
+			RewardDestination::Account(a) => Some(a),
+			#[allow(deprecated)]
+			_ => {
+				defensive!("reward destination not set or set as deprecated controller");
+				None
+			},
+		}
+	}
+
+}
+
 /// Preference of what happens regarding validation.
 #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, Default, MaxEncodedLen)]
 pub struct ValidatorPrefs {
diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs
index e28de7932e497..eb7f9cb9e60ff 100644
--- a/substrate/frame/staking/src/mock.rs
+++ b/substrate/frame/staking/src/mock.rs
@@ -296,6 +296,8 @@ impl crate::pallet::pallet::Config for Test {
 	type CurrencyBalance = <Self as pallet_balances::Config>::Balance;
 
 	type StakeBalanceProvider = Staking;
+
+	type RewardDestinationChecker = ();
 	type UnixTime = Timestamp;
 	type CurrencyToVote = ();
 	type RewardRemainder = RewardRemainderMock;
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index c0fd4fcc99371..ec03c2a5029bf 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -41,7 +41,7 @@ use sp_runtime::{
 use sp_staking::{
 	currency_to_vote::CurrencyToVote,
 	offence::{DisableStrategy, OffenceDetails, OnOffenceHandler},
-	EraIndex, Page, SessionIndex, Stake, StakeBalanceProvider, StakeBalanceType,
+	EraIndex, Page, SessionIndex, Stake, StakingBalanceProvider, StakeBalanceType,
 	StakingAccount::{self, Controller, Stash},
 	StakingInterface,
 };
@@ -1823,7 +1823,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 }
 
-impl<T: Config> StakeBalanceProvider for Pallet<T> {
+impl<T: Config> StakingBalanceProvider for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index 508218dcfd4f8..fa26f412c1a18 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -37,7 +37,7 @@ use sp_runtime::{
 };
 
 use sp_staking::{
-	EraIndex, Page, SessionIndex, StakeBalanceProvider,
+	EraIndex, Page, SessionIndex, StakingBalanceProvider,
 	StakingAccount::{self, Controller, Stash},
 };
 use sp_std::prelude::*;
@@ -106,11 +106,13 @@ pub mod pallet {
 
 		/// Something that provides stakeable balance of an account as well as a way to hold and
 		/// release this stake.
-		type StakeBalanceProvider: StakeBalanceProvider<
+		type StakeBalanceProvider: StakingBalanceProvider<
 			Balance = Self::CurrencyBalance,
 			AccountId = Self::AccountId,
 		>;
 
+		type RewardDestinationChecker: sp_staking::RewardDestinationChecker<Self::AccountId>;
+
 		/// Time used for computing era duration.
 		///
 		/// It is guaranteed to start being called from the first `on_finalize`. Thus value at
@@ -855,6 +857,8 @@ pub mod pallet {
 		BoundNotMet,
 		/// Used when attempting to use deprecated controller account logic.
 		ControllerDeprecated,
+		/// Provided reward destination is not allowed.
+		RewardDestinationRestricted,
 	}
 
 	#[pallet::hooks]
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 6b1cd16329437..6a3ab7374a7d3 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -98,9 +98,6 @@ pub struct Stake<Balance> {
 #[impl_trait_for_tuples::impl_for_tuples(10)]
 pub trait OnStakingUpdate<AccountId, Balance> {
 	/// Fired when the stake amount of someone updates.
-	///
-	/// This is effectively any changes to the bond amount, such as bonding more funds, and
-	/// unbonding.
 	fn on_stake_update(_who: &AccountId, _prev_stake: Option<Stake<Balance>>) {}
 
 	/// Fired when someone sets their intention to nominate.
@@ -116,9 +113,6 @@ pub trait OnStakingUpdate<AccountId, Balance> {
 	fn on_nominator_update(_who: &AccountId, _prev_nominations: Vec<AccountId>) {}
 
 	/// Fired when someone removes their intention to nominate, either due to chill or validating.
-	///
-	/// The set of nominations at the time of removal is provided as it can no longer be fetched in
-	/// any way.
 	fn on_nominator_remove(_who: &AccountId, _nominations: Vec<AccountId>) {}
 
 	/// Fired when someone sets their intention to validate.
@@ -154,9 +148,6 @@ pub trait OnStakingUpdate<AccountId, Balance> {
 }
 
 /// A generic representation of a staking implementation.
-///
-/// This interface uses the terminology of NPoS, but it is aims to be generic enough to cover other
-/// implementations as well.
 pub trait StakingInterface {
 	/// Balance type used by the staking system.
 	type Balance: Sub<Output = Self::Balance>
@@ -352,10 +343,9 @@ impl<
 				Vec::with_capacity(chunk.len());
 			for individual in chunk.iter() {
 				page_total.saturating_accrue(individual.value);
-				others.push(IndividualExposure {
-					who: individual.who.clone(),
-					value: individual.value,
-				})
+				others.push(
+					IndividualExposure { who: individual.who.clone(), value: individual.value }
+				)
 			}
 
 			exposure_pages.push(ExposurePage { page_total, others });
@@ -421,7 +411,7 @@ pub struct PagedExposureMetadata<Balance: HasCompact + codec::MaxEncodedLen> {
 }
 
 /// Something that provides stakeable balance and a mechanism to reserve this balance.
-pub trait StakeBalanceProvider {
+pub trait StakingBalanceProvider {
 	/// Balance type used by the staking system.
 	type Balance: Sub<Output = Self::Balance>
 		+ Ord
@@ -436,14 +426,33 @@ pub trait StakeBalanceProvider {
 	/// AccountId type used by the staking system.
 	type AccountId: Clone + sp_std::fmt::Debug;
 
+	/// Balance of who which is available for stake.
 	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance;
+
+	/// Update amount held for bonded stake.
 	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult;
+
+	/// Release all amount held for stake.
 	fn release(who: &Self::AccountId);
 
 	#[cfg(feature = "std")]
 	fn stake_type(who: &Self::AccountId) -> StakeBalanceType;
 }
 
+/// Something that ensures destination for staking rewards is allowed.
+pub trait RewardDestinationChecker<AccountId: Clone> {
+
+	/// Returns true if `who` is not allowed to have provided `reward_destination`.
+	fn restrict(who: &AccountId, reward_destination: Option<AccountId>) -> bool;
+}
+
+impl<AccountId: Clone> RewardDestinationChecker<AccountId> for () {
+	fn restrict(_who: &AccountId, _reward_destination: Option<AccountId>) -> bool {
+		// never restrict
+		false
+	}
+}
+
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub enum StakeBalanceType {
 	Direct,

From 8cf31b9ad5fbedf140ce69321f1bf3eccce86faf Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 16:40:26 +0100
Subject: [PATCH 028/202] refactor reward acc restricter in delegation support
 trait

---
 substrate/frame/delegated-staking/src/lib.rs  |  6 ++---
 substrate/frame/delegated-staking/src/mock.rs |  2 +-
 .../frame/delegated-staking/src/tests.rs      |  2 +-
 substrate/frame/staking/src/ledger.rs         | 11 ++++-----
 substrate/frame/staking/src/mock.rs           |  5 +---
 substrate/frame/staking/src/pallet/impls.rs   |  6 ++---
 substrate/frame/staking/src/pallet/mod.rs     | 12 ++++------
 substrate/primitives/staking/src/lib.rs       | 23 ++++++-------------
 8 files changed, 26 insertions(+), 41 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index c52f93448f5af..513c3a7e11f7e 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -47,7 +47,7 @@ pub type BalanceOf<T> =
 #[frame_support::pallet]
 pub mod pallet {
 	use super::*;
-	use sp_staking::StakingBalanceProvider;
+	use sp_staking::StakingDelegationSupport;
 
 	#[pallet::pallet]
 	pub struct Pallet<T>(PhantomData<T>);
@@ -68,7 +68,7 @@ pub mod pallet {
 		/// Core Staking Balance Provider.
 		///
 		/// Fallback implementation when an account is not a delegatee.
-		type FallbackBalanceProvider: StakingBalanceProvider<
+		type FallbackBalanceProvider: StakingDelegationSupport<
 			Balance = BalanceOf<Self>,
 			AccountId = Self::AccountId,
 		>;
@@ -409,7 +409,7 @@ impl<T: Config> Delegator for Pallet<T> {
 	}
 }
 
-impl<T: Config> sp_staking::StakingBalanceProvider for Pallet<T> {
+impl<T: Config> sp_staking::StakingDelegationSupport for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index e136ee56fa3a4..0a586c89b25e9 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -108,7 +108,7 @@ impl onchain::Config for OnChainSeqPhragmen {
 impl pallet_staking::Config for Runtime {
 	type Currency = Balances;
 	type CurrencyBalance = Balance;
-	type StakeBalanceProvider = DelegatedStaking;
+	type DelegationSupport = DelegatedStaking;
 	type UnixTime = pallet_timestamp::Pallet<Self>;
 	type CurrencyToVote = ();
 	type RewardRemainder = ();
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 0713261b5394d..945a2f8a75428 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -21,7 +21,7 @@ use super::*;
 use crate::{mock::*, Event};
 use frame_support::{assert_noop, assert_ok};
 use pallet_staking::Error as StakingError;
-use sp_staking::{StakingBalanceProvider, StakeBalanceType};
+use sp_staking::{StakingDelegationSupport, StakeBalanceType};
 use frame_support::traits::fungible::InspectHold;
 
 #[test]
diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs
index a9d46b098aa21..c5cd29276f859 100644
--- a/substrate/frame/staking/src/ledger.rs
+++ b/substrate/frame/staking/src/ledger.rs
@@ -18,11 +18,10 @@
 //! A Ledger implementation for stakers.
 
 use frame_support::defensive;
-use sp_staking::{StakingAccount, StakingBalanceProvider};
+use sp_staking::{StakingAccount, StakingDelegationSupport};
 use sp_std::prelude::*;
 
 use crate::{BalanceOf, Bonded, Config, Error, Ledger, Payee, RewardDestination, StakingLedger};
-use sp_staking::RewardDestinationChecker;
 
 #[cfg(any(feature = "runtime-benchmarks", test))]
 use sp_runtime::traits::Zero;
@@ -142,7 +141,7 @@ impl<T: Config> StakingLedger<T> {
 			return Err(Error::<T>::NotStash)
 		}
 
-		T::StakeBalanceProvider::update_hold(&self.stash, self.total)
+		T::DelegationSupport::update_hold(&self.stash, self.total)
 			.map_err(|_| Error::<T>::BadState)?;
 		Ledger::<T>::insert(
 			&self.controller().ok_or_else(|| {
@@ -163,7 +162,7 @@ impl<T: Config> StakingLedger<T> {
 			return Err(Error::<T>::AlreadyBonded);
 		}
 
-		if T::RewardDestinationChecker::restrict(&self.stash, payee.clone().from(&self.stash)) {
+		if T::DelegationSupport::restrict_reward_destination(&self.stash, payee.clone().from(&self.stash)) {
 			return Err(Error::<T>::RewardDestinationRestricted);
 		}
 
@@ -178,7 +177,7 @@ impl<T: Config> StakingLedger<T> {
 			return Err(Error::<T>::NotStash);
 		}
 
-		if T::RewardDestinationChecker::restrict(&self.stash, payee.clone().from(&self.stash)) {
+		if T::DelegationSupport::restrict_reward_destination(&self.stash, payee.clone().from(&self.stash)) {
 			return Err(Error::<T>::RewardDestinationRestricted);
 		}
 
@@ -192,7 +191,7 @@ impl<T: Config> StakingLedger<T> {
 		let controller = <Bonded<T>>::get(stash).ok_or(Error::<T>::NotStash)?;
 
 		<Ledger<T>>::get(&controller).ok_or(Error::<T>::NotController).map(|ledger| {
-			T::StakeBalanceProvider::release(&ledger.stash);
+			T::DelegationSupport::release(&ledger.stash);
 			Ledger::<T>::remove(controller);
 
 			<Bonded<T>>::remove(&stash);
diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs
index eb7f9cb9e60ff..20c533f62b1b1 100644
--- a/substrate/frame/staking/src/mock.rs
+++ b/substrate/frame/staking/src/mock.rs
@@ -294,10 +294,7 @@ impl OnStakingUpdate<AccountId, Balance> for EventListenerMock {
 impl crate::pallet::pallet::Config for Test {
 	type Currency = Balances;
 	type CurrencyBalance = <Self as pallet_balances::Config>::Balance;
-
-	type StakeBalanceProvider = Staking;
-
-	type RewardDestinationChecker = ();
+	type DelegationSupport = Staking;
 	type UnixTime = Timestamp;
 	type CurrencyToVote = ();
 	type RewardRemainder = RewardRemainderMock;
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index ec03c2a5029bf..cd672fd8daf52 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -41,7 +41,7 @@ use sp_runtime::{
 use sp_staking::{
 	currency_to_vote::CurrencyToVote,
 	offence::{DisableStrategy, OffenceDetails, OnOffenceHandler},
-	EraIndex, Page, SessionIndex, Stake, StakingBalanceProvider, StakeBalanceType,
+	EraIndex, Page, SessionIndex, Stake, StakingDelegationSupport, StakeBalanceType,
 	StakingAccount::{self, Controller, Stash},
 	StakingInterface,
 };
@@ -1818,12 +1818,12 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	fn force_unlock(who: &Self::AccountId) -> sp_runtime::DispatchResult {
-		T::StakeBalanceProvider::release(who);
+		T::DelegationSupport::release(who);
 		Ok(())
 	}
 }
 
-impl<T: Config> StakingBalanceProvider for Pallet<T> {
+impl<T: Config> StakingDelegationSupport for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index fa26f412c1a18..a8610ae0a59a5 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -37,7 +37,7 @@ use sp_runtime::{
 };
 
 use sp_staking::{
-	EraIndex, Page, SessionIndex, StakingBalanceProvider,
+	EraIndex, Page, SessionIndex, StakingDelegationSupport,
 	StakingAccount::{self, Controller, Stash},
 };
 use sp_std::prelude::*;
@@ -106,13 +106,11 @@ pub mod pallet {
 
 		/// Something that provides stakeable balance of an account as well as a way to hold and
 		/// release this stake.
-		type StakeBalanceProvider: StakingBalanceProvider<
+		type DelegationSupport: StakingDelegationSupport<
 			Balance = Self::CurrencyBalance,
 			AccountId = Self::AccountId,
 		>;
 
-		type RewardDestinationChecker: sp_staking::RewardDestinationChecker<Self::AccountId>;
-
 		/// Time used for computing era duration.
 		///
 		/// It is guaranteed to start being called from the first `on_finalize`. Thus value at
@@ -713,7 +711,7 @@ pub mod pallet {
 					status
 				);
 				assert!(
-					T::StakeBalanceProvider::stakeable_balance(stash) >= balance,
+					T::DelegationSupport::stakeable_balance(stash) >= balance,
 					"Stash does not have enough balance to bond."
 				);
 				frame_support::assert_ok!(<Pallet<T>>::bond(
@@ -948,7 +946,7 @@ pub mod pallet {
 
 			frame_system::Pallet::<T>::inc_consumers(&stash).map_err(|_| Error::<T>::BadState)?;
 
-			let stash_balance = T::StakeBalanceProvider::stakeable_balance(&stash);
+			let stash_balance = T::DelegationSupport::stakeable_balance(&stash);
 			let value = value.min(stash_balance);
 			Self::deposit_event(Event::<T>::Bonded { stash: stash.clone(), amount: value });
 			let ledger = StakingLedger::<T>::new(stash.clone(), value);
@@ -984,7 +982,7 @@ pub mod pallet {
 
 			let mut ledger = Self::ledger(StakingAccount::Stash(stash.clone()))?;
 
-			let stash_balance = T::StakeBalanceProvider::stakeable_balance(&stash);
+			let stash_balance = T::DelegationSupport::stakeable_balance(&stash);
 			if let Some(extra) = stash_balance.checked_sub(&ledger.total) {
 				let extra = extra.min(max_additional);
 				ledger.total += extra;
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 6a3ab7374a7d3..3afefc50cef36 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -410,8 +410,8 @@ pub struct PagedExposureMetadata<Balance: HasCompact + codec::MaxEncodedLen> {
 	pub page_count: Page,
 }
 
-/// Something that provides stakeable balance and a mechanism to reserve this balance.
-pub trait StakingBalanceProvider {
+/// Something that provides delegation support to core staking.
+pub trait StakingDelegationSupport{
 	/// Balance type used by the staking system.
 	type Balance: Sub<Output = Self::Balance>
 		+ Ord
@@ -435,22 +435,13 @@ pub trait StakingBalanceProvider {
 	/// Release all amount held for stake.
 	fn release(who: &Self::AccountId);
 
-	#[cfg(feature = "std")]
-	fn stake_type(who: &Self::AccountId) -> StakeBalanceType;
-}
-
-/// Something that ensures destination for staking rewards is allowed.
-pub trait RewardDestinationChecker<AccountId: Clone> {
-
-	/// Returns true if `who` is not allowed to have provided `reward_destination`.
-	fn restrict(who: &AccountId, reward_destination: Option<AccountId>) -> bool;
-}
-
-impl<AccountId: Clone> RewardDestinationChecker<AccountId> for () {
-	fn restrict(_who: &AccountId, _reward_destination: Option<AccountId>) -> bool {
-		// never restrict
+	fn restrict_reward_destination(_who: &Self::AccountId, _reward_destination: Option<Self::AccountId>) -> bool {
+		// never restrict by default
 		false
 	}
+
+	#[cfg(feature = "std")]
+	fn stake_type(who: &Self::AccountId) -> StakeBalanceType;
 }
 
 #[derive(Clone, Debug, Eq, PartialEq)]

From 7d7ce787c3084eda9ba39ff6469998217c0d3213 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 16:42:44 +0100
Subject: [PATCH 029/202] fmt

---
 substrate/frame/delegated-staking/src/tests.rs | 12 +++++++-----
 substrate/frame/staking/src/ledger.rs          | 10 ++++++++--
 substrate/frame/staking/src/lib.rs             |  1 -
 substrate/frame/staking/src/pallet/impls.rs    |  4 ++--
 substrate/frame/staking/src/pallet/mod.rs      |  3 ++-
 substrate/primitives/staking/src/lib.rs        | 14 +++++++++-----
 6 files changed, 28 insertions(+), 16 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 945a2f8a75428..6a1193ff49444 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -19,10 +19,9 @@
 
 use super::*;
 use crate::{mock::*, Event};
-use frame_support::{assert_noop, assert_ok};
+use frame_support::{assert_noop, assert_ok, traits::fungible::InspectHold};
 use pallet_staking::Error as StakingError;
-use sp_staking::{StakingDelegationSupport, StakeBalanceType};
-use frame_support::traits::fungible::InspectHold;
+use sp_staking::{StakeBalanceType, StakingDelegationSupport};
 
 #[test]
 fn create_a_delegatee_with_first_delegator() {
@@ -140,10 +139,13 @@ mod integration {
 			// set some delegations
 			for delegator in 200..250 {
 				assert_ok!(DelegatedStaking::delegate(&fund(delegator, 1000), &delegatee, 100));
-				assert_eq!(Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator), 100);
+				assert_eq!(
+					Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator),
+					100
+				);
 				assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100);
 
-				assert_ok!(Staking::bond(RuntimeOrigin::signed(delegatee), ));
+				assert_ok!(Staking::bond(RuntimeOrigin::signed(delegatee),));
 			}
 
 			//
diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs
index c5cd29276f859..9dac51e42577d 100644
--- a/substrate/frame/staking/src/ledger.rs
+++ b/substrate/frame/staking/src/ledger.rs
@@ -162,7 +162,10 @@ impl<T: Config> StakingLedger<T> {
 			return Err(Error::<T>::AlreadyBonded);
 		}
 
-		if T::DelegationSupport::restrict_reward_destination(&self.stash, payee.clone().from(&self.stash)) {
+		if T::DelegationSupport::restrict_reward_destination(
+			&self.stash,
+			payee.clone().from(&self.stash),
+		) {
 			return Err(Error::<T>::RewardDestinationRestricted);
 		}
 
@@ -177,7 +180,10 @@ impl<T: Config> StakingLedger<T> {
 			return Err(Error::<T>::NotStash);
 		}
 
-		if T::DelegationSupport::restrict_reward_destination(&self.stash, payee.clone().from(&self.stash)) {
+		if T::DelegationSupport::restrict_reward_destination(
+			&self.stash,
+			payee.clone().from(&self.stash),
+		) {
 			return Err(Error::<T>::RewardDestinationRestricted);
 		}
 
diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs
index 97398e457cc03..dc89944d8e019 100644
--- a/substrate/frame/staking/src/lib.rs
+++ b/substrate/frame/staking/src/lib.rs
@@ -426,7 +426,6 @@ impl<AccountId: Clone> RewardDestination<AccountId> {
 			},
 		}
 	}
-
 }
 
 /// Preference of what happens regarding validation.
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index cd672fd8daf52..245e3636d9a61 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -41,9 +41,9 @@ use sp_runtime::{
 use sp_staking::{
 	currency_to_vote::CurrencyToVote,
 	offence::{DisableStrategy, OffenceDetails, OnOffenceHandler},
-	EraIndex, Page, SessionIndex, Stake, StakingDelegationSupport, StakeBalanceType,
+	EraIndex, Page, SessionIndex, Stake, StakeBalanceType,
 	StakingAccount::{self, Controller, Stash},
-	StakingInterface,
+	StakingDelegationSupport, StakingInterface,
 };
 use sp_std::prelude::*;
 
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index a8610ae0a59a5..d20322dbb881e 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -37,8 +37,9 @@ use sp_runtime::{
 };
 
 use sp_staking::{
-	EraIndex, Page, SessionIndex, StakingDelegationSupport,
+	EraIndex, Page, SessionIndex,
 	StakingAccount::{self, Controller, Stash},
+	StakingDelegationSupport,
 };
 use sp_std::prelude::*;
 
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 3afefc50cef36..66a4fe299a93c 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -343,9 +343,10 @@ impl<
 				Vec::with_capacity(chunk.len());
 			for individual in chunk.iter() {
 				page_total.saturating_accrue(individual.value);
-				others.push(
-					IndividualExposure { who: individual.who.clone(), value: individual.value }
-				)
+				others.push(IndividualExposure {
+					who: individual.who.clone(),
+					value: individual.value,
+				})
 			}
 
 			exposure_pages.push(ExposurePage { page_total, others });
@@ -411,7 +412,7 @@ pub struct PagedExposureMetadata<Balance: HasCompact + codec::MaxEncodedLen> {
 }
 
 /// Something that provides delegation support to core staking.
-pub trait StakingDelegationSupport{
+pub trait StakingDelegationSupport {
 	/// Balance type used by the staking system.
 	type Balance: Sub<Output = Self::Balance>
 		+ Ord
@@ -435,7 +436,10 @@ pub trait StakingDelegationSupport{
 	/// Release all amount held for stake.
 	fn release(who: &Self::AccountId);
 
-	fn restrict_reward_destination(_who: &Self::AccountId, _reward_destination: Option<Self::AccountId>) -> bool {
+	fn restrict_reward_destination(
+		_who: &Self::AccountId,
+		_reward_destination: Option<Self::AccountId>,
+	) -> bool {
 		// never restrict by default
 		false
 	}

From 59f285d7772387d306091c7fd0e32e346b00a117 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 16:56:16 +0100
Subject: [PATCH 030/202] explicitly set Staking to have NoDelegation impl

---
 substrate/frame/delegated-staking/src/lib.rs | 16 ++++++++++++++--
 substrate/frame/staking/src/lib.rs           |  2 +-
 substrate/frame/staking/src/mock.rs          |  2 +-
 substrate/frame/staking/src/pallet/impls.rs  |  4 +++-
 4 files changed, 19 insertions(+), 5 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 513c3a7e11f7e..01fadc6d943c1 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -37,7 +37,7 @@ use pallet::*;
 use sp_runtime::{traits::Zero, DispatchResult, RuntimeDebug, Saturating};
 use sp_staking::{
 	delegation::{Delegatee, Delegator},
-	StakeBalanceType, StakerStatus, StakingInterface,
+	StakeBalanceType, StakerStatus, StakingDelegationSupport, StakingInterface,
 };
 use sp_std::{convert::TryInto, prelude::*};
 
@@ -409,7 +409,7 @@ impl<T: Config> Delegator for Pallet<T> {
 	}
 }
 
-impl<T: Config> sp_staking::StakingDelegationSupport for Pallet<T> {
+impl<T: Config> StakingDelegationSupport for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
@@ -428,6 +428,18 @@ impl<T: Config> sp_staking::StakingDelegationSupport for Pallet<T> {
 		T::FallbackBalanceProvider::release(who)
 	}
 
+	fn restrict_reward_destination(
+		who: &Self::AccountId,
+		reward_destination: Option<Self::AccountId>,
+	) -> bool {
+		// for non delegatee accounts, use default implementation.
+		if !Self::is_delegatee(who) {
+			return T::FallbackBalanceProvider::restrict_reward_destination(who, reward_destination);
+		}
+
+		// restrict if reward destination not set or set as delegatee account itself.
+		reward_destination.map_or_else(|| true, |reward_acc| who == reward_destination)
+	}
 	#[cfg(feature = "std")]
 	fn stake_type(who: &Self::AccountId) -> StakeBalanceType {
 		if Self::is_delegatee(who) {
diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs
index dc89944d8e019..d8d20fc651054 100644
--- a/substrate/frame/staking/src/lib.rs
+++ b/substrate/frame/staking/src/lib.rs
@@ -322,7 +322,7 @@ pub use sp_staking::{Exposure, IndividualExposure, StakerStatus};
 use sp_std::{collections::btree_map::BTreeMap, prelude::*};
 pub use weights::WeightInfo;
 
-pub use pallet::{pallet::*, UseNominatorsAndValidatorsMap, UseValidatorsMap};
+pub use pallet::{pallet::*, NoDelegation, UseNominatorsAndValidatorsMap, UseValidatorsMap};
 
 pub(crate) const STAKING_ID: LockIdentifier = *b"staking ";
 pub(crate) const LOG_TARGET: &str = "runtime::staking";
diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs
index 20c533f62b1b1..dfbf5ea53d407 100644
--- a/substrate/frame/staking/src/mock.rs
+++ b/substrate/frame/staking/src/mock.rs
@@ -294,7 +294,7 @@ impl OnStakingUpdate<AccountId, Balance> for EventListenerMock {
 impl crate::pallet::pallet::Config for Test {
 	type Currency = Balances;
 	type CurrencyBalance = <Self as pallet_balances::Config>::Balance;
-	type DelegationSupport = Staking;
+	type DelegationSupport = pallet_staking::NoDelegation<Self>;
 	type UnixTime = Timestamp;
 	type CurrencyToVote = ();
 	type RewardRemainder = RewardRemainderMock;
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 245e3636d9a61..0a4a49f028640 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1823,7 +1823,8 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 }
 
-impl<T: Config> StakingDelegationSupport for Pallet<T> {
+pub struct NoDelegation<T>(PhantomData<T>);
+impl<T: Config> StakingDelegationSupport for NoDelegation<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
@@ -1845,6 +1846,7 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 		StakeBalanceType::Direct
 	}
 }
+
 #[cfg(any(test, feature = "try-runtime"))]
 impl<T: Config> Pallet<T> {
 	pub(crate) fn do_try_state(_: BlockNumberFor<T>) -> Result<(), TryRuntimeError> {

From 1441013a0b1e1a647fa2e0c7c7e5a690883abc51 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 17:14:36 +0100
Subject: [PATCH 031/202] fix delegated staking and refactor

---
 substrate/frame/delegated-staking/src/lib.rs   | 16 ++++++++--------
 substrate/frame/delegated-staking/src/mock.rs  |  2 +-
 substrate/frame/delegated-staking/src/tests.rs |  4 ++--
 3 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 01fadc6d943c1..712d52d7df727 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -65,10 +65,10 @@ pub mod pallet {
 		/// Core staking implementation.
 		type Staking: StakingInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
 
-		/// Core Staking Balance Provider.
+		/// Non Delegatee Staking Support.
 		///
 		/// Fallback implementation when an account is not a delegatee.
-		type FallbackBalanceProvider: StakingDelegationSupport<
+		type FallbackSupportProvider: StakingDelegationSupport<
 			Balance = BalanceOf<Self>,
 			AccountId = Self::AccountId,
 		>;
@@ -415,17 +415,17 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 
 	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
 		<Delegatees<T>>::get(who).map_or_else(
-			|| T::FallbackBalanceProvider::stakeable_balance(who),
+			|| T::FallbackSupportProvider::stakeable_balance(who),
 			|delegatee| delegatee.effective_balance(),
 		)
 	}
 
 	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
-		T::FallbackBalanceProvider::update_hold(who, amount)
+		T::FallbackSupportProvider::update_hold(who, amount)
 	}
 
 	fn release(who: &Self::AccountId) {
-		T::FallbackBalanceProvider::release(who)
+		T::FallbackSupportProvider::release(who)
 	}
 
 	fn restrict_reward_destination(
@@ -434,11 +434,11 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 	) -> bool {
 		// for non delegatee accounts, use default implementation.
 		if !Self::is_delegatee(who) {
-			return T::FallbackBalanceProvider::restrict_reward_destination(who, reward_destination);
+			return T::FallbackSupportProvider::restrict_reward_destination(who, reward_destination);
 		}
 
 		// restrict if reward destination not set or set as delegatee account itself.
-		reward_destination.map_or_else(|| true, |reward_acc| who == reward_destination)
+		reward_destination.map_or_else(|| true, |reward_acc| who == &reward_acc)
 	}
 	#[cfg(feature = "std")]
 	fn stake_type(who: &Self::AccountId) -> StakeBalanceType {
@@ -446,7 +446,7 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 			return StakeBalanceType::Delegated;
 		}
 
-		T::FallbackBalanceProvider::stake_type(who)
+		T::FallbackSupportProvider::stake_type(who)
 	}
 }
 
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 0a586c89b25e9..cab9bf33de3ca 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -141,7 +141,7 @@ impl delegated_staking::Config for Runtime {
 	type Currency = Balances;
 	type RuntimeHoldReason = RuntimeHoldReason;
 	type Staking = Staking;
-	type FallbackBalanceProvider = Staking;
+	type FallbackSupportProvider = pallet_staking::NoDelegation<Self>;
 }
 
 frame_support::construct_runtime!(
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 6a1193ff49444..1b1f63999f6ac 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -143,9 +143,9 @@ mod integration {
 					Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator),
 					100
 				);
-				assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100);
+				// assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100);
 
-				assert_ok!(Staking::bond(RuntimeOrigin::signed(delegatee),));
+				// assert_ok!(Staking::bond(RuntimeOrigin::signed(delegatee),));
 			}
 
 			//

From 2a7376d6d6ad79f8abd7bbc1d1749a8ccea58d8d Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 19:43:19 +0100
Subject: [PATCH 032/202] bond test

---
 substrate/frame/delegated-staking/src/lib.rs  | 92 +++++++++++++++----
 substrate/frame/delegated-staking/src/mock.rs |  9 +-
 .../frame/delegated-staking/src/tests.rs      | 41 +++++++--
 .../primitives/staking/src/delegation.rs      |  5 +-
 4 files changed, 112 insertions(+), 35 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 712d52d7df727..b7b23f2d3c58a 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -26,11 +26,13 @@ mod tests;
 
 #[cfg(feature = "runtime-benchmarks")]
 mod benchmarking;
+
 use frame_support::{
 	pallet_prelude::*,
 	traits::{
 		fungible::{hold::Mutate as FunHoldMutate, Inspect as FunInspect, Mutate as FunMutate},
 		tokens::{Fortitude, Precision, Preservation},
+		DefensiveOption,
 	},
 };
 use pallet::*;
@@ -68,7 +70,7 @@ pub mod pallet {
 		/// Non Delegatee Staking Support.
 		///
 		/// Fallback implementation when an account is not a delegatee.
-		type FallbackSupportProvider: StakingDelegationSupport<
+		type FallbackSupport: StakingDelegationSupport<
 			Balance = BalanceOf<Self>,
 			AccountId = Self::AccountId,
 		>;
@@ -95,6 +97,8 @@ pub mod pallet {
 		NotDelegatee,
 		/// Some corruption in internal state.
 		BadState,
+		/// Unapplied pending slash restricts operation on delegatee.
+		UnappliedSlash,
 	}
 
 	/// A reason for placing a hold on funds.
@@ -147,7 +151,10 @@ pub struct DelegationRegister<T: Config> {
 	pub payee: T::AccountId,
 	/// Sum of all delegated funds to this delegatee.
 	#[codec(compact)]
-	pub balance: BalanceOf<T>,
+	pub total_delegated: BalanceOf<T>,
+	/// Amount that is bonded and held.
+	#[codec(compact)]
+	pub hold: BalanceOf<T>,
 	/// Slashes that are not yet applied.
 	#[codec(compact)]
 	pub pending_slash: BalanceOf<T>,
@@ -156,8 +163,20 @@ pub struct DelegationRegister<T: Config> {
 }
 
 impl<T: Config> DelegationRegister<T> {
-	pub fn effective_balance(&self) -> BalanceOf<T> {
-		self.balance.saturating_sub(self.pending_slash)
+	/// balance that can be staked.
+	pub fn delegated_balance(&self) -> BalanceOf<T> {
+		// do not allow to stake more than unapplied slash
+		self.total_delegated.saturating_sub(self.pending_slash)
+	}
+
+	/// balance that is delegated but not bonded.
+	pub fn unbonded_balance(&self) -> BalanceOf<T> {
+		self.total_delegated.saturating_sub(self.hold)
+	}
+
+	/// consumes self and returns Delegation Register with updated hold amount.
+	pub fn update_hold(self, amount: BalanceOf<T>) -> Self {
+		DelegationRegister { hold: amount, ..self }
 	}
 }
 
@@ -165,9 +184,14 @@ impl<T: Config> Delegatee for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
-	fn delegate_balance(who: Self::AccountId) -> Self::Balance {
+	fn delegated_balance(who: &Self::AccountId) -> Self::Balance {
 		<Delegatees<T>>::get(who)
-			.map_or_else(|| 0u32.into(), |register| register.effective_balance())
+			.map_or_else(|| 0u32.into(), |register| register.delegated_balance())
+	}
+
+	fn unbonded_balance(who: &Self::AccountId) -> Self::Balance {
+		<Delegatees<T>>::get(who)
+			.map_or_else(|| 0u32.into(), |register| register.unbonded_balance())
 	}
 
 	fn accept_delegations(
@@ -191,7 +215,8 @@ impl<T: Config> Delegatee for Pallet<T> {
 			} else {
 				*maybe_register = Some(DelegationRegister {
 					payee: reward_destination.clone(),
-					balance: Zero::zero(),
+					total_delegated: Zero::zero(),
+					hold: Zero::zero(),
 					pending_slash: Zero::zero(),
 					blocked: false,
 				});
@@ -264,7 +289,7 @@ impl<T: Config> Delegatee for Pallet<T> {
 
 	fn update_bond(who: &Self::AccountId) -> DispatchResult {
 		let delegatee = <Delegatees<T>>::get(who).ok_or(Error::<T>::NotDelegatee)?;
-		let delegated_balance = delegatee.effective_balance();
+		let delegated_balance = delegatee.delegated_balance();
 
 		match T::Staking::stake(who) {
 			Ok(stake) => {
@@ -303,7 +328,7 @@ impl<T: Config> Delegatee for Pallet<T> {
 
 		<Delegatees<T>>::mutate(delegatee, |maybe_register| match maybe_register {
 			Some(ledger) => {
-				ledger.balance.saturating_reduce(value);
+				ledger.total_delegated.saturating_reduce(value);
 				Ok(())
 			},
 			None => {
@@ -391,7 +416,7 @@ impl<T: Config> Delegator for Pallet<T> {
 		<Delegators<T>>::insert(delegator, (delegatee, new_delegation_amount));
 		<Delegatees<T>>::mutate(delegatee, |maybe_register| {
 			if let Some(register) = maybe_register {
-				register.balance.saturating_accrue(value);
+				register.total_delegated.saturating_accrue(value);
 			}
 		});
 
@@ -415,30 +440,57 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 
 	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
 		<Delegatees<T>>::get(who).map_or_else(
-			|| T::FallbackSupportProvider::stakeable_balance(who),
-			|delegatee| delegatee.effective_balance(),
+			|| T::FallbackSupport::stakeable_balance(who),
+			|delegatee| delegatee.delegated_balance(),
 		)
 	}
 
 	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
-		T::FallbackSupportProvider::update_hold(who, amount)
+		if !Self::is_delegatee(who) {
+			return T::FallbackSupport::update_hold(who, amount);
+		}
+
+		// delegation register should exist since `who` is a delegatee.
+		let delegation_register =
+			<Delegatees<T>>::get(who).defensive_ok_or(Error::<T>::BadState)?;
+		ensure!(delegation_register.total_delegated >= amount, Error::<T>::NotEnoughFunds);
+		ensure!(delegation_register.pending_slash <= amount, Error::<T>::UnappliedSlash);
+
+		let updated_register = delegation_register.update_hold(amount);
+		<Delegatees<T>>::insert(who, updated_register);
+
+		Ok(())
 	}
 
 	fn release(who: &Self::AccountId) {
-		T::FallbackSupportProvider::release(who)
+		let delegation_register = <Delegatees<T>>::get(who);
+		if delegation_register.is_some() {
+			todo!("handle kill delegatee")
+		} else {
+			T::FallbackSupport::release(who)
+		}
 	}
 
 	fn restrict_reward_destination(
 		who: &Self::AccountId,
 		reward_destination: Option<Self::AccountId>,
 	) -> bool {
-		// for non delegatee accounts, use default implementation.
-		if !Self::is_delegatee(who) {
-			return T::FallbackSupportProvider::restrict_reward_destination(who, reward_destination);
+		let maybe_register = <Delegatees<T>>::get(who);
+		// if not delegatee, use fallback.
+		if maybe_register.is_none() {
+			return T::FallbackSupport::restrict_reward_destination(who, reward_destination);
 		}
 
-		// restrict if reward destination not set or set as delegatee account itself.
-		reward_destination.map_or_else(|| true, |reward_acc| who == &reward_acc)
+		// restrict if reward destination is not set
+		if reward_destination.is_none() {
+			return true;
+		}
+
+		let register = maybe_register.expect("checked above; qed");
+		let reward_acc = reward_destination.expect("checked above; qed");
+
+		// restrict if reward account is not what delegatee registered.
+		register.payee != reward_acc
 	}
 	#[cfg(feature = "std")]
 	fn stake_type(who: &Self::AccountId) -> StakeBalanceType {
@@ -446,7 +498,7 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 			return StakeBalanceType::Delegated;
 		}
 
-		T::FallbackSupportProvider::stake_type(who)
+		T::FallbackSupport::stake_type(who)
 	}
 }
 
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index cab9bf33de3ca..cc80708761eaf 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -17,16 +17,13 @@
 
 use crate::{self as delegated_staking};
 use frame_support::{
-	assert_ok, derive_impl,
+	derive_impl,
 	pallet_prelude::*,
 	parameter_types,
 	traits::{ConstU64, Currency},
 };
 
-use sp_runtime::{
-	traits::{Convert, IdentityLookup},
-	BuildStorage, Perbill,
-};
+use sp_runtime::{traits::IdentityLookup, BuildStorage, Perbill};
 
 use frame_election_provider_support::{
 	bounds::{ElectionBounds, ElectionBoundsBuilder},
@@ -141,7 +138,7 @@ impl delegated_staking::Config for Runtime {
 	type Currency = Balances;
 	type RuntimeHoldReason = RuntimeHoldReason;
 	type Staking = Staking;
-	type FallbackSupportProvider = pallet_staking::NoDelegation<Self>;
+	type FallbackSupport = pallet_staking::NoDelegation<Self>;
 }
 
 frame_support::construct_runtime!(
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 1b1f63999f6ac..d2937f082af68 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -18,7 +18,7 @@
 //! Tests for pallet-delegated-staking.
 
 use super::*;
-use crate::{mock::*, Event};
+use crate::mock::*;
 use frame_support::{assert_noop, assert_ok, traits::fungible::InspectHold};
 use pallet_staking::Error as StakingError;
 use sp_staking::{StakeBalanceType, StakingDelegationSupport};
@@ -124,6 +124,7 @@ fn migrate_to_delegator() {
 /// Integration tests with pallet-staking.
 mod integration {
 	use super::*;
+	use pallet_staking::RewardDestination;
 
 	#[test]
 	fn bond() {
@@ -131,24 +132,48 @@ mod integration {
 			let delegatee: AccountId = 99;
 			let reward_acc: AccountId = 100;
 			assert_eq!(Staking::status(&delegatee), Err(StakingError::<T>::NotStash.into()));
-			assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 0);
-			assert_eq!(Balances::free_balance(delegatee), 0);
 
 			// set intention to become a delegatee
 			assert_ok!(DelegatedStaking::accept_delegations(&fund(delegatee, 100), &reward_acc));
+			assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 0);
+
+			// first delegation
+			assert_ok!(DelegatedStaking::delegate(&fund(200, 200), &delegatee, 100));
+			// stakeable balance is now 100.
+			let mut expected_stakeable_balance = 100;
+			assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), expected_stakeable_balance);
+			assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 100);
+			// bond delegatee
+			assert_ok!(Staking::bond(
+				RuntimeOrigin::signed(delegatee),
+				100,
+				RewardDestination::Account(reward_acc)
+			));
+			// after bond, unbonded balance is 0
+			assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
+
 			// set some delegations
-			for delegator in 200..250 {
-				assert_ok!(DelegatedStaking::delegate(&fund(delegator, 1000), &delegatee, 100));
+			for delegator in 201..250 {
+				assert_ok!(DelegatedStaking::delegate(&fund(delegator, 200), &delegatee, 100));
+				expected_stakeable_balance += 100;
 				assert_eq!(
 					Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator),
 					100
 				);
-				// assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100);
 
-				// assert_ok!(Staking::bond(RuntimeOrigin::signed(delegatee),));
+				assert_eq!(
+					DelegatedStaking::stakeable_balance(&delegatee),
+					expected_stakeable_balance
+				);
+
+				// unbonded balance is the newly delegated 100
+				assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 100);
+				assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(delegatee), 100));
+				// after bond, unbonded balance is 0
+				assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
 			}
 
-			//
+			// check ledger total stake..
 		});
 	}
 
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 71e756e47cfd7..64a27d607094c 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -37,7 +37,10 @@ pub trait Delegatee {
 	type AccountId: Clone + sp_std::fmt::Debug;
 
 	/// Total delegated balance to this account.
-	fn delegate_balance(who: Self::AccountId) -> Self::Balance;
+	fn delegated_balance(who: &Self::AccountId) -> Self::Balance;
+
+	/// Total delegated balance to this account that is not yet bonded to staking.
+	fn unbonded_balance(who: &Self::AccountId) -> Self::Balance;
 
 	/// Set intention to accept delegations.
 	fn accept_delegations(

From 8b2d6417e97344211df3740b90256c28777451a3 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 19:56:03 +0100
Subject: [PATCH 033/202] check stake

---
 substrate/frame/delegated-staking/src/tests.rs | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index d2937f082af68..cca9d42204e4c 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -125,6 +125,7 @@ fn migrate_to_delegator() {
 mod integration {
 	use super::*;
 	use pallet_staking::RewardDestination;
+	use sp_staking::Stake;
 
 	#[test]
 	fn bond() {
@@ -173,15 +174,13 @@ mod integration {
 				assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
 			}
 
-			// check ledger total stake..
+			assert_eq!(Staking::stake(&delegatee).unwrap(), Stake {
+				total: 50*100,
+				active: 50*100,
+			})
 		});
 	}
 
-	#[test]
-	fn bond_extra() {
-		ExtBuilder::default().build_and_execute(|| assert!(true));
-	}
-
 	#[test]
 	fn partial_withdraw() {
 		ExtBuilder::default().build_and_execute(|| assert!(true));

From e072a83596bfcbb4f736b9005b11ead2e158b5e1 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 20:37:14 +0100
Subject: [PATCH 034/202] test refactor

---
 substrate/frame/delegated-staking/src/mock.rs | 41 +++++++++++++++----
 .../frame/delegated-staking/src/tests.rs      | 22 ++++++----
 2 files changed, 47 insertions(+), 16 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index cc80708761eaf..ac8d3ada170c4 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -16,12 +16,7 @@
 // limitations under the License.
 
 use crate::{self as delegated_staking};
-use frame_support::{
-	derive_impl,
-	pallet_prelude::*,
-	parameter_types,
-	traits::{ConstU64, Currency},
-};
+use frame_support::{assert_ok, derive_impl, pallet_prelude::*, parameter_types, traits::{ConstU64, Currency}};
 
 use sp_runtime::{traits::IdentityLookup, BuildStorage, Perbill};
 
@@ -29,6 +24,12 @@ use frame_election_provider_support::{
 	bounds::{ElectionBounds, ElectionBoundsBuilder},
 	onchain, SequentialPhragmen,
 };
+use frame_support::traits::fungible::InspectHold;
+use sp_staking::delegation::Delegatee;
+use sp_staking::StakingDelegationSupport;
+use crate::pallet::HoldReason;
+use pallet_staking::RewardDestination;
+use sp_staking::delegation::Delegator;
 
 pub type T = Runtime;
 type Block = frame_system::mocking::MockBlock<Runtime>;
@@ -228,7 +229,31 @@ impl ExtBuilder {
 }
 
 /// fund and return who.
-pub fn fund(who: AccountId, amount: Balance) -> AccountId {
-	let _ = Balances::deposit_creating(&who, amount);
+pub fn fund(who: &AccountId, amount: Balance) -> &AccountId {
+	let _ = Balances::deposit_creating(who, amount);
 	who
 }
+
+
+pub fn setup_delegation(delegatee: AccountId, reward_acc: AccountId, delegators: Vec<AccountId>, delegate_amount: Balance) {
+	assert_ok!(DelegatedStaking::accept_delegations(fund(&delegatee, 100), &reward_acc));
+	assert_ok!(DelegatedStaking::delegate(fund(&delegators[0], delegate_amount + ExistentialDeposit::get()), &delegatee, delegate_amount));
+	assert_ok!(Staking::bond(
+				RuntimeOrigin::signed(delegatee),
+				delegate_amount,
+				RewardDestination::Account(reward_acc)
+			));
+
+	for delegator in &delegators[1..] {
+		assert_ok!(DelegatedStaking::delegate(fund(delegator, 200), &delegatee, 100));
+		assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(delegatee), 100));
+	}
+
+
+	// sanity checks
+	assert_eq!(
+		DelegatedStaking::stakeable_balance(&delegatee),
+		delegate_amount * delegators.len() as Balance
+	);
+	assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
+}
\ No newline at end of file
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index cca9d42204e4c..516dda3078814 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -31,10 +31,10 @@ fn create_a_delegatee_with_first_delegator() {
 		let delegator: AccountId = 202;
 
 		// set intention to accept delegation.
-		assert_ok!(DelegatedStaking::accept_delegations(&fund(delegatee, 1000), &reward_account));
+		assert_ok!(DelegatedStaking::accept_delegations(fund(&delegatee, 1000), &reward_account));
 
 		// delegate to this account
-		assert_ok!(DelegatedStaking::delegate(&fund(delegator, 1000), &delegatee, 100));
+		assert_ok!(DelegatedStaking::delegate(fund(&delegator, 1000), &delegatee, 100));
 
 		// verify
 		assert_eq!(DelegatedStaking::stake_type(&delegatee), StakeBalanceType::Delegated);
@@ -77,7 +77,7 @@ fn create_multiple_delegators() {
 		let reward_account: AccountId = 201;
 
 		// before becoming a delegatee, stakeable balance is only direct balance.
-		assert_eq!(DelegatedStaking::stake_type(&fund(delegatee, 1000)), StakeBalanceType::Direct);
+		assert_eq!(DelegatedStaking::stake_type(fund(&delegatee, 1000)), StakeBalanceType::Direct);
 		assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 1000);
 
 		// set intention to accept delegation.
@@ -86,7 +86,7 @@ fn create_multiple_delegators() {
 		// create 100 delegators
 		for i in 202..302 {
 			assert_ok!(DelegatedStaking::delegate(
-				&fund(i, 100 + ExistentialDeposit::get()),
+				fund(&i, 100 + ExistentialDeposit::get()),
 				&delegatee,
 				100
 			));
@@ -135,11 +135,11 @@ mod integration {
 			assert_eq!(Staking::status(&delegatee), Err(StakingError::<T>::NotStash.into()));
 
 			// set intention to become a delegatee
-			assert_ok!(DelegatedStaking::accept_delegations(&fund(delegatee, 100), &reward_acc));
+			assert_ok!(DelegatedStaking::accept_delegations(fund(&delegatee, 100), &reward_acc));
 			assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 0);
 
 			// first delegation
-			assert_ok!(DelegatedStaking::delegate(&fund(200, 200), &delegatee, 100));
+			assert_ok!(DelegatedStaking::delegate(fund(&200, 200), &delegatee, 100));
 			// stakeable balance is now 100.
 			let mut expected_stakeable_balance = 100;
 			assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), expected_stakeable_balance);
@@ -155,7 +155,7 @@ mod integration {
 
 			// set some delegations
 			for delegator in 201..250 {
-				assert_ok!(DelegatedStaking::delegate(&fund(delegator, 200), &delegatee, 100));
+				assert_ok!(DelegatedStaking::delegate(fund(&delegator, 200), &delegatee, 100));
 				expected_stakeable_balance += 100;
 				assert_eq!(
 					Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator),
@@ -183,7 +183,13 @@ mod integration {
 
 	#[test]
 	fn partial_withdraw() {
-		ExtBuilder::default().build_and_execute(|| assert!(true));
+		ExtBuilder::default().build_and_execute(|| {
+			let delegatee: AccountId = 99;
+			let reward_acc: AccountId = 100;
+			let delegators: Vec<AccountId> = (200..250).collect();
+			let delegate_amount: Balance = 100;
+			setup_delegation(delegatee, reward_acc, delegators, delegate_amount)
+		});
 	}
 
 	#[test]

From 5b881f72aa642e95cacad1fcde8316788d530720 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 20:39:44 +0100
Subject: [PATCH 035/202] test fix

---
 substrate/frame/delegated-staking/src/mock.rs | 45 ++++++++++++-------
 .../frame/delegated-staking/src/tests.rs      | 12 ++---
 2 files changed, 34 insertions(+), 23 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index ac8d3ada170c4..28241d0b0ff8b 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -16,7 +16,12 @@
 // limitations under the License.
 
 use crate::{self as delegated_staking};
-use frame_support::{assert_ok, derive_impl, pallet_prelude::*, parameter_types, traits::{ConstU64, Currency}};
+use frame_support::{
+	assert_ok, derive_impl,
+	pallet_prelude::*,
+	parameter_types,
+	traits::{ConstU64, Currency},
+};
 
 use sp_runtime::{traits::IdentityLookup, BuildStorage, Perbill};
 
@@ -24,12 +29,11 @@ use frame_election_provider_support::{
 	bounds::{ElectionBounds, ElectionBoundsBuilder},
 	onchain, SequentialPhragmen,
 };
-use frame_support::traits::fungible::InspectHold;
-use sp_staking::delegation::Delegatee;
-use sp_staking::StakingDelegationSupport;
-use crate::pallet::HoldReason;
 use pallet_staking::RewardDestination;
-use sp_staking::delegation::Delegator;
+use sp_staking::{
+	delegation::{Delegatee, Delegator},
+	StakingDelegationSupport,
+};
 
 pub type T = Runtime;
 type Block = frame_system::mocking::MockBlock<Runtime>;
@@ -234,26 +238,33 @@ pub fn fund(who: &AccountId, amount: Balance) -> &AccountId {
 	who
 }
 
-
-pub fn setup_delegation(delegatee: AccountId, reward_acc: AccountId, delegators: Vec<AccountId>, delegate_amount: Balance) {
+pub fn setup_delegation(
+	delegatee: AccountId,
+	reward_acc: AccountId,
+	delegators: Vec<AccountId>,
+	delegate_amount: Balance,
+) {
 	assert_ok!(DelegatedStaking::accept_delegations(fund(&delegatee, 100), &reward_acc));
-	assert_ok!(DelegatedStaking::delegate(fund(&delegators[0], delegate_amount + ExistentialDeposit::get()), &delegatee, delegate_amount));
+	assert_ok!(DelegatedStaking::delegate(
+		fund(&delegators[0], delegate_amount + ExistentialDeposit::get()),
+		&delegatee,
+		delegate_amount
+	));
 	assert_ok!(Staking::bond(
-				RuntimeOrigin::signed(delegatee),
-				delegate_amount,
-				RewardDestination::Account(reward_acc)
-			));
+		RuntimeOrigin::signed(delegatee),
+		delegate_amount,
+		RewardDestination::Account(reward_acc)
+	));
 
 	for delegator in &delegators[1..] {
-		assert_ok!(DelegatedStaking::delegate(fund(delegator, 200), &delegatee, 100));
-		assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(delegatee), 100));
+		assert_ok!(DelegatedStaking::delegate(fund(delegator, delegate_amount + ExistentialDeposit::get()), &delegatee, delegate_amount));
+		assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(delegatee), delegate_amount));
 	}
 
-
 	// sanity checks
 	assert_eq!(
 		DelegatedStaking::stakeable_balance(&delegatee),
 		delegate_amount * delegators.len() as Balance
 	);
 	assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
-}
\ No newline at end of file
+}
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 516dda3078814..3c20c500e147a 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -174,10 +174,10 @@ mod integration {
 				assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
 			}
 
-			assert_eq!(Staking::stake(&delegatee).unwrap(), Stake {
-				total: 50*100,
-				active: 50*100,
-			})
+			assert_eq!(
+				Staking::stake(&delegatee).unwrap(),
+				Stake { total: 50 * 100, active: 50 * 100 }
+			)
 		});
 	}
 
@@ -186,8 +186,8 @@ mod integration {
 		ExtBuilder::default().build_and_execute(|| {
 			let delegatee: AccountId = 99;
 			let reward_acc: AccountId = 100;
-			let delegators: Vec<AccountId> = (200..250).collect();
-			let delegate_amount: Balance = 100;
+			let delegators: Vec<AccountId> = (200..300).collect();
+			let delegate_amount: Balance = 200;
 			setup_delegation(delegatee, reward_acc, delegators, delegate_amount)
 		});
 	}

From 171c4d9ba544aa16e02785863a652c48ca90f72a Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 3 Dec 2023 21:01:57 +0100
Subject: [PATCH 036/202] new fn in Staking Interface partial_withdraw_unbond

---
 substrate/frame/delegated-staking/src/tests.rs | 13 ++++++++-----
 substrate/frame/staking/src/pallet/impls.rs    | 14 +++++++++++++-
 substrate/frame/staking/src/pallet/mod.rs      |  4 ++--
 substrate/primitives/staking/src/lib.rs        |  9 +++++++++
 4 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 3c20c500e147a..6aa233252827c 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -184,11 +184,14 @@ mod integration {
 	#[test]
 	fn partial_withdraw() {
 		ExtBuilder::default().build_and_execute(|| {
-			let delegatee: AccountId = 99;
-			let reward_acc: AccountId = 100;
-			let delegators: Vec<AccountId> = (200..300).collect();
-			let delegate_amount: Balance = 200;
-			setup_delegation(delegatee, reward_acc, delegators, delegate_amount)
+			let delegatee: AccountId = 200;
+			let reward_acc: AccountId = 201;
+			let delegators: Vec<AccountId> = (300..400).collect();
+			let delegate_amount: Balance = 500;
+			setup_delegation(delegatee, reward_acc, delegators, delegate_amount);
+
+			assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(delegatee), 100));
+
 		});
 	}
 
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 0a4a49f028640..535bf0946fc64 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -121,11 +121,12 @@ impl<T: Config> Pallet<T> {
 	pub(super) fn do_withdraw_unbonded(
 		controller: &T::AccountId,
 		num_slashing_spans: u32,
+		maybe_limit: Option<BalanceOf<T>>,
 	) -> Result<Weight, DispatchError> {
 		let mut ledger = Self::ledger(Controller(controller.clone()))?;
 		let (stash, old_total) = (ledger.stash.clone(), ledger.total);
 		if let Some(current_era) = Self::current_era() {
-			ledger = ledger.consolidate_unlocked(current_era, None)
+			ledger = ledger.consolidate_unlocked(current_era, maybe_limit)
 		}
 		let new_total = ledger.total;
 
@@ -1713,6 +1714,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		Self::chill(RawOrigin::Signed(ctrl).into())
 	}
 
+	// FIXME(ank4n): Refactor withdraw unbonded to take limit and remove partial_withdraw_unbonded
 	fn withdraw_unbonded(
 		who: Self::AccountId,
 		num_slashing_spans: u32,
@@ -1723,6 +1725,16 @@ impl<T: Config> StakingInterface for Pallet<T> {
 			.map_err(|with_post| with_post.error)
 	}
 
+	fn partial_withdraw_unbonded(
+		who: Self::AccountId,
+		num_slashing_spans: u32,
+		maybe_limit: Option<BalanceOf<T>>,
+	) -> Result<bool, DispatchError> {
+		let ctrl = Self::bonded(&who).ok_or(Error::<T>::NotStash)?;
+		Self::do_withdraw_unbonded(&ctrl, num_slashing_spans, maybe_limit)
+			.map(|_| !Ledger::<T>::contains_key(&ctrl))
+	}
+
 	fn bond(
 		who: &Self::AccountId,
 		value: Self::Balance,
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index d20322dbb881e..d6dabff9f61c7 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -1043,7 +1043,7 @@ pub mod pallet {
 				if unlocking == T::MaxUnlockingChunks::get() as usize {
 					let real_num_slashing_spans =
 						Self::slashing_spans(&controller).map_or(0, |s| s.iter().count());
-					Some(Self::do_withdraw_unbonded(&controller, real_num_slashing_spans as u32)?)
+					Some(Self::do_withdraw_unbonded(&controller, real_num_slashing_spans as u32, None)?)
 				} else {
 					None
 				}
@@ -1147,7 +1147,7 @@ pub mod pallet {
 		) -> DispatchResultWithPostInfo {
 			let controller = ensure_signed(origin)?;
 
-			let actual_weight = Self::do_withdraw_unbonded(&controller, num_slashing_spans)?;
+			let actual_weight = Self::do_withdraw_unbonded(&controller, num_slashing_spans, None)?;
 			Ok(Some(actual_weight).into())
 		}
 
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 66a4fe299a93c..9b40d26e12d53 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -248,6 +248,15 @@ pub trait StakingInterface {
 		num_slashing_spans: u32,
 	) -> Result<bool, DispatchError>;
 
+	/// Unlock any funds schedule to unlock before or at the current era upto a provided limit.
+	///
+	/// Returns whether the stash was killed because of this withdraw or not.
+	fn partial_withdraw_unbonded(
+		stash: Self::AccountId,
+		num_slashing_spans: u32,
+		maybe_limit: Option<Self::Balance>,
+	) -> Result<bool, DispatchError>;
+
 	/// The ideal number of active validators.
 	fn desired_validator_count() -> u32;
 

From cc4aae2bb2ec52b4f812362a150692a7e69497ff Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Mon, 4 Dec 2023 19:59:27 +0100
Subject: [PATCH 037/202] move to delegation module

---
 substrate/frame/delegated-staking/src/lib.rs  |  6 +--
 substrate/frame/delegated-staking/src/mock.rs | 11 ++---
 .../frame/delegated-staking/src/tests.rs      |  3 +-
 substrate/frame/staking/src/ledger.rs         |  2 +-
 substrate/frame/staking/src/pallet/impls.rs   |  5 ++-
 substrate/frame/staking/src/pallet/mod.rs     |  8 +++-
 .../primitives/staking/src/delegation.rs      | 43 +++++++++++++++++++
 substrate/primitives/staking/src/lib.rs       | 43 -------------------
 8 files changed, 63 insertions(+), 58 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index b7b23f2d3c58a..03a317d6f6a8c 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -38,8 +38,8 @@ use frame_support::{
 use pallet::*;
 use sp_runtime::{traits::Zero, DispatchResult, RuntimeDebug, Saturating};
 use sp_staking::{
-	delegation::{Delegatee, Delegator},
-	StakeBalanceType, StakerStatus, StakingDelegationSupport, StakingInterface,
+	delegation::{Delegatee, Delegator, StakeBalanceType, StakingDelegationSupport},
+	StakerStatus, StakingInterface,
 };
 use sp_std::{convert::TryInto, prelude::*};
 
@@ -49,7 +49,7 @@ pub type BalanceOf<T> =
 #[frame_support::pallet]
 pub mod pallet {
 	use super::*;
-	use sp_staking::StakingDelegationSupport;
+	use sp_staking::delegation::StakingDelegationSupport;
 
 	#[pallet::pallet]
 	pub struct Pallet<T>(PhantomData<T>);
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 28241d0b0ff8b..f995ed8f797c1 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -30,10 +30,7 @@ use frame_election_provider_support::{
 	onchain, SequentialPhragmen,
 };
 use pallet_staking::RewardDestination;
-use sp_staking::{
-	delegation::{Delegatee, Delegator},
-	StakingDelegationSupport,
-};
+use sp_staking::delegation::{Delegatee, Delegator, StakingDelegationSupport};
 
 pub type T = Runtime;
 type Block = frame_system::mocking::MockBlock<Runtime>;
@@ -257,7 +254,11 @@ pub fn setup_delegation(
 	));
 
 	for delegator in &delegators[1..] {
-		assert_ok!(DelegatedStaking::delegate(fund(delegator, delegate_amount + ExistentialDeposit::get()), &delegatee, delegate_amount));
+		assert_ok!(DelegatedStaking::delegate(
+			fund(delegator, delegate_amount + ExistentialDeposit::get()),
+			&delegatee,
+			delegate_amount
+		));
 		assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(delegatee), delegate_amount));
 	}
 
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 6aa233252827c..27040d1f3933b 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -21,7 +21,7 @@ use super::*;
 use crate::mock::*;
 use frame_support::{assert_noop, assert_ok, traits::fungible::InspectHold};
 use pallet_staking::Error as StakingError;
-use sp_staking::{StakeBalanceType, StakingDelegationSupport};
+use sp_staking::delegation::{StakeBalanceType, StakingDelegationSupport};
 
 #[test]
 fn create_a_delegatee_with_first_delegator() {
@@ -191,7 +191,6 @@ mod integration {
 			setup_delegation(delegatee, reward_acc, delegators, delegate_amount);
 
 			assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(delegatee), 100));
-
 		});
 	}
 
diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs
index 9dac51e42577d..b636eedf4e579 100644
--- a/substrate/frame/staking/src/ledger.rs
+++ b/substrate/frame/staking/src/ledger.rs
@@ -18,7 +18,7 @@
 //! A Ledger implementation for stakers.
 
 use frame_support::defensive;
-use sp_staking::{StakingAccount, StakingDelegationSupport};
+use sp_staking::{delegation::StakingDelegationSupport, StakingAccount};
 use sp_std::prelude::*;
 
 use crate::{BalanceOf, Bonded, Config, Error, Ledger, Payee, RewardDestination, StakingLedger};
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 535bf0946fc64..d0738c599a8b0 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -40,10 +40,11 @@ use sp_runtime::{
 };
 use sp_staking::{
 	currency_to_vote::CurrencyToVote,
+	delegation::{StakeBalanceType, StakingDelegationSupport},
 	offence::{DisableStrategy, OffenceDetails, OnOffenceHandler},
-	EraIndex, Page, SessionIndex, Stake, StakeBalanceType,
+	EraIndex, Page, SessionIndex, Stake,
 	StakingAccount::{self, Controller, Stash},
-	StakingDelegationSupport, StakingInterface,
+	StakingInterface,
 };
 use sp_std::prelude::*;
 
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index d6dabff9f61c7..a2fed2a640e5f 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -37,9 +37,9 @@ use sp_runtime::{
 };
 
 use sp_staking::{
+	delegation::StakingDelegationSupport,
 	EraIndex, Page, SessionIndex,
 	StakingAccount::{self, Controller, Stash},
-	StakingDelegationSupport,
 };
 use sp_std::prelude::*;
 
@@ -1043,7 +1043,11 @@ pub mod pallet {
 				if unlocking == T::MaxUnlockingChunks::get() as usize {
 					let real_num_slashing_spans =
 						Self::slashing_spans(&controller).map_or(0, |s| s.iter().count());
-					Some(Self::do_withdraw_unbonded(&controller, real_num_slashing_spans as u32, None)?)
+					Some(Self::do_withdraw_unbonded(
+						&controller,
+						real_num_slashing_spans as u32,
+						None,
+					)?)
 				} else {
 					None
 				}
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 64a27d607094c..bb1db7aa8038c 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -140,3 +140,46 @@ pub trait Delegator {
 		value: Self::Balance,
 	) -> DispatchResult;
 }
+
+/// Something that provides delegation support to core staking.
+pub trait StakingDelegationSupport {
+	/// Balance type used by the staking system.
+	type Balance: Sub<Output = Self::Balance>
+		+ Ord
+		+ PartialEq
+		+ Default
+		+ Copy
+		+ MaxEncodedLen
+		+ FullCodec
+		+ TypeInfo
+		+ Saturating;
+
+	/// AccountId type used by the staking system.
+	type AccountId: Clone + sp_std::fmt::Debug;
+
+	/// Balance of who which is available for stake.
+	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance;
+
+	/// Update amount held for bonded stake.
+	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult;
+
+	/// Release all amount held for stake.
+	fn release(who: &Self::AccountId);
+
+	fn restrict_reward_destination(
+		_who: &Self::AccountId,
+		_reward_destination: Option<Self::AccountId>,
+	) -> bool {
+		// never restrict by default
+		false
+	}
+
+	#[cfg(feature = "std")]
+	fn stake_type(who: &Self::AccountId) -> StakeBalanceType;
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum StakeBalanceType {
+	Direct,
+	Delegated,
+}
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 9b40d26e12d53..6bf0204fc4d82 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -420,47 +420,4 @@ pub struct PagedExposureMetadata<Balance: HasCompact + codec::MaxEncodedLen> {
 	pub page_count: Page,
 }
 
-/// Something that provides delegation support to core staking.
-pub trait StakingDelegationSupport {
-	/// Balance type used by the staking system.
-	type Balance: Sub<Output = Self::Balance>
-		+ Ord
-		+ PartialEq
-		+ Default
-		+ Copy
-		+ MaxEncodedLen
-		+ FullCodec
-		+ TypeInfo
-		+ Saturating;
-
-	/// AccountId type used by the staking system.
-	type AccountId: Clone + sp_std::fmt::Debug;
-
-	/// Balance of who which is available for stake.
-	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance;
-
-	/// Update amount held for bonded stake.
-	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult;
-
-	/// Release all amount held for stake.
-	fn release(who: &Self::AccountId);
-
-	fn restrict_reward_destination(
-		_who: &Self::AccountId,
-		_reward_destination: Option<Self::AccountId>,
-	) -> bool {
-		// never restrict by default
-		false
-	}
-
-	#[cfg(feature = "std")]
-	fn stake_type(who: &Self::AccountId) -> StakeBalanceType;
-}
-
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub enum StakeBalanceType {
-	Direct,
-	Delegated,
-}
-
 sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $);

From b8bed53ae40c42782bf5b46f28b5f5f5e488afc7 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Mon, 4 Dec 2023 20:59:30 +0100
Subject: [PATCH 038/202] compiles after refactor

---
 substrate/frame/delegated-staking/src/lib.rs  | 66 +++++++++----------
 substrate/frame/delegated-staking/src/mock.rs |  3 +-
 substrate/frame/staking/src/ledger.rs         |  2 +-
 substrate/frame/staking/src/pallet/impls.rs   | 33 ++++++----
 .../primitives/staking/src/delegation.rs      | 28 ++------
 substrate/primitives/staking/src/lib.rs       | 22 +++++++
 6 files changed, 83 insertions(+), 71 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 03a317d6f6a8c..54caace122af7 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -65,15 +65,8 @@ pub mod pallet {
 		type RuntimeHoldReason: From<HoldReason>;
 
 		/// Core staking implementation.
-		type Staking: StakingInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
-
-		/// Non Delegatee Staking Support.
-		///
-		/// Fallback implementation when an account is not a delegatee.
-		type FallbackSupport: StakingDelegationSupport<
-			Balance = BalanceOf<Self>,
-			AccountId = Self::AccountId,
-		>;
+		type CoreStaking: StakingInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId>
+			+ sp_staking::StakingHoldProvider<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
 	}
 
 	#[pallet::error]
@@ -202,7 +195,7 @@ impl<T: Config> Delegatee for Pallet<T> {
 		ensure!(!<Delegatees<T>>::contains_key(who), Error::<T>::NotAllowed);
 
 		// make sure they are not already a direct staker
-		ensure!(T::Staking::status(who).is_err(), Error::<T>::AlreadyStaker);
+		ensure!(T::CoreStaking::status(who).is_err(), Error::<T>::AlreadyStaker);
 
 		// payee account cannot be same as delegatee
 		ensure!(reward_destination != who, Error::<T>::InvalidRewardDestination);
@@ -246,16 +239,16 @@ impl<T: Config> Delegatee for Pallet<T> {
 		);
 
 		// ensure staker is a nominator
-		let status = T::Staking::status(new_delegatee)?;
+		let status = T::CoreStaking::status(new_delegatee)?;
 		match status {
 			StakerStatus::Nominator(_) => (),
 			_ => return Err(Error::<T>::InvalidDelegation.into()),
 		}
 
-		let stake = T::Staking::stake(new_delegatee)?;
+		let stake = T::CoreStaking::stake(new_delegatee)?;
 
 		// unlock funds from staker
-		T::Staking::force_unlock(new_delegatee)?;
+		T::CoreStaking::force_unlock(new_delegatee)?;
 
 		// try transferring the staked amount. This should never fail but if it does, it indicates
 		// bad state and we abort.
@@ -291,14 +284,14 @@ impl<T: Config> Delegatee for Pallet<T> {
 		let delegatee = <Delegatees<T>>::get(who).ok_or(Error::<T>::NotDelegatee)?;
 		let delegated_balance = delegatee.delegated_balance();
 
-		match T::Staking::stake(who) {
+		match T::CoreStaking::stake(who) {
 			Ok(stake) => {
 				let unstaked_delegated_balance = delegated_balance.saturating_sub(stake.total);
-				T::Staking::bond_extra(who, unstaked_delegated_balance)
+				T::CoreStaking::bond_extra(who, unstaked_delegated_balance)
 			},
 			Err(_) => {
 				// If stake not found, it means this is the first bond
-				T::Staking::bond(who, delegated_balance, &delegatee.payee)
+				T::CoreStaking::bond(who, delegated_balance, &delegatee.payee)
 			},
 		}
 	}
@@ -434,20 +427,13 @@ impl<T: Config> Delegator for Pallet<T> {
 	}
 }
 
-impl<T: Config> StakingDelegationSupport for Pallet<T> {
+impl<T: Config> sp_staking::StakingHoldProvider for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
-	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
-		<Delegatees<T>>::get(who).map_or_else(
-			|| T::FallbackSupport::stakeable_balance(who),
-			|delegatee| delegatee.delegated_balance(),
-		)
-	}
-
 	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
 		if !Self::is_delegatee(who) {
-			return T::FallbackSupport::update_hold(who, amount);
+			return T::CoreStaking::update_hold(who, amount);
 		}
 
 		// delegation register should exist since `who` is a delegatee.
@@ -463,12 +449,20 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 	}
 
 	fn release(who: &Self::AccountId) {
-		let delegation_register = <Delegatees<T>>::get(who);
-		if delegation_register.is_some() {
-			todo!("handle kill delegatee")
-		} else {
-			T::FallbackSupport::release(who)
+		if !Self::is_delegatee(who) {
+			T::CoreStaking::release(who);
 		}
+
+		let _delegation_register = <Delegatees<T>>::get(who);
+		todo!("handle kill delegatee")
+	}
+}
+impl<T: Config> StakingDelegationSupport for Pallet<T> {
+	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
+		<Delegatees<T>>::get(who).map_or_else(
+			|| T::Currency::reducible_balance(who, Preservation::Expendable, Fortitude::Polite),
+			|delegatee| delegatee.delegated_balance(),
+		)
 	}
 
 	fn restrict_reward_destination(
@@ -476,9 +470,10 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 		reward_destination: Option<Self::AccountId>,
 	) -> bool {
 		let maybe_register = <Delegatees<T>>::get(who);
-		// if not delegatee, use fallback.
+
 		if maybe_register.is_none() {
-			return T::FallbackSupport::restrict_reward_destination(who, reward_destination);
+			// no restrictions for non delegatees.
+			return false;
 		}
 
 		// restrict if reward destination is not set
@@ -492,13 +487,14 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 		// restrict if reward account is not what delegatee registered.
 		register.payee != reward_acc
 	}
+
 	#[cfg(feature = "std")]
 	fn stake_type(who: &Self::AccountId) -> StakeBalanceType {
-		if Self::is_delegatee(who) {
-			return StakeBalanceType::Delegated;
+		if !Self::is_delegatee(who) {
+			return StakeBalanceType::Direct;
 		}
 
-		T::FallbackSupport::stake_type(who)
+		StakeBalanceType::Delegated
 	}
 }
 
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index f995ed8f797c1..52551881f89dc 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -139,8 +139,7 @@ impl delegated_staking::Config for Runtime {
 	type RuntimeEvent = RuntimeEvent;
 	type Currency = Balances;
 	type RuntimeHoldReason = RuntimeHoldReason;
-	type Staking = Staking;
-	type FallbackSupport = pallet_staking::NoDelegation<Self>;
+	type CoreStaking = Staking;
 }
 
 frame_support::construct_runtime!(
diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs
index b636eedf4e579..9a4f2ade3f11c 100644
--- a/substrate/frame/staking/src/ledger.rs
+++ b/substrate/frame/staking/src/ledger.rs
@@ -18,7 +18,7 @@
 //! A Ledger implementation for stakers.
 
 use frame_support::defensive;
-use sp_staking::{delegation::StakingDelegationSupport, StakingAccount};
+use sp_staking::{delegation::StakingDelegationSupport, StakingAccount, StakingHoldProvider};
 use sp_std::prelude::*;
 
 use crate::{BalanceOf, Bonded, Config, Error, Ledger, Payee, RewardDestination, StakingLedger};
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index d0738c599a8b0..204ad17978b8e 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -40,11 +40,11 @@ use sp_runtime::{
 };
 use sp_staking::{
 	currency_to_vote::CurrencyToVote,
-	delegation::{StakeBalanceType, StakingDelegationSupport},
+	delegation::StakingDelegationSupport,
 	offence::{DisableStrategy, OffenceDetails, OnOffenceHandler},
 	EraIndex, Page, SessionIndex, Stake,
 	StakingAccount::{self, Controller, Stash},
-	StakingInterface,
+	StakingHoldProvider, StakingInterface,
 };
 use sp_std::prelude::*;
 
@@ -1836,15 +1836,10 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 }
 
-pub struct NoDelegation<T>(PhantomData<T>);
-impl<T: Config> StakingDelegationSupport for NoDelegation<T> {
+impl<T: Config> StakingHoldProvider for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
-	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
-		T::Currency::free_balance(who)
-	}
-
 	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> sp_runtime::DispatchResult {
 		T::Currency::set_lock(crate::STAKING_ID, who, amount, WithdrawReasons::all());
 		Ok(())
@@ -1853,10 +1848,26 @@ impl<T: Config> StakingDelegationSupport for NoDelegation<T> {
 	fn release(who: &Self::AccountId) {
 		T::Currency::remove_lock(crate::STAKING_ID, who)
 	}
+}
+
+/// Standard implementation of `StakingDelegationSupport` that supports only direct staking and no
+/// delegated staking.
+pub struct NoDelegation<T>(PhantomData<T>);
+impl<T: Config> StakingHoldProvider for NoDelegation<T> {
+	type Balance = BalanceOf<T>;
+	type AccountId = T::AccountId;
+
+	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> sp_runtime::DispatchResult {
+		Pallet::<T>::update_hold(who, amount)
+	}
 
-	#[cfg(feature = "std")]
-	fn stake_type(_: &Self::AccountId) -> StakeBalanceType {
-		StakeBalanceType::Direct
+	fn release(who: &Self::AccountId) {
+		Pallet::<T>::release(who)
+	}
+}
+impl<T: Config> StakingDelegationSupport for NoDelegation<T> {
+	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
+		T::Currency::free_balance(who)
 	}
 }
 
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index bb1db7aa8038c..acff7a87e2a55 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -15,6 +15,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+use crate::StakingHoldProvider;
 use codec::{FullCodec, MaxEncodedLen};
 use scale_info::TypeInfo;
 use sp_runtime::{DispatchResult, Saturating};
@@ -142,30 +143,11 @@ pub trait Delegator {
 }
 
 /// Something that provides delegation support to core staking.
-pub trait StakingDelegationSupport {
-	/// Balance type used by the staking system.
-	type Balance: Sub<Output = Self::Balance>
-		+ Ord
-		+ PartialEq
-		+ Default
-		+ Copy
-		+ MaxEncodedLen
-		+ FullCodec
-		+ TypeInfo
-		+ Saturating;
-
-	/// AccountId type used by the staking system.
-	type AccountId: Clone + sp_std::fmt::Debug;
-
+pub trait StakingDelegationSupport: StakingHoldProvider {
 	/// Balance of who which is available for stake.
 	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance;
 
-	/// Update amount held for bonded stake.
-	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult;
-
-	/// Release all amount held for stake.
-	fn release(who: &Self::AccountId);
-
+	/// Returns true if provided reward destination is not allowed.
 	fn restrict_reward_destination(
 		_who: &Self::AccountId,
 		_reward_destination: Option<Self::AccountId>,
@@ -175,7 +157,9 @@ pub trait StakingDelegationSupport {
 	}
 
 	#[cfg(feature = "std")]
-	fn stake_type(who: &Self::AccountId) -> StakeBalanceType;
+	fn stake_type(_who: &Self::AccountId) -> StakeBalanceType {
+		StakeBalanceType::Direct
+	}
 }
 
 #[derive(Clone, Debug, Eq, PartialEq)]
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 6bf0204fc4d82..13656b55c01cb 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -420,4 +420,26 @@ pub struct PagedExposureMetadata<Balance: HasCompact + codec::MaxEncodedLen> {
 	pub page_count: Page,
 }
 
+/// Something that can hold and release funds for staking.
+pub trait StakingHoldProvider {
+	/// Balance type used by the staking system.
+	type Balance: Sub<Output = Self::Balance>
+		+ Ord
+		+ PartialEq
+		+ Default
+		+ Copy
+		+ MaxEncodedLen
+		+ FullCodec
+		+ TypeInfo
+		+ Saturating;
+
+	/// AccountId type used by the staking system.
+	type AccountId: Clone + sp_std::fmt::Debug;
+
+	/// Update amount held for bonded stake.
+	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult;
+
+	/// Release all amount held for stake.
+	fn release(who: &Self::AccountId);
+}
 sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $);

From 51cfa262b9e9a677d380be4e5415ff2268426d71 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Wed, 6 Dec 2023 16:53:39 +0100
Subject: [PATCH 039/202] incomplete withdraw test

---
 substrate/frame/delegated-staking/src/mock.rs | 16 ++++++--
 .../frame/delegated-staking/src/tests.rs      | 38 ++++++++++++++++++-
 2 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 52551881f89dc..1b203fb4d041f 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -29,7 +29,7 @@ use frame_election_provider_support::{
 	bounds::{ElectionBounds, ElectionBoundsBuilder},
 	onchain, SequentialPhragmen,
 };
-use pallet_staking::RewardDestination;
+use pallet_staking::{RewardDestination, CurrentEra};
 use sp_staking::delegation::{Delegatee, Delegator, StakingDelegationSupport};
 
 pub type T = Runtime;
@@ -91,7 +91,6 @@ pallet_staking_reward_curve::build! {
 parameter_types! {
 	pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS;
 	pub static BondingDuration: u32 = 3;
-	pub static CurrentEra: u32 = 0;
 	pub static ElectionsBoundsOnChain: ElectionBounds = ElectionBoundsBuilder::default().build();
 }
 pub struct OnChainSeqPhragmen;
@@ -229,12 +228,12 @@ impl ExtBuilder {
 }
 
 /// fund and return who.
-pub fn fund(who: &AccountId, amount: Balance) -> &AccountId {
+pub(crate) fn fund(who: &AccountId, amount: Balance) -> &AccountId {
 	let _ = Balances::deposit_creating(who, amount);
 	who
 }
 
-pub fn setup_delegation(
+pub(crate) fn setup_delegation(
 	delegatee: AccountId,
 	reward_acc: AccountId,
 	delegators: Vec<AccountId>,
@@ -268,3 +267,12 @@ pub fn setup_delegation(
 	);
 	assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
 }
+
+pub(crate) fn start_era(era: sp_staking::EraIndex) {
+	CurrentEra::<T>::set(Some(era));
+}
+
+pub(crate) fn eq_stake(who: AccountId, total: Balance, active: Balance) -> bool {
+	use sp_staking::{StakingInterface, Stake};
+	Staking::stake(&who).unwrap() == Stake { total, active }
+}
\ No newline at end of file
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 27040d1f3933b..e92990b6fdf42 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -182,15 +182,49 @@ mod integration {
 	}
 
 	#[test]
-	fn partial_withdraw() {
+	fn withdraw_test() {
 		ExtBuilder::default().build_and_execute(|| {
+			// initial era
+			start_era(1);
 			let delegatee: AccountId = 200;
 			let reward_acc: AccountId = 201;
 			let delegators: Vec<AccountId> = (300..400).collect();
 			let delegate_amount: Balance = 500;
-			setup_delegation(delegatee, reward_acc, delegators, delegate_amount);
+			setup_delegation(delegatee, reward_acc, delegators.clone(), delegate_amount);
+			let expected_staked = delegate_amount * delegators.len() as Balance;
 
+			// lets go to a new era
+			start_era(2);
+
+			assert!(eq_stake(delegatee, expected_staked, expected_staked));
+			// Withdrawing without unbonding would not do anything
 			assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(delegatee), 100));
+			// active and total stake remains same
+			assert!(eq_stake(delegatee, expected_staked, expected_staked));
+
+			// 200 wants to unbond 50 in era 2, withdrawable in era 5.
+			assert_ok!(Staking::unbond(RuntimeOrigin::signed(delegatee), 50));
+			// 201 wants to unbond 100 in era 3, withdrawable in era 6.
+			start_era(3);
+			assert_ok!(Staking::unbond(RuntimeOrigin::signed(delegatee), 100));
+			// 202 wants to unbond 100 in era 4, withdrawable in era 7.
+			start_era(4);
+			assert_ok!(Staking::unbond(RuntimeOrigin::signed(delegatee), 200));
+
+			// active stake is now reduced..
+			let mut expected_active = expected_staked - (50 + 100 + 200);
+			assert!(eq_stake(delegatee, expected_staked, expected_active));
+
+			// lets try withdrawing now, still should do nothing as we are at era 4.
+			assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(delegatee), 50));
+			assert!(eq_stake(delegatee, expected_staked, expected_active));
+			assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
+			// full amount is still delegated
+			assert_eq!(DelegatedStaking::delegated_balance(&delegatee), expected_staked);
+
+			start_era(5);
+			// at era 5, 50 tokens are withdrawable
+			assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(delegatee), 50));
 		});
 	}
 

From 4a5659c3b0ef66e611446897a8d0fbe688071277 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Wed, 6 Dec 2023 18:00:57 +0100
Subject: [PATCH 040/202] introduce withdraw_exact, test failing

---
 substrate/frame/delegated-staking/src/lib.rs  | 110 ++++++++++--------
 substrate/frame/delegated-staking/src/mock.rs |  15 +--
 .../frame/delegated-staking/src/tests.rs      |  43 +++----
 substrate/frame/staking/src/pallet/impls.rs   |  19 +--
 substrate/frame/staking/src/pallet/mod.rs     |   4 +-
 .../primitives/staking/src/delegation.rs      |   9 +-
 substrate/primitives/staking/src/lib.rs       |   6 +-
 7 files changed, 97 insertions(+), 109 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 54caace122af7..cda7a4d2aba76 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -88,6 +88,8 @@ pub mod pallet {
 		NotEnoughFunds,
 		/// Not an existing delegatee account.
 		NotDelegatee,
+		/// Not a Delegator account.
+		NotDelegator,
 		/// Some corruption in internal state.
 		BadState,
 		/// Unapplied pending slash restricts operation on delegatee.
@@ -282,16 +284,15 @@ impl<T: Config> Delegatee for Pallet<T> {
 
 	fn update_bond(who: &Self::AccountId) -> DispatchResult {
 		let delegatee = <Delegatees<T>>::get(who).ok_or(Error::<T>::NotDelegatee)?;
-		let delegated_balance = delegatee.delegated_balance();
+		let amount_to_bond = delegatee.unbonded_balance();
 
 		match T::CoreStaking::stake(who) {
 			Ok(stake) => {
-				let unstaked_delegated_balance = delegated_balance.saturating_sub(stake.total);
-				T::CoreStaking::bond_extra(who, unstaked_delegated_balance)
+				T::CoreStaking::bond_extra(who, amount_to_bond)
 			},
 			Err(_) => {
 				// If stake not found, it means this is the first bond
-				T::CoreStaking::bond(who, delegated_balance, &delegatee.payee)
+				T::CoreStaking::bond(who, amount_to_bond, &delegatee.payee)
 			},
 		}
 	}
@@ -300,46 +301,11 @@ impl<T: Config> Delegatee for Pallet<T> {
 		delegator: &Self::AccountId,
 		delegatee: &Self::AccountId,
 		value: Self::Balance,
+		num_slashing_spans: u32,
 	) -> DispatchResult {
-		<Delegators<T>>::mutate_exists(delegator, |maybe_delegate| match maybe_delegate {
-			Some((current_delegatee, delegate_balance)) => {
-				ensure!(&current_delegatee.clone() == delegatee, Error::<T>::NotDelegatee);
-				ensure!(*delegate_balance >= value, Error::<T>::NotAllowed);
-
-				delegate_balance.saturating_reduce(value);
-
-				if *delegate_balance == BalanceOf::<T>::zero() {
-					*maybe_delegate = None;
-				}
-				Ok(())
-			},
-			None => {
-				// delegator does not exist
-				return Err(Error::<T>::NotAllowed)
-			},
-		})?;
-
-		<Delegatees<T>>::mutate(delegatee, |maybe_register| match maybe_register {
-			Some(ledger) => {
-				ledger.total_delegated.saturating_reduce(value);
-				Ok(())
-			},
-			None => {
-				// Delegatee not found
-				return Err(Error::<T>::NotDelegatee)
-			},
-		})?;
-
-		let released = T::Currency::release(
-			&HoldReason::Delegating.into(),
-			&delegator,
-			value,
-			Precision::BestEffort,
-		)?;
-
-		defensive_assert!(released == value, "hold should have been released fully");
-
-		Ok(())
+		// fixme(ank4n) handle killing of stash
+		let _ = T::CoreStaking::withdraw_exact(delegatee, value, num_slashing_spans);
+		Self::delegation_withdraw(delegator, delegatee, value)
 	}
 
 	fn apply_slash(
@@ -365,7 +331,7 @@ impl<T: Config> Delegatee for Pallet<T> {
 		ensure!(!<Delegatees<T>>::contains_key(delegatee), Error::<T>::NotDelegatee);
 
 		// remove delegation of `value` from `existing_delegator`.
-		Self::withdraw(existing_delegator, delegatee, value)?;
+		Self::delegation_withdraw(existing_delegator, delegatee, value)?;
 
 		// transfer the withdrawn value to `new_delegator`.
 		T::Currency::transfer(existing_delegator, new_delegator, value, Preservation::Expendable)
@@ -418,12 +384,8 @@ impl<T: Config> Delegator for Pallet<T> {
 		Ok(())
 	}
 
-	fn request_undelegate(
-		delegator: &Self::AccountId,
-		delegatee: &Self::AccountId,
-		value: Self::Balance,
-	) -> DispatchResult {
-		todo!()
+	fn unbond(delegatee: &Self::AccountId, value: Self::Balance) -> DispatchResult {
+		T::CoreStaking::unbond(delegatee, value)
 	}
 }
 
@@ -502,6 +464,52 @@ impl<T: Config> Pallet<T> {
 	fn is_delegatee(who: &T::AccountId) -> bool {
 		<Delegatees<T>>::contains_key(who)
 	}
+
+	fn delegation_withdraw(
+		delegator: &T::AccountId,
+		delegatee: &T::AccountId,
+		value: BalanceOf<T>,
+	) -> DispatchResult {
+		<Delegators<T>>::mutate_exists(delegator, |maybe_delegate| match maybe_delegate {
+			Some((current_delegatee, delegate_balance)) => {
+				ensure!(&current_delegatee.clone() == delegatee, Error::<T>::NotDelegatee);
+				ensure!(*delegate_balance >= value, Error::<T>::NotEnoughFunds);
+
+				delegate_balance.saturating_reduce(value);
+
+				if *delegate_balance == BalanceOf::<T>::zero() {
+					*maybe_delegate = None;
+				}
+				Ok(())
+			},
+			None => {
+				// delegator does not exist
+				return Err(Error::<T>::NotDelegator)
+			},
+		})?;
+
+		<Delegatees<T>>::mutate(delegatee, |maybe_register| match maybe_register {
+			Some(ledger) => {
+				ledger.total_delegated.saturating_reduce(value);
+				Ok(())
+			},
+			None => {
+				// Delegatee not found
+				return Err(Error::<T>::NotDelegatee)
+			},
+		})?;
+
+		let released = T::Currency::release(
+			&HoldReason::Delegating.into(),
+			&delegator,
+			value,
+			Precision::BestEffort,
+		)?;
+
+		defensive_assert!(released == value, "hold should have been released fully");
+
+		Ok(())
+	}
 }
 
 #[cfg(any(test, feature = "try-runtime"))]
@@ -509,4 +517,4 @@ impl<T: Config> Pallet<T> {
 	pub(crate) fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> {
 		Ok(())
 	}
-}
+}
\ No newline at end of file
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 1b203fb4d041f..149310ef96274 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -240,24 +240,13 @@ pub(crate) fn setup_delegation(
 	delegate_amount: Balance,
 ) {
 	assert_ok!(DelegatedStaking::accept_delegations(fund(&delegatee, 100), &reward_acc));
-	assert_ok!(DelegatedStaking::delegate(
-		fund(&delegators[0], delegate_amount + ExistentialDeposit::get()),
-		&delegatee,
-		delegate_amount
-	));
-	assert_ok!(Staking::bond(
-		RuntimeOrigin::signed(delegatee),
-		delegate_amount,
-		RewardDestination::Account(reward_acc)
-	));
-
-	for delegator in &delegators[1..] {
+	for delegator in &delegators {
 		assert_ok!(DelegatedStaking::delegate(
 			fund(delegator, delegate_amount + ExistentialDeposit::get()),
 			&delegatee,
 			delegate_amount
 		));
-		assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(delegatee), delegate_amount));
+		assert_ok!(DelegatedStaking::update_bond(&delegatee));
 	}
 
 	// sanity checks
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index e92990b6fdf42..83eb4952219ef 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -138,25 +138,11 @@ mod integration {
 			assert_ok!(DelegatedStaking::accept_delegations(fund(&delegatee, 100), &reward_acc));
 			assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 0);
 
-			// first delegation
-			assert_ok!(DelegatedStaking::delegate(fund(&200, 200), &delegatee, 100));
-			// stakeable balance is now 100.
-			let mut expected_stakeable_balance = 100;
-			assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), expected_stakeable_balance);
-			assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 100);
-			// bond delegatee
-			assert_ok!(Staking::bond(
-				RuntimeOrigin::signed(delegatee),
-				100,
-				RewardDestination::Account(reward_acc)
-			));
-			// after bond, unbonded balance is 0
-			assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
-
+			let mut delegated_balance: Balance = 0;
 			// set some delegations
-			for delegator in 201..250 {
+			for delegator in 200..250 {
 				assert_ok!(DelegatedStaking::delegate(fund(&delegator, 200), &delegatee, 100));
-				expected_stakeable_balance += 100;
+				delegated_balance += 100;
 				assert_eq!(
 					Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator),
 					100
@@ -164,12 +150,12 @@ mod integration {
 
 				assert_eq!(
 					DelegatedStaking::stakeable_balance(&delegatee),
-					expected_stakeable_balance
+					delegated_balance
 				);
 
 				// unbonded balance is the newly delegated 100
 				assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 100);
-				assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(delegatee), 100));
+				assert_ok!(DelegatedStaking::update_bond(&delegatee));
 				// after bond, unbonded balance is 0
 				assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
 			}
@@ -198,25 +184,26 @@ mod integration {
 
 			assert!(eq_stake(delegatee, expected_staked, expected_staked));
 			// Withdrawing without unbonding would not do anything
-			assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(delegatee), 100));
+			assert_ok!(DelegatedStaking::withdraw(&300, &delegatee, 50, 0));
+			// assert_noop!(DelegatedStaking::withdraw(&200, &delegatee, 50, 0), Error::<T>::NotAllowed);
 			// active and total stake remains same
 			assert!(eq_stake(delegatee, expected_staked, expected_staked));
 
-			// 200 wants to unbond 50 in era 2, withdrawable in era 5.
-			assert_ok!(Staking::unbond(RuntimeOrigin::signed(delegatee), 50));
-			// 201 wants to unbond 100 in era 3, withdrawable in era 6.
+			// 300 wants to unbond 50 in era 2, withdrawable in era 5.
+			assert_ok!(DelegatedStaking::unbond(&delegatee, 50));
+			// 301 wants to unbond 100 in era 3, withdrawable in era 6.
 			start_era(3);
-			assert_ok!(Staking::unbond(RuntimeOrigin::signed(delegatee), 100));
-			// 202 wants to unbond 100 in era 4, withdrawable in era 7.
+			assert_ok!(DelegatedStaking::unbond(&delegatee, 100));
+			// 302 wants to unbond 100 in era 4, withdrawable in era 7.
 			start_era(4);
-			assert_ok!(Staking::unbond(RuntimeOrigin::signed(delegatee), 200));
+			assert_ok!(DelegatedStaking::unbond(&delegatee, 200));
 
 			// active stake is now reduced..
 			let mut expected_active = expected_staked - (50 + 100 + 200);
 			assert!(eq_stake(delegatee, expected_staked, expected_active));
 
 			// lets try withdrawing now, still should do nothing as we are at era 4.
-			assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(delegatee), 50));
+			assert_ok!(DelegatedStaking::withdraw(&300, &delegatee, 50, 0));
 			assert!(eq_stake(delegatee, expected_staked, expected_active));
 			assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
 			// full amount is still delegated
@@ -224,7 +211,7 @@ mod integration {
 
 			start_era(5);
 			// at era 5, 50 tokens are withdrawable
-			assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(delegatee), 50));
+			assert_ok!(DelegatedStaking::withdraw(&300, &delegatee, 50, 0));
 		});
 	}
 
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 204ad17978b8e..e0fbd903f5962 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -122,15 +122,20 @@ impl<T: Config> Pallet<T> {
 	pub(super) fn do_withdraw_unbonded(
 		controller: &T::AccountId,
 		num_slashing_spans: u32,
-		maybe_limit: Option<BalanceOf<T>>,
+		maybe_amount: Option<BalanceOf<T>>,
 	) -> Result<Weight, DispatchError> {
 		let mut ledger = Self::ledger(Controller(controller.clone()))?;
 		let (stash, old_total) = (ledger.stash.clone(), ledger.total);
 		if let Some(current_era) = Self::current_era() {
-			ledger = ledger.consolidate_unlocked(current_era, maybe_limit)
+			ledger = ledger.consolidate_unlocked(current_era, maybe_amount)
 		}
 		let new_total = ledger.total;
 
+		if let Some(amount) = maybe_amount {
+			ensure!(
+			old_total.saturating_sub(new_total) == amount,
+			Error::<T>::NotEnoughFunds);
+		};
 		let used_weight =
 			if ledger.unlocking.is_empty() && ledger.active < T::Currency::minimum_balance() {
 				// This account must have called `unbond()` with some value that caused the active
@@ -1726,13 +1731,13 @@ impl<T: Config> StakingInterface for Pallet<T> {
 			.map_err(|with_post| with_post.error)
 	}
 
-	fn partial_withdraw_unbonded(
-		who: Self::AccountId,
+	fn withdraw_exact(
+		who: &Self::AccountId,
+		amount: BalanceOf<T>,
 		num_slashing_spans: u32,
-		maybe_limit: Option<BalanceOf<T>>,
 	) -> Result<bool, DispatchError> {
-		let ctrl = Self::bonded(&who).ok_or(Error::<T>::NotStash)?;
-		Self::do_withdraw_unbonded(&ctrl, num_slashing_spans, maybe_limit)
+		let ctrl = Self::bonded(who).ok_or(Error::<T>::NotStash)?;
+		Self::do_withdraw_unbonded(&ctrl, num_slashing_spans, Some(amount))
 			.map(|_| !Ledger::<T>::contains_key(&ctrl))
 	}
 
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index a2fed2a640e5f..13f357e39e80d 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -858,6 +858,9 @@ pub mod pallet {
 		ControllerDeprecated,
 		/// Provided reward destination is not allowed.
 		RewardDestinationRestricted,
+		// FIXME(ank4n): look at the error again
+		/// Not enough funds available to withdraw
+		NotEnoughFunds,
 	}
 
 	#[pallet::hooks]
@@ -1058,7 +1061,6 @@ pub mod pallet {
 			let mut ledger = Self::ledger(Controller(controller))?;
 			let mut value = value.min(ledger.active);
 			let stash = ledger.stash.clone();
-
 			ensure!(
 				ledger.unlocking.len() < T::MaxUnlockingChunks::get() as usize,
 				Error::<T>::NoMoreChunks,
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index acff7a87e2a55..fb35e2e88b3d9 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -84,6 +84,7 @@ pub trait Delegatee {
 		delegatee: &Self::AccountId,
 		delegator: &Self::AccountId,
 		value: Self::Balance,
+		num_slashing_spans: u32,
 	) -> DispatchResult;
 
 	/// Applies a pending slash on delegatee by passing a delegator account who should be slashed
@@ -134,12 +135,8 @@ pub trait Delegator {
 		value: Self::Balance,
 	) -> DispatchResult;
 
-	/// Request removal of delegated stake.
-	fn request_undelegate(
-		delegator: &Self::AccountId,
-		delegatee: &Self::AccountId,
-		value: Self::Balance,
-	) -> DispatchResult;
+	/// Unbond stake.
+	fn unbond(delegatee: &Self::AccountId, value: Self::Balance) -> DispatchResult;
 }
 
 /// Something that provides delegation support to core staking.
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 13656b55c01cb..5bbe49fa8f21e 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -251,10 +251,10 @@ pub trait StakingInterface {
 	/// Unlock any funds schedule to unlock before or at the current era upto a provided limit.
 	///
 	/// Returns whether the stash was killed because of this withdraw or not.
-	fn partial_withdraw_unbonded(
-		stash: Self::AccountId,
+	fn withdraw_exact(
+		stash: &Self::AccountId,
+		amount: Self::Balance,
 		num_slashing_spans: u32,
-		maybe_limit: Option<Self::Balance>,
 	) -> Result<bool, DispatchError>;
 
 	/// The ideal number of active validators.

From 6e4ea51fd20bfc449bdb531556c0a90d416638a6 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Wed, 6 Dec 2023 19:51:12 +0100
Subject: [PATCH 041/202] tests for withdraw

---
 substrate/frame/delegated-staking/src/lib.rs  | 21 +++--
 substrate/frame/delegated-staking/src/mock.rs | 31 ++++--
 .../frame/delegated-staking/src/tests.rs      | 94 ++++++++++++++-----
 .../primitives/staking/src/delegation.rs      |  5 +-
 4 files changed, 104 insertions(+), 47 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index cda7a4d2aba76..15d7bb07b469e 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -27,14 +27,11 @@ mod tests;
 #[cfg(feature = "runtime-benchmarks")]
 mod benchmarking;
 
-use frame_support::{
-	pallet_prelude::*,
-	traits::{
-		fungible::{hold::Mutate as FunHoldMutate, Inspect as FunInspect, Mutate as FunMutate},
-		tokens::{Fortitude, Precision, Preservation},
-		DefensiveOption,
-	},
-};
+use frame_support::{pallet_prelude::*, traits::{
+	fungible::{hold::Mutate as FunHoldMutate, Inspect as FunInspect, Mutate as FunMutate},
+	tokens::{Fortitude, Precision, Preservation},
+	DefensiveOption,
+}, transactional};
 use pallet::*;
 use sp_runtime::{traits::Zero, DispatchResult, RuntimeDebug, Saturating};
 use sp_staking::{
@@ -94,6 +91,8 @@ pub mod pallet {
 		BadState,
 		/// Unapplied pending slash restricts operation on delegatee.
 		UnappliedSlash,
+		/// Failed to withdraw amount from Core Staking Ledger.
+		WithdrawFailed,
 	}
 
 	/// A reason for placing a hold on funds.
@@ -297,6 +296,7 @@ impl<T: Config> Delegatee for Pallet<T> {
 		}
 	}
 
+	#[transactional]
 	fn withdraw(
 		delegator: &Self::AccountId,
 		delegatee: &Self::AccountId,
@@ -304,7 +304,7 @@ impl<T: Config> Delegatee for Pallet<T> {
 		num_slashing_spans: u32,
 	) -> DispatchResult {
 		// fixme(ank4n) handle killing of stash
-		let _ = T::CoreStaking::withdraw_exact(delegatee, value, num_slashing_spans);
+		let _stash_killed: bool = T::CoreStaking::withdraw_exact(delegatee, value, num_slashing_spans).map_err(|_| Error::<T>::WithdrawFailed)?;
 		Self::delegation_withdraw(delegator, delegatee, value)
 	}
 
@@ -319,6 +319,7 @@ impl<T: Config> Delegatee for Pallet<T> {
 
 	/// Move funds from proxy delegator to actual delegator.
 	// TODO: Keep track of proxy delegator and only allow movement from proxy -> new delegator
+	#[transactional]
 	fn migrate_delegator(
 		delegatee: &Self::AccountId,
 		existing_delegator: &Self::AccountId,
@@ -401,9 +402,9 @@ impl<T: Config> sp_staking::StakingHoldProvider for Pallet<T> {
 		// delegation register should exist since `who` is a delegatee.
 		let delegation_register =
 			<Delegatees<T>>::get(who).defensive_ok_or(Error::<T>::BadState)?;
+
 		ensure!(delegation_register.total_delegated >= amount, Error::<T>::NotEnoughFunds);
 		ensure!(delegation_register.pending_slash <= amount, Error::<T>::UnappliedSlash);
-
 		let updated_register = delegation_register.update_hold(amount);
 		<Delegatees<T>>::insert(who, updated_register);
 
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 149310ef96274..c0d12a7013dcf 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -29,7 +29,7 @@ use frame_election_provider_support::{
 	bounds::{ElectionBounds, ElectionBoundsBuilder},
 	onchain, SequentialPhragmen,
 };
-use pallet_staking::{RewardDestination, CurrentEra};
+use pallet_staking::{CurrentEra, RewardDestination};
 use sp_staking::delegation::{Delegatee, Delegator, StakingDelegationSupport};
 
 pub type T = Runtime;
@@ -233,18 +233,27 @@ pub(crate) fn fund(who: &AccountId, amount: Balance) -> &AccountId {
 	who
 }
 
-pub(crate) fn setup_delegation(
+/// Sets up delegation for passed delegators, returns total delegated amount.
+///
+/// `delegate_amount` is incremented by the amount `increment` starting with `base_delegate_amount`
+/// from lower index to higher index of delegators.
+pub(crate) fn setup_delegation_stake(
 	delegatee: AccountId,
 	reward_acc: AccountId,
 	delegators: Vec<AccountId>,
-	delegate_amount: Balance,
-) {
+	base_delegate_amount: Balance,
+	increment: Balance,
+) -> Balance {
 	assert_ok!(DelegatedStaking::accept_delegations(fund(&delegatee, 100), &reward_acc));
-	for delegator in &delegators {
+	let mut delegated_amount: Balance = 0;
+	for (index, delegator) in delegators.iter().enumerate() {
+		let amount_to_delegate = base_delegate_amount + increment * index as Balance;
+		delegated_amount += amount_to_delegate;
+
 		assert_ok!(DelegatedStaking::delegate(
-			fund(delegator, delegate_amount + ExistentialDeposit::get()),
+			fund(delegator, amount_to_delegate + ExistentialDeposit::get()),
 			&delegatee,
-			delegate_amount
+			amount_to_delegate
 		));
 		assert_ok!(DelegatedStaking::update_bond(&delegatee));
 	}
@@ -252,9 +261,11 @@ pub(crate) fn setup_delegation(
 	// sanity checks
 	assert_eq!(
 		DelegatedStaking::stakeable_balance(&delegatee),
-		delegate_amount * delegators.len() as Balance
+		delegated_amount
 	);
 	assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
+
+	delegated_amount
 }
 
 pub(crate) fn start_era(era: sp_staking::EraIndex) {
@@ -262,6 +273,6 @@ pub(crate) fn start_era(era: sp_staking::EraIndex) {
 }
 
 pub(crate) fn eq_stake(who: AccountId, total: Balance, active: Balance) -> bool {
-	use sp_staking::{StakingInterface, Stake};
+	use sp_staking::{Stake, StakingInterface};
 	Staking::stake(&who).unwrap() == Stake { total, active }
-}
\ No newline at end of file
+}
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 83eb4952219ef..19f2b7785fe5c 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -148,10 +148,7 @@ mod integration {
 					100
 				);
 
-				assert_eq!(
-					DelegatedStaking::stakeable_balance(&delegatee),
-					delegated_balance
-				);
+				assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), delegated_balance);
 
 				// unbonded balance is the newly delegated 100
 				assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 100);
@@ -174,44 +171,89 @@ mod integration {
 			start_era(1);
 			let delegatee: AccountId = 200;
 			let reward_acc: AccountId = 201;
-			let delegators: Vec<AccountId> = (300..400).collect();
-			let delegate_amount: Balance = 500;
-			setup_delegation(delegatee, reward_acc, delegators.clone(), delegate_amount);
-			let expected_staked = delegate_amount * delegators.len() as Balance;
+			let delegators: Vec<AccountId> = (301..=350).collect();
+			let total_staked =
+				setup_delegation_stake(delegatee, reward_acc, delegators.clone(), 10, 10);
 
 			// lets go to a new era
 			start_era(2);
 
-			assert!(eq_stake(delegatee, expected_staked, expected_staked));
-			// Withdrawing without unbonding would not do anything
-			assert_ok!(DelegatedStaking::withdraw(&300, &delegatee, 50, 0));
-			// assert_noop!(DelegatedStaking::withdraw(&200, &delegatee, 50, 0), Error::<T>::NotAllowed);
-			// active and total stake remains same
-			assert!(eq_stake(delegatee, expected_staked, expected_staked));
-
-			// 300 wants to unbond 50 in era 2, withdrawable in era 5.
+			assert!(eq_stake(delegatee, total_staked, total_staked));
+			// Withdrawing without unbonding would fail.
+			assert_noop!(
+				DelegatedStaking::withdraw(&300, &delegatee, 50, 0),
+				Error::<T>::WithdrawFailed
+			);
+			// assert_noop!(DelegatedStaking::withdraw(&200, &delegatee, 50, 0),
+			// Error::<T>::NotAllowed); active and total stake remains same
+			assert!(eq_stake(delegatee, total_staked, total_staked));
+
+			// 305 wants to unbond 50 in era 2, withdrawable in era 5.
 			assert_ok!(DelegatedStaking::unbond(&delegatee, 50));
-			// 301 wants to unbond 100 in era 3, withdrawable in era 6.
+			// 310 wants to unbond 100 in era 3, withdrawable in era 6.
 			start_era(3);
 			assert_ok!(DelegatedStaking::unbond(&delegatee, 100));
-			// 302 wants to unbond 100 in era 4, withdrawable in era 7.
+			// 320 wants to unbond 200 in era 4, withdrawable in era 7.
 			start_era(4);
 			assert_ok!(DelegatedStaking::unbond(&delegatee, 200));
 
 			// active stake is now reduced..
-			let mut expected_active = expected_staked - (50 + 100 + 200);
-			assert!(eq_stake(delegatee, expected_staked, expected_active));
+			let mut expected_active = total_staked - (50 + 100 + 200);
+			assert!(eq_stake(delegatee, total_staked, expected_active));
+
+			// nothing to withdraw at era 4
+			assert_noop!(
+				DelegatedStaking::withdraw(&305, &delegatee, 50, 0),
+				Error::<T>::WithdrawFailed
+			);
 
-			// lets try withdrawing now, still should do nothing as we are at era 4.
-			assert_ok!(DelegatedStaking::withdraw(&300, &delegatee, 50, 0));
-			assert!(eq_stake(delegatee, expected_staked, expected_active));
+			assert!(eq_stake(delegatee, total_staked, expected_active));
 			assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
 			// full amount is still delegated
-			assert_eq!(DelegatedStaking::delegated_balance(&delegatee), expected_staked);
+			assert_eq!(DelegatedStaking::delegated_balance(&delegatee), total_staked);
 
 			start_era(5);
-			// at era 5, 50 tokens are withdrawable
-			assert_ok!(DelegatedStaking::withdraw(&300, &delegatee, 50, 0));
+			// at era 5, 50 tokens are withdrawable, cannot withdraw more.
+			assert_noop!(
+				DelegatedStaking::withdraw(&305, &delegatee, 51, 0),
+				Error::<T>::WithdrawFailed
+			);
+			// less is possible
+			assert_ok!(DelegatedStaking::withdraw(&305, &delegatee, 30, 0));
+			assert_ok!(DelegatedStaking::withdraw(&305, &delegatee, 20, 0));
+
+			// Lets go to future era where everything is unbonded. Withdrawable amount: 100 + 200
+			start_era(7);
+			// 305 has no more amount delegated so it cannot withdraw.
+			assert_noop!(
+				DelegatedStaking::withdraw(&305, &delegatee, 5, 0),
+				Error::<T>::NotDelegator
+			);
+			// 309 is an active delegator but has total delegation of 90, so it cannot withdraw more
+			// than that.
+			assert_noop!(
+				DelegatedStaking::withdraw(&309, &delegatee, 91, 0),
+				Error::<T>::NotEnoughFunds
+			);
+			// 310 cannot withdraw more than delegated funds.
+			assert_noop!(
+				DelegatedStaking::withdraw(&310, &delegatee, 101, 0),
+				Error::<T>::NotEnoughFunds
+			);
+			// but can withdraw all its delegation amount.
+			assert_ok!(DelegatedStaking::withdraw(&310, &delegatee, 100, 0));
+			// 320 can withdraw all its delegation amount.
+			assert_ok!(DelegatedStaking::withdraw(&320, &delegatee, 200, 0));
+
+			// cannot withdraw anything more..
+			assert_noop!(
+				DelegatedStaking::withdraw(&301, &delegatee, 1, 0),
+				Error::<T>::WithdrawFailed
+			);
+			assert_noop!(
+				DelegatedStaking::withdraw(&350, &delegatee, 1, 0),
+				Error::<T>::WithdrawFailed
+			);
 		});
 	}
 
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index fb35e2e88b3d9..f50b953dc65a6 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -79,7 +79,10 @@ pub trait Delegatee {
 	/// Update bond whenever there is a new delegate funds that are not staked.
 	fn update_bond(delegatee: &Self::AccountId) -> DispatchResult;
 
-	/// Request removal of delegated stake.
+	/// Request withdrawal of unbonded stake of `delegatee` belonging to the provided `delegator`.
+	///
+	/// Important: It is upto `delegatee` to enforce which `delegator` can withdraw `value`. The
+	/// withdrawn value is released in `delegator`'s account.
 	fn withdraw(
 		delegatee: &Self::AccountId,
 		delegator: &Self::AccountId,

From 9ce869feceeeff374fc2f6210a985abc490ac0b1 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Wed, 6 Dec 2023 19:53:26 +0100
Subject: [PATCH 042/202] rearrange

---
 substrate/frame/delegated-staking/src/tests.rs | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 19f2b7785fe5c..01a90ebc7e724 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -116,11 +116,6 @@ fn distribute_rewards() {
 	ExtBuilder::default().build_and_execute(|| assert!(true));
 }
 
-#[test]
-fn migrate_to_delegator() {
-	ExtBuilder::default().build_and_execute(|| assert!(true));
-}
-
 /// Integration tests with pallet-staking.
 mod integration {
 	use super::*;
@@ -266,4 +261,10 @@ mod integration {
 	fn slash_works() {
 		ExtBuilder::default().build_and_execute(|| assert!(true));
 	}
+
+	#[test]
+	fn migration_works() {
+		ExtBuilder::default().build_and_execute(|| assert!(true));
+	}
+
 }

From bba90d186263f6c2e6f19188d60163746ea828dd Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Wed, 6 Dec 2023 21:43:57 +0100
Subject: [PATCH 043/202] test to impl

---
 substrate/frame/delegated-staking/src/tests.rs | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 01a90ebc7e724..0c2cb356459a2 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -253,13 +253,23 @@ mod integration {
 	}
 
 	#[test]
-	fn claim_reward() {
+	fn reward_destination_cannot_be_delegatee() {
 		ExtBuilder::default().build_and_execute(|| assert!(true));
 	}
 
+	fn nominate_test() {
+		ExtBuilder::default().build_and_execute(|| assert!(true));
+	}
 	#[test]
 	fn slash_works() {
-		ExtBuilder::default().build_and_execute(|| assert!(true));
+		ExtBuilder::default().build_and_execute(|| {
+			setup_delegation_stake(200, 201, (210..250).collect(), 100, 0);
+			start_era(1);
+
+			// delegatee is slashed
+
+
+		});
 	}
 
 	#[test]

From 1b28825369433a33e951fc520e5b9392486facd5 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Wed, 6 Dec 2023 22:51:29 +0100
Subject: [PATCH 044/202] impl Staking Interface for Delegated Staking

---
 substrate/frame/delegated-staking/src/lib.rs  | 248 ++++++++++++++++--
 substrate/frame/delegated-staking/src/mock.rs |   7 +-
 .../frame/delegated-staking/src/tests.rs      |   4 +-
 .../primitives/staking/src/delegation.rs      |   3 -
 4 files changed, 226 insertions(+), 36 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 15d7bb07b469e..9936639d6b8f0 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -27,16 +27,20 @@ mod tests;
 #[cfg(feature = "runtime-benchmarks")]
 mod benchmarking;
 
-use frame_support::{pallet_prelude::*, traits::{
-	fungible::{hold::Mutate as FunHoldMutate, Inspect as FunInspect, Mutate as FunMutate},
-	tokens::{Fortitude, Precision, Preservation},
-	DefensiveOption,
-}, transactional};
+use frame_support::{
+	pallet_prelude::*,
+	traits::{
+		fungible::{hold::Mutate as FunHoldMutate, Inspect as FunInspect, Mutate as FunMutate},
+		tokens::{Fortitude, Precision, Preservation},
+		DefensiveOption,
+	},
+	transactional,
+};
 use pallet::*;
 use sp_runtime::{traits::Zero, DispatchResult, RuntimeDebug, Saturating};
 use sp_staking::{
 	delegation::{Delegatee, Delegator, StakeBalanceType, StakingDelegationSupport},
-	StakerStatus, StakingInterface,
+	EraIndex, Stake, StakerStatus, StakingInterface,
 };
 use sp_std::{convert::TryInto, prelude::*};
 
@@ -46,7 +50,6 @@ pub type BalanceOf<T> =
 #[frame_support::pallet]
 pub mod pallet {
 	use super::*;
-	use sp_staking::delegation::StakingDelegationSupport;
 
 	#[pallet::pallet]
 	pub struct Pallet<T>(PhantomData<T>);
@@ -93,6 +96,8 @@ pub mod pallet {
 		UnappliedSlash,
 		/// Failed to withdraw amount from Core Staking Ledger.
 		WithdrawFailed,
+		/// This operation is not supported with Delegation Staking.
+		NotSupported,
 	}
 
 	/// A reason for placing a hold on funds.
@@ -119,7 +124,7 @@ pub mod pallet {
 		Withdrawn { delegatee: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
 	}
 
-	/// Map of Delegators to their delegation.
+	/// Map of Delegators to their delegation, i.e. (delegatee, delegation_amount).
 	///
 	/// Note: We are not using a double map with delegator and delegatee account as keys since we
 	/// want to restrict delegators to delegate only to one account.
@@ -277,7 +282,7 @@ impl<T: Config> Delegatee for Pallet<T> {
 		})
 	}
 
-	fn kill_delegatee(delegatee: &Self::AccountId) -> DispatchResult {
+	fn kill_delegatee(_delegatee: &Self::AccountId) -> DispatchResult {
 		todo!()
 	}
 
@@ -286,13 +291,10 @@ impl<T: Config> Delegatee for Pallet<T> {
 		let amount_to_bond = delegatee.unbonded_balance();
 
 		match T::CoreStaking::stake(who) {
-			Ok(stake) => {
-				T::CoreStaking::bond_extra(who, amount_to_bond)
-			},
-			Err(_) => {
-				// If stake not found, it means this is the first bond
-				T::CoreStaking::bond(who, amount_to_bond, &delegatee.payee)
-			},
+			// already bonded
+			Ok(_) => T::CoreStaking::bond_extra(who, amount_to_bond),
+			// first bond
+			Err(_) => T::CoreStaking::bond(who, amount_to_bond, &delegatee.payee),
 		}
 	}
 
@@ -304,15 +306,17 @@ impl<T: Config> Delegatee for Pallet<T> {
 		num_slashing_spans: u32,
 	) -> DispatchResult {
 		// fixme(ank4n) handle killing of stash
-		let _stash_killed: bool = T::CoreStaking::withdraw_exact(delegatee, value, num_slashing_spans).map_err(|_| Error::<T>::WithdrawFailed)?;
+		let _stash_killed: bool =
+			T::CoreStaking::withdraw_exact(delegatee, value, num_slashing_spans)
+				.map_err(|_| Error::<T>::WithdrawFailed)?;
 		Self::delegation_withdraw(delegator, delegatee, value)
 	}
 
 	fn apply_slash(
-		delegatee: &Self::AccountId,
-		delegator: &Self::AccountId,
-		value: Self::Balance,
-		reporter: Option<Self::AccountId>,
+		_delegatee: &Self::AccountId,
+		_delegator: &Self::AccountId,
+		_value: Self::Balance,
+		_reporter: Option<Self::AccountId>,
 	) -> DispatchResult {
 		todo!()
 	}
@@ -384,10 +388,6 @@ impl<T: Config> Delegator for Pallet<T> {
 
 		Ok(())
 	}
-
-	fn unbond(delegatee: &Self::AccountId, value: Self::Balance) -> DispatchResult {
-		T::CoreStaking::unbond(delegatee, value)
-	}
 }
 
 impl<T: Config> sp_staking::StakingHoldProvider for Pallet<T> {
@@ -461,11 +461,207 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 	}
 }
 
+/// StakingInterface implementation with delegation support.
+///
+/// Only supports Nominators via Delegated Bonds. It is possible for a nominator to migrate to a
+/// Delegatee.
+impl<T: Config> StakingInterface for Pallet<T> {
+	type Balance = BalanceOf<T>;
+	type AccountId = T::AccountId;
+	type CurrencyToVote = <T::CoreStaking as StakingInterface>::CurrencyToVote;
+
+	fn minimum_nominator_bond() -> Self::Balance {
+		T::CoreStaking::minimum_nominator_bond()
+	}
+
+	fn minimum_validator_bond() -> Self::Balance {
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+		T::CoreStaking::minimum_validator_bond()
+	}
+
+	fn stash_by_ctrl(_controller: &Self::AccountId) -> Result<Self::AccountId, DispatchError> {
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+		// ctrl are deprecated, just return err.
+		Err(Error::<T>::NotSupported.into())
+	}
+
+	fn bonding_duration() -> EraIndex {
+		T::CoreStaking::bonding_duration()
+	}
+
+	fn current_era() -> EraIndex {
+		T::CoreStaking::current_era()
+	}
+
+	fn stake(who: &Self::AccountId) -> Result<Stake<Self::Balance>, DispatchError> {
+		if Self::is_delegatee(who) {
+			return T::CoreStaking::stake(who);
+		}
+
+		Err(Error::<T>::NotSupported.into())
+	}
+
+	fn total_stake(who: &Self::AccountId) -> Result<Self::Balance, DispatchError> {
+		if Self::is_delegatee(who) {
+			return T::CoreStaking::total_stake(who);
+		}
+
+		if Self::is_delegator(who) {
+			let (_, delegation_amount) =
+				<Delegators<T>>::get(who).defensive_ok_or(Error::<T>::BadState)?;
+			return Ok(delegation_amount)
+		}
+
+		Err(Error::<T>::NotSupported.into())
+	}
+
+	fn active_stake(who: &Self::AccountId) -> Result<Self::Balance, DispatchError> {
+		T::CoreStaking::active_stake(who)
+	}
+
+	fn is_unbonding(who: &Self::AccountId) -> Result<bool, DispatchError> {
+		T::CoreStaking::is_unbonding(who)
+	}
+
+	fn fully_unbond(who: &Self::AccountId) -> DispatchResult {
+		if Self::is_delegatee(who) {
+			return T::CoreStaking::fully_unbond(who);
+		}
+
+		Err(Error::<T>::NotSupported.into())
+	}
+
+	fn bond(
+		who: &Self::AccountId,
+		value: Self::Balance,
+		payee: &Self::AccountId,
+	) -> DispatchResult {
+		// ensure who is not already staked
+		ensure!(T::CoreStaking::status(who).is_err(), Error::<T>::NotDelegatee);
+		let delegation_register = <Delegatees<T>>::get(who).ok_or(Error::<T>::NotDelegatee)?;
+
+		ensure!(delegation_register.unbonded_balance() >= value, Error::<T>::NotEnoughFunds);
+		ensure!(delegation_register.payee == *payee, Error::<T>::InvalidRewardDestination);
+
+		T::CoreStaking::bond(who, value, payee)
+	}
+
+	fn nominate(who: &Self::AccountId, validators: Vec<Self::AccountId>) -> DispatchResult {
+		if Self::is_delegatee(who) {
+			return T::CoreStaking::nominate(who, validators);
+		}
+
+		Err(Error::<T>::NotSupported.into())
+	}
+
+	fn chill(who: &Self::AccountId) -> DispatchResult {
+		if Self::is_delegatee(who) {
+			return T::CoreStaking::chill(who);
+		}
+
+		Err(Error::<T>::NotSupported.into())
+	}
+
+	fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult {
+		let delegation_register = <Delegatees<T>>::get(who).ok_or(Error::<T>::NotDelegatee)?;
+		ensure!(delegation_register.unbonded_balance() >= extra, Error::<T>::NotEnoughFunds);
+
+		T::CoreStaking::bond_extra(who, extra)
+	}
+
+	fn unbond(stash: &Self::AccountId, value: Self::Balance) -> DispatchResult {
+		let delegation_register = <Delegatees<T>>::get(stash).ok_or(Error::<T>::NotDelegatee)?;
+		ensure!(delegation_register.hold >= value, Error::<T>::NotEnoughFunds);
+
+		T::CoreStaking::unbond(stash, value)
+	}
+
+	/// Not supported, call [`Delegatee::withdraw`]
+	fn withdraw_unbonded(
+		_stash: Self::AccountId,
+		_num_slashing_spans: u32,
+	) -> Result<bool, DispatchError> {
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+		Err(Error::<T>::NotSupported.into())
+	}
+
+	/// Not supported, call [`Delegatee::withdraw`]
+	fn withdraw_exact(
+		_stash: &Self::AccountId,
+		_amount: Self::Balance,
+		_num_slashing_spans: u32,
+	) -> Result<bool, DispatchError> {
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+		Err(Error::<T>::NotSupported.into())
+	}
+
+	fn desired_validator_count() -> u32 {
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+		T::CoreStaking::desired_validator_count()
+	}
+
+	fn election_ongoing() -> bool {
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+		T::CoreStaking::election_ongoing()
+	}
+
+	fn force_unstake(_who: Self::AccountId) -> DispatchResult {
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+		Err(Error::<T>::NotSupported.into())
+	}
+
+	fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool {
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+		T::CoreStaking::is_exposed_in_era(who, era)
+	}
+
+	fn status(who: &Self::AccountId) -> Result<StakerStatus<Self::AccountId>, DispatchError> {
+		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
+		T::CoreStaking::status(who)
+	}
+
+	fn is_validator(who: &Self::AccountId) -> bool {
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+		T::CoreStaking::is_validator(who)
+	}
+
+	fn nominations(who: &Self::AccountId) -> Option<Vec<Self::AccountId>> {
+		T::CoreStaking::nominations(who)
+	}
+
+	fn force_unlock(_who: &Self::AccountId) -> DispatchResult {
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+		Err(Error::<T>::NotSupported.into())
+	}
+
+	#[cfg(feature = "runtime-benchmarks")]
+	fn max_exposure_page_size() -> sp_staking::Page {
+		T::CoreStaking::max_exposure_page_size()
+	}
+
+	#[cfg(feature = "runtime-benchmarks")]
+	fn add_era_stakers(
+		current_era: &EraIndex,
+		stash: &Self::AccountId,
+		exposures: Vec<(Self::AccountId, Self::Balance)>,
+	) {
+		T::CoreStaking::add_era_stakers(current_era, stash, exposures)
+	}
+
+	#[cfg(feature = "runtime-benchmarks")]
+	fn set_current_era(era: EraIndex) {
+		T::CoreStaking::set_current_era(era)
+	}
+}
 impl<T: Config> Pallet<T> {
 	fn is_delegatee(who: &T::AccountId) -> bool {
 		<Delegatees<T>>::contains_key(who)
 	}
 
+	fn is_delegator(who: &T::AccountId) -> bool {
+		<Delegators<T>>::contains_key(who)
+	}
+
 	fn delegation_withdraw(
 		delegator: &T::AccountId,
 		delegatee: &T::AccountId,
@@ -518,4 +714,4 @@ impl<T: Config> Pallet<T> {
 	pub(crate) fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> {
 		Ok(())
 	}
-}
\ No newline at end of file
+}
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index c0d12a7013dcf..dd76c2ef94837 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -29,7 +29,7 @@ use frame_election_provider_support::{
 	bounds::{ElectionBounds, ElectionBoundsBuilder},
 	onchain, SequentialPhragmen,
 };
-use pallet_staking::{CurrentEra, RewardDestination};
+use pallet_staking::CurrentEra;
 use sp_staking::delegation::{Delegatee, Delegator, StakingDelegationSupport};
 
 pub type T = Runtime;
@@ -259,10 +259,7 @@ pub(crate) fn setup_delegation_stake(
 	}
 
 	// sanity checks
-	assert_eq!(
-		DelegatedStaking::stakeable_balance(&delegatee),
-		delegated_amount
-	);
+	assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), delegated_amount);
 	assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
 
 	delegated_amount
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 0c2cb356459a2..7812819c7f8a3 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -119,7 +119,6 @@ fn distribute_rewards() {
 /// Integration tests with pallet-staking.
 mod integration {
 	use super::*;
-	use pallet_staking::RewardDestination;
 	use sp_staking::Stake;
 
 	#[test]
@@ -193,7 +192,7 @@ mod integration {
 			assert_ok!(DelegatedStaking::unbond(&delegatee, 200));
 
 			// active stake is now reduced..
-			let mut expected_active = total_staked - (50 + 100 + 200);
+			let expected_active = total_staked - (50 + 100 + 200);
 			assert!(eq_stake(delegatee, total_staked, expected_active));
 
 			// nothing to withdraw at era 4
@@ -257,6 +256,7 @@ mod integration {
 		ExtBuilder::default().build_and_execute(|| assert!(true));
 	}
 
+	#[test]
 	fn nominate_test() {
 		ExtBuilder::default().build_and_execute(|| assert!(true));
 	}
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index f50b953dc65a6..a956824df0667 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -137,9 +137,6 @@ pub trait Delegator {
 		delegatee: &Self::AccountId,
 		value: Self::Balance,
 	) -> DispatchResult;
-
-	/// Unbond stake.
-	fn unbond(delegatee: &Self::AccountId, value: Self::Balance) -> DispatchResult;
 }
 
 /// Something that provides delegation support to core staking.

From 8f8b1d6e3e8a57422a298353c690493d0ad8be2a Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Wed, 6 Dec 2023 22:53:40 +0100
Subject: [PATCH 045/202] fmt

---
 substrate/frame/delegated-staking/src/tests.rs | 3 ---
 substrate/frame/staking/src/pallet/impls.rs    | 4 +---
 2 files changed, 1 insertion(+), 6 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 7812819c7f8a3..c2f7ae8074f9f 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -267,8 +267,6 @@ mod integration {
 			start_era(1);
 
 			// delegatee is slashed
-
-
 		});
 	}
 
@@ -276,5 +274,4 @@ mod integration {
 	fn migration_works() {
 		ExtBuilder::default().build_and_execute(|| assert!(true));
 	}
-
 }
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index e0fbd903f5962..aa0a11598d952 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -132,9 +132,7 @@ impl<T: Config> Pallet<T> {
 		let new_total = ledger.total;
 
 		if let Some(amount) = maybe_amount {
-			ensure!(
-			old_total.saturating_sub(new_total) == amount,
-			Error::<T>::NotEnoughFunds);
+			ensure!(old_total.saturating_sub(new_total) == amount, Error::<T>::NotEnoughFunds);
 		};
 		let used_weight =
 			if ledger.unlocking.is_empty() && ledger.active < T::Currency::minimum_balance() {

From dd21409a2c8722fdc0d9c644d3ec3b22c1df5291 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 7 Dec 2023 00:08:06 +0100
Subject: [PATCH 046/202] merge delegatee and delegator in one

---
 substrate/frame/delegated-staking/src/lib.rs  | 16 +++-------
 substrate/frame/delegated-staking/src/mock.rs |  2 +-
 .../frame/delegated-staking/src/tests.rs      |  8 ++---
 substrate/frame/staking/src/pallet/impls.rs   |  2 ++
 .../primitives/staking/src/delegation.rs      | 30 ++-----------------
 5 files changed, 14 insertions(+), 44 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 9936639d6b8f0..d4129b103faac 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -39,7 +39,7 @@ use frame_support::{
 use pallet::*;
 use sp_runtime::{traits::Zero, DispatchResult, RuntimeDebug, Saturating};
 use sp_staking::{
-	delegation::{Delegatee, Delegator, StakeBalanceType, StakingDelegationSupport},
+	delegation::{Delegatee, StakingDelegationSupport},
 	EraIndex, Stake, StakerStatus, StakingInterface,
 };
 use sp_std::{convert::TryInto, prelude::*};
@@ -345,11 +345,6 @@ impl<T: Config> Delegatee for Pallet<T> {
 		// add the above removed delegation to `new_delegator`.
 		Self::delegate(new_delegator, delegatee, value)
 	}
-}
-
-impl<T: Config> Delegator for Pallet<T> {
-	type Balance = BalanceOf<T>;
-	type AccountId = T::AccountId;
 
 	fn delegate(
 		delegator: &Self::AccountId,
@@ -388,6 +383,7 @@ impl<T: Config> Delegator for Pallet<T> {
 
 		Ok(())
 	}
+
 }
 
 impl<T: Config> sp_staking::StakingHoldProvider for Pallet<T> {
@@ -452,12 +448,8 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 	}
 
 	#[cfg(feature = "std")]
-	fn stake_type(who: &Self::AccountId) -> StakeBalanceType {
-		if !Self::is_delegatee(who) {
-			return StakeBalanceType::Direct;
-		}
-
-		StakeBalanceType::Delegated
+	fn is_delegatee(who: &Self::AccountId) -> bool {
+		Self::is_delegatee(who)
 	}
 }
 
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index dd76c2ef94837..9e80ee3da371d 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -30,7 +30,7 @@ use frame_election_provider_support::{
 	onchain, SequentialPhragmen,
 };
 use pallet_staking::CurrentEra;
-use sp_staking::delegation::{Delegatee, Delegator, StakingDelegationSupport};
+use sp_staking::delegation::{Delegatee, StakingDelegationSupport};
 
 pub type T = Runtime;
 type Block = frame_system::mocking::MockBlock<Runtime>;
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index c2f7ae8074f9f..a3e0f58b1a66b 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -21,7 +21,7 @@ use super::*;
 use crate::mock::*;
 use frame_support::{assert_noop, assert_ok, traits::fungible::InspectHold};
 use pallet_staking::Error as StakingError;
-use sp_staking::delegation::{StakeBalanceType, StakingDelegationSupport};
+use sp_staking::delegation::StakingDelegationSupport;
 
 #[test]
 fn create_a_delegatee_with_first_delegator() {
@@ -37,7 +37,7 @@ fn create_a_delegatee_with_first_delegator() {
 		assert_ok!(DelegatedStaking::delegate(fund(&delegator, 1000), &delegatee, 100));
 
 		// verify
-		assert_eq!(DelegatedStaking::stake_type(&delegatee), StakeBalanceType::Delegated);
+		assert!(DelegatedStaking::is_delegatee(&delegatee));
 		assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100);
 		assert_eq!(Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator), 100);
 	});
@@ -77,7 +77,7 @@ fn create_multiple_delegators() {
 		let reward_account: AccountId = 201;
 
 		// before becoming a delegatee, stakeable balance is only direct balance.
-		assert_eq!(DelegatedStaking::stake_type(fund(&delegatee, 1000)), StakeBalanceType::Direct);
+		assert!(!DelegatedStaking::is_delegatee(fund(&delegatee, 1000)));
 		assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 1000);
 
 		// set intention to accept delegation.
@@ -95,7 +95,7 @@ fn create_multiple_delegators() {
 		}
 
 		// verify
-		assert_eq!(DelegatedStaking::stake_type(&delegatee), StakeBalanceType::Delegated);
+		assert!(DelegatedStaking::is_delegatee(&delegatee));
 		assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100 * 100);
 	});
 }
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index aa0a11598d952..0c50022fc72fa 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1868,10 +1868,12 @@ impl<T: Config> StakingHoldProvider for NoDelegation<T> {
 		Pallet::<T>::release(who)
 	}
 }
+
 impl<T: Config> StakingDelegationSupport for NoDelegation<T> {
 	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
 		T::Currency::free_balance(who)
 	}
+	fn is_delegatee(_who: &Self::AccountId) -> bool { false }
 }
 
 #[cfg(any(test, feature = "try-runtime"))]
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index a956824df0667..6c0ced227a950 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -114,24 +114,8 @@ pub trait Delegatee {
 		delegator_to: &Self::AccountId,
 		value: Self::Balance,
 	) -> DispatchResult;
-}
-
-/// Allows an account to delegate their stakes to a delegatee.
-pub trait Delegator {
-	type Balance: Sub<Output = Self::Balance>
-		+ Ord
-		+ PartialEq
-		+ Default
-		+ Copy
-		+ MaxEncodedLen
-		+ FullCodec
-		+ TypeInfo
-		+ Saturating;
-
-	/// AccountId type used by the staking system.
-	type AccountId: Clone + sp_std::fmt::Debug;
 
-	/// Delegate some funds to a Delegatee
+	/// As a `delegator`, delegate some funds to a Delegatee
 	fn delegate(
 		delegator: &Self::AccountId,
 		delegatee: &Self::AccountId,
@@ -154,13 +138,5 @@ pub trait StakingDelegationSupport: StakingHoldProvider {
 	}
 
 	#[cfg(feature = "std")]
-	fn stake_type(_who: &Self::AccountId) -> StakeBalanceType {
-		StakeBalanceType::Direct
-	}
-}
-
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub enum StakeBalanceType {
-	Direct,
-	Delegated,
-}
+	fn is_delegatee(_who: &Self::AccountId) -> bool;
+}
\ No newline at end of file

From 54bebb3e53d866ff5eda799c15e1ece3e2eae3d0 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 7 Dec 2023 00:14:24 +0100
Subject: [PATCH 047/202] rename traits

---
 substrate/frame/delegated-staking/src/lib.rs   |  9 ++++-----
 substrate/frame/delegated-staking/src/mock.rs  |  2 +-
 substrate/frame/staking/src/ledger.rs          |  2 +-
 substrate/frame/staking/src/pallet/impls.rs    | 12 +++++++-----
 substrate/primitives/staking/src/delegation.rs |  4 ++--
 substrate/primitives/staking/src/lib.rs        |  2 +-
 6 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index d4129b103faac..eec0f407d127b 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -39,7 +39,7 @@ use frame_support::{
 use pallet::*;
 use sp_runtime::{traits::Zero, DispatchResult, RuntimeDebug, Saturating};
 use sp_staking::{
-	delegation::{Delegatee, StakingDelegationSupport},
+	delegation::{DelegationInterface, StakingDelegationSupport},
 	EraIndex, Stake, StakerStatus, StakingInterface,
 };
 use sp_std::{convert::TryInto, prelude::*};
@@ -179,7 +179,7 @@ impl<T: Config> DelegationRegister<T> {
 	}
 }
 
-impl<T: Config> Delegatee for Pallet<T> {
+impl<T: Config> DelegationInterface for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
@@ -383,7 +383,6 @@ impl<T: Config> Delegatee for Pallet<T> {
 
 		Ok(())
 	}
-
 }
 
 impl<T: Config> sp_staking::StakingHoldProvider for Pallet<T> {
@@ -407,9 +406,9 @@ impl<T: Config> sp_staking::StakingHoldProvider for Pallet<T> {
 		Ok(())
 	}
 
-	fn release(who: &Self::AccountId) {
+	fn release_all(who: &Self::AccountId) {
 		if !Self::is_delegatee(who) {
-			T::CoreStaking::release(who);
+			T::CoreStaking::release_all(who);
 		}
 
 		let _delegation_register = <Delegatees<T>>::get(who);
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 9e80ee3da371d..d77862c5157f8 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -30,7 +30,7 @@ use frame_election_provider_support::{
 	onchain, SequentialPhragmen,
 };
 use pallet_staking::CurrentEra;
-use sp_staking::delegation::{Delegatee, StakingDelegationSupport};
+use sp_staking::delegation::{DelegationInterface, StakingDelegationSupport};
 
 pub type T = Runtime;
 type Block = frame_system::mocking::MockBlock<Runtime>;
diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs
index 9a4f2ade3f11c..962353b04e7fd 100644
--- a/substrate/frame/staking/src/ledger.rs
+++ b/substrate/frame/staking/src/ledger.rs
@@ -197,7 +197,7 @@ impl<T: Config> StakingLedger<T> {
 		let controller = <Bonded<T>>::get(stash).ok_or(Error::<T>::NotStash)?;
 
 		<Ledger<T>>::get(&controller).ok_or(Error::<T>::NotController).map(|ledger| {
-			T::DelegationSupport::release(&ledger.stash);
+			T::DelegationSupport::release_all(&ledger.stash);
 			Ledger::<T>::remove(controller);
 
 			<Bonded<T>>::remove(&stash);
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 0c50022fc72fa..4dda02320f0f1 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1834,7 +1834,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	fn force_unlock(who: &Self::AccountId) -> sp_runtime::DispatchResult {
-		T::DelegationSupport::release(who);
+		T::DelegationSupport::release_all(who);
 		Ok(())
 	}
 }
@@ -1848,7 +1848,7 @@ impl<T: Config> StakingHoldProvider for Pallet<T> {
 		Ok(())
 	}
 
-	fn release(who: &Self::AccountId) {
+	fn release_all(who: &Self::AccountId) {
 		T::Currency::remove_lock(crate::STAKING_ID, who)
 	}
 }
@@ -1864,8 +1864,8 @@ impl<T: Config> StakingHoldProvider for NoDelegation<T> {
 		Pallet::<T>::update_hold(who, amount)
 	}
 
-	fn release(who: &Self::AccountId) {
-		Pallet::<T>::release(who)
+	fn release_all(who: &Self::AccountId) {
+		Pallet::<T>::release_all(who)
 	}
 }
 
@@ -1873,7 +1873,9 @@ impl<T: Config> StakingDelegationSupport for NoDelegation<T> {
 	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
 		T::Currency::free_balance(who)
 	}
-	fn is_delegatee(_who: &Self::AccountId) -> bool { false }
+	fn is_delegatee(_who: &Self::AccountId) -> bool {
+		false
+	}
 }
 
 #[cfg(any(test, feature = "try-runtime"))]
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 6c0ced227a950..c736a3a7a28a7 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -22,7 +22,7 @@ use sp_runtime::{DispatchResult, Saturating};
 use sp_std::ops::Sub;
 
 /// Allows an account to accept stake delegations and manage its operations.
-pub trait Delegatee {
+pub trait DelegationInterface {
 	/// Balance type used by the staking system.
 	type Balance: Sub<Output = Self::Balance>
 		+ Ord
@@ -139,4 +139,4 @@ pub trait StakingDelegationSupport: StakingHoldProvider {
 
 	#[cfg(feature = "std")]
 	fn is_delegatee(_who: &Self::AccountId) -> bool;
-}
\ No newline at end of file
+}
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 5bbe49fa8f21e..5f04c5e36eecc 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -440,6 +440,6 @@ pub trait StakingHoldProvider {
 	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult;
 
 	/// Release all amount held for stake.
-	fn release(who: &Self::AccountId);
+	fn release_all(who: &Self::AccountId);
 }
 sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $);

From 50f051a6a171540b404d46c723ccbe4a89e664eb Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 7 Dec 2023 00:19:47 +0100
Subject: [PATCH 048/202] add events for delegated and withdrawn

---
 substrate/frame/delegated-staking/src/lib.rs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index eec0f407d127b..086ce09ad0b4d 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -381,6 +381,8 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 
 		T::Currency::hold(&HoldReason::Delegating.into(), &delegator, value)?;
 
+		Self::deposit_event(Event::<T>::Delegated { delegatee: delegatee.clone(), delegator: delegator.clone(), amount: value });
+
 		Ok(())
 	}
 }
@@ -695,6 +697,7 @@ impl<T: Config> Pallet<T> {
 		)?;
 
 		defensive_assert!(released == value, "hold should have been released fully");
+		Self::deposit_event(Event::<T>::Withdrawn { delegatee: delegatee.clone(), delegator: delegator.clone(), amount: value });
 
 		Ok(())
 	}

From c159d109159003c6051174636b5165a0d1439ff6 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 7 Dec 2023 00:22:21 +0100
Subject: [PATCH 049/202] fmt

---
 substrate/frame/delegated-staking/src/lib.rs | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 086ce09ad0b4d..f66d4f84e1000 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -381,7 +381,11 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 
 		T::Currency::hold(&HoldReason::Delegating.into(), &delegator, value)?;
 
-		Self::deposit_event(Event::<T>::Delegated { delegatee: delegatee.clone(), delegator: delegator.clone(), amount: value });
+		Self::deposit_event(Event::<T>::Delegated {
+			delegatee: delegatee.clone(),
+			delegator: delegator.clone(),
+			amount: value,
+		});
 
 		Ok(())
 	}
@@ -697,7 +701,11 @@ impl<T: Config> Pallet<T> {
 		)?;
 
 		defensive_assert!(released == value, "hold should have been released fully");
-		Self::deposit_event(Event::<T>::Withdrawn { delegatee: delegatee.clone(), delegator: delegator.clone(), amount: value });
+		Self::deposit_event(Event::<T>::Withdrawn {
+			delegatee: delegatee.clone(),
+			delegator: delegator.clone(),
+			amount: value,
+		});
 
 		Ok(())
 	}

From 8cb22c7c683934c71c4cb1d4e006e6abebef9e70 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 7 Dec 2023 00:43:52 +0100
Subject: [PATCH 050/202] migrate delegator docs

---
 substrate/frame/delegated-staking/src/lib.rs  | 28 +++++++++++--------
 substrate/frame/staking/src/pallet/impls.rs   |  5 ----
 .../primitives/staking/src/delegation.rs      | 10 ++-----
 substrate/primitives/staking/src/lib.rs       |  3 --
 4 files changed, 20 insertions(+), 26 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index f66d4f84e1000..8710688b2795b 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -40,7 +40,7 @@ use pallet::*;
 use sp_runtime::{traits::Zero, DispatchResult, RuntimeDebug, Saturating};
 use sp_staking::{
 	delegation::{DelegationInterface, StakingDelegationSupport},
-	EraIndex, Stake, StakerStatus, StakingInterface,
+	EraIndex, Stake, StakerStatus, StakingInterface, StakingHoldProvider,
 };
 use sp_std::{convert::TryInto, prelude::*};
 
@@ -98,6 +98,8 @@ pub mod pallet {
 		WithdrawFailed,
 		/// This operation is not supported with Delegation Staking.
 		NotSupported,
+		/// This delegatee is not set as a migrating account.
+		NotMigrating,
 	}
 
 	/// A reason for placing a hold on funds.
@@ -136,6 +138,14 @@ pub mod pallet {
 	#[pallet::storage]
 	pub(crate) type Delegatees<T: Config> =
 		CountedStorageMap<_, Twox64Concat, T::AccountId, DelegationRegister<T>, OptionQuery>;
+
+	/// Map of Delegatee and its proxy delegator account while its actual delegators are migrating.
+	///
+	/// Helps ensure correctness of ongoing migration of a direct nominator to a delegatee. If a
+	/// delegatee does not exist, it implies it is not going through migration.
+	#[pallet::storage]
+	pub(crate) type DelegateeMigration<T: Config> =
+		CountedStorageMap<_, Twox64Concat, T::AccountId, T::AccountId, OptionQuery>;
 }
 
 /// Register of all delegations to a `Delegatee`.
@@ -251,10 +261,11 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 			_ => return Err(Error::<T>::InvalidDelegation.into()),
 		}
 
+		<DelegateeMigration<T>>::insert(&new_delegatee, &proxy_delegator);
 		let stake = T::CoreStaking::stake(new_delegatee)?;
 
 		// unlock funds from staker
-		T::CoreStaking::force_unlock(new_delegatee)?;
+		T::CoreStaking::release_all(new_delegatee);
 
 		// try transferring the staked amount. This should never fail but if it does, it indicates
 		// bad state and we abort.
@@ -326,7 +337,6 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 	#[transactional]
 	fn migrate_delegator(
 		delegatee: &Self::AccountId,
-		existing_delegator: &Self::AccountId,
 		new_delegator: &Self::AccountId,
 		value: Self::Balance,
 	) -> DispatchResult {
@@ -334,12 +344,13 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 
 		// ensure delegatee exists.
 		ensure!(!<Delegatees<T>>::contains_key(delegatee), Error::<T>::NotDelegatee);
+		let proxy_delegator = <DelegateeMigration<T>>::get(delegatee).ok_or(Error::<T>::NotMigrating)?;
 
-		// remove delegation of `value` from `existing_delegator`.
-		Self::delegation_withdraw(existing_delegator, delegatee, value)?;
+		// remove delegation of `value` from `proxy_delegator`.
+		Self::delegation_withdraw(&proxy_delegator, delegatee, value)?;
 
 		// transfer the withdrawn value to `new_delegator`.
-		T::Currency::transfer(existing_delegator, new_delegator, value, Preservation::Expendable)
+		T::Currency::transfer(&proxy_delegator, new_delegator, value, Preservation::Expendable)
 			.map_err(|_| Error::<T>::BadState)?;
 
 		// add the above removed delegation to `new_delegator`.
@@ -626,11 +637,6 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		T::CoreStaking::nominations(who)
 	}
 
-	fn force_unlock(_who: &Self::AccountId) -> DispatchResult {
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
-		Err(Error::<T>::NotSupported.into())
-	}
-
 	#[cfg(feature = "runtime-benchmarks")]
 	fn max_exposure_page_size() -> sp_staking::Page {
 		T::CoreStaking::max_exposure_page_size()
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 4dda02320f0f1..40006537c2e3d 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1832,11 +1832,6 @@ impl<T: Config> StakingInterface for Pallet<T> {
 			T::MaxExposurePageSize::get()
 		}
 	}
-
-	fn force_unlock(who: &Self::AccountId) -> sp_runtime::DispatchResult {
-		T::DelegationSupport::release_all(who);
-		Ok(())
-	}
 }
 
 impl<T: Config> StakingHoldProvider for Pallet<T> {
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index c736a3a7a28a7..0da13c738e150 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -100,18 +100,14 @@ pub trait DelegationInterface {
 		reporter: Option<Self::AccountId>,
 	) -> DispatchResult;
 
-	/// Swap a delegated `value` from `delegator_from` to `delegator_to`, with delegatee remaining
-	/// the same.
+	/// Move a delegated amount from `proxy_delegator` to `new_delegator`.
 	///
+	/// Delegatee must have used [`Self::migrate_accept_delegations`] to setup a `proxy_delegator`.
 	/// This is useful for migrating old pool accounts using direct staking to lazily move
 	/// delegators to the new delegated pool account.
-	///
-	/// FIXME(ank4n): delegator_from should be removed and be always `proxy_delegator` that was
-	/// registered while calling [`Self::migrate_accept_delegations`].
 	fn migrate_delegator(
 		delegatee: &Self::AccountId,
-		delegator_from: &Self::AccountId,
-		delegator_to: &Self::AccountId,
+		new_delegator: &Self::AccountId,
 		value: Self::Balance,
 	) -> DispatchResult;
 
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 5f04c5e36eecc..c32145f8c563b 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -285,9 +285,6 @@ pub trait StakingInterface {
 		}
 	}
 
-	/// Used for migration of locks.
-	fn force_unlock(who: &Self::AccountId) -> DispatchResult;
-
 	#[cfg(feature = "runtime-benchmarks")]
 	fn max_exposure_page_size() -> Page;
 

From 39f435f48e033fab64a047d627392bbaf26beb57 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 7 Dec 2023 00:47:06 +0100
Subject: [PATCH 051/202] empty tests

---
 substrate/frame/delegated-staking/src/tests.rs | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index a3e0f58b1a66b..6dba90ee8725d 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -252,7 +252,12 @@ mod integration {
 	}
 
 	#[test]
-	fn reward_destination_cannot_be_delegatee() {
+	fn direct_withdraw_ends_up_in_limbo() {
+
+	}
+
+	#[test]
+	fn reward_destination_restrictions() {
 		ExtBuilder::default().build_and_execute(|| assert!(true));
 	}
 

From 3172da679e75f26fbcc125b45ee2be1e8ecccadb Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 8 Dec 2023 01:13:46 +0100
Subject: [PATCH 052/202] refactor and additional tests

---
 substrate/frame/delegated-staking/src/lib.rs  | 61 +++++++++----------
 .../frame/delegated-staking/src/tests.rs      | 42 ++++++++++++-
 2 files changed, 69 insertions(+), 34 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 8710688b2795b..cf99a5e96f85f 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -316,10 +316,18 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		value: Self::Balance,
 		num_slashing_spans: u32,
 	) -> DispatchResult {
-		// fixme(ank4n) handle killing of stash
-		let _stash_killed: bool =
-			T::CoreStaking::withdraw_exact(delegatee, value, num_slashing_spans)
-				.map_err(|_| Error::<T>::WithdrawFailed)?;
+		// check how much is already unbonded
+		let delegation_register = <Delegatees<T>>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
+		let unbonded_balance = delegation_register.unbonded_balance();
+
+		if unbonded_balance < value {
+			// fixme(ank4n) handle killing of stash
+			let amount_to_withdraw = value.saturating_sub(unbonded_balance);
+			let _stash_killed: bool =
+				T::CoreStaking::withdraw_exact(delegatee, amount_to_withdraw, num_slashing_spans)
+					.map_err(|_| Error::<T>::WithdrawFailed)?;
+		}
+
 		Self::delegation_withdraw(delegator, delegatee, value)
 	}
 
@@ -369,7 +377,7 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		ensure!(delegatee != delegator, Error::<T>::InvalidDelegation);
 		ensure!(<Delegatees<T>>::contains_key(delegatee), Error::<T>::NotDelegatee);
 
-		// cannot delegate to another delegatee.
+		// A delegatee cannot delegate.
 		if <Delegatees<T>>::contains_key(delegator) {
 			return Err(Error::<T>::InvalidDelegation.into())
 		}
@@ -670,34 +678,25 @@ impl<T: Config> Pallet<T> {
 		delegatee: &T::AccountId,
 		value: BalanceOf<T>,
 	) -> DispatchResult {
-		<Delegators<T>>::mutate_exists(delegator, |maybe_delegate| match maybe_delegate {
-			Some((current_delegatee, delegate_balance)) => {
-				ensure!(&current_delegatee.clone() == delegatee, Error::<T>::NotDelegatee);
-				ensure!(*delegate_balance >= value, Error::<T>::NotEnoughFunds);
 
-				delegate_balance.saturating_reduce(value);
+		let mut delegation_register = <Delegatees<T>>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
+		ensure!(delegation_register.unbonded_balance() >= value, Error::<T>::BadState);
 
-				if *delegate_balance == BalanceOf::<T>::zero() {
-					*maybe_delegate = None;
-				}
-				Ok(())
-			},
-			None => {
-				// delegator does not exist
-				return Err(Error::<T>::NotDelegator)
-			},
-		})?;
-
-		<Delegatees<T>>::mutate(delegatee, |maybe_register| match maybe_register {
-			Some(ledger) => {
-				ledger.total_delegated.saturating_reduce(value);
-				Ok(())
-			},
-			None => {
-				// Delegatee not found
-				return Err(Error::<T>::NotDelegatee)
-			},
-		})?;
+		delegation_register.total_delegated.saturating_reduce(value);
+		<Delegatees<T>>::insert(delegatee, delegation_register);
+
+		let (assigned_delegatee, delegate_balance) = <Delegators<T>>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
+		// delegator should already be delegating to delegatee
+		ensure!(&assigned_delegatee == delegatee, Error::<T>::NotDelegatee);
+		ensure!(delegate_balance >= value, Error::<T>::NotEnoughFunds);
+		let updated_delegate_balance = delegate_balance.saturating_sub(value);
+
+		// remove delegator if nothing delegated anymore
+		if updated_delegate_balance == BalanceOf::<T>::zero() {
+			<Delegators<T>>::remove(delegator);
+		} else {
+			<Delegators<T>>::insert(delegator, (delegatee, updated_delegate_balance));
+		}
 
 		let released = T::Currency::release(
 			&HoldReason::Delegating.into(),
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 6dba90ee8725d..a4e69592d6959 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -101,9 +101,29 @@ fn create_multiple_delegators() {
 }
 
 #[test]
-fn withdraw_delegation() {
+fn delegate_restrictions() {
 	// Similar to creating a nomination pool
-	ExtBuilder::default().build_and_execute(|| assert!(true));
+	ExtBuilder::default().build_and_execute(|| {
+		let delegatee_one = 200;
+		let delegator_one = 210;
+		assert_ok!(DelegatedStaking::accept_delegations(fund(&delegatee_one, 100), &(delegatee_one+1)));
+		assert_ok!(DelegatedStaking::delegate(fund(&delegator_one, 200), &delegatee_one, 100));
+
+		let delegatee_two = 300;
+		let delegator_two = 310;
+		assert_ok!(DelegatedStaking::accept_delegations(fund(&delegatee_two, 100), &(delegatee_two+1)));
+		assert_ok!(DelegatedStaking::delegate(fund(&delegator_two, 200), &delegatee_two, 100));
+
+		// delegatee one tries to delegate to delegatee 2
+		assert_noop!(DelegatedStaking::delegate(&delegatee_one, &delegatee_two, 10), Error::<T>::InvalidDelegation);
+
+		// delegatee one tries to delegate to a delegator
+		assert_noop!(DelegatedStaking::delegate(&delegatee_one, &delegator_one, 10), Error::<T>::NotDelegatee);
+		assert_noop!(DelegatedStaking::delegate(&delegatee_one, &delegator_two, 10), Error::<T>::NotDelegatee);
+
+		// delegator one tries to delegate to delegatee 2 as well (it already delegates to delegatee 1)
+		assert_noop!(DelegatedStaking::delegate(&delegator_one, &delegatee_two, 10), Error::<T>::InvalidDelegation);
+	});
 }
 
 #[test]
@@ -252,8 +272,24 @@ mod integration {
 	}
 
 	#[test]
-	fn direct_withdraw_ends_up_in_limbo() {
+	fn withdraw_happens_with_unbonded_balance_first() {
+		ExtBuilder::default().build_and_execute(|| {
+			let delegatee = 200;
+			setup_delegation_stake(delegatee, 201, (300..350).collect(), 100, 0);
+
+			// verify withdraw not possible yet
+			assert_noop!(DelegatedStaking::withdraw(&300, &delegatee, 100, 0), Error::<T>::WithdrawFailed);
+
+			// add new delegation that is not staked
+			assert_ok!(DelegatedStaking::delegate(fund(&300, 1000), &delegatee, 100));
 
+			// verify unbonded balance
+			assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 100);
+
+			// withdraw works now without unbonding
+			assert_ok!(DelegatedStaking::withdraw(&300, &delegatee, 100, 0));
+			assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
+		});
 	}
 
 	#[test]

From d469759a2d6cd753fffb4d724718962f6147c8c8 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 8 Dec 2023 01:48:43 +0100
Subject: [PATCH 053/202] add todos in tests

---
 substrate/frame/delegated-staking/src/lib.rs  | 15 +++---
 .../frame/delegated-staking/src/tests.rs      | 52 +++++++++++++++----
 2 files changed, 50 insertions(+), 17 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index cf99a5e96f85f..43559a3dbdd53 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -40,7 +40,7 @@ use pallet::*;
 use sp_runtime::{traits::Zero, DispatchResult, RuntimeDebug, Saturating};
 use sp_staking::{
 	delegation::{DelegationInterface, StakingDelegationSupport},
-	EraIndex, Stake, StakerStatus, StakingInterface, StakingHoldProvider,
+	EraIndex, Stake, StakerStatus, StakingHoldProvider, StakingInterface,
 };
 use sp_std::{convert::TryInto, prelude::*};
 
@@ -317,7 +317,8 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		num_slashing_spans: u32,
 	) -> DispatchResult {
 		// check how much is already unbonded
-		let delegation_register = <Delegatees<T>>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
+		let delegation_register =
+			<Delegatees<T>>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
 		let unbonded_balance = delegation_register.unbonded_balance();
 
 		if unbonded_balance < value {
@@ -352,7 +353,8 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 
 		// ensure delegatee exists.
 		ensure!(!<Delegatees<T>>::contains_key(delegatee), Error::<T>::NotDelegatee);
-		let proxy_delegator = <DelegateeMigration<T>>::get(delegatee).ok_or(Error::<T>::NotMigrating)?;
+		let proxy_delegator =
+			<DelegateeMigration<T>>::get(delegatee).ok_or(Error::<T>::NotMigrating)?;
 
 		// remove delegation of `value` from `proxy_delegator`.
 		Self::delegation_withdraw(&proxy_delegator, delegatee, value)?;
@@ -678,14 +680,15 @@ impl<T: Config> Pallet<T> {
 		delegatee: &T::AccountId,
 		value: BalanceOf<T>,
 	) -> DispatchResult {
-
-		let mut delegation_register = <Delegatees<T>>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
+		let mut delegation_register =
+			<Delegatees<T>>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
 		ensure!(delegation_register.unbonded_balance() >= value, Error::<T>::BadState);
 
 		delegation_register.total_delegated.saturating_reduce(value);
 		<Delegatees<T>>::insert(delegatee, delegation_register);
 
-		let (assigned_delegatee, delegate_balance) = <Delegators<T>>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
+		let (assigned_delegatee, delegate_balance) =
+			<Delegators<T>>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
 		// delegator should already be delegating to delegatee
 		ensure!(&assigned_delegatee == delegatee, Error::<T>::NotDelegatee);
 		ensure!(delegate_balance >= value, Error::<T>::NotEnoughFunds);
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index a4e69592d6959..c31fef3e78e29 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -106,34 +106,57 @@ fn delegate_restrictions() {
 	ExtBuilder::default().build_and_execute(|| {
 		let delegatee_one = 200;
 		let delegator_one = 210;
-		assert_ok!(DelegatedStaking::accept_delegations(fund(&delegatee_one, 100), &(delegatee_one+1)));
+		assert_ok!(DelegatedStaking::accept_delegations(
+			fund(&delegatee_one, 100),
+			&(delegatee_one + 1)
+		));
 		assert_ok!(DelegatedStaking::delegate(fund(&delegator_one, 200), &delegatee_one, 100));
 
 		let delegatee_two = 300;
 		let delegator_two = 310;
-		assert_ok!(DelegatedStaking::accept_delegations(fund(&delegatee_two, 100), &(delegatee_two+1)));
+		assert_ok!(DelegatedStaking::accept_delegations(
+			fund(&delegatee_two, 100),
+			&(delegatee_two + 1)
+		));
 		assert_ok!(DelegatedStaking::delegate(fund(&delegator_two, 200), &delegatee_two, 100));
 
 		// delegatee one tries to delegate to delegatee 2
-		assert_noop!(DelegatedStaking::delegate(&delegatee_one, &delegatee_two, 10), Error::<T>::InvalidDelegation);
+		assert_noop!(
+			DelegatedStaking::delegate(&delegatee_one, &delegatee_two, 10),
+			Error::<T>::InvalidDelegation
+		);
 
 		// delegatee one tries to delegate to a delegator
-		assert_noop!(DelegatedStaking::delegate(&delegatee_one, &delegator_one, 10), Error::<T>::NotDelegatee);
-		assert_noop!(DelegatedStaking::delegate(&delegatee_one, &delegator_two, 10), Error::<T>::NotDelegatee);
+		assert_noop!(
+			DelegatedStaking::delegate(&delegatee_one, &delegator_one, 10),
+			Error::<T>::NotDelegatee
+		);
+		assert_noop!(
+			DelegatedStaking::delegate(&delegatee_one, &delegator_two, 10),
+			Error::<T>::NotDelegatee
+		);
 
-		// delegator one tries to delegate to delegatee 2 as well (it already delegates to delegatee 1)
-		assert_noop!(DelegatedStaking::delegate(&delegator_one, &delegatee_two, 10), Error::<T>::InvalidDelegation);
+		// delegator one tries to delegate to delegatee 2 as well (it already delegates to delegatee
+		// 1)
+		assert_noop!(
+			DelegatedStaking::delegate(&delegator_one, &delegatee_two, 10),
+			Error::<T>::InvalidDelegation
+		);
 	});
 }
 
 #[test]
 fn apply_pending_slash() {
-	ExtBuilder::default().build_and_execute(|| assert!(true));
+	ExtBuilder::default().build_and_execute(|| {
+		todo!()
+	});
 }
 
 #[test]
 fn distribute_rewards() {
-	ExtBuilder::default().build_and_execute(|| assert!(true));
+	ExtBuilder::default().build_and_execute(|| {
+		todo!()
+	});
 }
 
 /// Integration tests with pallet-staking.
@@ -278,7 +301,10 @@ mod integration {
 			setup_delegation_stake(delegatee, 201, (300..350).collect(), 100, 0);
 
 			// verify withdraw not possible yet
-			assert_noop!(DelegatedStaking::withdraw(&300, &delegatee, 100, 0), Error::<T>::WithdrawFailed);
+			assert_noop!(
+				DelegatedStaking::withdraw(&300, &delegatee, 100, 0),
+				Error::<T>::WithdrawFailed
+			);
 
 			// add new delegation that is not staked
 			assert_ok!(DelegatedStaking::delegate(fund(&300, 1000), &delegatee, 100));
@@ -301,6 +327,7 @@ mod integration {
 	fn nominate_test() {
 		ExtBuilder::default().build_and_execute(|| assert!(true));
 	}
+
 	#[test]
 	fn slash_works() {
 		ExtBuilder::default().build_and_execute(|| {
@@ -308,11 +335,14 @@ mod integration {
 			start_era(1);
 
 			// delegatee is slashed
+			todo!()
 		});
 	}
 
 	#[test]
 	fn migration_works() {
-		ExtBuilder::default().build_and_execute(|| assert!(true));
+		ExtBuilder::default().build_and_execute(|| {
+			todo!()
+		});
 	}
 }

From 430fb6b0538d7f6063c96f43f4e31ef099c0e732 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 8 Dec 2023 03:01:24 +0100
Subject: [PATCH 054/202] reward destination restriction test

---
 .../frame/delegated-staking/src/tests.rs      | 38 +++++++++++++++++--
 1 file changed, 35 insertions(+), 3 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index c31fef3e78e29..1140a6238bc7d 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -161,6 +161,7 @@ fn distribute_rewards() {
 
 /// Integration tests with pallet-staking.
 mod integration {
+	use pallet_staking::RewardDestination;
 	use super::*;
 	use sp_staking::Stake;
 
@@ -320,12 +321,43 @@ mod integration {
 
 	#[test]
 	fn reward_destination_restrictions() {
-		ExtBuilder::default().build_and_execute(|| assert!(true));
+		ExtBuilder::default().build_and_execute(|| {
+			// give some funds to 200
+			fund(&200, 1000);
+			let balance_200 = Balances::free_balance(200);
+
+			// delegatee cannot be reward destination
+			assert_noop!(DelegatedStaking::accept_delegations(&200, &200), Error::<T>::InvalidRewardDestination);
+
+			// different reward account works
+			assert_ok!(DelegatedStaking::accept_delegations(&200, &201));
+			// add some delegations to it
+			assert_ok!(DelegatedStaking::delegate(fund(&300, 1000), &200, 100));
+
+
+			// if delegatee calls Staking pallet directly with a different reward destination, it fails.
+			assert_noop!(Staking::bond(RuntimeOrigin::signed(200), 100, RewardDestination::Stash), StakingError::<T>::RewardDestinationRestricted);
+			// non stash account different than one passed to DelegatedStaking also does not work..
+			assert_noop!(Staking::bond(RuntimeOrigin::signed(200), 100, RewardDestination::Account(202)), StakingError::<T>::RewardDestinationRestricted);
+			// passing correct reward destination works
+			assert_ok!(Staking::bond(RuntimeOrigin::signed(200), 100, RewardDestination::Account(201)));
+			// amount is staked correctly
+			assert!(eq_stake(200, 100, 100));
+			assert_eq!(DelegatedStaking::unbonded_balance(&200), 0);
+			assert_eq!(DelegatedStaking::delegated_balance(&200), 100);
+
+			// free balance of delegatee is untouched
+			assert_eq!(Balances::free_balance(200), balance_200);
+		});
 	}
 
 	#[test]
-	fn nominate_test() {
-		ExtBuilder::default().build_and_execute(|| assert!(true));
+	fn delegatee_restrictions() {
+		ExtBuilder::default().build_and_execute(|| {
+			// delegatee cannot be reward destination
+			assert_noop!(DelegatedStaking::accept_delegations(fund(&200, 1000), &200), Error::<T>::InvalidRewardDestination);
+
+		});
 	}
 
 	#[test]

From 6ba4f827f3b00d163788a4f188d61483ebe3b779 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 8 Dec 2023 03:46:42 +0100
Subject: [PATCH 055/202] more tests

---
 substrate/frame/delegated-staking/src/lib.rs  | 67 +++++++------
 .../frame/delegated-staking/src/tests.rs      | 93 ++++++++++++++-----
 substrate/frame/staking/src/pallet/mod.rs     |  4 +-
 .../primitives/staking/src/delegation.rs      |  5 +-
 4 files changed, 113 insertions(+), 56 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 43559a3dbdd53..1624ddc5a4bff 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -100,6 +100,8 @@ pub mod pallet {
 		NotSupported,
 		/// This delegatee is not set as a migrating account.
 		NotMigrating,
+		/// Delegatee no longer accepting new delegations.
+		DelegationsBlocked,
 	}
 
 	/// A reason for placing a hold on funds.
@@ -207,30 +209,29 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		who: &Self::AccountId,
 		reward_destination: &Self::AccountId,
 	) -> DispatchResult {
-		// Existing delegatee cannot accept delegation
+		// Existing delegatee cannot register again.
 		ensure!(!<Delegatees<T>>::contains_key(who), Error::<T>::NotAllowed);
 
+		// A delegator cannot become a delegatee.
+		ensure!(!<Delegators<T>>::contains_key(who), Error::<T>::NotAllowed);
+
 		// make sure they are not already a direct staker
 		ensure!(T::CoreStaking::status(who).is_err(), Error::<T>::AlreadyStaker);
 
 		// payee account cannot be same as delegatee
 		ensure!(reward_destination != who, Error::<T>::InvalidRewardDestination);
 
-		// if already a delegator, unblock and return success
-		<Delegatees<T>>::mutate(who, |maybe_register| {
-			if let Some(register) = maybe_register {
-				register.blocked = false;
-				register.payee = reward_destination.clone();
-			} else {
-				*maybe_register = Some(DelegationRegister {
-					payee: reward_destination.clone(),
-					total_delegated: Zero::zero(),
-					hold: Zero::zero(),
-					pending_slash: Zero::zero(),
-					blocked: false,
-				});
-			}
-		});
+		// already checked delegatees exist
+		<Delegatees<T>>::insert(
+			who,
+			DelegationRegister {
+				payee: reward_destination.clone(),
+				total_delegated: Zero::zero(),
+				hold: Zero::zero(),
+				pending_slash: Zero::zero(),
+				blocked: false,
+			},
+		);
 
 		Ok(())
 	}
@@ -283,14 +284,19 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 	}
 
 	fn block_delegations(delegatee: &Self::AccountId) -> DispatchResult {
-		<Delegatees<T>>::mutate(delegatee, |maybe_register| {
-			if let Some(register) = maybe_register {
-				register.blocked = true;
-				Ok(())
-			} else {
-				Err(Error::<T>::NotDelegatee.into())
-			}
-		})
+		let mut register = <Delegatees<T>>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
+		register.blocked = true;
+		<Delegatees<T>>::insert(delegatee, register);
+
+		Ok(())
+	}
+
+	fn unblock_delegations(delegatee: &Self::AccountId) -> DispatchResult {
+		let mut register = <Delegatees<T>>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
+		register.blocked = false;
+		<Delegatees<T>>::insert(delegatee, register);
+
+		Ok(())
 	}
 
 	fn kill_delegatee(_delegatee: &Self::AccountId) -> DispatchResult {
@@ -377,7 +383,10 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		ensure!(value >= T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
 		ensure!(delegator_balance >= value, Error::<T>::NotEnoughFunds);
 		ensure!(delegatee != delegator, Error::<T>::InvalidDelegation);
-		ensure!(<Delegatees<T>>::contains_key(delegatee), Error::<T>::NotDelegatee);
+
+		let mut delegation_register =
+			<Delegatees<T>>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
+		ensure!(!delegation_register.blocked, Error::<T>::DelegationsBlocked);
 
 		// A delegatee cannot delegate.
 		if <Delegatees<T>>::contains_key(delegator) {
@@ -393,12 +402,10 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 			value
 		};
 
+		delegation_register.total_delegated.saturating_accrue(value);
+
 		<Delegators<T>>::insert(delegator, (delegatee, new_delegation_amount));
-		<Delegatees<T>>::mutate(delegatee, |maybe_register| {
-			if let Some(register) = maybe_register {
-				register.total_delegated.saturating_accrue(value);
-			}
-		});
+		<Delegatees<T>>::insert(delegatee, delegation_register);
 
 		T::Currency::hold(&HoldReason::Delegating.into(), &delegator, value)?;
 
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 1140a6238bc7d..9c77a137922e6 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -147,22 +147,13 @@ fn delegate_restrictions() {
 
 #[test]
 fn apply_pending_slash() {
-	ExtBuilder::default().build_and_execute(|| {
-		todo!()
-	});
-}
-
-#[test]
-fn distribute_rewards() {
-	ExtBuilder::default().build_and_execute(|| {
-		todo!()
-	});
+	ExtBuilder::default().build_and_execute(|| todo!());
 }
 
 /// Integration tests with pallet-staking.
 mod integration {
-	use pallet_staking::RewardDestination;
 	use super::*;
+	use pallet_staking::RewardDestination;
 	use sp_staking::Stake;
 
 	#[test]
@@ -327,20 +318,33 @@ mod integration {
 			let balance_200 = Balances::free_balance(200);
 
 			// delegatee cannot be reward destination
-			assert_noop!(DelegatedStaking::accept_delegations(&200, &200), Error::<T>::InvalidRewardDestination);
+			assert_noop!(
+				DelegatedStaking::accept_delegations(&200, &200),
+				Error::<T>::InvalidRewardDestination
+			);
 
 			// different reward account works
 			assert_ok!(DelegatedStaking::accept_delegations(&200, &201));
 			// add some delegations to it
 			assert_ok!(DelegatedStaking::delegate(fund(&300, 1000), &200, 100));
 
-
-			// if delegatee calls Staking pallet directly with a different reward destination, it fails.
-			assert_noop!(Staking::bond(RuntimeOrigin::signed(200), 100, RewardDestination::Stash), StakingError::<T>::RewardDestinationRestricted);
+			// if delegatee calls Staking pallet directly with a different reward destination, it
+			// fails.
+			assert_noop!(
+				Staking::bond(RuntimeOrigin::signed(200), 100, RewardDestination::Stash),
+				StakingError::<T>::RewardDestinationRestricted
+			);
 			// non stash account different than one passed to DelegatedStaking also does not work..
-			assert_noop!(Staking::bond(RuntimeOrigin::signed(200), 100, RewardDestination::Account(202)), StakingError::<T>::RewardDestinationRestricted);
+			assert_noop!(
+				Staking::bond(RuntimeOrigin::signed(200), 100, RewardDestination::Account(202)),
+				StakingError::<T>::RewardDestinationRestricted
+			);
 			// passing correct reward destination works
-			assert_ok!(Staking::bond(RuntimeOrigin::signed(200), 100, RewardDestination::Account(201)));
+			assert_ok!(Staking::bond(
+				RuntimeOrigin::signed(200),
+				100,
+				RewardDestination::Account(201)
+			));
 			// amount is staked correctly
 			assert!(eq_stake(200, 100, 100));
 			assert_eq!(DelegatedStaking::unbonded_balance(&200), 0);
@@ -348,15 +352,62 @@ mod integration {
 
 			// free balance of delegatee is untouched
 			assert_eq!(Balances::free_balance(200), balance_200);
+
+			// trying to change reward destination later directly via staking does not work.
+			assert_noop!(
+				Staking::set_payee(RuntimeOrigin::signed(200), RewardDestination::Staked),
+				StakingError::<T>::RewardDestinationRestricted
+			);
+			assert_noop!(
+				Staking::set_payee(RuntimeOrigin::signed(200), RewardDestination::Account(300)),
+				StakingError::<T>::RewardDestinationRestricted
+			);
 		});
 	}
 
 	#[test]
 	fn delegatee_restrictions() {
 		ExtBuilder::default().build_and_execute(|| {
-			// delegatee cannot be reward destination
-			assert_noop!(DelegatedStaking::accept_delegations(fund(&200, 1000), &200), Error::<T>::InvalidRewardDestination);
+			setup_delegation_stake(200, 201, (202..203).collect(), 100, 0);
+
+			// Registering again is noop
+			assert_noop!(DelegatedStaking::accept_delegations(&200, &201), Error::<T>::NotAllowed);
+			// a delegator cannot become delegatee
+			assert_noop!(DelegatedStaking::accept_delegations(&202, &203), Error::<T>::NotAllowed);
+			// existing staker cannot become a delegatee
+			assert_noop!(
+				DelegatedStaking::accept_delegations(&GENESIS_NOMINATOR_ONE, &201),
+				Error::<T>::AlreadyStaker
+			);
+			assert_noop!(
+				DelegatedStaking::accept_delegations(&GENESIS_VALIDATOR, &201),
+				Error::<T>::AlreadyStaker
+			);
+		});
+	}
+
+	#[test]
+	fn block_delegations() {
+		ExtBuilder::default().build_and_execute(|| {
+			assert_ok!(DelegatedStaking::accept_delegations(&200, &201));
+
+			// delegation works
+			assert_ok!(DelegatedStaking::delegate(fund(&300, 1000), &200, 100));
 
+			// delegatee blocks delegation
+			assert_ok!(DelegatedStaking::block_delegations(&200));
+
+			// cannot delegate to it anymore
+			assert_noop!(
+				DelegatedStaking::delegate(&300, &200, 100),
+				Error::<T>::DelegationsBlocked
+			);
+
+			// delegatee can unblock delegation
+			assert_ok!(DelegatedStaking::unblock_delegations(&200));
+
+			// delegation works again
+			assert_ok!(DelegatedStaking::delegate(&300, &200, 100));
 		});
 	}
 
@@ -373,8 +424,6 @@ mod integration {
 
 	#[test]
 	fn migration_works() {
-		ExtBuilder::default().build_and_execute(|| {
-			todo!()
-		});
+		ExtBuilder::default().build_and_execute(|| todo!());
 	}
 }
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index 13f357e39e80d..fa154e6440e47 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -1317,9 +1317,7 @@ pub mod pallet {
 				Error::<T>::ControllerDeprecated
 			);
 
-			let _ = ledger
-				.set_payee(payee)
-				.defensive_proof("ledger was retrieved from storage, thus its bonded; qed.")?;
+			ledger.set_payee(payee)?;
 
 			Ok(())
 		}
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 0da13c738e150..7109671cbdf28 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -68,9 +68,12 @@ pub trait DelegationInterface {
 		payee: &Self::AccountId,
 	) -> DispatchResult;
 
-	/// Stop accepting new delegations on this account.
+	/// Stop accepting new delegations to this account.
 	fn block_delegations(delegatee: &Self::AccountId) -> DispatchResult;
 
+	/// Unblock delegations to this account.
+	fn unblock_delegations(delegatee: &Self::AccountId) -> DispatchResult;
+
 	/// Remove oneself as Delegatee.
 	///
 	/// This will only succeed if all delegations to this delegatee are withdrawn.

From 071450cbe864378e3c27f1746792c7aee806a31d Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 8 Dec 2023 05:18:55 +0100
Subject: [PATCH 056/202] add migration test

---
 substrate/frame/delegated-staking/src/lib.rs  | 56 ++++++++++++---
 .../frame/delegated-staking/src/tests.rs      | 70 ++++++++++++++++++-
 2 files changed, 116 insertions(+), 10 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 1624ddc5a4bff..d1647e1811687 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -215,12 +215,12 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		// A delegator cannot become a delegatee.
 		ensure!(!<Delegators<T>>::contains_key(who), Error::<T>::NotAllowed);
 
-		// make sure they are not already a direct staker
-		ensure!(T::CoreStaking::status(who).is_err(), Error::<T>::AlreadyStaker);
-
 		// payee account cannot be same as delegatee
 		ensure!(reward_destination != who, Error::<T>::InvalidRewardDestination);
 
+		// make sure they are not already a direct staker or they are migrating.
+		ensure!(T::CoreStaking::status(who).is_err() || <DelegateeMigration<T>>::contains_key(who), Error::<T>::AlreadyStaker);
+
 		// already checked delegatees exist
 		<Delegatees<T>>::insert(
 			who,
@@ -280,7 +280,10 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 
 		// delegate from new delegator to staker.
 		Self::accept_delegations(new_delegatee, payee)?;
-		Self::delegate(proxy_delegator, new_delegatee, stake.total)
+		// todo(ank4n): for existing nominators, how this payee should be propagated to CoreStaking?
+
+		Self::delegate(proxy_delegator, new_delegatee, stake.total)?;
+		Self::update_bond(new_delegatee)
 	}
 
 	fn block_delegations(delegatee: &Self::AccountId) -> DispatchResult {
@@ -356,21 +359,52 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		value: Self::Balance,
 	) -> DispatchResult {
 		ensure!(value >= T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
-
-		// ensure delegatee exists.
-		ensure!(!<Delegatees<T>>::contains_key(delegatee), Error::<T>::NotDelegatee);
+		// make sure new delegator is not an existing delegator or a delegatee
+		ensure!(!<Delegatees<T>>::contains_key(new_delegator), Error::<T>::NotAllowed);
+		ensure!(!<Delegators<T>>::contains_key(new_delegator), Error::<T>::NotAllowed);
+		// ensure we are migrating
 		let proxy_delegator =
 			<DelegateeMigration<T>>::get(delegatee).ok_or(Error::<T>::NotMigrating)?;
+		// proxy delegator must exist
+		let (assigned_delegatee, delegate_balance) =
+			<Delegators<T>>::get(&proxy_delegator).ok_or(Error::<T>::BadState)?;
+		ensure!(assigned_delegatee == *delegatee, Error::<T>::BadState);
+
+		// make sure proxy delegator has enough balance to support this migration.
+		ensure!(delegate_balance >= value, Error::<T>::NotEnoughFunds);
 
 		// remove delegation of `value` from `proxy_delegator`.
-		Self::delegation_withdraw(&proxy_delegator, delegatee, value)?;
+		let updated_delegate_balance = delegate_balance.saturating_sub(value);
+
+		// if all funds are migrated out of proxy delegator, clean up.
+		if updated_delegate_balance == BalanceOf::<T>::zero() {
+			<Delegators<T>>::remove(&proxy_delegator);
+			<DelegateeMigration<T>>::remove(delegatee);
+		} else {
+			// else update proxy delegator
+			<Delegators<T>>::insert(&proxy_delegator, (delegatee, updated_delegate_balance));
+		}
+
+		let released = T::Currency::release(
+			&HoldReason::Delegating.into(),
+			&proxy_delegator,
+			value,
+			Precision::BestEffort,
+		)?;
+
+		defensive_assert!(released == value, "hold should have been released fully");
 
 		// transfer the withdrawn value to `new_delegator`.
 		T::Currency::transfer(&proxy_delegator, new_delegator, value, Preservation::Expendable)
 			.map_err(|_| Error::<T>::BadState)?;
 
+
 		// add the above removed delegation to `new_delegator`.
-		Self::delegate(new_delegator, delegatee, value)
+		<Delegators<T>>::insert(new_delegator, (delegatee, value));
+		// hold the funds again in the new delegator account.
+		T::Currency::hold(&HoldReason::Delegating.into(), &new_delegator, value)?;
+
+		Ok(())
 	}
 
 	fn delegate(
@@ -682,6 +716,10 @@ impl<T: Config> Pallet<T> {
 		<Delegators<T>>::contains_key(who)
 	}
 
+	fn is_migrating(delegatee: &T::AccountId) -> bool {
+		<DelegateeMigration<T>>::contains_key(delegatee)
+	}
+
 	fn delegation_withdraw(
 		delegator: &T::AccountId,
 		delegatee: &T::AccountId,
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 9c77a137922e6..e89b670f02bd4 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -424,6 +424,74 @@ mod integration {
 
 	#[test]
 	fn migration_works() {
-		ExtBuilder::default().build_and_execute(|| todo!());
+		ExtBuilder::default().build_and_execute(|| {
+			// add a nominator
+			fund(&200, 5000);
+			let staked_amount = 4000;
+			assert_ok!(Staking::bond(
+				RuntimeOrigin::signed(200),
+				staked_amount,
+				RewardDestination::Account(201)
+			));
+			assert_ok!(Staking::nominate(
+				RuntimeOrigin::signed(200),
+				vec![GENESIS_VALIDATOR],
+			));
+			let init_stake = Staking::stake(&200).unwrap();
+
+			// scenario: 200 is a pool account, and the stake comes from its 4 delegators (300..304)
+			// in equal parts. lets try to migrate this nominator into delegatee based stake.
+
+			// all balance currently is in 200
+			assert_eq!(Balances::free_balance(200), 5000);
+
+			// to migrate, nominator needs to set an account as a proxy delegator where staked funds
+			// will be moved and delegated back to this old nominator account. This should be funded
+			// with at least ED.
+			let proxy_delegator = fund(&202, ExistentialDeposit::get());
+
+			assert_ok!(DelegatedStaking::migrate_accept_delegations(&200, &proxy_delegator, &201));
+			assert!(DelegatedStaking::is_migrating(&200));
+
+			// verify all went well
+			let mut expected_proxy_delegated_amount = staked_amount;
+			assert_eq!(
+				Balances::balance_on_hold(&HoldReason::Delegating.into(), &proxy_delegator),
+				expected_proxy_delegated_amount
+			);
+			assert_eq!(Balances::free_balance(200), 5000 - staked_amount);
+			assert_eq!(DelegatedStaking::stake(&200).unwrap(), init_stake);
+			assert_eq!(DelegatedStaking::delegated_balance(&200), 4000);
+			assert_eq!(DelegatedStaking::unbonded_balance(&200), 0);
+
+			// now lets migrate the delegators
+			let delegator_share = staked_amount/4;
+			for delegator in 300..304 {
+				assert_eq!(Balances::free_balance(delegator), 0);
+				// fund them with ED
+				fund(&delegator, ExistentialDeposit::get());
+				// migrate 1/4th amount into each delegator
+				assert_ok!(DelegatedStaking::migrate_delegator(&200, &delegator, delegator_share));
+				assert_eq!(
+					Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator),
+					delegator_share
+				);
+				expected_proxy_delegated_amount -= delegator_share;
+				assert_eq!(
+					Balances::balance_on_hold(&HoldReason::Delegating.into(), &proxy_delegator),
+					expected_proxy_delegated_amount
+				);
+
+				// delegatee stake is unchanged.
+				assert_eq!(DelegatedStaking::stake(&200).unwrap(), init_stake);
+				assert_eq!(DelegatedStaking::delegated_balance(&200), 4000);
+				assert_eq!(DelegatedStaking::unbonded_balance(&200), 0);
+			}
+
+			assert!(!DelegatedStaking::is_migrating(&200));
+
+			// cannot use migrate delegator anymore
+			assert_noop!(DelegatedStaking::migrate_delegator(&200, &305, 1), Error::<T>::NotMigrating);
+		});
 	}
 }

From 6cf4a35433c9060c32cb32a2bdad4021da2296db Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 8 Dec 2023 05:19:30 +0100
Subject: [PATCH 057/202] fmt

---
 substrate/frame/delegated-staking/src/lib.rs   |  6 ++++--
 substrate/frame/delegated-staking/src/tests.rs | 12 ++++++------
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index d1647e1811687..d5ae4d546eaec 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -219,7 +219,10 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		ensure!(reward_destination != who, Error::<T>::InvalidRewardDestination);
 
 		// make sure they are not already a direct staker or they are migrating.
-		ensure!(T::CoreStaking::status(who).is_err() || <DelegateeMigration<T>>::contains_key(who), Error::<T>::AlreadyStaker);
+		ensure!(
+			T::CoreStaking::status(who).is_err() || <DelegateeMigration<T>>::contains_key(who),
+			Error::<T>::AlreadyStaker
+		);
 
 		// already checked delegatees exist
 		<Delegatees<T>>::insert(
@@ -398,7 +401,6 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		T::Currency::transfer(&proxy_delegator, new_delegator, value, Preservation::Expendable)
 			.map_err(|_| Error::<T>::BadState)?;
 
-
 		// add the above removed delegation to `new_delegator`.
 		<Delegators<T>>::insert(new_delegator, (delegatee, value));
 		// hold the funds again in the new delegator account.
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index e89b670f02bd4..51c949d05bd25 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -433,10 +433,7 @@ mod integration {
 				staked_amount,
 				RewardDestination::Account(201)
 			));
-			assert_ok!(Staking::nominate(
-				RuntimeOrigin::signed(200),
-				vec![GENESIS_VALIDATOR],
-			));
+			assert_ok!(Staking::nominate(RuntimeOrigin::signed(200), vec![GENESIS_VALIDATOR],));
 			let init_stake = Staking::stake(&200).unwrap();
 
 			// scenario: 200 is a pool account, and the stake comes from its 4 delegators (300..304)
@@ -465,7 +462,7 @@ mod integration {
 			assert_eq!(DelegatedStaking::unbonded_balance(&200), 0);
 
 			// now lets migrate the delegators
-			let delegator_share = staked_amount/4;
+			let delegator_share = staked_amount / 4;
 			for delegator in 300..304 {
 				assert_eq!(Balances::free_balance(delegator), 0);
 				// fund them with ED
@@ -491,7 +488,10 @@ mod integration {
 			assert!(!DelegatedStaking::is_migrating(&200));
 
 			// cannot use migrate delegator anymore
-			assert_noop!(DelegatedStaking::migrate_delegator(&200, &305, 1), Error::<T>::NotMigrating);
+			assert_noop!(
+				DelegatedStaking::migrate_delegator(&200, &305, 1),
+				Error::<T>::NotMigrating
+			);
 		});
 	}
 }

From b1249e0ea9fd481af0514ff5f1e2e8d6c3aed257 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 8 Dec 2023 22:11:32 +0100
Subject: [PATCH 058/202] todo

---
 substrate/frame/delegated-staking/src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index d5ae4d546eaec..fed1a1fde8796 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -282,8 +282,8 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		.map_err(|_| Error::<T>::BadState)?;
 
 		// delegate from new delegator to staker.
+		// todo(ank4n) : inline this fn and propagate payee to core staking..
 		Self::accept_delegations(new_delegatee, payee)?;
-		// todo(ank4n): for existing nominators, how this payee should be propagated to CoreStaking?
 
 		Self::delegate(proxy_delegator, new_delegatee, stake.total)?;
 		Self::update_bond(new_delegatee)

From 066cdec1a76d0bb320c56e1ab3140bd8873b4eea Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 14 Dec 2023 00:42:24 +0100
Subject: [PATCH 059/202] is_delegatee for non_tests

---
 substrate/frame/delegated-staking/src/lib.rs   | 12 +++---------
 substrate/primitives/staking/src/delegation.rs |  1 -
 2 files changed, 3 insertions(+), 10 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index fed1a1fde8796..7966101a59603 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -66,7 +66,7 @@ pub mod pallet {
 
 		/// Core staking implementation.
 		type CoreStaking: StakingInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId>
-			+ sp_staking::StakingHoldProvider<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
+			+ StakingHoldProvider<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
 	}
 
 	#[pallet::error]
@@ -184,11 +184,6 @@ impl<T: Config> DelegationRegister<T> {
 	pub fn unbonded_balance(&self) -> BalanceOf<T> {
 		self.total_delegated.saturating_sub(self.hold)
 	}
-
-	/// consumes self and returns Delegation Register with updated hold amount.
-	pub fn update_hold(self, amount: BalanceOf<T>) -> Self {
-		DelegationRegister { hold: amount, ..self }
-	}
 }
 
 impl<T: Config> DelegationInterface for Pallet<T> {
@@ -455,7 +450,7 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 	}
 }
 
-impl<T: Config> sp_staking::StakingHoldProvider for Pallet<T> {
+impl<T: Config> StakingHoldProvider for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
@@ -470,7 +465,7 @@ impl<T: Config> sp_staking::StakingHoldProvider for Pallet<T> {
 
 		ensure!(delegation_register.total_delegated >= amount, Error::<T>::NotEnoughFunds);
 		ensure!(delegation_register.pending_slash <= amount, Error::<T>::UnappliedSlash);
-		let updated_register = delegation_register.update_hold(amount);
+		let updated_register = DelegationRegister { hold: amount, ..delegation_register };
 		<Delegatees<T>>::insert(who, updated_register);
 
 		Ok(())
@@ -516,7 +511,6 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 		register.payee != reward_acc
 	}
 
-	#[cfg(feature = "std")]
 	fn is_delegatee(who: &Self::AccountId) -> bool {
 		Self::is_delegatee(who)
 	}
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 7109671cbdf28..8d36941d2d1bc 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -136,6 +136,5 @@ pub trait StakingDelegationSupport: StakingHoldProvider {
 		false
 	}
 
-	#[cfg(feature = "std")]
 	fn is_delegatee(_who: &Self::AccountId) -> bool;
 }

From 1e38b9bcc7b88436d6c53fff697c6b36217b3959 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 14 Dec 2023 01:29:16 +0100
Subject: [PATCH 060/202] staking as orchestrator and everything passes

---
 substrate/frame/staking/src/ledger.rs       | 13 +++----
 substrate/frame/staking/src/pallet/impls.rs | 40 +++++++++++++++++----
 substrate/frame/staking/src/pallet/mod.rs   |  9 +++--
 3 files changed, 45 insertions(+), 17 deletions(-)

diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs
index 962353b04e7fd..55617fe32548f 100644
--- a/substrate/frame/staking/src/ledger.rs
+++ b/substrate/frame/staking/src/ledger.rs
@@ -18,10 +18,10 @@
 //! A Ledger implementation for stakers.
 
 use frame_support::defensive;
-use sp_staking::{delegation::StakingDelegationSupport, StakingAccount, StakingHoldProvider};
+use sp_staking::{StakingAccount, StakingHoldProvider};
 use sp_std::prelude::*;
 
-use crate::{BalanceOf, Bonded, Config, Error, Ledger, Payee, RewardDestination, StakingLedger};
+use crate::{BalanceOf, Bonded, Config, Error, Ledger, Pallet, Payee, RewardDestination, StakingLedger};
 
 #[cfg(any(feature = "runtime-benchmarks", test))]
 use sp_runtime::traits::Zero;
@@ -141,8 +141,9 @@ impl<T: Config> StakingLedger<T> {
 			return Err(Error::<T>::NotStash)
 		}
 
-		T::DelegationSupport::update_hold(&self.stash, self.total)
+		Pallet::<T>::update_hold(&self.stash, self.total)
 			.map_err(|_| Error::<T>::BadState)?;
+
 		Ledger::<T>::insert(
 			&self.controller().ok_or_else(|| {
 				defensive!("update called on a ledger that is not bonded.");
@@ -162,7 +163,7 @@ impl<T: Config> StakingLedger<T> {
 			return Err(Error::<T>::AlreadyBonded);
 		}
 
-		if T::DelegationSupport::restrict_reward_destination(
+		if Pallet::<T>::restrict_reward_destination(
 			&self.stash,
 			payee.clone().from(&self.stash),
 		) {
@@ -180,7 +181,7 @@ impl<T: Config> StakingLedger<T> {
 			return Err(Error::<T>::NotStash);
 		}
 
-		if T::DelegationSupport::restrict_reward_destination(
+		if Pallet::<T>::restrict_reward_destination(
 			&self.stash,
 			payee.clone().from(&self.stash),
 		) {
@@ -197,7 +198,7 @@ impl<T: Config> StakingLedger<T> {
 		let controller = <Bonded<T>>::get(stash).ok_or(Error::<T>::NotStash)?;
 
 		<Ledger<T>>::get(&controller).ok_or(Error::<T>::NotController).map(|ledger| {
-			T::DelegationSupport::release_all(&ledger.stash);
+			Pallet::<T>::release_all(&ledger.stash);
 			Ledger::<T>::remove(controller);
 
 			<Bonded<T>>::remove(&stash);
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 40006537c2e3d..16c83446fa62d 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1095,6 +1095,25 @@ impl<T: Config> Pallet<T> {
 	) -> Exposure<T::AccountId, BalanceOf<T>> {
 		EraInfo::<T>::get_full_exposure(era, account)
 	}
+
+	pub(crate) fn stakeable_balance(who: &T::AccountId) -> BalanceOf<T> {
+		if T::DelegationSupport::is_delegatee(who) {
+			return T::DelegationSupport::stakeable_balance(who);
+		}
+
+		T::Currency::free_balance(who)
+	}
+
+	pub(crate) fn restrict_reward_destination(
+		who: &T::AccountId,
+		reward_destination: Option<T::AccountId>,
+	) -> bool {
+		if T::DelegationSupport::is_delegatee(who) {
+			return T::DelegationSupport::restrict_reward_destination(who, reward_destination);
+		}
+
+		false
+	}
 }
 
 impl<T: Config> Pallet<T> {
@@ -1839,11 +1858,19 @@ impl<T: Config> StakingHoldProvider for Pallet<T> {
 	type AccountId = T::AccountId;
 
 	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> sp_runtime::DispatchResult {
+		if T::DelegationSupport::is_delegatee(who) {
+			return T::DelegationSupport::update_hold(who, amount);
+		}
+
 		T::Currency::set_lock(crate::STAKING_ID, who, amount, WithdrawReasons::all());
 		Ok(())
 	}
 
 	fn release_all(who: &Self::AccountId) {
+		if T::DelegationSupport::is_delegatee(who) {
+			return T::DelegationSupport::release_all(who);
+		}
+
 		T::Currency::remove_lock(crate::STAKING_ID, who)
 	}
 }
@@ -1855,18 +1882,19 @@ impl<T: Config> StakingHoldProvider for NoDelegation<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
-	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> sp_runtime::DispatchResult {
-		Pallet::<T>::update_hold(who, amount)
+	fn update_hold(_who: &Self::AccountId, _amount: Self::Balance) -> sp_runtime::DispatchResult {
+		defensive_assert!(true, "delegation update_hold should not be called for NoDelegation");
+		Err(Error::<T>::NotEnoughFunds.into())
 	}
 
-	fn release_all(who: &Self::AccountId) {
-		Pallet::<T>::release_all(who)
+	fn release_all(_who: &Self::AccountId) {
+		defensive_assert!(true, "delegation release_all should not be called for NoDelegation");
 	}
 }
 
 impl<T: Config> StakingDelegationSupport for NoDelegation<T> {
-	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
-		T::Currency::free_balance(who)
+	fn stakeable_balance(_who: &Self::AccountId) -> Self::Balance {
+		BalanceOf::<T>::zero()
 	}
 	fn is_delegatee(_who: &Self::AccountId) -> bool {
 		false
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index fa154e6440e47..b558d5650d89c 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -105,8 +105,7 @@ pub mod pallet {
 			+ TypeInfo
 			+ MaxEncodedLen;
 
-		/// Something that provides stakeable balance of an account as well as a way to hold and
-		/// release this stake.
+		/// Something that provides delegation support to staking pallet.
 		type DelegationSupport: StakingDelegationSupport<
 			Balance = Self::CurrencyBalance,
 			AccountId = Self::AccountId,
@@ -712,7 +711,7 @@ pub mod pallet {
 					status
 				);
 				assert!(
-					T::DelegationSupport::stakeable_balance(stash) >= balance,
+					Pallet::<T>::stakeable_balance(stash) >= balance,
 					"Stash does not have enough balance to bond."
 				);
 				frame_support::assert_ok!(<Pallet<T>>::bond(
@@ -950,7 +949,7 @@ pub mod pallet {
 
 			frame_system::Pallet::<T>::inc_consumers(&stash).map_err(|_| Error::<T>::BadState)?;
 
-			let stash_balance = T::DelegationSupport::stakeable_balance(&stash);
+			let stash_balance = Self::stakeable_balance(&stash);
 			let value = value.min(stash_balance);
 			Self::deposit_event(Event::<T>::Bonded { stash: stash.clone(), amount: value });
 			let ledger = StakingLedger::<T>::new(stash.clone(), value);
@@ -986,7 +985,7 @@ pub mod pallet {
 
 			let mut ledger = Self::ledger(StakingAccount::Stash(stash.clone()))?;
 
-			let stash_balance = T::DelegationSupport::stakeable_balance(&stash);
+			let stash_balance = Self::stakeable_balance(&stash);
 			if let Some(extra) = stash_balance.checked_sub(&ledger.total) {
 				let extra = extra.min(max_additional);
 				ledger.total += extra;

From 22155c0c5d20f9493ef7f1d4488fbde6d88de4cc Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 14 Dec 2023 01:48:42 +0100
Subject: [PATCH 061/202] fix test and refactor delegated staking

---
 substrate/frame/delegated-staking/src/lib.rs  | 39 ++++---------
 substrate/frame/delegated-staking/src/mock.rs | 13 ++---
 .../frame/delegated-staking/src/tests.rs      | 56 ++++++++++---------
 substrate/frame/staking/src/ledger.rs         | 17 ++----
 4 files changed, 53 insertions(+), 72 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 7966101a59603..326519f8fccd9 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -455,9 +455,7 @@ impl<T: Config> StakingHoldProvider for Pallet<T> {
 	type AccountId = T::AccountId;
 
 	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
-		if !Self::is_delegatee(who) {
-			return T::CoreStaking::update_hold(who, amount);
-		}
+		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
 
 		// delegation register should exist since `who` is a delegatee.
 		let delegation_register =
@@ -482,10 +480,9 @@ impl<T: Config> StakingHoldProvider for Pallet<T> {
 }
 impl<T: Config> StakingDelegationSupport for Pallet<T> {
 	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
-		<Delegatees<T>>::get(who).map_or_else(
-			|| T::Currency::reducible_balance(who, Preservation::Expendable, Fortitude::Polite),
-			|delegatee| delegatee.delegated_balance(),
-		)
+		<Delegatees<T>>::get(who)
+			.map(|delegatee| delegatee.delegated_balance())
+			.unwrap_or_default()
 	}
 
 	fn restrict_reward_destination(
@@ -549,11 +546,8 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	fn stake(who: &Self::AccountId) -> Result<Stake<Self::Balance>, DispatchError> {
-		if Self::is_delegatee(who) {
-			return T::CoreStaking::stake(who);
-		}
-
-		Err(Error::<T>::NotSupported.into())
+		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
+		return T::CoreStaking::stake(who);
 	}
 
 	fn total_stake(who: &Self::AccountId) -> Result<Self::Balance, DispatchError> {
@@ -579,11 +573,8 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	fn fully_unbond(who: &Self::AccountId) -> DispatchResult {
-		if Self::is_delegatee(who) {
-			return T::CoreStaking::fully_unbond(who);
-		}
-
-		Err(Error::<T>::NotSupported.into())
+		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
+		return T::CoreStaking::fully_unbond(who);
 	}
 
 	fn bond(
@@ -602,19 +593,13 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	fn nominate(who: &Self::AccountId, validators: Vec<Self::AccountId>) -> DispatchResult {
-		if Self::is_delegatee(who) {
-			return T::CoreStaking::nominate(who, validators);
-		}
-
-		Err(Error::<T>::NotSupported.into())
+		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
+		return T::CoreStaking::nominate(who, validators);
 	}
 
 	fn chill(who: &Self::AccountId) -> DispatchResult {
-		if Self::is_delegatee(who) {
-			return T::CoreStaking::chill(who);
-		}
-
-		Err(Error::<T>::NotSupported.into())
+		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
+		return T::CoreStaking::chill(who);
 	}
 
 	fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult {
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index d77862c5157f8..83666cdd17471 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -228,9 +228,8 @@ impl ExtBuilder {
 }
 
 /// fund and return who.
-pub(crate) fn fund(who: &AccountId, amount: Balance) -> &AccountId {
+pub(crate) fn fund(who: &AccountId, amount: Balance) {
 	let _ = Balances::deposit_creating(who, amount);
-	who
 }
 
 /// Sets up delegation for passed delegators, returns total delegated amount.
@@ -244,17 +243,15 @@ pub(crate) fn setup_delegation_stake(
 	base_delegate_amount: Balance,
 	increment: Balance,
 ) -> Balance {
-	assert_ok!(DelegatedStaking::accept_delegations(fund(&delegatee, 100), &reward_acc));
+	fund(&delegatee, 100);
+	assert_ok!(DelegatedStaking::accept_delegations(&delegatee, &reward_acc));
 	let mut delegated_amount: Balance = 0;
 	for (index, delegator) in delegators.iter().enumerate() {
 		let amount_to_delegate = base_delegate_amount + increment * index as Balance;
 		delegated_amount += amount_to_delegate;
 
-		assert_ok!(DelegatedStaking::delegate(
-			fund(delegator, amount_to_delegate + ExistentialDeposit::get()),
-			&delegatee,
-			amount_to_delegate
-		));
+		fund(delegator, amount_to_delegate + ExistentialDeposit::get());
+		assert_ok!(DelegatedStaking::delegate(delegator, &delegatee, amount_to_delegate));
 		assert_ok!(DelegatedStaking::update_bond(&delegatee));
 	}
 
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 51c949d05bd25..b2f41e68a9c94 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -31,10 +31,12 @@ fn create_a_delegatee_with_first_delegator() {
 		let delegator: AccountId = 202;
 
 		// set intention to accept delegation.
-		assert_ok!(DelegatedStaking::accept_delegations(fund(&delegatee, 1000), &reward_account));
+		fund(&delegatee, 1000);
+		assert_ok!(DelegatedStaking::accept_delegations(&delegatee, &reward_account));
 
 		// delegate to this account
-		assert_ok!(DelegatedStaking::delegate(fund(&delegator, 1000), &delegatee, 100));
+		fund(&delegator, 1000);
+		assert_ok!(DelegatedStaking::delegate(&delegator, &delegatee, 100));
 
 		// verify
 		assert!(DelegatedStaking::is_delegatee(&delegatee));
@@ -76,20 +78,18 @@ fn create_multiple_delegators() {
 		let delegatee: AccountId = 200;
 		let reward_account: AccountId = 201;
 
-		// before becoming a delegatee, stakeable balance is only direct balance.
-		assert!(!DelegatedStaking::is_delegatee(fund(&delegatee, 1000)));
-		assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 1000);
+		// stakeable balance is 0 for non delegatee
+		fund(&delegatee, 1000);
+		assert!(!DelegatedStaking::is_delegatee(&delegatee));
+		assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 0);
 
 		// set intention to accept delegation.
 		assert_ok!(DelegatedStaking::accept_delegations(&delegatee, &reward_account));
 
 		// create 100 delegators
 		for i in 202..302 {
-			assert_ok!(DelegatedStaking::delegate(
-				fund(&i, 100 + ExistentialDeposit::get()),
-				&delegatee,
-				100
-			));
+			fund(&i, 100 + ExistentialDeposit::get());
+			assert_ok!(DelegatedStaking::delegate(&i, &delegatee, 100));
 			// Balance of 100 held on delegator account for delegating to the delegatee.
 			assert_eq!(Balances::balance_on_hold(&HoldReason::Delegating.into(), &i), 100);
 		}
@@ -106,19 +106,17 @@ fn delegate_restrictions() {
 	ExtBuilder::default().build_and_execute(|| {
 		let delegatee_one = 200;
 		let delegator_one = 210;
-		assert_ok!(DelegatedStaking::accept_delegations(
-			fund(&delegatee_one, 100),
-			&(delegatee_one + 1)
-		));
-		assert_ok!(DelegatedStaking::delegate(fund(&delegator_one, 200), &delegatee_one, 100));
+		fund(&delegatee_one, 100);
+		assert_ok!(DelegatedStaking::accept_delegations(&delegatee_one, &(delegatee_one + 1)));
+		fund(&delegator_one, 200);
+		assert_ok!(DelegatedStaking::delegate(&delegator_one, &delegatee_one, 100));
 
 		let delegatee_two = 300;
 		let delegator_two = 310;
-		assert_ok!(DelegatedStaking::accept_delegations(
-			fund(&delegatee_two, 100),
-			&(delegatee_two + 1)
-		));
-		assert_ok!(DelegatedStaking::delegate(fund(&delegator_two, 200), &delegatee_two, 100));
+		fund(&delegatee_two, 100);
+		assert_ok!(DelegatedStaking::accept_delegations(&delegatee_two, &(delegatee_two + 1)));
+		fund(&delegator_two, 200);
+		assert_ok!(DelegatedStaking::delegate(&delegator_two, &delegatee_two, 100));
 
 		// delegatee one tries to delegate to delegatee 2
 		assert_noop!(
@@ -164,13 +162,15 @@ mod integration {
 			assert_eq!(Staking::status(&delegatee), Err(StakingError::<T>::NotStash.into()));
 
 			// set intention to become a delegatee
-			assert_ok!(DelegatedStaking::accept_delegations(fund(&delegatee, 100), &reward_acc));
+			fund(&delegatee, 100);
+			assert_ok!(DelegatedStaking::accept_delegations(&delegatee, &reward_acc));
 			assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 0);
 
 			let mut delegated_balance: Balance = 0;
 			// set some delegations
 			for delegator in 200..250 {
-				assert_ok!(DelegatedStaking::delegate(fund(&delegator, 200), &delegatee, 100));
+				fund(&delegator, 200);
+				assert_ok!(DelegatedStaking::delegate(&delegator, &delegatee, 100));
 				delegated_balance += 100;
 				assert_eq!(
 					Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator),
@@ -299,7 +299,8 @@ mod integration {
 			);
 
 			// add new delegation that is not staked
-			assert_ok!(DelegatedStaking::delegate(fund(&300, 1000), &delegatee, 100));
+			fund(&300, 1000);
+			assert_ok!(DelegatedStaking::delegate(&300, &delegatee, 100));
 
 			// verify unbonded balance
 			assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 100);
@@ -326,7 +327,8 @@ mod integration {
 			// different reward account works
 			assert_ok!(DelegatedStaking::accept_delegations(&200, &201));
 			// add some delegations to it
-			assert_ok!(DelegatedStaking::delegate(fund(&300, 1000), &200, 100));
+			fund(&300, 1000);
+			assert_ok!(DelegatedStaking::delegate(&300, &200, 100));
 
 			// if delegatee calls Staking pallet directly with a different reward destination, it
 			// fails.
@@ -392,7 +394,8 @@ mod integration {
 			assert_ok!(DelegatedStaking::accept_delegations(&200, &201));
 
 			// delegation works
-			assert_ok!(DelegatedStaking::delegate(fund(&300, 1000), &200, 100));
+			fund(&300, 1000);
+			assert_ok!(DelegatedStaking::delegate(&300, &200, 100));
 
 			// delegatee blocks delegation
 			assert_ok!(DelegatedStaking::block_delegations(&200));
@@ -445,7 +448,8 @@ mod integration {
 			// to migrate, nominator needs to set an account as a proxy delegator where staked funds
 			// will be moved and delegated back to this old nominator account. This should be funded
 			// with at least ED.
-			let proxy_delegator = fund(&202, ExistentialDeposit::get());
+			let proxy_delegator = 202;
+			fund(&proxy_delegator, ExistentialDeposit::get());
 
 			assert_ok!(DelegatedStaking::migrate_accept_delegations(&200, &proxy_delegator, &201));
 			assert!(DelegatedStaking::is_migrating(&200));
diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs
index 55617fe32548f..a6750a7c4c771 100644
--- a/substrate/frame/staking/src/ledger.rs
+++ b/substrate/frame/staking/src/ledger.rs
@@ -21,7 +21,9 @@ use frame_support::defensive;
 use sp_staking::{StakingAccount, StakingHoldProvider};
 use sp_std::prelude::*;
 
-use crate::{BalanceOf, Bonded, Config, Error, Ledger, Pallet, Payee, RewardDestination, StakingLedger};
+use crate::{
+	BalanceOf, Bonded, Config, Error, Ledger, Pallet, Payee, RewardDestination, StakingLedger,
+};
 
 #[cfg(any(feature = "runtime-benchmarks", test))]
 use sp_runtime::traits::Zero;
@@ -141,8 +143,7 @@ impl<T: Config> StakingLedger<T> {
 			return Err(Error::<T>::NotStash)
 		}
 
-		Pallet::<T>::update_hold(&self.stash, self.total)
-			.map_err(|_| Error::<T>::BadState)?;
+		Pallet::<T>::update_hold(&self.stash, self.total).map_err(|_| Error::<T>::BadState)?;
 
 		Ledger::<T>::insert(
 			&self.controller().ok_or_else(|| {
@@ -163,10 +164,7 @@ impl<T: Config> StakingLedger<T> {
 			return Err(Error::<T>::AlreadyBonded);
 		}
 
-		if Pallet::<T>::restrict_reward_destination(
-			&self.stash,
-			payee.clone().from(&self.stash),
-		) {
+		if Pallet::<T>::restrict_reward_destination(&self.stash, payee.clone().from(&self.stash)) {
 			return Err(Error::<T>::RewardDestinationRestricted);
 		}
 
@@ -181,10 +179,7 @@ impl<T: Config> StakingLedger<T> {
 			return Err(Error::<T>::NotStash);
 		}
 
-		if Pallet::<T>::restrict_reward_destination(
-			&self.stash,
-			payee.clone().from(&self.stash),
-		) {
+		if Pallet::<T>::restrict_reward_destination(&self.stash, payee.clone().from(&self.stash)) {
 			return Err(Error::<T>::RewardDestinationRestricted);
 		}
 

From b16ec42e4774a5d123d228b7215fe996280392b4 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 14 Dec 2023 02:31:11 +0100
Subject: [PATCH 062/202] report slash

---
 substrate/frame/delegated-staking/src/lib.rs   |  9 +++++++++
 substrate/frame/staking/src/pallet/impls.rs    |  8 ++++++--
 substrate/frame/staking/src/slashing.rs        | 12 ++++++++++--
 substrate/primitives/staking/src/delegation.rs |  6 +++++-
 4 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 326519f8fccd9..b668ee7732d9f 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -511,6 +511,15 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 	fn is_delegatee(who: &Self::AccountId) -> bool {
 		Self::is_delegatee(who)
 	}
+
+	fn report_slash(who: &Self::AccountId, slash: Self::Balance) {
+		<Delegatees<T>>::mutate(who, |maybe_register| match maybe_register {
+			Some(register) => register.pending_slash.saturating_accrue(slash),
+			None => {
+				defensive!("should not be called on non-delegatee");
+			},
+		});
+	}
 }
 
 /// StakingInterface implementation with delegation support.
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 16c83446fa62d..637eb125fcd6a 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1883,12 +1883,12 @@ impl<T: Config> StakingHoldProvider for NoDelegation<T> {
 	type AccountId = T::AccountId;
 
 	fn update_hold(_who: &Self::AccountId, _amount: Self::Balance) -> sp_runtime::DispatchResult {
-		defensive_assert!(true, "delegation update_hold should not be called for NoDelegation");
+		defensive!("delegation update_hold should not be have been called for NoDelegation");
 		Err(Error::<T>::NotEnoughFunds.into())
 	}
 
 	fn release_all(_who: &Self::AccountId) {
-		defensive_assert!(true, "delegation release_all should not be called for NoDelegation");
+		defensive!("delegation release_all should not have been called for NoDelegation");
 	}
 }
 
@@ -1899,6 +1899,10 @@ impl<T: Config> StakingDelegationSupport for NoDelegation<T> {
 	fn is_delegatee(_who: &Self::AccountId) -> bool {
 		false
 	}
+
+	fn report_slash(_who: &Self::AccountId, _slash: Self::Balance) {
+		defensive!("delegation report_slash should not be have been called for NoDelegation");
+	}
 }
 
 #[cfg(any(test, feature = "try-runtime"))]
diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs
index 709fd1441ec3a..2eeee0e8a3d66 100644
--- a/substrate/frame/staking/src/slashing.rs
+++ b/substrate/frame/staking/src/slashing.rs
@@ -64,7 +64,7 @@ use sp_runtime::{
 	traits::{Saturating, Zero},
 	DispatchResult, RuntimeDebug,
 };
-use sp_staking::{offence::DisableStrategy, EraIndex};
+use sp_staking::{delegation::StakingDelegationSupport, offence::DisableStrategy, EraIndex};
 use sp_std::vec::Vec;
 
 /// The proportion of the slashing reward to be paid out on the first slashing detection.
@@ -608,9 +608,17 @@ pub fn do_slash<T: Config>(
 			Err(_) => return, // nothing to do.
 		};
 
+	let lazy_slash = T::DelegationSupport::is_delegatee(stash);
 	let value = ledger.slash(value, T::Currency::minimum_balance(), slash_era);
 
-	if !value.is_zero() {
+	if value.is_zero() {
+		// nothing to do
+		return;
+	}
+	if lazy_slash {
+		// If delegated staking, report slash and move on.
+		T::DelegationSupport::report_slash(stash, value);
+	} else {
 		let (imbalance, missing) = T::Currency::slash(stash, value);
 		slashed_imbalance.subsume(imbalance);
 
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 8d36941d2d1bc..75503ca21d039 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -136,5 +136,9 @@ pub trait StakingDelegationSupport: StakingHoldProvider {
 		false
 	}
 
-	fn is_delegatee(_who: &Self::AccountId) -> bool;
+	/// Returns true if `who` accepts delegations for stake.
+	fn is_delegatee(who: &Self::AccountId) -> bool;
+
+	/// Reports an ongoing slash to the delegatee account that would be applied lazily.
+	fn report_slash(who: &Self::AccountId, slash: Self::Balance);
 }

From 360d5168a18e3102db07ee92a1d46877433a5be3 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 14 Dec 2023 04:52:00 +0100
Subject: [PATCH 063/202] partial implement onslash, need to add more tests and
 integrations

---
 substrate/frame/delegated-staking/src/lib.rs  | 55 +++++++++++++++----
 substrate/frame/delegated-staking/src/mock.rs |  1 +
 substrate/frame/staking/src/pallet/impls.rs   |  4 ++
 substrate/primitives/staking/src/lib.rs       |  8 +--
 4 files changed, 54 insertions(+), 14 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index b668ee7732d9f..66bf42c2f7fdc 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -30,14 +30,17 @@ mod benchmarking;
 use frame_support::{
 	pallet_prelude::*,
 	traits::{
-		fungible::{hold::Mutate as FunHoldMutate, Inspect as FunInspect, Mutate as FunMutate},
-		tokens::{Fortitude, Precision, Preservation},
-		DefensiveOption,
+		fungible::{
+			hold::{Balanced as FunHoldBalanced, Mutate as FunHoldMutate},
+			Balanced, Inspect as FunInspect, Mutate as FunMutate,
+		},
+		tokens::{Fortitude, Precision, Preservation, fungible::Credit},
+		DefensiveOption, Imbalance, OnUnbalanced,
 	},
 	transactional,
 };
 use pallet::*;
-use sp_runtime::{traits::Zero, DispatchResult, RuntimeDebug, Saturating};
+use sp_runtime::{traits::Zero, DispatchResult, Perbill, RuntimeDebug, Saturating};
 use sp_staking::{
 	delegation::{DelegationInterface, StakingDelegationSupport},
 	EraIndex, Stake, StakerStatus, StakingHoldProvider, StakingInterface,
@@ -60,7 +63,11 @@ pub mod pallet {
 		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
 
 		type Currency: FunHoldMutate<Self::AccountId, Reason = Self::RuntimeHoldReason>
-			+ FunMutate<Self::AccountId>;
+			+ FunMutate<Self::AccountId>
+			+ FunHoldBalanced<Self::AccountId>;
+
+		/// Handler for the unbalanced reduction when slashing a delegator.
+		type OnSlash: OnUnbalanced<Credit<Self::AccountId, Self::Currency>>;
 		/// Overarching hold reason.
 		type RuntimeHoldReason: From<HoldReason>;
 
@@ -340,12 +347,36 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 	}
 
 	fn apply_slash(
-		_delegatee: &Self::AccountId,
-		_delegator: &Self::AccountId,
-		_value: Self::Balance,
-		_reporter: Option<Self::AccountId>,
+		delegatee: &Self::AccountId,
+		delegator: &Self::AccountId,
+		value: Self::Balance,
+		maybe_reporter: Option<Self::AccountId>,
 	) -> DispatchResult {
-		todo!()
+		let mut delegation_register =
+			<Delegatees<T>>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
+		let (assigned_delegatee, delegate_balance) =
+			<Delegators<T>>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
+
+		ensure!(&assigned_delegatee == delegatee, Error::<T>::NotDelegatee);
+		ensure!(delegate_balance >= value, Error::<T>::NotEnoughFunds);
+
+		let (mut credit, _missing) =
+			T::Currency::slash(&HoldReason::Delegating.into(), &delegator, value);
+		let actual_slash = credit.peek();
+		// remove the slashed amount
+		delegation_register.pending_slash.saturating_sub(actual_slash);
+
+		if let Some(reporter) = maybe_reporter {
+			let reward_payout: BalanceOf<T> =
+				T::CoreStaking::slash_reward_fraction() * actual_slash;
+			let (reporter_reward, rest) = credit.split(reward_payout);
+			credit = rest;
+			// fixme(ank4n): handle error
+			let _ = T::Currency::resolve(&reporter, reporter_reward);
+		}
+
+		T::OnSlash::on_unbalanced(credit);
+		Ok(())
 	}
 
 	/// Move funds from proxy delegator to actual delegator.
@@ -678,6 +709,10 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		T::CoreStaking::nominations(who)
 	}
 
+	fn slash_reward_fraction() -> Perbill {
+		T::CoreStaking::slash_reward_fraction()
+	}
+
 	#[cfg(feature = "runtime-benchmarks")]
 	fn max_exposure_page_size() -> sp_staking::Page {
 		T::CoreStaking::max_exposure_page_size()
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 83666cdd17471..31c2f128bd6a9 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -137,6 +137,7 @@ impl pallet_staking::Config for Runtime {
 impl delegated_staking::Config for Runtime {
 	type RuntimeEvent = RuntimeEvent;
 	type Currency = Balances;
+	type OnSlash = ();
 	type RuntimeHoldReason = RuntimeHoldReason;
 	type CoreStaking = Staking;
 }
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 637eb125fcd6a..0b2fb24b34e66 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1851,6 +1851,10 @@ impl<T: Config> StakingInterface for Pallet<T> {
 			T::MaxExposurePageSize::get()
 		}
 	}
+
+	fn slash_reward_fraction() -> Perbill {
+		SlashRewardFraction::<T>::get()
+	}
 }
 
 impl<T: Config> StakingHoldProvider for Pallet<T> {
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index c32145f8c563b..63b2784906cd8 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -23,10 +23,7 @@
 use crate::currency_to_vote::CurrencyToVote;
 use codec::{Decode, Encode, FullCodec, HasCompact, MaxEncodedLen};
 use scale_info::TypeInfo;
-use sp_runtime::{
-	traits::{AtLeast32BitUnsigned, Zero},
-	DispatchError, DispatchResult, RuntimeDebug, Saturating,
-};
+use sp_runtime::{traits::{AtLeast32BitUnsigned, Zero}, DispatchError, DispatchResult, RuntimeDebug, Saturating, Perbill};
 use sp_std::{collections::btree_map::BTreeMap, ops::Sub, vec, vec::Vec};
 
 pub mod offence;
@@ -285,6 +282,9 @@ pub trait StakingInterface {
 		}
 	}
 
+	/// Returns the fraction of the slash to be rewarded to reporter.
+	fn slash_reward_fraction() -> Perbill;
+
 	#[cfg(feature = "runtime-benchmarks")]
 	fn max_exposure_page_size() -> Page;
 

From 6cfa2525339b8dac208c8168a3a85a3a55f68996 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 14 Dec 2023 05:11:35 +0100
Subject: [PATCH 064/202] doc

---
 substrate/frame/delegated-staking/src/lib.rs | 30 +++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 66bf42c2f7fdc..1e3fe25f1cb13 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -18,6 +18,34 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 #![deny(rustdoc::broken_intra_doc_links)]
 
+//! An implementation of a delegation system for staking that can be utilised using
+//! [`DelegationInterface`]. In future, if exposed via extrinsic, these primitives could also be
+//! used by off-chain entities, smart contracts or by other parachains via xcm.
+//!
+//! Delegatee: Someone who accepts delegations. An account can set their intention to accept
+//! delegations by calling [`DelegationInterface::accept_delegations`]. This account cannot have
+//! another role in the staking system and once set as delegatee, can only stake with their
+//! delegated balance, i.e. cannot use their own free balance to stake. They can also block new
+//! delegations by calling [`DelegationInterface::block_delegations`] or remove themselves from
+//! being a delegatee by calling [`DelegationInterface::kill_delegatee`] once all delegations to it
+//! are removed.
+//!
+//! Delegatee is also responsible for managing reward distribution and slashes of delegators.
+//!
+//! Delegator: Someone who delegates their funds to a delegatee. A delegator can delegate their
+//! funds to one and only one delegatee. They also can not be a nominator or validator.
+//!
+//! Reward payouts destination: Delegatees are restricted to have a reward payout destination that
+//! is different from the delegatee account. This means, it cannot be auto-compounded and needs to
+//! be staked again as a delegation. However, the reward payouts can then be distributed to
+//! delegators by the delegatee.
+//!
+//! Any slashes to a delegatee are recorded in [`DelegationRegister`] of the Delegatee as a pending
+//! slash. Since the actual amount is held in the delegator's account, this pallet does not know how
+//! to apply slash. It is Delegatee's responsibility to apply slashes for each delegator, one at a
+//! time. Staking pallet ensures the pending slash never exceeds staked amount and would freeze
+//! further withdraws until pending slashes are applied.
+
 #[cfg(test)]
 mod mock;
 
@@ -34,7 +62,7 @@ use frame_support::{
 			hold::{Balanced as FunHoldBalanced, Mutate as FunHoldMutate},
 			Balanced, Inspect as FunInspect, Mutate as FunMutate,
 		},
-		tokens::{Fortitude, Precision, Preservation, fungible::Credit},
+		tokens::{fungible::Credit, Fortitude, Precision, Preservation},
 		DefensiveOption, Imbalance, OnUnbalanced,
 	},
 	transactional,

From 468f569bf1ab9427b1b745e52efe9e00d80841d9 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 14 Dec 2023 05:11:52 +0100
Subject: [PATCH 065/202] fmt

---
 substrate/primitives/staking/src/lib.rs | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 63b2784906cd8..25266877b45e1 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -23,7 +23,10 @@
 use crate::currency_to_vote::CurrencyToVote;
 use codec::{Decode, Encode, FullCodec, HasCompact, MaxEncodedLen};
 use scale_info::TypeInfo;
-use sp_runtime::{traits::{AtLeast32BitUnsigned, Zero}, DispatchError, DispatchResult, RuntimeDebug, Saturating, Perbill};
+use sp_runtime::{
+	traits::{AtLeast32BitUnsigned, Zero},
+	DispatchError, DispatchResult, Perbill, RuntimeDebug, Saturating,
+};
 use sp_std::{collections::btree_map::BTreeMap, ops::Sub, vec, vec::Vec};
 
 pub mod offence;

From a151a0135a315effd245fed8d5e2c3f831a9c736 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 14 Dec 2023 05:20:22 +0100
Subject: [PATCH 066/202] update register

---
 substrate/frame/delegated-staking/src/lib.rs  | 3 ++-
 substrate/frame/delegated-staking/src/mock.rs | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 1e3fe25f1cb13..9ed9f6220a852 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -392,7 +392,8 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 			T::Currency::slash(&HoldReason::Delegating.into(), &delegator, value);
 		let actual_slash = credit.peek();
 		// remove the slashed amount
-		delegation_register.pending_slash.saturating_sub(actual_slash);
+		delegation_register.pending_slash.saturating_reduce(actual_slash);
+		<Delegatees<T>>::insert(delegatee, delegation_register);
 
 		if let Some(reporter) = maybe_reporter {
 			let reward_payout: BalanceOf<T> =
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 31c2f128bd6a9..6c57adc6afefb 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -129,6 +129,7 @@ impl pallet_staking::Config for Runtime {
 	type TargetList = pallet_staking::UseValidatorsMap<Self>;
 	type NominationsQuota = pallet_staking::FixedNominationsQuota<16>;
 	type MaxUnlockingChunks = ConstU32<32>;
+	type MaxControllersInDeprecationBatch = ConstU32<100>;
 	type EventListeners = ();
 	type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
 	type WeightInfo = ();

From 366809738bc70d59c5bcfab26e677ddba4828e10 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 14 Dec 2023 07:54:48 +0100
Subject: [PATCH 067/202] add dependencies to test staking

---
 Cargo.lock                                     |  2 ++
 substrate/frame/delegated-staking/src/lib.rs   |  2 ++
 .../nomination-pools/benchmarking/Cargo.toml   |  3 +++
 substrate/frame/nomination-pools/src/lib.rs    |  3 ++-
 .../nomination-pools/test-staking/Cargo.toml   |  1 +
 .../nomination-pools/test-staking/src/mock.rs  | 18 ++++++++++++++----
 6 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index b6356a491be68..eae94190560e1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -10300,6 +10300,7 @@ dependencies = [
  "frame-system",
  "pallet-bags-list",
  "pallet-balances",
+ "pallet-delegated-staking",
  "pallet-nomination-pools",
  "pallet-staking",
  "pallet-staking-reward-curve",
@@ -10349,6 +10350,7 @@ dependencies = [
  "log",
  "pallet-bags-list",
  "pallet-balances",
+ "pallet-delegated-staking",
  "pallet-nomination-pools",
  "pallet-staking",
  "pallet-staking-reward-curve",
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 9ed9f6220a852..b58058566c47e 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -52,6 +52,8 @@ mod mock;
 #[cfg(test)]
 mod tests;
 
+pub use pallet::*;
+
 #[cfg(feature = "runtime-benchmarks")]
 mod benchmarking;
 
diff --git a/substrate/frame/nomination-pools/benchmarking/Cargo.toml b/substrate/frame/nomination-pools/benchmarking/Cargo.toml
index 8a4ee07dd7449..387c65600bed6 100644
--- a/substrate/frame/nomination-pools/benchmarking/Cargo.toml
+++ b/substrate/frame/nomination-pools/benchmarking/Cargo.toml
@@ -27,6 +27,7 @@ frame-support = { path = "../../support", default-features = false }
 frame-system = { path = "../../system", default-features = false }
 pallet-bags-list = { path = "../../bags-list", default-features = false }
 pallet-staking = { path = "../../staking", default-features = false }
+pallet-delegated-staking = { path = "../../delegated-staking", default-features = false }
 pallet-nomination-pools = { path = "..", default-features = false }
 
 # Substrate Primitives
@@ -55,6 +56,7 @@ std = [
 	"pallet-balances/std",
 	"pallet-nomination-pools/std",
 	"pallet-staking/std",
+	"pallet-delegated-staking/std",
 	"pallet-timestamp/std",
 	"scale-info/std",
 	"sp-core/std",
@@ -74,6 +76,7 @@ runtime-benchmarks = [
 	"pallet-balances/runtime-benchmarks",
 	"pallet-nomination-pools/runtime-benchmarks",
 	"pallet-staking/runtime-benchmarks",
+	"pallet-delegated-staking/runtime-benchmarks",
 	"pallet-timestamp/runtime-benchmarks",
 	"sp-runtime/runtime-benchmarks",
 	"sp-staking/runtime-benchmarks",
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index c3fd6a98e8846..981ea8991d30e 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -1591,6 +1591,7 @@ pub mod pallet {
 	use frame_support::traits::StorageVersion;
 	use frame_system::{ensure_signed, pallet_prelude::*};
 	use sp_runtime::Perbill;
+	use sp_staking::delegation::DelegationInterface;
 
 	/// The current storage version.
 	const STORAGE_VERSION: StorageVersion = StorageVersion::new(8);
@@ -1658,7 +1659,7 @@ pub mod pallet {
 		type U256ToBalance: Convert<U256, BalanceOf<Self>>;
 
 		/// The interface for nominating.
-		type Staking: StakingInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
+		type Staking: StakingInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId> + DelegationInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
 
 		/// The amount of eras a `SubPools::with_era` pool can exist before it gets merged into the
 		/// `SubPools::no_era` pool. In other words, this is the amount of eras a member will be
diff --git a/substrate/frame/nomination-pools/test-staking/Cargo.toml b/substrate/frame/nomination-pools/test-staking/Cargo.toml
index 845535ae04f56..0302fe969c379 100644
--- a/substrate/frame/nomination-pools/test-staking/Cargo.toml
+++ b/substrate/frame/nomination-pools/test-staking/Cargo.toml
@@ -32,6 +32,7 @@ frame-election-provider-support = { path = "../../election-provider-support" }
 pallet-timestamp = { path = "../../timestamp" }
 pallet-balances = { path = "../../balances" }
 pallet-staking = { path = "../../staking" }
+pallet-delegated-staking = { path = "../../delegated-staking" }
 pallet-bags-list = { path = "../../bags-list" }
 pallet-staking-reward-curve = { path = "../../staking/reward-curve" }
 pallet-nomination-pools = { path = ".." }
diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs
index 491cd61916198..f5a8fa83ae4ef 100644
--- a/substrate/frame/nomination-pools/test-staking/src/mock.rs
+++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs
@@ -88,9 +88,9 @@ impl pallet_balances::Config for Runtime {
 	type WeightInfo = ();
 	type FreezeIdentifier = RuntimeFreezeReason;
 	type MaxFreezes = ConstU32<1>;
-	type RuntimeHoldReason = ();
-	type RuntimeFreezeReason = ();
-	type MaxHolds = ();
+	type RuntimeHoldReason = RuntimeHoldReason;
+	type RuntimeFreezeReason = RuntimeFreezeReason;
+	type MaxHolds = ConstU32<1>;
 }
 
 pallet_staking_reward_curve::build! {
@@ -112,6 +112,7 @@ parameter_types! {
 impl pallet_staking::Config for Runtime {
 	type Currency = Balances;
 	type CurrencyBalance = Balance;
+	type DelegationSupport = DelegatedStaking;
 	type UnixTime = pallet_timestamp::Pallet<Self>;
 	type CurrencyToVote = ();
 	type RewardRemainder = ();
@@ -168,6 +169,14 @@ impl Convert<sp_core::U256, Balance> for U256ToBalance {
 	}
 }
 
+impl pallet_delegated_staking::Config for Runtime {
+	type RuntimeEvent = RuntimeEvent;
+	type Currency = Balances;
+	type OnSlash = ();
+	type RuntimeHoldReason = RuntimeHoldReason;
+	type CoreStaking = Staking;
+}
+
 parameter_types! {
 	pub const PostUnbondingPoolsWindow: u32 = 10;
 	pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls");
@@ -181,7 +190,7 @@ impl pallet_nomination_pools::Config for Runtime {
 	type RewardCounter = FixedU128;
 	type BalanceToU256 = BalanceToU256;
 	type U256ToBalance = U256ToBalance;
-	type Staking = Staking;
+	type Staking = DelegatedStaking;
 	type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow;
 	type MaxMetadataLen = ConstU32<256>;
 	type MaxUnbonding = ConstU32<8>;
@@ -199,6 +208,7 @@ frame_support::construct_runtime!(
 		Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
 		Staking: pallet_staking::{Pallet, Call, Config<T>, Storage, Event<T>},
 		VoterList: pallet_bags_list::<Instance1>::{Pallet, Call, Storage, Event<T>},
+		DelegatedStaking: pallet_delegated_staking::{Pallet, Storage, Event<T>, HoldReason},
 		Pools: pallet_nomination_pools::{Pallet, Call, Storage, Event<T>, FreezeReason},
 	}
 );

From 27e59402f60c312405a1815095b90a2d327e4f39 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 15 Dec 2023 00:20:39 +0100
Subject: [PATCH 068/202] refactor from feedbacks

---
 substrate/frame/delegated-staking/src/lib.rs   | 18 +++++++++---------
 substrate/frame/delegated-staking/src/mock.rs  |  2 +-
 substrate/frame/delegated-staking/src/tests.rs |  2 +-
 substrate/frame/staking/src/pallet/impls.rs    |  1 -
 substrate/frame/staking/src/slashing.rs        |  3 ++-
 substrate/primitives/staking/src/delegation.rs |  4 ++--
 substrate/primitives/staking/src/lib.rs        |  1 +
 7 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index b58058566c47e..e5edbd96e3189 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -40,7 +40,7 @@
 //! be staked again as a delegation. However, the reward payouts can then be distributed to
 //! delegators by the delegatee.
 //!
-//! Any slashes to a delegatee are recorded in [`DelegationRegister`] of the Delegatee as a pending
+//! Any slashes to a delegatee are recorded in [`DelegationLedger`] of the Delegatee as a pending
 //! slash. Since the actual amount is held in the delegator's account, this pallet does not know how
 //! to apply slash. It is Delegatee's responsibility to apply slashes for each delegator, one at a
 //! time. Staking pallet ensures the pending slash never exceeds staked amount and would freeze
@@ -176,7 +176,7 @@ pub mod pallet {
 	/// Map of Delegatee to their Ledger.
 	#[pallet::storage]
 	pub(crate) type Delegatees<T: Config> =
-		CountedStorageMap<_, Twox64Concat, T::AccountId, DelegationRegister<T>, OptionQuery>;
+		CountedStorageMap<_, Twox64Concat, T::AccountId, DelegationLedger<T>, OptionQuery>;
 
 	/// Map of Delegatee and its proxy delegator account while its actual delegators are migrating.
 	///
@@ -194,13 +194,14 @@ pub mod pallet {
 /// among other things.
 #[derive(Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
 #[scale_info(skip_type_params(T))]
-pub struct DelegationRegister<T: Config> {
+pub struct DelegationLedger<T: Config> {
 	/// Where the reward should be paid out.
 	pub payee: T::AccountId,
 	/// Sum of all delegated funds to this delegatee.
 	#[codec(compact)]
 	pub total_delegated: BalanceOf<T>,
 	/// Amount that is bonded and held.
+	// FIXME(ank4n) (can we remove it)
 	#[codec(compact)]
 	pub hold: BalanceOf<T>,
 	/// Slashes that are not yet applied.
@@ -210,7 +211,7 @@ pub struct DelegationRegister<T: Config> {
 	pub blocked: bool,
 }
 
-impl<T: Config> DelegationRegister<T> {
+impl<T: Config> DelegationLedger<T> {
 	/// balance that can be staked.
 	pub fn delegated_balance(&self) -> BalanceOf<T> {
 		// do not allow to stake more than unapplied slash
@@ -259,7 +260,7 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		// already checked delegatees exist
 		<Delegatees<T>>::insert(
 			who,
-			DelegationRegister {
+			DelegationLedger {
 				payee: reward_destination.clone(),
 				total_delegated: Zero::zero(),
 				hold: Zero::zero(),
@@ -318,7 +319,7 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		Self::accept_delegations(new_delegatee, payee)?;
 
 		Self::delegate(proxy_delegator, new_delegatee, stake.total)?;
-		Self::update_bond(new_delegatee)
+		Self::bond_all(new_delegatee)
 	}
 
 	fn block_delegations(delegatee: &Self::AccountId) -> DispatchResult {
@@ -341,7 +342,7 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		todo!()
 	}
 
-	fn update_bond(who: &Self::AccountId) -> DispatchResult {
+	fn bond_all(who: &Self::AccountId) -> DispatchResult {
 		let delegatee = <Delegatees<T>>::get(who).ok_or(Error::<T>::NotDelegatee)?;
 		let amount_to_bond = delegatee.unbonded_balance();
 
@@ -411,7 +412,6 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 	}
 
 	/// Move funds from proxy delegator to actual delegator.
-	// TODO: Keep track of proxy delegator and only allow movement from proxy -> new delegator
 	#[transactional]
 	fn migrate_delegator(
 		delegatee: &Self::AccountId,
@@ -525,7 +525,7 @@ impl<T: Config> StakingHoldProvider for Pallet<T> {
 
 		ensure!(delegation_register.total_delegated >= amount, Error::<T>::NotEnoughFunds);
 		ensure!(delegation_register.pending_slash <= amount, Error::<T>::UnappliedSlash);
-		let updated_register = DelegationRegister { hold: amount, ..delegation_register };
+		let updated_register = DelegationLedger { hold: amount, ..delegation_register };
 		<Delegatees<T>>::insert(who, updated_register);
 
 		Ok(())
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 6c57adc6afefb..cb207e2565dd4 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -254,7 +254,7 @@ pub(crate) fn setup_delegation_stake(
 
 		fund(delegator, amount_to_delegate + ExistentialDeposit::get());
 		assert_ok!(DelegatedStaking::delegate(delegator, &delegatee, amount_to_delegate));
-		assert_ok!(DelegatedStaking::update_bond(&delegatee));
+		assert_ok!(DelegatedStaking::bond_all(&delegatee));
 	}
 
 	// sanity checks
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index b2f41e68a9c94..86e7de8f8c535 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -181,7 +181,7 @@ mod integration {
 
 				// unbonded balance is the newly delegated 100
 				assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 100);
-				assert_ok!(DelegatedStaking::update_bond(&delegatee));
+				assert_ok!(DelegatedStaking::bond_all(&delegatee));
 				// after bond, unbonded balance is 0
 				assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
 			}
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 0b2fb24b34e66..5cf47aaaf65be 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1737,7 +1737,6 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		Self::chill(RawOrigin::Signed(ctrl).into())
 	}
 
-	// FIXME(ank4n): Refactor withdraw unbonded to take limit and remove partial_withdraw_unbonded
 	fn withdraw_unbonded(
 		who: Self::AccountId,
 		num_slashing_spans: u32,
diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs
index 2eeee0e8a3d66..ae4ea2bec909d 100644
--- a/substrate/frame/staking/src/slashing.rs
+++ b/substrate/frame/staking/src/slashing.rs
@@ -619,7 +619,8 @@ pub fn do_slash<T: Config>(
 		// If delegated staking, report slash and move on.
 		T::DelegationSupport::report_slash(stash, value);
 	} else {
-		let (imbalance, missing) = T::Currency::slash(stash, value);
+		let (imbalance, missing) =
+			T::Currency::slash(stash, value);
 		slashed_imbalance.subsume(imbalance);
 
 		if !missing.is_zero() {
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 75503ca21d039..05ad7d70371c9 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -79,8 +79,8 @@ pub trait DelegationInterface {
 	/// This will only succeed if all delegations to this delegatee are withdrawn.
 	fn kill_delegatee(delegatee: &Self::AccountId) -> DispatchResult;
 
-	/// Update bond whenever there is a new delegate funds that are not staked.
-	fn update_bond(delegatee: &Self::AccountId) -> DispatchResult;
+	/// Bond all fund that is delegated but not staked.
+	fn bond_all(delegatee: &Self::AccountId) -> DispatchResult;
 
 	/// Request withdrawal of unbonded stake of `delegatee` belonging to the provided `delegator`.
 	///
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 25266877b45e1..7561da4f2b10f 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -437,6 +437,7 @@ pub trait StakingHoldProvider {
 	type AccountId: Clone + sp_std::fmt::Debug;
 
 	/// Update amount held for bonded stake.
+	/// FIXME(ank4n) remove this
 	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult;
 
 	/// Release all amount held for stake.

From 199bb724f057c77013203257fca793059553fc45 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 15 Dec 2023 00:23:14 +0100
Subject: [PATCH 069/202] fmt

---
 substrate/frame/nomination-pools/src/lib.rs | 3 ++-
 substrate/frame/staking/src/slashing.rs     | 3 +--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index 981ea8991d30e..5736700ca3e36 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -1659,7 +1659,8 @@ pub mod pallet {
 		type U256ToBalance: Convert<U256, BalanceOf<Self>>;
 
 		/// The interface for nominating.
-		type Staking: StakingInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId> + DelegationInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
+		type Staking: StakingInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId>
+			+ DelegationInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
 
 		/// The amount of eras a `SubPools::with_era` pool can exist before it gets merged into the
 		/// `SubPools::no_era` pool. In other words, this is the amount of eras a member will be
diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs
index ae4ea2bec909d..2eeee0e8a3d66 100644
--- a/substrate/frame/staking/src/slashing.rs
+++ b/substrate/frame/staking/src/slashing.rs
@@ -619,8 +619,7 @@ pub fn do_slash<T: Config>(
 		// If delegated staking, report slash and move on.
 		T::DelegationSupport::report_slash(stash, value);
 	} else {
-		let (imbalance, missing) =
-			T::Currency::slash(stash, value);
+		let (imbalance, missing) = T::Currency::slash(stash, value);
 		slashed_imbalance.subsume(imbalance);
 
 		if !missing.is_zero() {

From 6f4d150c7438ed889e6409ba6e39f938258a1e9f Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 15 Dec 2023 00:38:13 +0100
Subject: [PATCH 070/202] remove staking hold provider

---
 substrate/frame/delegated-staking/src/lib.rs  | 54 ++++++++-----------
 substrate/frame/staking/src/ledger.rs         |  2 +-
 substrate/frame/staking/src/pallet/impls.rs   | 50 +++++++----------
 .../primitives/staking/src/delegation.rs      | 20 ++++++-
 substrate/primitives/staking/src/lib.rs       | 28 ++--------
 5 files changed, 65 insertions(+), 89 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index e5edbd96e3189..0e46d838e8d93 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -69,11 +69,11 @@ use frame_support::{
 	},
 	transactional,
 };
-use pallet::*;
+
 use sp_runtime::{traits::Zero, DispatchResult, Perbill, RuntimeDebug, Saturating};
 use sp_staking::{
 	delegation::{DelegationInterface, StakingDelegationSupport},
-	EraIndex, Stake, StakerStatus, StakingHoldProvider, StakingInterface,
+	EraIndex, Stake, StakerStatus, StakingInterface,
 };
 use sp_std::{convert::TryInto, prelude::*};
 
@@ -102,8 +102,7 @@ pub mod pallet {
 		type RuntimeHoldReason: From<HoldReason>;
 
 		/// Core staking implementation.
-		type CoreStaking: StakingInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId>
-			+ StakingHoldProvider<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
+		type CoreStaking: StakingInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
 	}
 
 	#[pallet::error]
@@ -512,35 +511,9 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 	}
 }
 
-impl<T: Config> StakingHoldProvider for Pallet<T> {
+impl<T: Config> StakingDelegationSupport for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
-
-	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
-		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
-
-		// delegation register should exist since `who` is a delegatee.
-		let delegation_register =
-			<Delegatees<T>>::get(who).defensive_ok_or(Error::<T>::BadState)?;
-
-		ensure!(delegation_register.total_delegated >= amount, Error::<T>::NotEnoughFunds);
-		ensure!(delegation_register.pending_slash <= amount, Error::<T>::UnappliedSlash);
-		let updated_register = DelegationLedger { hold: amount, ..delegation_register };
-		<Delegatees<T>>::insert(who, updated_register);
-
-		Ok(())
-	}
-
-	fn release_all(who: &Self::AccountId) {
-		if !Self::is_delegatee(who) {
-			T::CoreStaking::release_all(who);
-		}
-
-		let _delegation_register = <Delegatees<T>>::get(who);
-		todo!("handle kill delegatee")
-	}
-}
-impl<T: Config> StakingDelegationSupport for Pallet<T> {
 	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
 		<Delegatees<T>>::get(who)
 			.map(|delegatee| delegatee.delegated_balance())
@@ -574,6 +547,21 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 		Self::is_delegatee(who)
 	}
 
+	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
+
+		// delegation register should exist since `who` is a delegatee.
+		let delegation_register =
+			<Delegatees<T>>::get(who).defensive_ok_or(Error::<T>::BadState)?;
+
+		ensure!(delegation_register.total_delegated >= amount, Error::<T>::NotEnoughFunds);
+		ensure!(delegation_register.pending_slash <= amount, Error::<T>::UnappliedSlash);
+		let updated_register = DelegationLedger { hold: amount, ..delegation_register };
+		<Delegatees<T>>::insert(who, updated_register);
+
+		Ok(())
+	}
+
 	fn report_slash(who: &Self::AccountId, slash: Self::Balance) {
 		<Delegatees<T>>::mutate(who, |maybe_register| match maybe_register {
 			Some(register) => register.pending_slash.saturating_accrue(slash),
@@ -744,6 +732,10 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		T::CoreStaking::slash_reward_fraction()
 	}
 
+	fn release_all(_who: &Self::AccountId) {
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+	}
+
 	#[cfg(feature = "runtime-benchmarks")]
 	fn max_exposure_page_size() -> sp_staking::Page {
 		T::CoreStaking::max_exposure_page_size()
diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs
index a6750a7c4c771..c46b8d0d71a86 100644
--- a/substrate/frame/staking/src/ledger.rs
+++ b/substrate/frame/staking/src/ledger.rs
@@ -18,7 +18,7 @@
 //! A Ledger implementation for stakers.
 
 use frame_support::defensive;
-use sp_staking::{StakingAccount, StakingHoldProvider};
+use sp_staking::{StakingAccount, StakingInterface};
 use sp_std::prelude::*;
 
 use crate::{
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 5cf47aaaf65be..2ad3afef9e0f7 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -44,7 +44,7 @@ use sp_staking::{
 	offence::{DisableStrategy, OffenceDetails, OnOffenceHandler},
 	EraIndex, Page, SessionIndex, Stake,
 	StakingAccount::{self, Controller, Stash},
-	StakingHoldProvider, StakingInterface,
+	StakingInterface,
 };
 use sp_std::prelude::*;
 
@@ -1114,6 +1114,18 @@ impl<T: Config> Pallet<T> {
 
 		false
 	}
+
+	pub(crate) fn update_hold(
+		who: &T::AccountId,
+		amount: BalanceOf<T>,
+	) -> sp_runtime::DispatchResult {
+		if T::DelegationSupport::is_delegatee(who) {
+			return T::DelegationSupport::update_hold(who, amount);
+		}
+
+		T::Currency::set_lock(crate::STAKING_ID, who, amount, WithdrawReasons::all());
+		Ok(())
+	}
 }
 
 impl<T: Config> Pallet<T> {
@@ -1854,26 +1866,8 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	fn slash_reward_fraction() -> Perbill {
 		SlashRewardFraction::<T>::get()
 	}
-}
-
-impl<T: Config> StakingHoldProvider for Pallet<T> {
-	type Balance = BalanceOf<T>;
-	type AccountId = T::AccountId;
-
-	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> sp_runtime::DispatchResult {
-		if T::DelegationSupport::is_delegatee(who) {
-			return T::DelegationSupport::update_hold(who, amount);
-		}
-
-		T::Currency::set_lock(crate::STAKING_ID, who, amount, WithdrawReasons::all());
-		Ok(())
-	}
 
 	fn release_all(who: &Self::AccountId) {
-		if T::DelegationSupport::is_delegatee(who) {
-			return T::DelegationSupport::release_all(who);
-		}
-
 		T::Currency::remove_lock(crate::STAKING_ID, who)
 	}
 }
@@ -1881,27 +1875,19 @@ impl<T: Config> StakingHoldProvider for Pallet<T> {
 /// Standard implementation of `StakingDelegationSupport` that supports only direct staking and no
 /// delegated staking.
 pub struct NoDelegation<T>(PhantomData<T>);
-impl<T: Config> StakingHoldProvider for NoDelegation<T> {
+impl<T: Config> StakingDelegationSupport for NoDelegation<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
-
-	fn update_hold(_who: &Self::AccountId, _amount: Self::Balance) -> sp_runtime::DispatchResult {
-		defensive!("delegation update_hold should not be have been called for NoDelegation");
-		Err(Error::<T>::NotEnoughFunds.into())
-	}
-
-	fn release_all(_who: &Self::AccountId) {
-		defensive!("delegation release_all should not have been called for NoDelegation");
-	}
-}
-
-impl<T: Config> StakingDelegationSupport for NoDelegation<T> {
 	fn stakeable_balance(_who: &Self::AccountId) -> Self::Balance {
 		BalanceOf::<T>::zero()
 	}
 	fn is_delegatee(_who: &Self::AccountId) -> bool {
 		false
 	}
+	fn update_hold(_who: &Self::AccountId, _amount: Self::Balance) -> sp_runtime::DispatchResult {
+		defensive!("delegation update_hold should not be have been called for NoDelegation");
+		Err(Error::<T>::NotEnoughFunds.into())
+	}
 
 	fn report_slash(_who: &Self::AccountId, _slash: Self::Balance) {
 		defensive!("delegation report_slash should not be have been called for NoDelegation");
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 05ad7d70371c9..008850f7e820a 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -15,7 +15,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use crate::StakingHoldProvider;
 use codec::{FullCodec, MaxEncodedLen};
 use scale_info::TypeInfo;
 use sp_runtime::{DispatchResult, Saturating};
@@ -123,7 +122,21 @@ pub trait DelegationInterface {
 }
 
 /// Something that provides delegation support to core staking.
-pub trait StakingDelegationSupport: StakingHoldProvider {
+pub trait StakingDelegationSupport {
+	/// Balance type used by the staking system.
+	type Balance: Sub<Output = Self::Balance>
+		+ Ord
+		+ PartialEq
+		+ Default
+		+ Copy
+		+ MaxEncodedLen
+		+ FullCodec
+		+ TypeInfo
+		+ Saturating;
+
+	/// AccountId type used by the staking system.
+	type AccountId: Clone + sp_std::fmt::Debug;
+
 	/// Balance of who which is available for stake.
 	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance;
 
@@ -139,6 +152,9 @@ pub trait StakingDelegationSupport: StakingHoldProvider {
 	/// Returns true if `who` accepts delegations for stake.
 	fn is_delegatee(who: &Self::AccountId) -> bool;
 
+	/// Update amount held for bonded stake.
+	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult;
+
 	/// Reports an ongoing slash to the delegatee account that would be applied lazily.
 	fn report_slash(who: &Self::AccountId, slash: Self::Balance);
 }
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 7561da4f2b10f..dcf7fa41e2885 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -288,6 +288,11 @@ pub trait StakingInterface {
 	/// Returns the fraction of the slash to be rewarded to reporter.
 	fn slash_reward_fraction() -> Perbill;
 
+	/// Release all funds bonded for stake.
+	///
+	/// Unsafe, only used for migration of delegatee accounts.
+	fn release_all(who: &Self::AccountId);
+
 	#[cfg(feature = "runtime-benchmarks")]
 	fn max_exposure_page_size() -> Page;
 
@@ -420,27 +425,4 @@ pub struct PagedExposureMetadata<Balance: HasCompact + codec::MaxEncodedLen> {
 	pub page_count: Page,
 }
 
-/// Something that can hold and release funds for staking.
-pub trait StakingHoldProvider {
-	/// Balance type used by the staking system.
-	type Balance: Sub<Output = Self::Balance>
-		+ Ord
-		+ PartialEq
-		+ Default
-		+ Copy
-		+ MaxEncodedLen
-		+ FullCodec
-		+ TypeInfo
-		+ Saturating;
-
-	/// AccountId type used by the staking system.
-	type AccountId: Clone + sp_std::fmt::Debug;
-
-	/// Update amount held for bonded stake.
-	/// FIXME(ank4n) remove this
-	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult;
-
-	/// Release all amount held for stake.
-	fn release_all(who: &Self::AccountId);
-}
 sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $);

From cb4d3ceb39194b78409770063b57258327f16a94 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 15 Dec 2023 23:18:49 +0100
Subject: [PATCH 071/202] some todos for NP integration

---
 substrate/frame/nomination-pools/src/lib.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index 5736700ca3e36..b0f85b1d66672 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -1250,6 +1250,7 @@ impl<T: Config> BondedPool<T> {
 	) -> Result<BalanceOf<T>, DispatchError> {
 		// Cache the value
 		let bonded_account = self.bonded_account();
+		// TODO(ank4n) joining a pool: delegate funds to pool account..
 		T::Currency::transfer(
 			who,
 			&bonded_account,
@@ -1264,6 +1265,7 @@ impl<T: Config> BondedPool<T> {
 		let points_issued = self.issue(amount);
 
 		match ty {
+			// TODO(ank4n): When type create, also do accept delegation call..
 			BondType::Create => T::Staking::bond(&bonded_account, amount, &self.reward_account())?,
 			// The pool should always be created in such a way its in a state to bond extra, but if
 			// the active balance is slashed below the minimum bonded or the account cannot be

From 2d61dd4400d5e5b49e7c36f8483370d93fafc81f Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Mon, 12 Feb 2024 14:54:57 +0100
Subject: [PATCH 072/202] fix compile after rebase with master

---
 substrate/frame/delegated-staking/src/mock.rs |  1 -
 substrate/frame/staking/src/lib.rs            | 15 +++++++++++++++
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index cb207e2565dd4..ae062155dab0b 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -74,7 +74,6 @@ impl pallet_balances::Config for Runtime {
 	type MaxFreezes = ();
 	type RuntimeHoldReason = RuntimeHoldReason;
 	type RuntimeFreezeReason = ();
-	type MaxHolds = ConstU32<1>;
 }
 
 pallet_staking_reward_curve::build! {
diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs
index 28c8c879b9379..15ded13ef745e 100644
--- a/substrate/frame/staking/src/lib.rs
+++ b/substrate/frame/staking/src/lib.rs
@@ -407,6 +407,21 @@ pub enum RewardDestination<AccountId> {
 	None,
 }
 
+impl<AccountId: Clone> RewardDestination<AccountId> {
+	fn from(self, stash: &AccountId) -> Option<AccountId> {
+		match self {
+			// FIXME(ank4n): Figure out later how to handle Controller
+			RewardDestination::Staked | RewardDestination::Stash => Some(stash.clone()),
+			RewardDestination::Account(a) => Some(a),
+			#[allow(deprecated)]
+			_ => {
+				defensive!("reward destination not set or set as deprecated controller");
+				None
+			},
+		}
+	}
+
+}
 
 /// Preference of what happens regarding validation.
 #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, Default, MaxEncodedLen)]

From 873b702ff67d888944878005121a46e0c54fd44d Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 15 Feb 2024 10:29:04 +0100
Subject: [PATCH 073/202] update dep

---
 Cargo.lock | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 28c66457eadf4..82df11b91f837 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -9706,8 +9706,8 @@ dependencies = [
  "sp-io",
  "sp-runtime",
  "sp-staking",
- "sp-std 8.0.0",
- "sp-tracing 10.0.0",
+ "sp-std 14.0.0",
+ "sp-tracing 16.0.0",
  "substrate-test-utils",
 ]
 

From 1a6ce99ff5b3dc8af570aa6c9befc03965d82703 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 15 Feb 2024 10:43:16 +0100
Subject: [PATCH 074/202] fix conflicts

---
 .../nomination-pools/test-staking/src/mock.rs      | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs
index 90676d566ea85..c01c91e5ad7d7 100644
--- a/substrate/frame/nomination-pools/test-staking/src/mock.rs
+++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs
@@ -199,25 +199,15 @@ impl pallet_nomination_pools::Config for Runtime {
 type Block = frame_system::mocking::MockBlock<Runtime>;
 
 frame_support::construct_runtime!(
-<<<<<<< HEAD
-	pub struct Runtime
-	{
-		System: frame_system::{Pallet, Call, Event<T>},
-		Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent},
-		Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
-		Staking: pallet_staking::{Pallet, Call, Config<T>, Storage, Event<T>},
-		VoterList: pallet_bags_list::<Instance1>::{Pallet, Call, Storage, Event<T>},
-		DelegatedStaking: pallet_delegated_staking::{Pallet, Storage, Event<T>, HoldReason},
+pub enum Runtime {
 		Pools: pallet_nomination_pools::{Pallet, Call, Storage, Event<T>, FreezeReason},
-=======
-	pub enum Runtime {
 		System: frame_system,
 		Timestamp: pallet_timestamp,
 		Balances: pallet_balances,
 		Staking: pallet_staking,
 		VoterList: pallet_bags_list::<Instance1>,
 		Pools: pallet_nomination_pools,
->>>>>>> master
+		DelegatedStaking: pallet_delegated_staking::{Pallet, Storage, Event<T>, HoldReason},
 	}
 );
 

From b6709f921df229ec63bbb207105ec7062fc8899e Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 15 Feb 2024 10:43:51 +0100
Subject: [PATCH 075/202] new contruct runtime syntax

---
 substrate/frame/delegated-staking/src/mock.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index ae062155dab0b..d1296da226231 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -143,7 +143,7 @@ impl delegated_staking::Config for Runtime {
 }
 
 frame_support::construct_runtime!(
-	pub struct Runtime {
+	pub enum Runtime {
 		System: frame_system,
 		Timestamp: pallet_timestamp,
 		Balances: pallet_balances,

From 05206ceaea1f7a653d139cdd24af4b3e3e1c9cee Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 15 Feb 2024 11:26:22 +0100
Subject: [PATCH 076/202] conflict compile fix

---
 substrate/frame/nomination-pools/test-staking/src/mock.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs
index c01c91e5ad7d7..7875ba41e3aff 100644
--- a/substrate/frame/nomination-pools/test-staking/src/mock.rs
+++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs
@@ -88,7 +88,8 @@ impl pallet_balances::Config for Runtime {
 	type WeightInfo = ();
 	type FreezeIdentifier = RuntimeFreezeReason;
 	type MaxFreezes = ConstU32<1>;
-	type MaxHolds = ConstU32<1>;
+	type RuntimeHoldReason = RuntimeHoldReason;
+	type RuntimeFreezeReason = RuntimeFreezeReason;
 }
 
 pallet_staking_reward_curve::build! {
@@ -200,7 +201,6 @@ type Block = frame_system::mocking::MockBlock<Runtime>;
 
 frame_support::construct_runtime!(
 pub enum Runtime {
-		Pools: pallet_nomination_pools::{Pallet, Call, Storage, Event<T>, FreezeReason},
 		System: frame_system,
 		Timestamp: pallet_timestamp,
 		Balances: pallet_balances,

From ee75c0570ee19f7b08aa98f66508fe612f5462e0 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 16 Feb 2024 01:44:21 +0100
Subject: [PATCH 077/202] rough np integration works

---
 substrate/frame/delegated-staking/src/lib.rs  |   3 +-
 .../frame/delegated-staking/src/tests.rs      |  30 ++--
 substrate/frame/nomination-pools/src/lib.rs   |  63 ++++---
 .../nomination-pools/test-staking/src/lib.rs  | 163 ++++++++++++++++++
 substrate/frame/staking/src/pallet/mod.rs     |   1 -
 .../primitives/staking/src/delegation.rs      |   1 +
 6 files changed, 210 insertions(+), 51 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 0e46d838e8d93..f06f22343c276 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -355,8 +355,8 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 
 	#[transactional]
 	fn withdraw(
-		delegator: &Self::AccountId,
 		delegatee: &Self::AccountId,
+		delegator: &Self::AccountId,
 		value: Self::Balance,
 		num_slashing_spans: u32,
 	) -> DispatchResult {
@@ -680,6 +680,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		_stash: Self::AccountId,
 		_num_slashing_spans: u32,
 	) -> Result<bool, DispatchError> {
+		// FIXME(ank4n): Support withdrawing to self account.
 		defensive_assert!(false, "not supported for delegated impl of staking interface");
 		Err(Error::<T>::NotSupported.into())
 	}
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 86e7de8f8c535..6201d3f30ca22 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -210,10 +210,10 @@ mod integration {
 			assert!(eq_stake(delegatee, total_staked, total_staked));
 			// Withdrawing without unbonding would fail.
 			assert_noop!(
-				DelegatedStaking::withdraw(&300, &delegatee, 50, 0),
+				DelegatedStaking::withdraw(&delegatee, &300, 50, 0),
 				Error::<T>::WithdrawFailed
 			);
-			// assert_noop!(DelegatedStaking::withdraw(&200, &delegatee, 50, 0),
+			// assert_noop!(DelegatedStaking::withdraw(&delegatee, &200, 50, 0),
 			// Error::<T>::NotAllowed); active and total stake remains same
 			assert!(eq_stake(delegatee, total_staked, total_staked));
 
@@ -232,7 +232,7 @@ mod integration {
 
 			// nothing to withdraw at era 4
 			assert_noop!(
-				DelegatedStaking::withdraw(&305, &delegatee, 50, 0),
+				DelegatedStaking::withdraw(&delegatee, &305, 50, 0),
 				Error::<T>::WithdrawFailed
 			);
 
@@ -244,43 +244,43 @@ mod integration {
 			start_era(5);
 			// at era 5, 50 tokens are withdrawable, cannot withdraw more.
 			assert_noop!(
-				DelegatedStaking::withdraw(&305, &delegatee, 51, 0),
+				DelegatedStaking::withdraw(&delegatee, &305, 51, 0),
 				Error::<T>::WithdrawFailed
 			);
 			// less is possible
-			assert_ok!(DelegatedStaking::withdraw(&305, &delegatee, 30, 0));
-			assert_ok!(DelegatedStaking::withdraw(&305, &delegatee, 20, 0));
+			assert_ok!(DelegatedStaking::withdraw(&delegatee, &305, 30, 0));
+			assert_ok!(DelegatedStaking::withdraw(&delegatee, &305, 20, 0));
 
 			// Lets go to future era where everything is unbonded. Withdrawable amount: 100 + 200
 			start_era(7);
 			// 305 has no more amount delegated so it cannot withdraw.
 			assert_noop!(
-				DelegatedStaking::withdraw(&305, &delegatee, 5, 0),
+				DelegatedStaking::withdraw(&delegatee, &305, 5, 0),
 				Error::<T>::NotDelegator
 			);
 			// 309 is an active delegator but has total delegation of 90, so it cannot withdraw more
 			// than that.
 			assert_noop!(
-				DelegatedStaking::withdraw(&309, &delegatee, 91, 0),
+				DelegatedStaking::withdraw(&delegatee, &309, 91, 0),
 				Error::<T>::NotEnoughFunds
 			);
 			// 310 cannot withdraw more than delegated funds.
 			assert_noop!(
-				DelegatedStaking::withdraw(&310, &delegatee, 101, 0),
+				DelegatedStaking::withdraw(&delegatee, &310, 101, 0),
 				Error::<T>::NotEnoughFunds
 			);
 			// but can withdraw all its delegation amount.
-			assert_ok!(DelegatedStaking::withdraw(&310, &delegatee, 100, 0));
+			assert_ok!(DelegatedStaking::withdraw(&delegatee, &310, 100, 0));
 			// 320 can withdraw all its delegation amount.
-			assert_ok!(DelegatedStaking::withdraw(&320, &delegatee, 200, 0));
+			assert_ok!(DelegatedStaking::withdraw(&delegatee, &320, 200, 0));
 
 			// cannot withdraw anything more..
 			assert_noop!(
-				DelegatedStaking::withdraw(&301, &delegatee, 1, 0),
+				DelegatedStaking::withdraw(&delegatee, &301, 1, 0),
 				Error::<T>::WithdrawFailed
 			);
 			assert_noop!(
-				DelegatedStaking::withdraw(&350, &delegatee, 1, 0),
+				DelegatedStaking::withdraw(&delegatee, &350, 1, 0),
 				Error::<T>::WithdrawFailed
 			);
 		});
@@ -294,7 +294,7 @@ mod integration {
 
 			// verify withdraw not possible yet
 			assert_noop!(
-				DelegatedStaking::withdraw(&300, &delegatee, 100, 0),
+				DelegatedStaking::withdraw(&delegatee, &300, 100, 0),
 				Error::<T>::WithdrawFailed
 			);
 
@@ -306,7 +306,7 @@ mod integration {
 			assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 100);
 
 			// withdraw works now without unbonding
-			assert_ok!(DelegatedStaking::withdraw(&300, &delegatee, 100, 0));
+			assert_ok!(DelegatedStaking::withdraw(&delegatee, &300, 100, 0));
 			assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
 		});
 	}
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index 0cbe26bc30a0b..5182f69c32cdd 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -373,7 +373,7 @@ use sp_runtime::{
 	},
 	FixedPointNumber, Perbill,
 };
-use sp_staking::{EraIndex, StakingInterface};
+use sp_staking::{EraIndex, StakingInterface, delegation::DelegationInterface};
 use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, ops::Div, vec::Vec};
 
 #[cfg(any(feature = "try-runtime", feature = "fuzzing", test, debug_assertions))]
@@ -1259,7 +1259,7 @@ impl<T: Config> BondedPool<T> {
 		T::Currency::transfer(
 			who,
 			&bonded_account,
-			amount,
+			T::Currency::minimum_balance(),
 			match ty {
 				BondType::Create => Preservation::Expendable,
 				BondType::Later => Preservation::Preserve,
@@ -1271,11 +1271,19 @@ impl<T: Config> BondedPool<T> {
 
 		match ty {
 			// TODO(ank4n): When type create, also do accept delegation call..
-			BondType::Create => T::Staking::bond(&bonded_account, amount, &self.reward_account())?,
+			BondType::Create => {
+				T::Staking::accept_delegations(&bonded_account, &self.reward_account())?;
+				T::Staking::delegate(&who, &bonded_account, amount)?;
+				T::Staking::bond(&bonded_account, amount, &self.reward_account())?
+			},
+
 			// The pool should always be created in such a way its in a state to bond extra, but if
 			// the active balance is slashed below the minimum bonded or the account cannot be
 			// found, we exit early.
-			BondType::Later => T::Staking::bond_extra(&bonded_account, amount)?,
+			BondType::Later => {
+				T::Staking::delegate(&who, &bonded_account, amount)?;
+				T::Staking::bond_extra(&bonded_account, amount)?
+			},
 		}
 		TotalValueLocked::<T>::mutate(|tvl| {
 			tvl.saturating_accrue(amount);
@@ -1577,7 +1585,6 @@ pub mod pallet {
 	use frame_support::traits::StorageVersion;
 	use frame_system::{ensure_signed, pallet_prelude::*};
 	use sp_runtime::Perbill;
-	use sp_staking::delegation::DelegationInterface;
 
 	/// The current storage version.
 	const STORAGE_VERSION: StorageVersion = StorageVersion::new(8);
@@ -2256,18 +2263,6 @@ pub mod pallet {
 			let withdrawn_points = member.withdraw_unlocked(current_era);
 			ensure!(!withdrawn_points.is_empty(), Error::<T>::CannotWithdrawAny);
 
-			// Before calculating the `balance_to_unbond`, we call withdraw unbonded to ensure the
-			// `transferrable_balance` is correct.
-			let stash_killed =
-				T::Staking::withdraw_unbonded(bonded_pool.bonded_account(), num_slashing_spans)?;
-
-			// defensive-only: the depositor puts enough funds into the stash so that it will only
-			// be destroyed when they are leaving.
-			ensure!(
-				!stash_killed || caller == bonded_pool.roles.depositor,
-				Error::<T>::Defensive(DefensiveError::BondedStashKilledPrematurely)
-			);
-
 			let mut sum_unlocked_points: BalanceOf<T> = Zero::zero();
 			let balance_to_unbond = withdrawn_points
 				.iter()
@@ -2284,23 +2279,23 @@ pub mod pallet {
 						// era-less pool.
 						accumulator.saturating_add(sub_pools.no_era.dissolve(*unlocked_points))
 					}
-				})
-				// A call to this transaction may cause the pool's stash to get dusted. If this
-				// happens before the last member has withdrawn, then all subsequent withdraws will
-				// be 0. However the unbond pools do no get updated to reflect this. In the
-				// aforementioned scenario, this check ensures we don't try to withdraw funds that
-				// don't exist. This check is also defensive in cases where the unbond pool does not
-				// update its balance (e.g. a bug in the slashing hook.) We gracefully proceed in
-				// order to ensure members can leave the pool and it can be destroyed.
-				.min(bonded_pool.transferable_balance());
-
-			T::Currency::transfer(
-				&bonded_pool.bonded_account(),
-				&member_account,
-				balance_to_unbond,
-				Preservation::Expendable,
-			)
-			.defensive()?;
+				});
+			// fixme(ank4n): Transfer whatever is minimum transferable.
+			// Withdraw upto limit and return the amount withdrawn and whether stash killed.
+
+			// Before calculating the `balance_to_unbond`, we call withdraw unbonded to ensure the
+			// `transferrable_balance` is correct.
+			// fixme(ank4n): Handle result.
+			let _withdraw_result =
+				T::Staking::withdraw(&bonded_pool.bonded_account(), &member_account, balance_to_unbond, num_slashing_spans)?;
+
+			// defensive-only: the depositor puts enough funds into the stash so that it will only
+			// be destroyed when they are leaving.
+			// ensure!(
+			// 	!stash_killed || caller == bonded_pool.roles.depositor,
+			// 	Error::<T>::Defensive(DefensiveError::BondedStashKilledPrematurely)
+			// );
+
 
 			Self::deposit_event(Event::<T>::Withdrawn {
 				member: member_account.clone(),
diff --git a/substrate/frame/nomination-pools/test-staking/src/lib.rs b/substrate/frame/nomination-pools/test-staking/src/lib.rs
index 865b7a71e6884..e960d027f3e07 100644
--- a/substrate/frame/nomination-pools/test-staking/src/lib.rs
+++ b/substrate/frame/nomination-pools/test-staking/src/lib.rs
@@ -191,6 +191,169 @@ fn pool_lifecycle_e2e() {
 	})
 }
 
+#[test]
+fn pool_migration_to_delegation_e2e() {
+	new_test_ext().execute_with(|| {
+		assert_eq!(Balances::minimum_balance(), 5);
+		assert_eq!(Staking::current_era(), None);
+
+		// create the pool, we know this has id 1.
+		assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10));
+		assert_eq!(LastPoolId::<Runtime>::get(), 1);
+
+		// have the pool nominate.
+		assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]));
+
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![
+				PoolsEvent::Created { depositor: 10, pool_id: 1 },
+				PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true },
+			]
+		);
+
+		// have two members join
+		assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1));
+		assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1));
+
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![
+				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 },
+				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 },
+			]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![
+				PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true },
+				PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true },
+			]
+		);
+
+		// pool goes into destroying
+		assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying));
+
+		// depositor cannot unbond yet.
+		assert_noop!(
+			Pools::unbond(RuntimeOrigin::signed(10), 10, 50),
+			PoolsError::<Runtime>::MinimumBondNotMet,
+		);
+
+		// now the members want to unbond.
+		assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10));
+		assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10));
+
+		assert_eq!(PoolMembers::<Runtime>::get(20).unwrap().unbonding_eras.len(), 1);
+		assert_eq!(PoolMembers::<Runtime>::get(20).unwrap().points, 0);
+		assert_eq!(PoolMembers::<Runtime>::get(21).unwrap().unbonding_eras.len(), 1);
+		assert_eq!(PoolMembers::<Runtime>::get(21).unwrap().points, 0);
+
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![
+				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
+				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
+			]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![
+				PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying },
+				PoolsEvent::Unbonded { member: 20, pool_id: 1, points: 10, balance: 10, era: 3 },
+				PoolsEvent::Unbonded { member: 21, pool_id: 1, points: 10, balance: 10, era: 3 },
+			]
+		);
+
+		// depositor cannot still unbond
+		assert_noop!(
+			Pools::unbond(RuntimeOrigin::signed(10), 10, 50),
+			PoolsError::<Runtime>::MinimumBondNotMet,
+		);
+
+		for e in 1..BondingDuration::get() {
+			CurrentEra::<Runtime>::set(Some(e));
+			assert_noop!(
+				Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0),
+				PoolsError::<Runtime>::CannotWithdrawAny
+			);
+		}
+
+		// members are now unlocked.
+		CurrentEra::<Runtime>::set(Some(BondingDuration::get()));
+
+		// depositor cannot still unbond
+		assert_noop!(
+			Pools::unbond(RuntimeOrigin::signed(10), 10, 50),
+			PoolsError::<Runtime>::MinimumBondNotMet,
+		);
+
+		// but members can now withdraw.
+		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0));
+		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0));
+		assert!(PoolMembers::<Runtime>::get(20).is_none());
+		assert!(PoolMembers::<Runtime>::get(21).is_none());
+
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 },]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![
+				PoolsEvent::Withdrawn { member: 20, pool_id: 1, points: 10, balance: 10 },
+				PoolsEvent::MemberRemoved { pool_id: 1, member: 20 },
+				PoolsEvent::Withdrawn { member: 21, pool_id: 1, points: 10, balance: 10 },
+				PoolsEvent::MemberRemoved { pool_id: 1, member: 21 },
+			]
+		);
+
+		// as soon as all members have left, the depositor can try to unbond, but since the
+		// min-nominator intention is set, they must chill first.
+		assert_noop!(
+			Pools::unbond(RuntimeOrigin::signed(10), 10, 50),
+			pallet_staking::Error::<Runtime>::InsufficientBond
+		);
+
+		assert_ok!(Pools::chill(RuntimeOrigin::signed(10), 1));
+		assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 50));
+
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![
+				StakingEvent::Chilled { stash: POOL1_BONDED },
+				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 50 },
+			]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![PoolsEvent::Unbonded { member: 10, pool_id: 1, points: 50, balance: 50, era: 6 }]
+		);
+
+		// waiting another bonding duration:
+		CurrentEra::<Runtime>::set(Some(BondingDuration::get() * 2));
+		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 1));
+
+		// pools is fully destroyed now.
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 50 },]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![
+				PoolsEvent::Withdrawn { member: 10, pool_id: 1, points: 50, balance: 50 },
+				PoolsEvent::MemberRemoved { pool_id: 1, member: 10 },
+				PoolsEvent::Destroyed { pool_id: 1 }
+			]
+		);
+	})
+}
+
 #[test]
 fn pool_slash_e2e() {
 	new_test_ext().execute_with(|| {
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index 50faa5b963f9e..dec406e4e2d04 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -948,7 +948,6 @@ pub mod pallet {
 			}
 
 			frame_system::Pallet::<T>::inc_consumers(&stash).map_err(|_| Error::<T>::BadState)?;
-
 			let stash_balance = Self::stakeable_balance(&stash);
 			let value = value.min(stash_balance);
 			Self::deposit_event(Event::<T>::Bonded { stash: stash.clone(), amount: value });
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 008850f7e820a..da2ec27427506 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -79,6 +79,7 @@ pub trait DelegationInterface {
 	fn kill_delegatee(delegatee: &Self::AccountId) -> DispatchResult;
 
 	/// Bond all fund that is delegated but not staked.
+	/// FIXME(ank4n): Should not be allowed as withdrawn funds would get restaked.
 	fn bond_all(delegatee: &Self::AccountId) -> DispatchResult;
 
 	/// Request withdrawal of unbonded stake of `delegatee` belonging to the provided `delegator`.

From 5482c9685f33fa1686af663dd7a13ae0e32c457e Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 17 Feb 2024 06:55:15 +0100
Subject: [PATCH 078/202] restore doc

---
 substrate/frame/staking/src/ledger.rs | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs
index 7543f8d1a70f5..eed459500a641 100644
--- a/substrate/frame/staking/src/ledger.rs
+++ b/substrate/frame/staking/src/ledger.rs
@@ -16,6 +16,20 @@
 // limitations under the License.
 
 //! A Ledger implementation for stakers.
+//!
+//! A [`StakingLedger`] encapsulates all the state and logic related to the stake of bonded
+//! stakers, namely, it handles the following storage items:
+//! * [`Bonded`]: mutates and reads the state of the controller <> stash bond map (to be deprecated
+//! soon);
+//! * [`Ledger`]: mutates and reads the state of all the stakers. The [`Ledger`] storage item stores
+//!   instances of [`StakingLedger`] keyed by the staker's controller account and should be mutated
+//!   and read through the [`StakingLedger`] API;
+//! * [`Payee`]: mutates and reads the reward destination preferences for a bonded stash.
+//! * Staking locks: mutates the locks for staking.
+//!
+//! NOTE: All the storage operations related to the staking ledger (both reads and writes) *MUST* be
+//! performed through the methods exposed by the [`StakingLedger`] implementation in order to ensure
+//! state consistency.
 
 use frame_support::defensive;
 use sp_staking::{StakingAccount, StakingInterface};

From 7d901572d2b98ec20a06a1057f786c1ef7164525 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 17 Feb 2024 07:24:42 +0100
Subject: [PATCH 079/202] rename delegatee to delegate

---
 substrate/frame/delegated-staking/src/lib.rs  | 284 +++++++++---------
 substrate/frame/delegated-staking/src/mock.rs |  14 +-
 .../frame/delegated-staking/src/tests.rs      | 184 ++++++------
 substrate/frame/staking/src/pallet/impls.rs   |   8 +-
 substrate/frame/staking/src/slashing.rs       |   2 +-
 .../primitives/staking/src/delegation.rs      |  49 +--
 substrate/primitives/staking/src/lib.rs       |   2 +-
 7 files changed, 268 insertions(+), 275 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index f06f22343c276..8e7fefae24bc4 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -22,27 +22,26 @@
 //! [`DelegationInterface`]. In future, if exposed via extrinsic, these primitives could also be
 //! used by off-chain entities, smart contracts or by other parachains via xcm.
 //!
-//! Delegatee: Someone who accepts delegations. An account can set their intention to accept
+//! Delegate: Someone who accepts delegations. An account can set their intention to accept
 //! delegations by calling [`DelegationInterface::accept_delegations`]. This account cannot have
-//! another role in the staking system and once set as delegatee, can only stake with their
+//! another role in the staking system and once set as `delegate`, can only stake with their
 //! delegated balance, i.e. cannot use their own free balance to stake. They can also block new
 //! delegations by calling [`DelegationInterface::block_delegations`] or remove themselves from
-//! being a delegatee by calling [`DelegationInterface::kill_delegatee`] once all delegations to it
+//! being a `delegate` by calling [`DelegationInterface::kill_delegate`] once all delegations to it
 //! are removed.
 //!
-//! Delegatee is also responsible for managing reward distribution and slashes of delegators.
+//! Delegate is also responsible for managing reward distribution and slashes of delegators.
 //!
-//! Delegator: Someone who delegates their funds to a delegatee. A delegator can delegate their
-//! funds to one and only one delegatee. They also can not be a nominator or validator.
+//! Delegator: Someone who delegates their funds to a `delegate`. A delegator can delegate their
+//! funds to one and only one `delegate`. They also can not be a nominator or validator.
 //!
-//! Reward payouts destination: Delegatees are restricted to have a reward payout destination that
-//! is different from the delegatee account. This means, it cannot be auto-compounded and needs to
-//! be staked again as a delegation. However, the reward payouts can then be distributed to
-//! delegators by the delegatee.
+//! Reward payouts destination: Rewards cannot be paid out to `delegate` account since these funds
+//! are not directly exposed. This implies, rewards cannot be auto-compounded and needs to be staked
+//! again after distributing it to delegators.
 //!
-//! Any slashes to a delegatee are recorded in [`DelegationLedger`] of the Delegatee as a pending
-//! slash. Since the actual amount is held in the delegator's account, this pallet does not know how
-//! to apply slash. It is Delegatee's responsibility to apply slashes for each delegator, one at a
+//! Any slashes to a `delegate` are posted in its [`DelegationLedger`] as a pending slash. Since the
+//! actual amount is held in the multiple `delegator` accounts, this pallet has no way to know how
+//! to apply slash. It is `delegate`'s responsibility to apply slashes for each delegator, one at a
 //! time. Staking pallet ensures the pending slash never exceeds staked amount and would freeze
 //! further withdraws until pending slashes are applied.
 
@@ -109,34 +108,34 @@ pub mod pallet {
 	pub enum Error<T> {
 		/// The account cannot perform this operation.
 		NotAllowed,
-		/// An existing staker cannot become a delegatee.
+		/// An existing staker cannot become a `delegate`.
 		AlreadyStaker,
-		/// Reward Destination cannot be delegatee account.
+		/// Reward Destination cannot be `delegate` account.
 		InvalidRewardDestination,
 		/// Delegation conditions are not met.
 		///
 		/// Possible issues are
 		/// 1) Account does not accept or has blocked delegation.
 		/// 2) Cannot delegate to self,
-		/// 3) Cannot delegate to multiple Delegatees,
+		/// 3) Cannot delegate to multiple delegates,
 		InvalidDelegation,
 		/// The account does not have enough funds to perform the operation.
 		NotEnoughFunds,
-		/// Not an existing delegatee account.
-		NotDelegatee,
+		/// Not an existing `delegate` account.
+		NotDelegate,
 		/// Not a Delegator account.
 		NotDelegator,
 		/// Some corruption in internal state.
 		BadState,
-		/// Unapplied pending slash restricts operation on delegatee.
+		/// Unapplied pending slash restricts operation on `delegate`.
 		UnappliedSlash,
 		/// Failed to withdraw amount from Core Staking Ledger.
 		WithdrawFailed,
 		/// This operation is not supported with Delegation Staking.
 		NotSupported,
-		/// This delegatee is not set as a migrating account.
+		/// This `delegate` is not set as a migrating account.
 		NotMigrating,
-		/// Delegatee no longer accepting new delegations.
+		/// Delegate no longer accepting new delegations.
 		DelegationsBlocked,
 	}
 
@@ -160,43 +159,43 @@ pub mod pallet {
 	#[pallet::event]
 	#[pallet::generate_deposit(pub(super) fn deposit_event)]
 	pub enum Event<T: Config> {
-		Delegated { delegatee: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
-		Withdrawn { delegatee: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
+		Delegated { delegate: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
+		Withdrawn { delegate: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
 	}
 
-	/// Map of Delegators to their delegation, i.e. (delegatee, delegation_amount).
+	/// Map of Delegators to their delegation, i.e. (delegate, delegation_amount).
 	///
-	/// Note: We are not using a double map with delegator and delegatee account as keys since we
+	/// Note: We are not using a double map with delegator and `delegate` account as keys since we
 	/// want to restrict delegators to delegate only to one account.
 	#[pallet::storage]
 	pub(crate) type Delegators<T: Config> =
 		CountedStorageMap<_, Twox64Concat, T::AccountId, (T::AccountId, BalanceOf<T>), OptionQuery>;
 
-	/// Map of Delegatee to their Ledger.
+	/// Map of Delegate to their Ledger.
 	#[pallet::storage]
-	pub(crate) type Delegatees<T: Config> =
+	pub(crate) type Delegates<T: Config> =
 		CountedStorageMap<_, Twox64Concat, T::AccountId, DelegationLedger<T>, OptionQuery>;
 
-	/// Map of Delegatee and its proxy delegator account while its actual delegators are migrating.
+	/// Map of Delegate and its proxy delegator account while its actual delegators are migrating.
 	///
-	/// Helps ensure correctness of ongoing migration of a direct nominator to a delegatee. If a
-	/// delegatee does not exist, it implies it is not going through migration.
+	/// Helps ensure correctness of ongoing migration of a direct nominator to a `delegate`. If a
+	/// `delegate` does not exist, it implies it is not going through migration.
 	#[pallet::storage]
-	pub(crate) type DelegateeMigration<T: Config> =
+	pub(crate) type DelegateMigration<T: Config> =
 		CountedStorageMap<_, Twox64Concat, T::AccountId, T::AccountId, OptionQuery>;
 }
 
-/// Register of all delegations to a `Delegatee`.
+/// Register of all delegations to a `Delegate`.
 ///
-/// This keeps track of the active balance of the delegatee that is made up from the funds that are
-/// currently delegated to this delegatee. It also tracks the pending slashes yet to be applied
+/// This keeps track of the active balance of the `delegate` that is made up from the funds that are
+/// currently delegated to this `delegate`. It also tracks the pending slashes yet to be applied
 /// among other things.
 #[derive(Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
 #[scale_info(skip_type_params(T))]
 pub struct DelegationLedger<T: Config> {
 	/// Where the reward should be paid out.
 	pub payee: T::AccountId,
-	/// Sum of all delegated funds to this delegatee.
+	/// Sum of all delegated funds to this `delegate`.
 	#[codec(compact)]
 	pub total_delegated: BalanceOf<T>,
 	/// Amount that is bonded and held.
@@ -206,7 +205,7 @@ pub struct DelegationLedger<T: Config> {
 	/// Slashes that are not yet applied.
 	#[codec(compact)]
 	pub pending_slash: BalanceOf<T>,
-	/// Whether this delegatee is blocked from receiving new delegations.
+	/// Whether this `delegate` is blocked from receiving new delegations.
 	pub blocked: bool,
 }
 
@@ -228,12 +227,12 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 	type AccountId = T::AccountId;
 
 	fn delegated_balance(who: &Self::AccountId) -> Self::Balance {
-		<Delegatees<T>>::get(who)
+		<Delegates<T>>::get(who)
 			.map_or_else(|| 0u32.into(), |register| register.delegated_balance())
 	}
 
 	fn unbonded_balance(who: &Self::AccountId) -> Self::Balance {
-		<Delegatees<T>>::get(who)
+		<Delegates<T>>::get(who)
 			.map_or_else(|| 0u32.into(), |register| register.unbonded_balance())
 	}
 
@@ -241,23 +240,23 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		who: &Self::AccountId,
 		reward_destination: &Self::AccountId,
 	) -> DispatchResult {
-		// Existing delegatee cannot register again.
-		ensure!(!<Delegatees<T>>::contains_key(who), Error::<T>::NotAllowed);
+		// Existing `delegate` cannot register again.
+		ensure!(!<Delegates<T>>::contains_key(who), Error::<T>::NotAllowed);
 
-		// A delegator cannot become a delegatee.
+		// A delegator cannot become a `delegate`.
 		ensure!(!<Delegators<T>>::contains_key(who), Error::<T>::NotAllowed);
 
-		// payee account cannot be same as delegatee
+		// payee account cannot be same as `delegate`
 		ensure!(reward_destination != who, Error::<T>::InvalidRewardDestination);
 
 		// make sure they are not already a direct staker or they are migrating.
 		ensure!(
-			T::CoreStaking::status(who).is_err() || <DelegateeMigration<T>>::contains_key(who),
+			T::CoreStaking::status(who).is_err() || <DelegateMigration<T>>::contains_key(who),
 			Error::<T>::AlreadyStaker
 		);
 
-		// already checked delegatees exist
-		<Delegatees<T>>::insert(
+		// already checked that `delegate` exist
+		<Delegates<T>>::insert(
 			who,
 			DelegationLedger {
 				payee: reward_destination.clone(),
@@ -272,13 +271,13 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 	}
 
 	/// Transfers funds from current staked account to `proxy_delegator`. Current staked account
-	/// becomes a delegatee with `proxy_delegator` delegating stakes to it.
+	/// becomes a `delegate` with `proxy_delegator` delegating stakes to it.
 	fn migrate_accept_delegations(
-		new_delegatee: &Self::AccountId,
+		new_delegate: &Self::AccountId,
 		proxy_delegator: &Self::AccountId,
 		payee: &Self::AccountId,
 	) -> DispatchResult {
-		ensure!(new_delegatee != proxy_delegator, Error::<T>::InvalidDelegation);
+		ensure!(new_delegate != proxy_delegator, Error::<T>::InvalidDelegation);
 
 		// ensure proxy delegator has at least minimum balance to keep the account alive.
 		ensure!(
@@ -291,103 +290,97 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		);
 
 		// ensure staker is a nominator
-		let status = T::CoreStaking::status(new_delegatee)?;
+		let status = T::CoreStaking::status(new_delegate)?;
 		match status {
 			StakerStatus::Nominator(_) => (),
 			_ => return Err(Error::<T>::InvalidDelegation.into()),
 		}
 
-		<DelegateeMigration<T>>::insert(&new_delegatee, &proxy_delegator);
-		let stake = T::CoreStaking::stake(new_delegatee)?;
+		<DelegateMigration<T>>::insert(&new_delegate, &proxy_delegator);
+		let stake = T::CoreStaking::stake(new_delegate)?;
 
 		// unlock funds from staker
-		T::CoreStaking::release_all(new_delegatee);
+		T::CoreStaking::release_all(new_delegate);
 
 		// try transferring the staked amount. This should never fail but if it does, it indicates
 		// bad state and we abort.
-		T::Currency::transfer(
-			new_delegatee,
-			proxy_delegator,
-			stake.total,
-			Preservation::Expendable,
-		)
-		.map_err(|_| Error::<T>::BadState)?;
+		T::Currency::transfer(new_delegate, proxy_delegator, stake.total, Preservation::Expendable)
+			.map_err(|_| Error::<T>::BadState)?;
 
 		// delegate from new delegator to staker.
 		// todo(ank4n) : inline this fn and propagate payee to core staking..
-		Self::accept_delegations(new_delegatee, payee)?;
+		Self::accept_delegations(new_delegate, payee)?;
 
-		Self::delegate(proxy_delegator, new_delegatee, stake.total)?;
-		Self::bond_all(new_delegatee)
+		Self::delegate(proxy_delegator, new_delegate, stake.total)?;
+		Self::bond_all(new_delegate)
 	}
 
-	fn block_delegations(delegatee: &Self::AccountId) -> DispatchResult {
-		let mut register = <Delegatees<T>>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
+	fn block_delegations(delegate: &Self::AccountId) -> DispatchResult {
+		let mut register = <Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
 		register.blocked = true;
-		<Delegatees<T>>::insert(delegatee, register);
+		<Delegates<T>>::insert(delegate, register);
 
 		Ok(())
 	}
 
-	fn unblock_delegations(delegatee: &Self::AccountId) -> DispatchResult {
-		let mut register = <Delegatees<T>>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
+	fn unblock_delegations(delegate: &Self::AccountId) -> DispatchResult {
+		let mut register = <Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
 		register.blocked = false;
-		<Delegatees<T>>::insert(delegatee, register);
+		<Delegates<T>>::insert(delegate, register);
 
 		Ok(())
 	}
 
-	fn kill_delegatee(_delegatee: &Self::AccountId) -> DispatchResult {
+	fn kill_delegate(_delegate: &Self::AccountId) -> DispatchResult {
 		todo!()
 	}
 
 	fn bond_all(who: &Self::AccountId) -> DispatchResult {
-		let delegatee = <Delegatees<T>>::get(who).ok_or(Error::<T>::NotDelegatee)?;
-		let amount_to_bond = delegatee.unbonded_balance();
+		let delegate = <Delegates<T>>::get(who).ok_or(Error::<T>::NotDelegate)?;
+		let amount_to_bond = delegate.unbonded_balance();
 
 		match T::CoreStaking::stake(who) {
 			// already bonded
 			Ok(_) => T::CoreStaking::bond_extra(who, amount_to_bond),
 			// first bond
-			Err(_) => T::CoreStaking::bond(who, amount_to_bond, &delegatee.payee),
+			Err(_) => T::CoreStaking::bond(who, amount_to_bond, &delegate.payee),
 		}
 	}
 
 	#[transactional]
 	fn withdraw(
-		delegatee: &Self::AccountId,
+		delegate: &Self::AccountId,
 		delegator: &Self::AccountId,
 		value: Self::Balance,
 		num_slashing_spans: u32,
 	) -> DispatchResult {
 		// check how much is already unbonded
-		let delegation_register =
-			<Delegatees<T>>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
+		let delegation_register = <Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
 		let unbonded_balance = delegation_register.unbonded_balance();
 
 		if unbonded_balance < value {
 			// fixme(ank4n) handle killing of stash
 			let amount_to_withdraw = value.saturating_sub(unbonded_balance);
 			let _stash_killed: bool =
-				T::CoreStaking::withdraw_exact(delegatee, amount_to_withdraw, num_slashing_spans)
+				T::CoreStaking::withdraw_exact(delegate, amount_to_withdraw, num_slashing_spans)
 					.map_err(|_| Error::<T>::WithdrawFailed)?;
 		}
 
-		Self::delegation_withdraw(delegator, delegatee, value)
+		Self::delegation_withdraw(delegator, delegate, value)
 	}
 
 	fn apply_slash(
-		delegatee: &Self::AccountId,
+		delegate: &Self::AccountId,
 		delegator: &Self::AccountId,
 		value: Self::Balance,
 		maybe_reporter: Option<Self::AccountId>,
 	) -> DispatchResult {
 		let mut delegation_register =
-			<Delegatees<T>>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
-		let (assigned_delegatee, delegate_balance) =
+			<Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
+		let (assigned_delegate, delegate_balance) =
 			<Delegators<T>>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
 
-		ensure!(&assigned_delegatee == delegatee, Error::<T>::NotDelegatee);
+		ensure!(&assigned_delegate == delegate, Error::<T>::NotDelegate);
 		ensure!(delegate_balance >= value, Error::<T>::NotEnoughFunds);
 
 		let (mut credit, _missing) =
@@ -395,7 +388,7 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		let actual_slash = credit.peek();
 		// remove the slashed amount
 		delegation_register.pending_slash.saturating_reduce(actual_slash);
-		<Delegatees<T>>::insert(delegatee, delegation_register);
+		<Delegates<T>>::insert(delegate, delegation_register);
 
 		if let Some(reporter) = maybe_reporter {
 			let reward_payout: BalanceOf<T> =
@@ -413,21 +406,21 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 	/// Move funds from proxy delegator to actual delegator.
 	#[transactional]
 	fn migrate_delegator(
-		delegatee: &Self::AccountId,
+		delegate: &Self::AccountId,
 		new_delegator: &Self::AccountId,
 		value: Self::Balance,
 	) -> DispatchResult {
 		ensure!(value >= T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
-		// make sure new delegator is not an existing delegator or a delegatee
-		ensure!(!<Delegatees<T>>::contains_key(new_delegator), Error::<T>::NotAllowed);
+		// make sure new delegator is not an existing delegator or a delegate
+		ensure!(!<Delegates<T>>::contains_key(new_delegator), Error::<T>::NotAllowed);
 		ensure!(!<Delegators<T>>::contains_key(new_delegator), Error::<T>::NotAllowed);
 		// ensure we are migrating
 		let proxy_delegator =
-			<DelegateeMigration<T>>::get(delegatee).ok_or(Error::<T>::NotMigrating)?;
+			<DelegateMigration<T>>::get(delegate).ok_or(Error::<T>::NotMigrating)?;
 		// proxy delegator must exist
-		let (assigned_delegatee, delegate_balance) =
+		let (assigned_delegate, delegate_balance) =
 			<Delegators<T>>::get(&proxy_delegator).ok_or(Error::<T>::BadState)?;
-		ensure!(assigned_delegatee == *delegatee, Error::<T>::BadState);
+		ensure!(assigned_delegate == *delegate, Error::<T>::BadState);
 
 		// make sure proxy delegator has enough balance to support this migration.
 		ensure!(delegate_balance >= value, Error::<T>::NotEnoughFunds);
@@ -438,10 +431,10 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		// if all funds are migrated out of proxy delegator, clean up.
 		if updated_delegate_balance == BalanceOf::<T>::zero() {
 			<Delegators<T>>::remove(&proxy_delegator);
-			<DelegateeMigration<T>>::remove(delegatee);
+			<DelegateMigration<T>>::remove(delegate);
 		} else {
 			// else update proxy delegator
-			<Delegators<T>>::insert(&proxy_delegator, (delegatee, updated_delegate_balance));
+			<Delegators<T>>::insert(&proxy_delegator, (delegate, updated_delegate_balance));
 		}
 
 		let released = T::Currency::release(
@@ -458,7 +451,7 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 			.map_err(|_| Error::<T>::BadState)?;
 
 		// add the above removed delegation to `new_delegator`.
-		<Delegators<T>>::insert(new_delegator, (delegatee, value));
+		<Delegators<T>>::insert(new_delegator, (delegate, value));
 		// hold the funds again in the new delegator account.
 		T::Currency::hold(&HoldReason::Delegating.into(), &new_delegator, value)?;
 
@@ -467,42 +460,41 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 
 	fn delegate(
 		delegator: &Self::AccountId,
-		delegatee: &Self::AccountId,
+		delegate: &Self::AccountId,
 		value: Self::Balance,
 	) -> DispatchResult {
 		let delegator_balance =
 			T::Currency::reducible_balance(&delegator, Preservation::Expendable, Fortitude::Polite);
 		ensure!(value >= T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
 		ensure!(delegator_balance >= value, Error::<T>::NotEnoughFunds);
-		ensure!(delegatee != delegator, Error::<T>::InvalidDelegation);
+		ensure!(delegate != delegator, Error::<T>::InvalidDelegation);
 
 		let mut delegation_register =
-			<Delegatees<T>>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
+			<Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
 		ensure!(!delegation_register.blocked, Error::<T>::DelegationsBlocked);
 
-		// A delegatee cannot delegate.
-		if <Delegatees<T>>::contains_key(delegator) {
+		// A delegate cannot delegate.
+		if <Delegates<T>>::contains_key(delegator) {
 			return Err(Error::<T>::InvalidDelegation.into())
 		}
 
-		let new_delegation_amount = if let Some((current_delegatee, current_delegation)) =
-			<Delegators<T>>::get(delegator)
-		{
-			ensure!(&current_delegatee == delegatee, Error::<T>::InvalidDelegation);
-			value.saturating_add(current_delegation)
-		} else {
-			value
-		};
+		let new_delegation_amount =
+			if let Some((current_delegate, current_delegation)) = <Delegators<T>>::get(delegator) {
+				ensure!(&current_delegate == delegate, Error::<T>::InvalidDelegation);
+				value.saturating_add(current_delegation)
+			} else {
+				value
+			};
 
 		delegation_register.total_delegated.saturating_accrue(value);
 
-		<Delegators<T>>::insert(delegator, (delegatee, new_delegation_amount));
-		<Delegatees<T>>::insert(delegatee, delegation_register);
+		<Delegators<T>>::insert(delegator, (delegate, new_delegation_amount));
+		<Delegates<T>>::insert(delegate, delegation_register);
 
 		T::Currency::hold(&HoldReason::Delegating.into(), &delegator, value)?;
 
 		Self::deposit_event(Event::<T>::Delegated {
-			delegatee: delegatee.clone(),
+			delegate: delegate.clone(),
 			delegator: delegator.clone(),
 			amount: value,
 		});
@@ -515,8 +507,8 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
-		<Delegatees<T>>::get(who)
-			.map(|delegatee| delegatee.delegated_balance())
+		<Delegates<T>>::get(who)
+			.map(|delegate| delegate.delegated_balance())
 			.unwrap_or_default()
 	}
 
@@ -524,10 +516,10 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 		who: &Self::AccountId,
 		reward_destination: Option<Self::AccountId>,
 	) -> bool {
-		let maybe_register = <Delegatees<T>>::get(who);
+		let maybe_register = <Delegates<T>>::get(who);
 
 		if maybe_register.is_none() {
-			// no restrictions for non delegatees.
+			// no restrictions for non delegates.
 			return false;
 		}
 
@@ -539,34 +531,34 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 		let register = maybe_register.expect("checked above; qed");
 		let reward_acc = reward_destination.expect("checked above; qed");
 
-		// restrict if reward account is not what delegatee registered.
+		// restrict if reward account is not what delegate registered.
 		register.payee != reward_acc
 	}
 
-	fn is_delegatee(who: &Self::AccountId) -> bool {
-		Self::is_delegatee(who)
+	fn is_delegate(who: &Self::AccountId) -> bool {
+		Self::is_delegate(who)
 	}
 
 	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
-		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
+		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
 
-		// delegation register should exist since `who` is a delegatee.
+		// delegation register should exist since `who` is a delegate.
 		let delegation_register =
-			<Delegatees<T>>::get(who).defensive_ok_or(Error::<T>::BadState)?;
+			<Delegates<T>>::get(who).defensive_ok_or(Error::<T>::BadState)?;
 
 		ensure!(delegation_register.total_delegated >= amount, Error::<T>::NotEnoughFunds);
 		ensure!(delegation_register.pending_slash <= amount, Error::<T>::UnappliedSlash);
 		let updated_register = DelegationLedger { hold: amount, ..delegation_register };
-		<Delegatees<T>>::insert(who, updated_register);
+		<Delegates<T>>::insert(who, updated_register);
 
 		Ok(())
 	}
 
 	fn report_slash(who: &Self::AccountId, slash: Self::Balance) {
-		<Delegatees<T>>::mutate(who, |maybe_register| match maybe_register {
+		<Delegates<T>>::mutate(who, |maybe_register| match maybe_register {
 			Some(register) => register.pending_slash.saturating_accrue(slash),
 			None => {
-				defensive!("should not be called on non-delegatee");
+				defensive!("should not be called on non-delegate");
 			},
 		});
 	}
@@ -574,8 +566,8 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 
 /// StakingInterface implementation with delegation support.
 ///
-/// Only supports Nominators via Delegated Bonds. It is possible for a nominator to migrate to a
-/// Delegatee.
+/// Only supports Nominators via Delegated Bonds. It is possible for a nominator to migrate and
+/// become a `Delegate`.
 impl<T: Config> StakingInterface for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
@@ -605,12 +597,12 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	fn stake(who: &Self::AccountId) -> Result<Stake<Self::Balance>, DispatchError> {
-		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
+		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
 		return T::CoreStaking::stake(who);
 	}
 
 	fn total_stake(who: &Self::AccountId) -> Result<Self::Balance, DispatchError> {
-		if Self::is_delegatee(who) {
+		if Self::is_delegate(who) {
 			return T::CoreStaking::total_stake(who);
 		}
 
@@ -632,7 +624,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	fn fully_unbond(who: &Self::AccountId) -> DispatchResult {
-		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
+		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
 		return T::CoreStaking::fully_unbond(who);
 	}
 
@@ -642,8 +634,8 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		payee: &Self::AccountId,
 	) -> DispatchResult {
 		// ensure who is not already staked
-		ensure!(T::CoreStaking::status(who).is_err(), Error::<T>::NotDelegatee);
-		let delegation_register = <Delegatees<T>>::get(who).ok_or(Error::<T>::NotDelegatee)?;
+		ensure!(T::CoreStaking::status(who).is_err(), Error::<T>::NotDelegate);
+		let delegation_register = <Delegates<T>>::get(who).ok_or(Error::<T>::NotDelegate)?;
 
 		ensure!(delegation_register.unbonded_balance() >= value, Error::<T>::NotEnoughFunds);
 		ensure!(delegation_register.payee == *payee, Error::<T>::InvalidRewardDestination);
@@ -652,30 +644,30 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	fn nominate(who: &Self::AccountId, validators: Vec<Self::AccountId>) -> DispatchResult {
-		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
+		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
 		return T::CoreStaking::nominate(who, validators);
 	}
 
 	fn chill(who: &Self::AccountId) -> DispatchResult {
-		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
+		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
 		return T::CoreStaking::chill(who);
 	}
 
 	fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult {
-		let delegation_register = <Delegatees<T>>::get(who).ok_or(Error::<T>::NotDelegatee)?;
+		let delegation_register = <Delegates<T>>::get(who).ok_or(Error::<T>::NotDelegate)?;
 		ensure!(delegation_register.unbonded_balance() >= extra, Error::<T>::NotEnoughFunds);
 
 		T::CoreStaking::bond_extra(who, extra)
 	}
 
 	fn unbond(stash: &Self::AccountId, value: Self::Balance) -> DispatchResult {
-		let delegation_register = <Delegatees<T>>::get(stash).ok_or(Error::<T>::NotDelegatee)?;
+		let delegation_register = <Delegates<T>>::get(stash).ok_or(Error::<T>::NotDelegate)?;
 		ensure!(delegation_register.hold >= value, Error::<T>::NotEnoughFunds);
 
 		T::CoreStaking::unbond(stash, value)
 	}
 
-	/// Not supported, call [`Delegatee::withdraw`]
+	/// Not supported, call [`Delegate::withdraw`]
 	fn withdraw_unbonded(
 		_stash: Self::AccountId,
 		_num_slashing_spans: u32,
@@ -685,7 +677,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		Err(Error::<T>::NotSupported.into())
 	}
 
-	/// Not supported, call [`Delegatee::withdraw`]
+	/// Not supported, call [`Delegate::withdraw`]
 	fn withdraw_exact(
 		_stash: &Self::AccountId,
 		_amount: Self::Balance,
@@ -716,7 +708,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	fn status(who: &Self::AccountId) -> Result<StakerStatus<Self::AccountId>, DispatchError> {
-		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
+		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
 		T::CoreStaking::status(who)
 	}
 
@@ -757,34 +749,34 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 }
 impl<T: Config> Pallet<T> {
-	fn is_delegatee(who: &T::AccountId) -> bool {
-		<Delegatees<T>>::contains_key(who)
+	fn is_delegate(who: &T::AccountId) -> bool {
+		<Delegates<T>>::contains_key(who)
 	}
 
 	fn is_delegator(who: &T::AccountId) -> bool {
 		<Delegators<T>>::contains_key(who)
 	}
 
-	fn is_migrating(delegatee: &T::AccountId) -> bool {
-		<DelegateeMigration<T>>::contains_key(delegatee)
+	fn is_migrating(delegate: &T::AccountId) -> bool {
+		<DelegateMigration<T>>::contains_key(delegate)
 	}
 
 	fn delegation_withdraw(
 		delegator: &T::AccountId,
-		delegatee: &T::AccountId,
+		delegate: &T::AccountId,
 		value: BalanceOf<T>,
 	) -> DispatchResult {
 		let mut delegation_register =
-			<Delegatees<T>>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
+			<Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
 		ensure!(delegation_register.unbonded_balance() >= value, Error::<T>::BadState);
 
 		delegation_register.total_delegated.saturating_reduce(value);
-		<Delegatees<T>>::insert(delegatee, delegation_register);
+		<Delegates<T>>::insert(delegate, delegation_register);
 
-		let (assigned_delegatee, delegate_balance) =
+		let (assigned_delegate, delegate_balance) =
 			<Delegators<T>>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
-		// delegator should already be delegating to delegatee
-		ensure!(&assigned_delegatee == delegatee, Error::<T>::NotDelegatee);
+		// delegator should already be delegating to `delegate`
+		ensure!(&assigned_delegate == delegate, Error::<T>::NotDelegate);
 		ensure!(delegate_balance >= value, Error::<T>::NotEnoughFunds);
 		let updated_delegate_balance = delegate_balance.saturating_sub(value);
 
@@ -792,7 +784,7 @@ impl<T: Config> Pallet<T> {
 		if updated_delegate_balance == BalanceOf::<T>::zero() {
 			<Delegators<T>>::remove(delegator);
 		} else {
-			<Delegators<T>>::insert(delegator, (delegatee, updated_delegate_balance));
+			<Delegators<T>>::insert(delegator, (delegate, updated_delegate_balance));
 		}
 
 		let released = T::Currency::release(
@@ -804,7 +796,7 @@ impl<T: Config> Pallet<T> {
 
 		defensive_assert!(released == value, "hold should have been released fully");
 		Self::deposit_event(Event::<T>::Withdrawn {
-			delegatee: delegatee.clone(),
+			delegate: delegate.clone(),
 			delegator: delegator.clone(),
 			amount: value,
 		});
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index d1296da226231..82c31c66038d6 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -238,27 +238,27 @@ pub(crate) fn fund(who: &AccountId, amount: Balance) {
 /// `delegate_amount` is incremented by the amount `increment` starting with `base_delegate_amount`
 /// from lower index to higher index of delegators.
 pub(crate) fn setup_delegation_stake(
-	delegatee: AccountId,
+	delegate: AccountId,
 	reward_acc: AccountId,
 	delegators: Vec<AccountId>,
 	base_delegate_amount: Balance,
 	increment: Balance,
 ) -> Balance {
-	fund(&delegatee, 100);
-	assert_ok!(DelegatedStaking::accept_delegations(&delegatee, &reward_acc));
+	fund(&delegate, 100);
+	assert_ok!(DelegatedStaking::accept_delegations(&delegate, &reward_acc));
 	let mut delegated_amount: Balance = 0;
 	for (index, delegator) in delegators.iter().enumerate() {
 		let amount_to_delegate = base_delegate_amount + increment * index as Balance;
 		delegated_amount += amount_to_delegate;
 
 		fund(delegator, amount_to_delegate + ExistentialDeposit::get());
-		assert_ok!(DelegatedStaking::delegate(delegator, &delegatee, amount_to_delegate));
-		assert_ok!(DelegatedStaking::bond_all(&delegatee));
+		assert_ok!(DelegatedStaking::delegate(delegator, &delegate, amount_to_delegate));
+		assert_ok!(DelegatedStaking::bond_all(&delegate));
 	}
 
 	// sanity checks
-	assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), delegated_amount);
-	assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
+	assert_eq!(DelegatedStaking::stakeable_balance(&delegate), delegated_amount);
+	assert_eq!(DelegatedStaking::unbonded_balance(&delegate), 0);
 
 	delegated_amount
 }
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 6201d3f30ca22..41478fa0ec6e7 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -24,43 +24,43 @@ use pallet_staking::Error as StakingError;
 use sp_staking::delegation::StakingDelegationSupport;
 
 #[test]
-fn create_a_delegatee_with_first_delegator() {
+fn create_a_delegate_with_first_delegator() {
 	ExtBuilder::default().build_and_execute(|| {
-		let delegatee: AccountId = 200;
+		let delegate: AccountId = 200;
 		let reward_account: AccountId = 201;
 		let delegator: AccountId = 202;
 
 		// set intention to accept delegation.
-		fund(&delegatee, 1000);
-		assert_ok!(DelegatedStaking::accept_delegations(&delegatee, &reward_account));
+		fund(&delegate, 1000);
+		assert_ok!(DelegatedStaking::accept_delegations(&delegate, &reward_account));
 
 		// delegate to this account
 		fund(&delegator, 1000);
-		assert_ok!(DelegatedStaking::delegate(&delegator, &delegatee, 100));
+		assert_ok!(DelegatedStaking::delegate(&delegator, &delegate, 100));
 
 		// verify
-		assert!(DelegatedStaking::is_delegatee(&delegatee));
-		assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100);
+		assert!(DelegatedStaking::is_delegate(&delegate));
+		assert_eq!(DelegatedStaking::stakeable_balance(&delegate), 100);
 		assert_eq!(Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator), 100);
 	});
 }
 
 #[test]
-fn cannot_become_delegatee() {
+fn cannot_become_delegate() {
 	ExtBuilder::default().build_and_execute(|| {
-		// cannot set reward account same as delegatee account
+		// cannot set reward account same as delegate account
 		assert_noop!(
 			DelegatedStaking::accept_delegations(&100, &100),
 			Error::<T>::InvalidRewardDestination
 		);
 
-		// an existing validator cannot become delegatee
+		// an existing validator cannot become delegate
 		assert_noop!(
 			DelegatedStaking::accept_delegations(&mock::GENESIS_VALIDATOR, &100),
 			Error::<T>::AlreadyStaker
 		);
 
-		// an existing nominator cannot become delegatee
+		// an existing nominator cannot become delegate
 		assert_noop!(
 			DelegatedStaking::accept_delegations(&mock::GENESIS_NOMINATOR_ONE, &100),
 			Error::<T>::AlreadyStaker
@@ -75,28 +75,28 @@ fn cannot_become_delegatee() {
 #[test]
 fn create_multiple_delegators() {
 	ExtBuilder::default().build_and_execute(|| {
-		let delegatee: AccountId = 200;
+		let delegate: AccountId = 200;
 		let reward_account: AccountId = 201;
 
-		// stakeable balance is 0 for non delegatee
-		fund(&delegatee, 1000);
-		assert!(!DelegatedStaking::is_delegatee(&delegatee));
-		assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 0);
+		// stakeable balance is 0 for non delegate
+		fund(&delegate, 1000);
+		assert!(!DelegatedStaking::is_delegate(&delegate));
+		assert_eq!(DelegatedStaking::stakeable_balance(&delegate), 0);
 
 		// set intention to accept delegation.
-		assert_ok!(DelegatedStaking::accept_delegations(&delegatee, &reward_account));
+		assert_ok!(DelegatedStaking::accept_delegations(&delegate, &reward_account));
 
 		// create 100 delegators
 		for i in 202..302 {
 			fund(&i, 100 + ExistentialDeposit::get());
-			assert_ok!(DelegatedStaking::delegate(&i, &delegatee, 100));
-			// Balance of 100 held on delegator account for delegating to the delegatee.
+			assert_ok!(DelegatedStaking::delegate(&i, &delegate, 100));
+			// Balance of 100 held on delegator account for delegating to the delegate.
 			assert_eq!(Balances::balance_on_hold(&HoldReason::Delegating.into(), &i), 100);
 		}
 
 		// verify
-		assert!(DelegatedStaking::is_delegatee(&delegatee));
-		assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100 * 100);
+		assert!(DelegatedStaking::is_delegate(&delegate));
+		assert_eq!(DelegatedStaking::stakeable_balance(&delegate), 100 * 100);
 	});
 }
 
@@ -104,40 +104,40 @@ fn create_multiple_delegators() {
 fn delegate_restrictions() {
 	// Similar to creating a nomination pool
 	ExtBuilder::default().build_and_execute(|| {
-		let delegatee_one = 200;
+		let delegate_one = 200;
 		let delegator_one = 210;
-		fund(&delegatee_one, 100);
-		assert_ok!(DelegatedStaking::accept_delegations(&delegatee_one, &(delegatee_one + 1)));
+		fund(&delegate_one, 100);
+		assert_ok!(DelegatedStaking::accept_delegations(&delegate_one, &(delegate_one + 1)));
 		fund(&delegator_one, 200);
-		assert_ok!(DelegatedStaking::delegate(&delegator_one, &delegatee_one, 100));
+		assert_ok!(DelegatedStaking::delegate(&delegator_one, &delegate_one, 100));
 
-		let delegatee_two = 300;
+		let delegate_two = 300;
 		let delegator_two = 310;
-		fund(&delegatee_two, 100);
-		assert_ok!(DelegatedStaking::accept_delegations(&delegatee_two, &(delegatee_two + 1)));
+		fund(&delegate_two, 100);
+		assert_ok!(DelegatedStaking::accept_delegations(&delegate_two, &(delegate_two + 1)));
 		fund(&delegator_two, 200);
-		assert_ok!(DelegatedStaking::delegate(&delegator_two, &delegatee_two, 100));
+		assert_ok!(DelegatedStaking::delegate(&delegator_two, &delegate_two, 100));
 
-		// delegatee one tries to delegate to delegatee 2
+		// delegate one tries to delegate to delegate 2
 		assert_noop!(
-			DelegatedStaking::delegate(&delegatee_one, &delegatee_two, 10),
+			DelegatedStaking::delegate(&delegate_one, &delegate_two, 10),
 			Error::<T>::InvalidDelegation
 		);
 
-		// delegatee one tries to delegate to a delegator
+		// delegate one tries to delegate to a delegator
 		assert_noop!(
-			DelegatedStaking::delegate(&delegatee_one, &delegator_one, 10),
-			Error::<T>::NotDelegatee
+			DelegatedStaking::delegate(&delegate_one, &delegator_one, 10),
+			Error::<T>::NotDelegate
 		);
 		assert_noop!(
-			DelegatedStaking::delegate(&delegatee_one, &delegator_two, 10),
-			Error::<T>::NotDelegatee
+			DelegatedStaking::delegate(&delegate_one, &delegator_two, 10),
+			Error::<T>::NotDelegate
 		);
 
-		// delegator one tries to delegate to delegatee 2 as well (it already delegates to delegatee
+		// delegator one tries to delegate to delegate 2 as well (it already delegates to delegate
 		// 1)
 		assert_noop!(
-			DelegatedStaking::delegate(&delegator_one, &delegatee_two, 10),
+			DelegatedStaking::delegate(&delegator_one, &delegate_two, 10),
 			Error::<T>::InvalidDelegation
 		);
 	});
@@ -157,37 +157,37 @@ mod integration {
 	#[test]
 	fn bond() {
 		ExtBuilder::default().build_and_execute(|| {
-			let delegatee: AccountId = 99;
+			let delegate: AccountId = 99;
 			let reward_acc: AccountId = 100;
-			assert_eq!(Staking::status(&delegatee), Err(StakingError::<T>::NotStash.into()));
+			assert_eq!(Staking::status(&delegate), Err(StakingError::<T>::NotStash.into()));
 
-			// set intention to become a delegatee
-			fund(&delegatee, 100);
-			assert_ok!(DelegatedStaking::accept_delegations(&delegatee, &reward_acc));
-			assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 0);
+			// set intention to become a delegate
+			fund(&delegate, 100);
+			assert_ok!(DelegatedStaking::accept_delegations(&delegate, &reward_acc));
+			assert_eq!(DelegatedStaking::stakeable_balance(&delegate), 0);
 
 			let mut delegated_balance: Balance = 0;
 			// set some delegations
 			for delegator in 200..250 {
 				fund(&delegator, 200);
-				assert_ok!(DelegatedStaking::delegate(&delegator, &delegatee, 100));
+				assert_ok!(DelegatedStaking::delegate(&delegator, &delegate, 100));
 				delegated_balance += 100;
 				assert_eq!(
 					Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator),
 					100
 				);
 
-				assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), delegated_balance);
+				assert_eq!(DelegatedStaking::stakeable_balance(&delegate), delegated_balance);
 
 				// unbonded balance is the newly delegated 100
-				assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 100);
-				assert_ok!(DelegatedStaking::bond_all(&delegatee));
+				assert_eq!(DelegatedStaking::unbonded_balance(&delegate), 100);
+				assert_ok!(DelegatedStaking::bond_all(&delegate));
 				// after bond, unbonded balance is 0
-				assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
+				assert_eq!(DelegatedStaking::unbonded_balance(&delegate), 0);
 			}
 
 			assert_eq!(
-				Staking::stake(&delegatee).unwrap(),
+				Staking::stake(&delegate).unwrap(),
 				Stake { total: 50 * 100, active: 50 * 100 }
 			)
 		});
@@ -198,89 +198,89 @@ mod integration {
 		ExtBuilder::default().build_and_execute(|| {
 			// initial era
 			start_era(1);
-			let delegatee: AccountId = 200;
+			let delegate: AccountId = 200;
 			let reward_acc: AccountId = 201;
 			let delegators: Vec<AccountId> = (301..=350).collect();
 			let total_staked =
-				setup_delegation_stake(delegatee, reward_acc, delegators.clone(), 10, 10);
+				setup_delegation_stake(delegate, reward_acc, delegators.clone(), 10, 10);
 
 			// lets go to a new era
 			start_era(2);
 
-			assert!(eq_stake(delegatee, total_staked, total_staked));
+			assert!(eq_stake(delegate, total_staked, total_staked));
 			// Withdrawing without unbonding would fail.
 			assert_noop!(
-				DelegatedStaking::withdraw(&delegatee, &300, 50, 0),
+				DelegatedStaking::withdraw(&delegate, &300, 50, 0),
 				Error::<T>::WithdrawFailed
 			);
-			// assert_noop!(DelegatedStaking::withdraw(&delegatee, &200, 50, 0),
+			// assert_noop!(DelegatedStaking::withdraw(&delegate, &200, 50, 0),
 			// Error::<T>::NotAllowed); active and total stake remains same
-			assert!(eq_stake(delegatee, total_staked, total_staked));
+			assert!(eq_stake(delegate, total_staked, total_staked));
 
 			// 305 wants to unbond 50 in era 2, withdrawable in era 5.
-			assert_ok!(DelegatedStaking::unbond(&delegatee, 50));
+			assert_ok!(DelegatedStaking::unbond(&delegate, 50));
 			// 310 wants to unbond 100 in era 3, withdrawable in era 6.
 			start_era(3);
-			assert_ok!(DelegatedStaking::unbond(&delegatee, 100));
+			assert_ok!(DelegatedStaking::unbond(&delegate, 100));
 			// 320 wants to unbond 200 in era 4, withdrawable in era 7.
 			start_era(4);
-			assert_ok!(DelegatedStaking::unbond(&delegatee, 200));
+			assert_ok!(DelegatedStaking::unbond(&delegate, 200));
 
 			// active stake is now reduced..
 			let expected_active = total_staked - (50 + 100 + 200);
-			assert!(eq_stake(delegatee, total_staked, expected_active));
+			assert!(eq_stake(delegate, total_staked, expected_active));
 
 			// nothing to withdraw at era 4
 			assert_noop!(
-				DelegatedStaking::withdraw(&delegatee, &305, 50, 0),
+				DelegatedStaking::withdraw(&delegate, &305, 50, 0),
 				Error::<T>::WithdrawFailed
 			);
 
-			assert!(eq_stake(delegatee, total_staked, expected_active));
-			assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
+			assert!(eq_stake(delegate, total_staked, expected_active));
+			assert_eq!(DelegatedStaking::unbonded_balance(&delegate), 0);
 			// full amount is still delegated
-			assert_eq!(DelegatedStaking::delegated_balance(&delegatee), total_staked);
+			assert_eq!(DelegatedStaking::delegated_balance(&delegate), total_staked);
 
 			start_era(5);
 			// at era 5, 50 tokens are withdrawable, cannot withdraw more.
 			assert_noop!(
-				DelegatedStaking::withdraw(&delegatee, &305, 51, 0),
+				DelegatedStaking::withdraw(&delegate, &305, 51, 0),
 				Error::<T>::WithdrawFailed
 			);
 			// less is possible
-			assert_ok!(DelegatedStaking::withdraw(&delegatee, &305, 30, 0));
-			assert_ok!(DelegatedStaking::withdraw(&delegatee, &305, 20, 0));
+			assert_ok!(DelegatedStaking::withdraw(&delegate, &305, 30, 0));
+			assert_ok!(DelegatedStaking::withdraw(&delegate, &305, 20, 0));
 
 			// Lets go to future era where everything is unbonded. Withdrawable amount: 100 + 200
 			start_era(7);
 			// 305 has no more amount delegated so it cannot withdraw.
 			assert_noop!(
-				DelegatedStaking::withdraw(&delegatee, &305, 5, 0),
+				DelegatedStaking::withdraw(&delegate, &305, 5, 0),
 				Error::<T>::NotDelegator
 			);
 			// 309 is an active delegator but has total delegation of 90, so it cannot withdraw more
 			// than that.
 			assert_noop!(
-				DelegatedStaking::withdraw(&delegatee, &309, 91, 0),
+				DelegatedStaking::withdraw(&delegate, &309, 91, 0),
 				Error::<T>::NotEnoughFunds
 			);
 			// 310 cannot withdraw more than delegated funds.
 			assert_noop!(
-				DelegatedStaking::withdraw(&delegatee, &310, 101, 0),
+				DelegatedStaking::withdraw(&delegate, &310, 101, 0),
 				Error::<T>::NotEnoughFunds
 			);
 			// but can withdraw all its delegation amount.
-			assert_ok!(DelegatedStaking::withdraw(&delegatee, &310, 100, 0));
+			assert_ok!(DelegatedStaking::withdraw(&delegate, &310, 100, 0));
 			// 320 can withdraw all its delegation amount.
-			assert_ok!(DelegatedStaking::withdraw(&delegatee, &320, 200, 0));
+			assert_ok!(DelegatedStaking::withdraw(&delegate, &320, 200, 0));
 
 			// cannot withdraw anything more..
 			assert_noop!(
-				DelegatedStaking::withdraw(&delegatee, &301, 1, 0),
+				DelegatedStaking::withdraw(&delegate, &301, 1, 0),
 				Error::<T>::WithdrawFailed
 			);
 			assert_noop!(
-				DelegatedStaking::withdraw(&delegatee, &350, 1, 0),
+				DelegatedStaking::withdraw(&delegate, &350, 1, 0),
 				Error::<T>::WithdrawFailed
 			);
 		});
@@ -289,25 +289,25 @@ mod integration {
 	#[test]
 	fn withdraw_happens_with_unbonded_balance_first() {
 		ExtBuilder::default().build_and_execute(|| {
-			let delegatee = 200;
-			setup_delegation_stake(delegatee, 201, (300..350).collect(), 100, 0);
+			let delegate = 200;
+			setup_delegation_stake(delegate, 201, (300..350).collect(), 100, 0);
 
 			// verify withdraw not possible yet
 			assert_noop!(
-				DelegatedStaking::withdraw(&delegatee, &300, 100, 0),
+				DelegatedStaking::withdraw(&delegate, &300, 100, 0),
 				Error::<T>::WithdrawFailed
 			);
 
 			// add new delegation that is not staked
 			fund(&300, 1000);
-			assert_ok!(DelegatedStaking::delegate(&300, &delegatee, 100));
+			assert_ok!(DelegatedStaking::delegate(&300, &delegate, 100));
 
 			// verify unbonded balance
-			assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 100);
+			assert_eq!(DelegatedStaking::unbonded_balance(&delegate), 100);
 
 			// withdraw works now without unbonding
-			assert_ok!(DelegatedStaking::withdraw(&delegatee, &300, 100, 0));
-			assert_eq!(DelegatedStaking::unbonded_balance(&delegatee), 0);
+			assert_ok!(DelegatedStaking::withdraw(&delegate, &300, 100, 0));
+			assert_eq!(DelegatedStaking::unbonded_balance(&delegate), 0);
 		});
 	}
 
@@ -318,7 +318,7 @@ mod integration {
 			fund(&200, 1000);
 			let balance_200 = Balances::free_balance(200);
 
-			// delegatee cannot be reward destination
+			// `delegate` account cannot be reward destination
 			assert_noop!(
 				DelegatedStaking::accept_delegations(&200, &200),
 				Error::<T>::InvalidRewardDestination
@@ -330,7 +330,7 @@ mod integration {
 			fund(&300, 1000);
 			assert_ok!(DelegatedStaking::delegate(&300, &200, 100));
 
-			// if delegatee calls Staking pallet directly with a different reward destination, it
+			// if delegate calls Staking pallet directly with a different reward destination, it
 			// fails.
 			assert_noop!(
 				Staking::bond(RuntimeOrigin::signed(200), 100, RewardDestination::Stash),
@@ -352,7 +352,7 @@ mod integration {
 			assert_eq!(DelegatedStaking::unbonded_balance(&200), 0);
 			assert_eq!(DelegatedStaking::delegated_balance(&200), 100);
 
-			// free balance of delegatee is untouched
+			// free balance of delegate is untouched
 			assert_eq!(Balances::free_balance(200), balance_200);
 
 			// trying to change reward destination later directly via staking does not work.
@@ -368,15 +368,15 @@ mod integration {
 	}
 
 	#[test]
-	fn delegatee_restrictions() {
+	fn delegate_restrictions() {
 		ExtBuilder::default().build_and_execute(|| {
 			setup_delegation_stake(200, 201, (202..203).collect(), 100, 0);
 
 			// Registering again is noop
 			assert_noop!(DelegatedStaking::accept_delegations(&200, &201), Error::<T>::NotAllowed);
-			// a delegator cannot become delegatee
+			// a delegator cannot become delegate
 			assert_noop!(DelegatedStaking::accept_delegations(&202, &203), Error::<T>::NotAllowed);
-			// existing staker cannot become a delegatee
+			// existing staker cannot become a delegate
 			assert_noop!(
 				DelegatedStaking::accept_delegations(&GENESIS_NOMINATOR_ONE, &201),
 				Error::<T>::AlreadyStaker
@@ -397,7 +397,7 @@ mod integration {
 			fund(&300, 1000);
 			assert_ok!(DelegatedStaking::delegate(&300, &200, 100));
 
-			// delegatee blocks delegation
+			// delegate blocks delegation
 			assert_ok!(DelegatedStaking::block_delegations(&200));
 
 			// cannot delegate to it anymore
@@ -406,7 +406,7 @@ mod integration {
 				Error::<T>::DelegationsBlocked
 			);
 
-			// delegatee can unblock delegation
+			// delegate can unblock delegation
 			assert_ok!(DelegatedStaking::unblock_delegations(&200));
 
 			// delegation works again
@@ -420,7 +420,7 @@ mod integration {
 			setup_delegation_stake(200, 201, (210..250).collect(), 100, 0);
 			start_era(1);
 
-			// delegatee is slashed
+			// delegate is slashed
 			todo!()
 		});
 	}
@@ -440,7 +440,7 @@ mod integration {
 			let init_stake = Staking::stake(&200).unwrap();
 
 			// scenario: 200 is a pool account, and the stake comes from its 4 delegators (300..304)
-			// in equal parts. lets try to migrate this nominator into delegatee based stake.
+			// in equal parts. lets try to migrate this nominator into delegate based stake.
 
 			// all balance currently is in 200
 			assert_eq!(Balances::free_balance(200), 5000);
@@ -483,7 +483,7 @@ mod integration {
 					expected_proxy_delegated_amount
 				);
 
-				// delegatee stake is unchanged.
+				// delegate stake is unchanged.
 				assert_eq!(DelegatedStaking::stake(&200).unwrap(), init_stake);
 				assert_eq!(DelegatedStaking::delegated_balance(&200), 4000);
 				assert_eq!(DelegatedStaking::unbonded_balance(&200), 0);
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 01f704076c7d1..05bb28193a6bb 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1098,7 +1098,7 @@ impl<T: Config> Pallet<T> {
 	}
 
 	pub(crate) fn stakeable_balance(who: &T::AccountId) -> BalanceOf<T> {
-		if T::DelegationSupport::is_delegatee(who) {
+		if T::DelegationSupport::is_delegate(who) {
 			return T::DelegationSupport::stakeable_balance(who);
 		}
 
@@ -1109,7 +1109,7 @@ impl<T: Config> Pallet<T> {
 		who: &T::AccountId,
 		reward_destination: Option<T::AccountId>,
 	) -> bool {
-		if T::DelegationSupport::is_delegatee(who) {
+		if T::DelegationSupport::is_delegate(who) {
 			return T::DelegationSupport::restrict_reward_destination(who, reward_destination);
 		}
 
@@ -1120,7 +1120,7 @@ impl<T: Config> Pallet<T> {
 		who: &T::AccountId,
 		amount: BalanceOf<T>,
 	) -> sp_runtime::DispatchResult {
-		if T::DelegationSupport::is_delegatee(who) {
+		if T::DelegationSupport::is_delegate(who) {
 			return T::DelegationSupport::update_hold(who, amount);
 		}
 
@@ -1882,7 +1882,7 @@ impl<T: Config> StakingDelegationSupport for NoDelegation<T> {
 	fn stakeable_balance(_who: &Self::AccountId) -> Self::Balance {
 		BalanceOf::<T>::zero()
 	}
-	fn is_delegatee(_who: &Self::AccountId) -> bool {
+	fn is_delegate(_who: &Self::AccountId) -> bool {
 		false
 	}
 	fn update_hold(_who: &Self::AccountId, _amount: Self::Balance) -> sp_runtime::DispatchResult {
diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs
index 2eeee0e8a3d66..b36f66d634d64 100644
--- a/substrate/frame/staking/src/slashing.rs
+++ b/substrate/frame/staking/src/slashing.rs
@@ -608,7 +608,7 @@ pub fn do_slash<T: Config>(
 			Err(_) => return, // nothing to do.
 		};
 
-	let lazy_slash = T::DelegationSupport::is_delegatee(stash);
+	let lazy_slash = T::DelegationSupport::is_delegate(stash);
 	let value = ledger.slash(value, T::Currency::minimum_balance(), slash_era);
 
 	if value.is_zero() {
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index da2ec27427506..e727d254f4cb7 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -44,60 +44,61 @@ pub trait DelegationInterface {
 
 	/// Set intention to accept delegations.
 	fn accept_delegations(
-		delegatee: &Self::AccountId,
+		delegate: &Self::AccountId,
 		reward_destination: &Self::AccountId,
 	) -> DispatchResult;
 
-	/// Migrate an nominator account into a delegatee.
+	/// Migrate a nominator account into a `delegate`.
 	///
 	/// # Arguments
 	///
-	/// * `new_delegatee`: This is the current nominator account. Funds will be moved from this
-	///   account to `proxy_delegator` and delegated back to `new_delegatee`.
+	/// * `new_delegate`: This is the current nominator account. Funds will be moved from this
+	///   account to `proxy_delegator` and delegated back to `new_delegate`.
 	/// * `proxy_delegator`: All existing staked funds will be moved to this account. Future
 	///   migration of funds from `proxy_delegator` to `delegator` is possible via calling
 	///   [`Self::migrate_delegator`].
-	///  * `payee`: Delegatees need to set where they want their rewards to be paid out.
+	/// * `payee`: `Delegate` needs to set where they want their rewards to be paid out. This can be
+	///   anything other than the `delegate` account itself.
 	///
 	/// This is similar to [`Self::accept_delegations`] but allows a current nominator to migrate to
-	/// a delegatee.
+	/// a `delegate`.
 	fn migrate_accept_delegations(
-		new_delegatee: &Self::AccountId,
+		new_delegate: &Self::AccountId,
 		proxy_delegator: &Self::AccountId,
 		payee: &Self::AccountId,
 	) -> DispatchResult;
 
 	/// Stop accepting new delegations to this account.
-	fn block_delegations(delegatee: &Self::AccountId) -> DispatchResult;
+	fn block_delegations(delegate: &Self::AccountId) -> DispatchResult;
 
 	/// Unblock delegations to this account.
-	fn unblock_delegations(delegatee: &Self::AccountId) -> DispatchResult;
+	fn unblock_delegations(delegate: &Self::AccountId) -> DispatchResult;
 
-	/// Remove oneself as Delegatee.
+	/// Remove oneself as a `delegate`.
 	///
-	/// This will only succeed if all delegations to this delegatee are withdrawn.
-	fn kill_delegatee(delegatee: &Self::AccountId) -> DispatchResult;
+	/// This will only succeed if all delegations to this `delegate` are withdrawn.
+	fn kill_delegate(delegate: &Self::AccountId) -> DispatchResult;
 
 	/// Bond all fund that is delegated but not staked.
 	/// FIXME(ank4n): Should not be allowed as withdrawn funds would get restaked.
-	fn bond_all(delegatee: &Self::AccountId) -> DispatchResult;
+	fn bond_all(delegate: &Self::AccountId) -> DispatchResult;
 
-	/// Request withdrawal of unbonded stake of `delegatee` belonging to the provided `delegator`.
+	/// Request withdrawal of unbonded stake of `delegate` belonging to the provided `delegator`.
 	///
-	/// Important: It is upto `delegatee` to enforce which `delegator` can withdraw `value`. The
+	/// Important: It is upto `delegate` to enforce which `delegator` can withdraw `value`. The
 	/// withdrawn value is released in `delegator`'s account.
 	fn withdraw(
-		delegatee: &Self::AccountId,
+		delegate: &Self::AccountId,
 		delegator: &Self::AccountId,
 		value: Self::Balance,
 		num_slashing_spans: u32,
 	) -> DispatchResult;
 
-	/// Applies a pending slash on delegatee by passing a delegator account who should be slashed
+	/// Applies a pending slash on `delegate` by passing a delegator account who should be slashed
 	/// and the value to be slashed. Optionally also takes a reporter account who will be rewarded
 	/// from part of the slash imbalance.
 	fn apply_slash(
-		delegatee: &Self::AccountId,
+		delegate: &Self::AccountId,
 		delegator: &Self::AccountId,
 		value: Self::Balance,
 		reporter: Option<Self::AccountId>,
@@ -105,19 +106,19 @@ pub trait DelegationInterface {
 
 	/// Move a delegated amount from `proxy_delegator` to `new_delegator`.
 	///
-	/// Delegatee must have used [`Self::migrate_accept_delegations`] to setup a `proxy_delegator`.
+	/// `Delegate` must have used [`Self::migrate_accept_delegations`] to setup a `proxy_delegator`.
 	/// This is useful for migrating old pool accounts using direct staking to lazily move
 	/// delegators to the new delegated pool account.
 	fn migrate_delegator(
-		delegatee: &Self::AccountId,
+		delegate: &Self::AccountId,
 		new_delegator: &Self::AccountId,
 		value: Self::Balance,
 	) -> DispatchResult;
 
-	/// As a `delegator`, delegate some funds to a Delegatee
+	/// Delegate some funds to a `delegate` account.
 	fn delegate(
 		delegator: &Self::AccountId,
-		delegatee: &Self::AccountId,
+		delegate: &Self::AccountId,
 		value: Self::Balance,
 	) -> DispatchResult;
 }
@@ -151,11 +152,11 @@ pub trait StakingDelegationSupport {
 	}
 
 	/// Returns true if `who` accepts delegations for stake.
-	fn is_delegatee(who: &Self::AccountId) -> bool;
+	fn is_delegate(who: &Self::AccountId) -> bool;
 
 	/// Update amount held for bonded stake.
 	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult;
 
-	/// Reports an ongoing slash to the delegatee account that would be applied lazily.
+	/// Reports an ongoing slash to the `delegate` account that would be applied lazily.
 	fn report_slash(who: &Self::AccountId, slash: Self::Balance);
 }
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index c0c62c3786e22..4b6115ce02c95 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -293,7 +293,7 @@ pub trait StakingInterface {
 
 	/// Release all funds bonded for stake.
 	///
-	/// Unsafe, only used for migration of delegatee accounts.
+	/// Unsafe, only used for migration of `delegate` accounts.
 	fn release_all(who: &Self::AccountId);
 
 	#[cfg(feature = "runtime-benchmarks")]

From 075e7935606845d456eac7b4057bc1d1bbfc855d Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 17 Feb 2024 10:33:11 +0100
Subject: [PATCH 080/202] create pot accounts

---
 substrate/frame/delegated-staking/src/lib.rs  | 35 ++++++++++++++++---
 substrate/frame/delegated-staking/src/mock.rs |  5 +++
 .../frame/delegated-staking/src/tests.rs      | 30 ++++++++--------
 substrate/frame/nomination-pools/src/lib.rs   |  2 +-
 .../primitives/staking/src/delegation.rs      |  2 +-
 5 files changed, 52 insertions(+), 22 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 8e7fefae24bc4..8057bdcd12794 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -20,7 +20,7 @@
 
 //! An implementation of a delegation system for staking that can be utilised using
 //! [`DelegationInterface`]. In future, if exposed via extrinsic, these primitives could also be
-//! used by off-chain entities, smart contracts or by other parachains via xcm.
+//! used by off-chain entities, or by foreign multi-locations (via xcm).
 //!
 //! Delegate: Someone who accepts delegations. An account can set their intention to accept
 //! delegations by calling [`DelegationInterface::accept_delegations`]. This account cannot have
@@ -69,7 +69,7 @@ use frame_support::{
 	transactional,
 };
 
-use sp_runtime::{traits::Zero, DispatchResult, Perbill, RuntimeDebug, Saturating};
+use sp_runtime::{traits::{Zero, AccountIdConversion}, DispatchResult, Perbill, RuntimeDebug, Saturating};
 use sp_staking::{
 	delegation::{DelegationInterface, StakingDelegationSupport},
 	EraIndex, Stake, StakerStatus, StakingInterface,
@@ -91,6 +91,10 @@ pub mod pallet {
 		/// The overarching event type.
 		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
 
+		/// Injected identifier for the pallet.
+		#[pallet::constant]
+		type PalletId: Get<frame_support::PalletId>;
+
 		type Currency: FunHoldMutate<Self::AccountId, Reason = Self::RuntimeHoldReason>
 			+ FunMutate<Self::AccountId>
 			+ FunHoldBalanced<Self::AccountId>;
@@ -207,19 +211,39 @@ pub struct DelegationLedger<T: Config> {
 	pub pending_slash: BalanceOf<T>,
 	/// Whether this `delegate` is blocked from receiving new delegations.
 	pub blocked: bool,
+	/// The `delegate` account associated with the ledger.
+	#[codec(skip)]
+	delegate: Option<T::AccountId>,
+}
+
+/// The type of pot account being created.
+#[derive(Encode, Decode)]
+enum AccountType {
+	/// Funds that are withdrawn from the staking ledger but not claimed by the `delegator` yet.
+	UnclaimedWithdrawal,
+	/// A proxy delegator account created for a nominator who migrated to a `delegate` account.
+	///
+	/// Funds for unmigrated `delegator` accounts of the `delegate` are kept here.
+	ProxyDelegator,
 }
 
 impl<T: Config> DelegationLedger<T> {
-	/// balance that can be staked.
+	/// Balance that is stakeable.
 	pub fn delegated_balance(&self) -> BalanceOf<T> {
 		// do not allow to stake more than unapplied slash
 		self.total_delegated.saturating_sub(self.pending_slash)
 	}
 
-	/// balance that is delegated but not bonded.
+	/// Balance that is delegated but not bonded.
+	///
+	/// Can be funds that are unbonded but not withdrawn.
 	pub fn unbonded_balance(&self) -> BalanceOf<T> {
 		self.total_delegated.saturating_sub(self.hold)
 	}
+
+	pub fn unclaimed_withdraw_account(&self) -> T::AccountId {
+		T::PalletId::get().into_sub_account_truncating(self.delegate.clone())
+	}
 }
 
 impl<T: Config> DelegationInterface for Pallet<T> {
@@ -264,6 +288,7 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 				hold: Zero::zero(),
 				pending_slash: Zero::zero(),
 				blocked: false,
+				delegate: Some(who.clone()),
 			},
 		);
 
@@ -348,7 +373,7 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 	}
 
 	#[transactional]
-	fn withdraw(
+	fn delegate_withdraw(
 		delegate: &Self::AccountId,
 		delegator: &Self::AccountId,
 		value: Self::Balance,
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 82c31c66038d6..f17c0cb2522d6 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -21,6 +21,7 @@ use frame_support::{
 	pallet_prelude::*,
 	parameter_types,
 	traits::{ConstU64, Currency},
+	PalletId,
 };
 
 use sp_runtime::{traits::IdentityLookup, BuildStorage, Perbill};
@@ -134,8 +135,12 @@ impl pallet_staking::Config for Runtime {
 	type WeightInfo = ();
 }
 
+parameter_types! {
+	pub const DelegatedStakingPalletId: PalletId = PalletId(*b"py/dlstk");
+}
 impl delegated_staking::Config for Runtime {
 	type RuntimeEvent = RuntimeEvent;
+	type PalletId = DelegatedStakingPalletId;
 	type Currency = Balances;
 	type OnSlash = ();
 	type RuntimeHoldReason = RuntimeHoldReason;
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 41478fa0ec6e7..889d9601564bb 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -210,10 +210,10 @@ mod integration {
 			assert!(eq_stake(delegate, total_staked, total_staked));
 			// Withdrawing without unbonding would fail.
 			assert_noop!(
-				DelegatedStaking::withdraw(&delegate, &300, 50, 0),
+				DelegatedStaking::delegate_withdraw(&delegate, &300, 50, 0),
 				Error::<T>::WithdrawFailed
 			);
-			// assert_noop!(DelegatedStaking::withdraw(&delegate, &200, 50, 0),
+			// assert_noop!(DelegatedStaking::delegate_withdraw(&delegate, &200, 50, 0),
 			// Error::<T>::NotAllowed); active and total stake remains same
 			assert!(eq_stake(delegate, total_staked, total_staked));
 
@@ -232,7 +232,7 @@ mod integration {
 
 			// nothing to withdraw at era 4
 			assert_noop!(
-				DelegatedStaking::withdraw(&delegate, &305, 50, 0),
+				DelegatedStaking::delegate_withdraw(&delegate, &305, 50, 0),
 				Error::<T>::WithdrawFailed
 			);
 
@@ -244,43 +244,43 @@ mod integration {
 			start_era(5);
 			// at era 5, 50 tokens are withdrawable, cannot withdraw more.
 			assert_noop!(
-				DelegatedStaking::withdraw(&delegate, &305, 51, 0),
+				DelegatedStaking::delegate_withdraw(&delegate, &305, 51, 0),
 				Error::<T>::WithdrawFailed
 			);
 			// less is possible
-			assert_ok!(DelegatedStaking::withdraw(&delegate, &305, 30, 0));
-			assert_ok!(DelegatedStaking::withdraw(&delegate, &305, 20, 0));
+			assert_ok!(DelegatedStaking::delegate_withdraw(&delegate, &305, 30, 0));
+			assert_ok!(DelegatedStaking::delegate_withdraw(&delegate, &305, 20, 0));
 
 			// Lets go to future era where everything is unbonded. Withdrawable amount: 100 + 200
 			start_era(7);
 			// 305 has no more amount delegated so it cannot withdraw.
 			assert_noop!(
-				DelegatedStaking::withdraw(&delegate, &305, 5, 0),
+				DelegatedStaking::delegate_withdraw(&delegate, &305, 5, 0),
 				Error::<T>::NotDelegator
 			);
 			// 309 is an active delegator but has total delegation of 90, so it cannot withdraw more
 			// than that.
 			assert_noop!(
-				DelegatedStaking::withdraw(&delegate, &309, 91, 0),
+				DelegatedStaking::delegate_withdraw(&delegate, &309, 91, 0),
 				Error::<T>::NotEnoughFunds
 			);
 			// 310 cannot withdraw more than delegated funds.
 			assert_noop!(
-				DelegatedStaking::withdraw(&delegate, &310, 101, 0),
+				DelegatedStaking::delegate_withdraw(&delegate, &310, 101, 0),
 				Error::<T>::NotEnoughFunds
 			);
 			// but can withdraw all its delegation amount.
-			assert_ok!(DelegatedStaking::withdraw(&delegate, &310, 100, 0));
+			assert_ok!(DelegatedStaking::delegate_withdraw(&delegate, &310, 100, 0));
 			// 320 can withdraw all its delegation amount.
-			assert_ok!(DelegatedStaking::withdraw(&delegate, &320, 200, 0));
+			assert_ok!(DelegatedStaking::delegate_withdraw(&delegate, &320, 200, 0));
 
 			// cannot withdraw anything more..
 			assert_noop!(
-				DelegatedStaking::withdraw(&delegate, &301, 1, 0),
+				DelegatedStaking::delegate_withdraw(&delegate, &301, 1, 0),
 				Error::<T>::WithdrawFailed
 			);
 			assert_noop!(
-				DelegatedStaking::withdraw(&delegate, &350, 1, 0),
+				DelegatedStaking::delegate_withdraw(&delegate, &350, 1, 0),
 				Error::<T>::WithdrawFailed
 			);
 		});
@@ -294,7 +294,7 @@ mod integration {
 
 			// verify withdraw not possible yet
 			assert_noop!(
-				DelegatedStaking::withdraw(&delegate, &300, 100, 0),
+				DelegatedStaking::delegate_withdraw(&delegate, &300, 100, 0),
 				Error::<T>::WithdrawFailed
 			);
 
@@ -306,7 +306,7 @@ mod integration {
 			assert_eq!(DelegatedStaking::unbonded_balance(&delegate), 100);
 
 			// withdraw works now without unbonding
-			assert_ok!(DelegatedStaking::withdraw(&delegate, &300, 100, 0));
+			assert_ok!(DelegatedStaking::delegate_withdraw(&delegate, &300, 100, 0));
 			assert_eq!(DelegatedStaking::unbonded_balance(&delegate), 0);
 		});
 	}
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index 5182f69c32cdd..fef5cfaccf5b4 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -2287,7 +2287,7 @@ pub mod pallet {
 			// `transferrable_balance` is correct.
 			// fixme(ank4n): Handle result.
 			let _withdraw_result =
-				T::Staking::withdraw(&bonded_pool.bonded_account(), &member_account, balance_to_unbond, num_slashing_spans)?;
+				T::Staking::delegate_withdraw(&bonded_pool.bonded_account(), &member_account, balance_to_unbond, num_slashing_spans)?;
 
 			// defensive-only: the depositor puts enough funds into the stash so that it will only
 			// be destroyed when they are leaving.
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index e727d254f4cb7..6aa4befa339d2 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -87,7 +87,7 @@ pub trait DelegationInterface {
 	///
 	/// Important: It is upto `delegate` to enforce which `delegator` can withdraw `value`. The
 	/// withdrawn value is released in `delegator`'s account.
-	fn withdraw(
+	fn delegate_withdraw(
 		delegate: &Self::AccountId,
 		delegator: &Self::AccountId,
 		value: Self::Balance,

From b4918e745b289f93d439600ed2f213a784273c4d Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 17 Feb 2024 11:16:56 +0100
Subject: [PATCH 081/202] add call signatures

---
 substrate/frame/delegated-staking/src/lib.rs | 81 ++++++++++++++++++--
 1 file changed, 76 insertions(+), 5 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 8057bdcd12794..a900bd9c7a953 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -67,9 +67,13 @@ use frame_support::{
 		DefensiveOption, Imbalance, OnUnbalanced,
 	},
 	transactional,
+	weights::Weight,
 };
 
-use sp_runtime::{traits::{Zero, AccountIdConversion}, DispatchResult, Perbill, RuntimeDebug, Saturating};
+use sp_runtime::{
+	traits::{AccountIdConversion, Zero},
+	DispatchResult, Perbill, RuntimeDebug, Saturating,
+};
 use sp_staking::{
 	delegation::{DelegationInterface, StakingDelegationSupport},
 	EraIndex, Stake, StakerStatus, StakingInterface,
@@ -82,6 +86,7 @@ pub type BalanceOf<T> =
 #[frame_support::pallet]
 pub mod pallet {
 	use super::*;
+	use frame_system::{ensure_signed, pallet_prelude::*};
 
 	#[pallet::pallet]
 	pub struct Pallet<T>(PhantomData<T>);
@@ -187,6 +192,74 @@ pub mod pallet {
 	#[pallet::storage]
 	pub(crate) type DelegateMigration<T: Config> =
 		CountedStorageMap<_, Twox64Concat, T::AccountId, T::AccountId, OptionQuery>;
+
+	#[pallet::call]
+	impl<T: Config> Pallet<T> {
+		/// Register an account to be a `Delegate`.
+		///
+		/// `Delegate` accounts accepts delegations from other `delegator`s and stake funds on their
+		/// behalf.
+		#[pallet::call_index(0)]
+		#[pallet::weight(Weight::default())]
+		pub fn register_as_delegate(
+			origin: OriginFor<T>,
+			reward_account: T::AccountId,
+		) -> DispatchResult {
+			todo!()
+		}
+
+		/// Migrate from a `Nominator` account to `Delegate` account.
+		#[pallet::call_index(1)]
+		#[pallet::weight(Weight::default())]
+		pub fn migrate_to_delegate(
+			origin: OriginFor<T>,
+			reward_account: T::AccountId,
+		) -> DispatchResult {
+			todo!()
+		}
+
+		/// Release delegated amount to delegator.
+		///
+		/// Tries to withdraw unbonded fund if needed from staking and release amount to delegator.
+		///
+		/// Only `delegate` account can call this.
+		#[pallet::call_index(2)]
+		#[pallet::weight(Weight::default())]
+		pub fn release (
+			origin: OriginFor<T>,
+			delegator: T::AccountId,
+			amount: BalanceOf<T>,
+			num_slashing_spans: u32,
+		) -> DispatchResult {
+			todo!()
+		}
+
+		/// Migrate delegated fund.
+		///
+		/// This moves delegator funds from `pxoxy_delegator` account to `delegator` account.
+		///
+		/// Only `delegate` account can call this.
+		#[pallet::call_index(3)]
+		#[pallet::weight(Weight::default())]
+		pub fn migrate_delegation(origin: OriginFor<T>, delegator: T::AccountId, amount: BalanceOf<T>) -> DispatchResult{
+			todo!()
+		}
+
+		/// Delegate funds to a `Delegate` account.
+		#[pallet::call_index(4)]
+		#[pallet::weight(Weight::default())]
+		// FIXME(ank4n): rename to `delegate`
+		pub fn delegate_funds(origin: OriginFor<T>, delegate: T::AccountId, amount: BalanceOf<T>) -> DispatchResult {
+			todo!()
+		}
+
+		/// Add funds to an existing delegation.
+		#[pallet::call_index(5)]
+		#[pallet::weight(Weight::default())]
+		pub fn delegate_extra(origin: OriginFor<T>, delegate: T::AccountId, amount: BalanceOf<T>) -> DispatchResult {
+			todo!()
+		}
+	}
 }
 
 /// Register of all delegations to a `Delegate`.
@@ -256,8 +329,7 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 	}
 
 	fn unbonded_balance(who: &Self::AccountId) -> Self::Balance {
-		<Delegates<T>>::get(who)
-			.map_or_else(|| 0u32.into(), |register| register.unbonded_balance())
+		<Delegates<T>>::get(who).map_or_else(|| 0u32.into(), |register| register.unbonded_balance())
 	}
 
 	fn accept_delegations(
@@ -568,8 +640,7 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
 
 		// delegation register should exist since `who` is a delegate.
-		let delegation_register =
-			<Delegates<T>>::get(who).defensive_ok_or(Error::<T>::BadState)?;
+		let delegation_register = <Delegates<T>>::get(who).defensive_ok_or(Error::<T>::BadState)?;
 
 		ensure!(delegation_register.total_delegated >= amount, Error::<T>::NotEnoughFunds);
 		ensure!(delegation_register.pending_slash <= amount, Error::<T>::UnappliedSlash);

From a635f1db3477eaa69a32542e5d0265d0a68917dc Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 17 Feb 2024 11:38:34 +0100
Subject: [PATCH 082/202] return correct error

---
 substrate/frame/staking/src/pallet/impls.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 05bb28193a6bb..3c6c24136a862 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1887,7 +1887,7 @@ impl<T: Config> StakingDelegationSupport for NoDelegation<T> {
 	}
 	fn update_hold(_who: &Self::AccountId, _amount: Self::Balance) -> sp_runtime::DispatchResult {
 		defensive!("delegation update_hold should not be have been called for NoDelegation");
-		Err(Error::<T>::NotEnoughFunds.into())
+		Err(Error::<T>::BadState.into())
 	}
 
 	fn report_slash(_who: &Self::AccountId, _slash: Self::Balance) {

From 309ddf5a827e8a4cf60d48388265d3db874f1790 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 17 Feb 2024 12:32:43 +0100
Subject: [PATCH 083/202] call register as delegate

---
 substrate/frame/delegated-staking/src/lib.rs | 92 +++++++++++++-------
 1 file changed, 60 insertions(+), 32 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index a900bd9c7a953..7a897d96703ee 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -83,10 +83,11 @@ use sp_std::{convert::TryInto, prelude::*};
 pub type BalanceOf<T> =
 	<<T as Config>::Currency as FunInspect<<T as frame_system::Config>::AccountId>>::Balance;
 
+use frame_system::{ensure_signed, pallet_prelude::*, RawOrigin};
+
 #[frame_support::pallet]
 pub mod pallet {
 	use super::*;
-	use frame_system::{ensure_signed, pallet_prelude::*};
 
 	#[pallet::pallet]
 	pub struct Pallet<T>(PhantomData<T>);
@@ -180,7 +181,7 @@ pub mod pallet {
 	pub(crate) type Delegators<T: Config> =
 		CountedStorageMap<_, Twox64Concat, T::AccountId, (T::AccountId, BalanceOf<T>), OptionQuery>;
 
-	/// Map of Delegate to their Ledger.
+	/// Map of `Delegate` to their Ledger.
 	#[pallet::storage]
 	pub(crate) type Delegates<T: Config> =
 		CountedStorageMap<_, Twox64Concat, T::AccountId, DelegationLedger<T>, OptionQuery>;
@@ -205,7 +206,23 @@ pub mod pallet {
 			origin: OriginFor<T>,
 			reward_account: T::AccountId,
 		) -> DispatchResult {
-			todo!()
+			let who = ensure_signed(origin)?;
+
+			// Existing `delegate` cannot register again.
+			ensure!(!Self::is_delegate(&who), Error::<T>::NotAllowed);
+
+			// A delegator cannot become a `delegate`.
+			ensure!(!Self::is_delegator(&who), Error::<T>::NotAllowed);
+
+			// payee account cannot be same as `delegate`
+			ensure!(reward_account != who, Error::<T>::InvalidRewardDestination);
+
+			// They cannot be already a direct staker in the staking pallet.
+			ensure!(Self::not_direct_staker(&who), Error::<T>::AlreadyStaker);
+
+			DelegationLedger::<T>::new(&reward_account).save(&who);
+
+			Ok(())
 		}
 
 		/// Migrate from a `Nominator` account to `Delegate` account.
@@ -301,6 +318,29 @@ enum AccountType {
 }
 
 impl<T: Config> DelegationLedger<T> {
+	pub fn new(reward_destination: &T::AccountId) -> Self {
+		DelegationLedger {
+			payee: reward_destination.clone(),
+			total_delegated: Zero::zero(),
+			hold: Zero::zero(),
+			pending_slash: Zero::zero(),
+			blocked: false,
+			delegate: None,
+		}
+	}
+
+	/// consumes self and returns a new copy with the key.
+	fn with_key(self, key: &T::AccountId) -> Self {
+		DelegationLedger {
+			delegate: Some(key.clone()),
+			..self
+		}
+	}
+
+	fn get(key: &T::AccountId) -> Option<Self<>>{
+		<Delegates<T>>::get(key).map(|d| d.with_key(key))
+	}
+
 	/// Balance that is stakeable.
 	pub fn delegated_balance(&self) -> BalanceOf<T> {
 		// do not allow to stake more than unapplied slash
@@ -317,6 +357,16 @@ impl<T: Config> DelegationLedger<T> {
 	pub fn unclaimed_withdraw_account(&self) -> T::AccountId {
 		T::PalletId::get().into_sub_account_truncating(self.delegate.clone())
 	}
+
+	pub fn save(self, key: &T::AccountId) -> Self {
+		let new_val = self.with_key(key);
+		<Delegates<T>>::insert(
+			key,
+			&new_val,
+		);
+
+		new_val
+	}
 }
 
 impl<T: Config> DelegationInterface for Pallet<T> {
@@ -336,35 +386,7 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		who: &Self::AccountId,
 		reward_destination: &Self::AccountId,
 	) -> DispatchResult {
-		// Existing `delegate` cannot register again.
-		ensure!(!<Delegates<T>>::contains_key(who), Error::<T>::NotAllowed);
-
-		// A delegator cannot become a `delegate`.
-		ensure!(!<Delegators<T>>::contains_key(who), Error::<T>::NotAllowed);
-
-		// payee account cannot be same as `delegate`
-		ensure!(reward_destination != who, Error::<T>::InvalidRewardDestination);
-
-		// make sure they are not already a direct staker or they are migrating.
-		ensure!(
-			T::CoreStaking::status(who).is_err() || <DelegateMigration<T>>::contains_key(who),
-			Error::<T>::AlreadyStaker
-		);
-
-		// already checked that `delegate` exist
-		<Delegates<T>>::insert(
-			who,
-			DelegationLedger {
-				payee: reward_destination.clone(),
-				total_delegated: Zero::zero(),
-				hold: Zero::zero(),
-				pending_slash: Zero::zero(),
-				blocked: false,
-				delegate: Some(who.clone()),
-			},
-		);
-
-		Ok(())
+		Self::register_as_delegate(RawOrigin::Signed(who.clone()).into(), reward_destination.clone())
 	}
 
 	/// Transfers funds from current staked account to `proxy_delegator`. Current staked account
@@ -857,6 +879,12 @@ impl<T: Config> Pallet<T> {
 		<DelegateMigration<T>>::contains_key(delegate)
 	}
 
+
+	/// Returns true if who is not already staking.
+	fn not_direct_staker(who: &T::AccountId) -> bool {
+		T::CoreStaking::status(&who).is_err()
+	}
+
 	fn delegation_withdraw(
 		delegator: &T::AccountId,
 		delegate: &T::AccountId,

From ea5d777223e537b6f2c70983dc3acfe523654604 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 17 Feb 2024 17:34:29 +0100
Subject: [PATCH 084/202] add mod for types

---
 substrate/frame/delegated-staking/src/lib.rs  | 220 ++++++++++--------
 .../frame/delegated-staking/src/types.rs      | 112 +++++++++
 substrate/primitives/staking/src/lib.rs       |   2 +-
 3 files changed, 232 insertions(+), 102 deletions(-)
 create mode 100644 substrate/frame/delegated-staking/src/types.rs

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 7a897d96703ee..2c426dfdec75a 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -53,6 +53,10 @@ mod tests;
 
 pub use pallet::*;
 
+mod types;
+
+use types::*;
+
 #[cfg(feature = "runtime-benchmarks")]
 mod benchmarking;
 
@@ -208,31 +212,39 @@ pub mod pallet {
 		) -> DispatchResult {
 			let who = ensure_signed(origin)?;
 
+			// They cannot be already a direct staker in the staking pallet.
+			ensure!(Self::not_direct_staker(&who), Error::<T>::AlreadyStaker);
+
 			// Existing `delegate` cannot register again.
 			ensure!(!Self::is_delegate(&who), Error::<T>::NotAllowed);
 
 			// A delegator cannot become a `delegate`.
 			ensure!(!Self::is_delegator(&who), Error::<T>::NotAllowed);
 
-			// payee account cannot be same as `delegate`
+			// Reward account cannot be same as `delegate` account.
 			ensure!(reward_account != who, Error::<T>::InvalidRewardDestination);
 
-			// They cannot be already a direct staker in the staking pallet.
-			ensure!(Self::not_direct_staker(&who), Error::<T>::AlreadyStaker);
-
 			DelegationLedger::<T>::new(&reward_account).save(&who);
 
 			Ok(())
 		}
 
 		/// Migrate from a `Nominator` account to `Delegate` account.
+		///
+		/// Internally transfers minimum balance to a proxy delegator account created for it.
 		#[pallet::call_index(1)]
 		#[pallet::weight(Weight::default())]
 		pub fn migrate_to_delegate(
 			origin: OriginFor<T>,
 			reward_account: T::AccountId,
 		) -> DispatchResult {
-			todo!()
+			let who = ensure_signed(origin)?;
+			ensure!(Self::is_direct_nominator(&who), Error::<T>::NotAllowed);
+
+			// Reward account cannot be same as `delegate` account.
+			ensure!(reward_account != who, Error::<T>::InvalidRewardDestination);
+
+			Self::do_migrate_to_delegate(&who, &reward_account)
 		}
 
 		/// Release delegated amount to delegator.
@@ -242,7 +254,7 @@ pub mod pallet {
 		/// Only `delegate` account can call this.
 		#[pallet::call_index(2)]
 		#[pallet::weight(Weight::default())]
-		pub fn release (
+		pub fn release(
 			origin: OriginFor<T>,
 			delegator: T::AccountId,
 			amount: BalanceOf<T>,
@@ -258,7 +270,11 @@ pub mod pallet {
 		/// Only `delegate` account can call this.
 		#[pallet::call_index(3)]
 		#[pallet::weight(Weight::default())]
-		pub fn migrate_delegation(origin: OriginFor<T>, delegator: T::AccountId, amount: BalanceOf<T>) -> DispatchResult{
+		pub fn migrate_delegation(
+			origin: OriginFor<T>,
+			delegator: T::AccountId,
+			amount: BalanceOf<T>,
+		) -> DispatchResult {
 			todo!()
 		}
 
@@ -266,109 +282,27 @@ pub mod pallet {
 		#[pallet::call_index(4)]
 		#[pallet::weight(Weight::default())]
 		// FIXME(ank4n): rename to `delegate`
-		pub fn delegate_funds(origin: OriginFor<T>, delegate: T::AccountId, amount: BalanceOf<T>) -> DispatchResult {
+		pub fn delegate_funds(
+			origin: OriginFor<T>,
+			delegate: T::AccountId,
+			amount: BalanceOf<T>,
+		) -> DispatchResult {
 			todo!()
 		}
 
 		/// Add funds to an existing delegation.
 		#[pallet::call_index(5)]
 		#[pallet::weight(Weight::default())]
-		pub fn delegate_extra(origin: OriginFor<T>, delegate: T::AccountId, amount: BalanceOf<T>) -> DispatchResult {
+		pub fn delegate_extra(
+			origin: OriginFor<T>,
+			delegate: T::AccountId,
+			amount: BalanceOf<T>,
+		) -> DispatchResult {
 			todo!()
 		}
 	}
 }
 
-/// Register of all delegations to a `Delegate`.
-///
-/// This keeps track of the active balance of the `delegate` that is made up from the funds that are
-/// currently delegated to this `delegate`. It also tracks the pending slashes yet to be applied
-/// among other things.
-#[derive(Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
-#[scale_info(skip_type_params(T))]
-pub struct DelegationLedger<T: Config> {
-	/// Where the reward should be paid out.
-	pub payee: T::AccountId,
-	/// Sum of all delegated funds to this `delegate`.
-	#[codec(compact)]
-	pub total_delegated: BalanceOf<T>,
-	/// Amount that is bonded and held.
-	// FIXME(ank4n) (can we remove it)
-	#[codec(compact)]
-	pub hold: BalanceOf<T>,
-	/// Slashes that are not yet applied.
-	#[codec(compact)]
-	pub pending_slash: BalanceOf<T>,
-	/// Whether this `delegate` is blocked from receiving new delegations.
-	pub blocked: bool,
-	/// The `delegate` account associated with the ledger.
-	#[codec(skip)]
-	delegate: Option<T::AccountId>,
-}
-
-/// The type of pot account being created.
-#[derive(Encode, Decode)]
-enum AccountType {
-	/// Funds that are withdrawn from the staking ledger but not claimed by the `delegator` yet.
-	UnclaimedWithdrawal,
-	/// A proxy delegator account created for a nominator who migrated to a `delegate` account.
-	///
-	/// Funds for unmigrated `delegator` accounts of the `delegate` are kept here.
-	ProxyDelegator,
-}
-
-impl<T: Config> DelegationLedger<T> {
-	pub fn new(reward_destination: &T::AccountId) -> Self {
-		DelegationLedger {
-			payee: reward_destination.clone(),
-			total_delegated: Zero::zero(),
-			hold: Zero::zero(),
-			pending_slash: Zero::zero(),
-			blocked: false,
-			delegate: None,
-		}
-	}
-
-	/// consumes self and returns a new copy with the key.
-	fn with_key(self, key: &T::AccountId) -> Self {
-		DelegationLedger {
-			delegate: Some(key.clone()),
-			..self
-		}
-	}
-
-	fn get(key: &T::AccountId) -> Option<Self<>>{
-		<Delegates<T>>::get(key).map(|d| d.with_key(key))
-	}
-
-	/// Balance that is stakeable.
-	pub fn delegated_balance(&self) -> BalanceOf<T> {
-		// do not allow to stake more than unapplied slash
-		self.total_delegated.saturating_sub(self.pending_slash)
-	}
-
-	/// Balance that is delegated but not bonded.
-	///
-	/// Can be funds that are unbonded but not withdrawn.
-	pub fn unbonded_balance(&self) -> BalanceOf<T> {
-		self.total_delegated.saturating_sub(self.hold)
-	}
-
-	pub fn unclaimed_withdraw_account(&self) -> T::AccountId {
-		T::PalletId::get().into_sub_account_truncating(self.delegate.clone())
-	}
-
-	pub fn save(self, key: &T::AccountId) -> Self {
-		let new_val = self.with_key(key);
-		<Delegates<T>>::insert(
-			key,
-			&new_val,
-		);
-
-		new_val
-	}
-}
-
 impl<T: Config> DelegationInterface for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
@@ -386,7 +320,10 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		who: &Self::AccountId,
 		reward_destination: &Self::AccountId,
 	) -> DispatchResult {
-		Self::register_as_delegate(RawOrigin::Signed(who.clone()).into(), reward_destination.clone())
+		Self::register_as_delegate(
+			RawOrigin::Signed(who.clone()).into(),
+			reward_destination.clone(),
+		)
 	}
 
 	/// Transfers funds from current staked account to `proxy_delegator`. Current staked account
@@ -867,6 +804,10 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 }
 impl<T: Config> Pallet<T> {
+	fn sub_account(account_type: AccountType, delegate_account: T::AccountId) -> T::AccountId {
+		T::PalletId::get().into_sub_account_truncating((account_type, delegate_account.clone()))
+	}
+
 	fn is_delegate(who: &T::AccountId) -> bool {
 		<Delegates<T>>::contains_key(who)
 	}
@@ -879,12 +820,89 @@ impl<T: Config> Pallet<T> {
 		<DelegateMigration<T>>::contains_key(delegate)
 	}
 
-
 	/// Returns true if who is not already staking.
 	fn not_direct_staker(who: &T::AccountId) -> bool {
 		T::CoreStaking::status(&who).is_err()
 	}
 
+	/// Returns true if who is not already staking.
+	fn is_direct_nominator(who: &T::AccountId) -> bool {
+		T::CoreStaking::status(who)
+			.map(|status| matches!(status, StakerStatus::Nominator(_)))
+			.unwrap_or(false)
+	}
+
+	fn do_migrate_to_delegate(who: &T::AccountId, reward_account: &T::AccountId) -> DispatchResult {
+		// Get current stake
+		let stake = T::CoreStaking::stake(who)?;
+
+		// release funds from core staking.
+		T::CoreStaking::release_all(who);
+
+		// We create a proxy delegator that will keep all the delegation funds until funds are
+		// transferred to actual delegator.
+		let proxy_delegator = Self::sub_account(AccountType::ProxyDelegator, who.clone());
+
+		// transferring just released staked amount. This should never fail but if it does, it
+		// indicates bad state and we abort.
+		T::Currency::transfer(who, &proxy_delegator, stake.total, Preservation::Protect)
+			.map_err(|_| Error::<T>::BadState)?;
+
+		DelegationLedger::<T>::new(&reward_account).save(&who);
+		// FIXME(ank4n) expose set payee in staking interface.
+		// T::CoreStaking::set_payee(who, reward_account)
+
+		Self::do_delegate(&proxy_delegator, who, stake.total)?;
+		Self::do_bond(who, stake.total)
+	}
+
+	fn do_bond(delegate: &T::AccountId, amount: BalanceOf<T>) -> DispatchResult {
+		let ledger = <Delegates<T>>::get(delegate).defensive_ok_or(Error::<T>::NotDelegate)?;
+
+		debug_assert!(amount == ledger.unbonded_balance());
+
+		match T::CoreStaking::stake(delegate) {
+			// already bonded
+			Ok(_) => T::CoreStaking::bond_extra(delegate, amount),
+			// first bond
+			Err(_) => T::CoreStaking::bond(delegate, amount, &ledger.payee),
+		}
+	}
+
+	fn do_delegate(
+		delegator: &T::AccountId,
+		delegate: &T::AccountId,
+		amount: BalanceOf<T>,
+	) -> DispatchResult {
+		// let mut delegation_register =
+		// 	<Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
+		// ensure!(!delegation_register.blocked, Error::<T>::DelegationsBlocked);
+		//
+		// let new_delegation_amount =
+		// 	if let Some((current_delegate, current_delegation)) = <Delegators<T>>::get(delegator) {
+		// 		ensure!(&current_delegate == delegate, Error::<T>::InvalidDelegation);
+		// 		value.saturating_add(current_delegation)
+		// 	} else {
+		// 		value
+		// 	};
+		//
+		// delegation_register.total_delegated.saturating_accrue(value);
+		//
+		// <Delegators<T>>::insert(delegator, (delegate, new_delegation_amount));
+		// <Delegates<T>>::insert(delegate, delegation_register);
+		//
+		// T::Currency::hold(&HoldReason::Delegating.into(), &delegator, value)?;
+		//
+		// Self::deposit_event(Event::<T>::Delegated {
+		// 	delegate: delegate.clone(),
+		// 	delegator: delegator.clone(),
+		// 	amount: value,
+		// });
+		//
+		// Ok(())
+
+		todo!()
+	}
 	fn delegation_withdraw(
 		delegator: &T::AccountId,
 		delegate: &T::AccountId,
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
new file mode 100644
index 0000000000000..6de552d235583
--- /dev/null
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -0,0 +1,112 @@
+// This file is part of Substrate.
+
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+//! Basic types used in delegated staking.
+
+use super::*;
+
+/// The type of pot account being created.
+#[derive(Encode, Decode)]
+pub(crate) enum AccountType {
+    /// Funds that are withdrawn from the staking ledger but not claimed by the `delegator` yet.
+    UnclaimedWithdrawal,
+    /// A proxy delegator account created for a nominator who migrated to a `delegate` account.
+    ///
+    /// Funds for unmigrated `delegator` accounts of the `delegate` are kept here.
+    ProxyDelegator,
+}
+
+#[derive(Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
+#[scale_info(skip_type_params(T))]
+pub struct Delegation<T: Config> {
+    // The target of delegation.
+    pub delegate: T::AccountId,
+    // The amount delegated.
+    pub amount: BalanceOf<T>,
+}
+
+/// Ledger of all delegations to a `Delegate`.
+///
+/// This keeps track of the active balance of the `delegate` that is made up from the funds that are
+/// currently delegated to this `delegate`. It also tracks the pending slashes yet to be applied
+/// among other things.
+#[derive(Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
+#[scale_info(skip_type_params(T))]
+pub struct DelegationLedger<T: Config> {
+    /// Where the reward should be paid out.
+    pub payee: T::AccountId,
+    /// Sum of all delegated funds to this `delegate`.
+    #[codec(compact)]
+    pub total_delegated: BalanceOf<T>,
+    /// Amount that is bonded and held.
+    // FIXME(ank4n) (can we remove it)
+    #[codec(compact)]
+    pub hold: BalanceOf<T>,
+    /// Slashes that are not yet applied.
+    #[codec(compact)]
+    pub pending_slash: BalanceOf<T>,
+    /// Whether this `delegate` is blocked from receiving new delegations.
+    pub blocked: bool,
+    /// The `delegate` account associated with the ledger.
+    #[codec(skip)]
+    pub delegate: Option<T::AccountId>,
+}
+
+
+
+impl<T: Config> DelegationLedger<T> {
+    pub fn new(reward_destination: &T::AccountId) -> Self {
+        DelegationLedger {
+            payee: reward_destination.clone(),
+            total_delegated: Zero::zero(),
+            hold: Zero::zero(),
+            pending_slash: Zero::zero(),
+            blocked: false,
+            delegate: None,
+        }
+    }
+
+    /// consumes self and returns a new copy with the key.
+    fn with_key(self, key: &T::AccountId) -> Self {
+        DelegationLedger { delegate: Some(key.clone()), ..self }
+    }
+
+    fn get(key: &T::AccountId) -> Option<Self> {
+        <Delegates<T>>::get(key).map(|d| d.with_key(key))
+    }
+
+    /// Balance that is stakeable.
+    pub fn delegated_balance(&self) -> BalanceOf<T> {
+        // do not allow to stake more than unapplied slash
+        self.total_delegated.saturating_sub(self.pending_slash)
+    }
+
+    /// Balance that is delegated but not bonded.
+    ///
+    /// Can be funds that are unbonded but not withdrawn.
+    pub fn unbonded_balance(&self) -> BalanceOf<T> {
+        self.total_delegated.saturating_sub(self.hold)
+    }
+
+    pub fn save(self, key: &T::AccountId) -> Self {
+        let new_val = self.with_key(key);
+        <Delegates<T>>::insert(key, &new_val);
+
+        new_val
+    }
+}
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 4b6115ce02c95..4819ea583a27d 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -272,7 +272,7 @@ pub trait StakingInterface {
 	/// Checks whether an account `staker` has been exposed in an era.
 	fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool;
 
-	/// Return the status of the given staker, `None` if not staked at all.
+	/// Return the status of the given staker, `Err` if not staked at all.
 	fn status(who: &Self::AccountId) -> Result<StakerStatus<Self::AccountId>, DispatchError>;
 
 	/// Checks whether or not this is a validator account.

From 259b3a7eb7e9c6c23c8d933134187c35446d6ec8 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 17 Feb 2024 17:42:57 +0100
Subject: [PATCH 085/202] move all public impls of traits to its own module

---
 .../frame/delegated-staking/src/impls.rs      | 523 ++++++++++++++++++
 substrate/frame/delegated-staking/src/lib.rs  | 502 +----------------
 2 files changed, 526 insertions(+), 499 deletions(-)
 create mode 100644 substrate/frame/delegated-staking/src/impls.rs

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
new file mode 100644
index 0000000000000..03fbe2437b6e9
--- /dev/null
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -0,0 +1,523 @@
+// This file is part of Substrate.
+
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+//! Implementations of public traits, namely [StakingInterface], [DelegationInterface] and
+//! [StakingDelegationSupport].
+
+use super::*;
+
+/// StakingInterface implementation with delegation support.
+///
+/// Only supports Nominators via Delegated Bonds. It is possible for a nominator to migrate and
+/// become a `Delegate`.
+impl<T: Config> StakingInterface for Pallet<T> {
+	type Balance = BalanceOf<T>;
+	type AccountId = T::AccountId;
+	type CurrencyToVote = <T::CoreStaking as StakingInterface>::CurrencyToVote;
+
+	fn minimum_nominator_bond() -> Self::Balance {
+		T::CoreStaking::minimum_nominator_bond()
+	}
+
+	fn minimum_validator_bond() -> Self::Balance {
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+		T::CoreStaking::minimum_validator_bond()
+	}
+
+	fn stash_by_ctrl(_controller: &Self::AccountId) -> Result<Self::AccountId, DispatchError> {
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+		// ctrl are deprecated, just return err.
+		Err(Error::<T>::NotSupported.into())
+	}
+
+	fn bonding_duration() -> EraIndex {
+		T::CoreStaking::bonding_duration()
+	}
+
+	fn current_era() -> EraIndex {
+		T::CoreStaking::current_era()
+	}
+
+	fn stake(who: &Self::AccountId) -> Result<Stake<Self::Balance>, DispatchError> {
+		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
+		return T::CoreStaking::stake(who);
+	}
+
+	fn total_stake(who: &Self::AccountId) -> Result<Self::Balance, DispatchError> {
+		if Self::is_delegate(who) {
+			return T::CoreStaking::total_stake(who);
+		}
+
+		if Self::is_delegator(who) {
+			let (_, delegation_amount) =
+				<Delegators<T>>::get(who).defensive_ok_or(Error::<T>::BadState)?;
+			return Ok(delegation_amount)
+		}
+
+		Err(Error::<T>::NotSupported.into())
+	}
+
+	fn active_stake(who: &Self::AccountId) -> Result<Self::Balance, DispatchError> {
+		T::CoreStaking::active_stake(who)
+	}
+
+	fn is_unbonding(who: &Self::AccountId) -> Result<bool, DispatchError> {
+		T::CoreStaking::is_unbonding(who)
+	}
+
+	fn fully_unbond(who: &Self::AccountId) -> DispatchResult {
+		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
+		return T::CoreStaking::fully_unbond(who);
+	}
+
+	fn bond(
+		who: &Self::AccountId,
+		value: Self::Balance,
+		payee: &Self::AccountId,
+	) -> DispatchResult {
+		// ensure who is not already staked
+		ensure!(T::CoreStaking::status(who).is_err(), Error::<T>::NotDelegate);
+		let delegation_register = <Delegates<T>>::get(who).ok_or(Error::<T>::NotDelegate)?;
+
+		ensure!(delegation_register.unbonded_balance() >= value, Error::<T>::NotEnoughFunds);
+		ensure!(delegation_register.payee == *payee, Error::<T>::InvalidRewardDestination);
+
+		T::CoreStaking::bond(who, value, payee)
+	}
+
+	fn nominate(who: &Self::AccountId, validators: Vec<Self::AccountId>) -> DispatchResult {
+		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
+		return T::CoreStaking::nominate(who, validators);
+	}
+
+	fn chill(who: &Self::AccountId) -> DispatchResult {
+		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
+		return T::CoreStaking::chill(who);
+	}
+
+	fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult {
+		let delegation_register = <Delegates<T>>::get(who).ok_or(Error::<T>::NotDelegate)?;
+		ensure!(delegation_register.unbonded_balance() >= extra, Error::<T>::NotEnoughFunds);
+
+		T::CoreStaking::bond_extra(who, extra)
+	}
+
+	fn unbond(stash: &Self::AccountId, value: Self::Balance) -> DispatchResult {
+		let delegation_register = <Delegates<T>>::get(stash).ok_or(Error::<T>::NotDelegate)?;
+		ensure!(delegation_register.hold >= value, Error::<T>::NotEnoughFunds);
+
+		T::CoreStaking::unbond(stash, value)
+	}
+
+	/// Not supported, call [`Delegate::withdraw`]
+	fn withdraw_unbonded(
+		_stash: Self::AccountId,
+		_num_slashing_spans: u32,
+	) -> Result<bool, DispatchError> {
+		// FIXME(ank4n): Support withdrawing to self account.
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+		Err(Error::<T>::NotSupported.into())
+	}
+
+	/// Not supported, call [`Delegate::withdraw`]
+	fn withdraw_exact(
+		_stash: &Self::AccountId,
+		_amount: Self::Balance,
+		_num_slashing_spans: u32,
+	) -> Result<bool, DispatchError> {
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+		Err(Error::<T>::NotSupported.into())
+	}
+
+	fn desired_validator_count() -> u32 {
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+		T::CoreStaking::desired_validator_count()
+	}
+
+	fn election_ongoing() -> bool {
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+		T::CoreStaking::election_ongoing()
+	}
+
+	fn force_unstake(_who: Self::AccountId) -> DispatchResult {
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+		Err(Error::<T>::NotSupported.into())
+	}
+
+	fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool {
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+		T::CoreStaking::is_exposed_in_era(who, era)
+	}
+
+	fn status(who: &Self::AccountId) -> Result<StakerStatus<Self::AccountId>, DispatchError> {
+		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
+		T::CoreStaking::status(who)
+	}
+
+	fn is_validator(who: &Self::AccountId) -> bool {
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+		T::CoreStaking::is_validator(who)
+	}
+
+	fn nominations(who: &Self::AccountId) -> Option<Vec<Self::AccountId>> {
+		T::CoreStaking::nominations(who)
+	}
+
+	fn slash_reward_fraction() -> Perbill {
+		T::CoreStaking::slash_reward_fraction()
+	}
+
+	fn release_all(_who: &Self::AccountId) {
+		defensive_assert!(false, "not supported for delegated impl of staking interface");
+	}
+
+	#[cfg(feature = "runtime-benchmarks")]
+	fn max_exposure_page_size() -> sp_staking::Page {
+		T::CoreStaking::max_exposure_page_size()
+	}
+
+	#[cfg(feature = "runtime-benchmarks")]
+	fn add_era_stakers(
+		current_era: &EraIndex,
+		stash: &Self::AccountId,
+		exposures: Vec<(Self::AccountId, Self::Balance)>,
+	) {
+		T::CoreStaking::add_era_stakers(current_era, stash, exposures)
+	}
+
+	#[cfg(feature = "runtime-benchmarks")]
+	fn set_current_era(era: EraIndex) {
+		T::CoreStaking::set_current_era(era)
+	}
+}
+
+impl<T: Config> DelegationInterface for Pallet<T> {
+	type Balance = BalanceOf<T>;
+	type AccountId = T::AccountId;
+
+	fn delegated_balance(who: &Self::AccountId) -> Self::Balance {
+		<Delegates<T>>::get(who)
+			.map_or_else(|| 0u32.into(), |register| register.delegated_balance())
+	}
+
+	fn unbonded_balance(who: &Self::AccountId) -> Self::Balance {
+		<Delegates<T>>::get(who).map_or_else(|| 0u32.into(), |register| register.unbonded_balance())
+	}
+
+	fn accept_delegations(
+		who: &Self::AccountId,
+		reward_destination: &Self::AccountId,
+	) -> DispatchResult {
+		Self::register_as_delegate(
+			RawOrigin::Signed(who.clone()).into(),
+			reward_destination.clone(),
+		)
+	}
+
+	/// Transfers funds from current staked account to `proxy_delegator`. Current staked account
+	/// becomes a `delegate` with `proxy_delegator` delegating stakes to it.
+	fn migrate_accept_delegations(
+		new_delegate: &Self::AccountId,
+		proxy_delegator: &Self::AccountId,
+		payee: &Self::AccountId,
+	) -> DispatchResult {
+		ensure!(new_delegate != proxy_delegator, Error::<T>::InvalidDelegation);
+
+		// ensure proxy delegator has at least minimum balance to keep the account alive.
+		ensure!(
+			T::Currency::reducible_balance(
+				proxy_delegator,
+				Preservation::Expendable,
+				Fortitude::Polite
+			) > Zero::zero(),
+			Error::<T>::NotEnoughFunds
+		);
+
+		// ensure staker is a nominator
+		let status = T::CoreStaking::status(new_delegate)?;
+		match status {
+			StakerStatus::Nominator(_) => (),
+			_ => return Err(Error::<T>::InvalidDelegation.into()),
+		}
+
+		<DelegateMigration<T>>::insert(&new_delegate, &proxy_delegator);
+		let stake = T::CoreStaking::stake(new_delegate)?;
+
+		// unlock funds from staker
+		T::CoreStaking::release_all(new_delegate);
+
+		// try transferring the staked amount. This should never fail but if it does, it indicates
+		// bad state and we abort.
+		T::Currency::transfer(new_delegate, proxy_delegator, stake.total, Preservation::Expendable)
+			.map_err(|_| Error::<T>::BadState)?;
+
+		// delegate from new delegator to staker.
+		// todo(ank4n) : inline this fn and propagate payee to core staking..
+		Self::accept_delegations(new_delegate, payee)?;
+
+		Self::delegate(proxy_delegator, new_delegate, stake.total)?;
+		Self::bond_all(new_delegate)
+	}
+
+	fn block_delegations(delegate: &Self::AccountId) -> DispatchResult {
+		let mut register = <Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
+		register.blocked = true;
+		<Delegates<T>>::insert(delegate, register);
+
+		Ok(())
+	}
+
+	fn unblock_delegations(delegate: &Self::AccountId) -> DispatchResult {
+		let mut register = <Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
+		register.blocked = false;
+		<Delegates<T>>::insert(delegate, register);
+
+		Ok(())
+	}
+
+	fn kill_delegate(_delegate: &Self::AccountId) -> DispatchResult {
+		todo!()
+	}
+
+	fn bond_all(who: &Self::AccountId) -> DispatchResult {
+		let delegate = <Delegates<T>>::get(who).ok_or(Error::<T>::NotDelegate)?;
+		let amount_to_bond = delegate.unbonded_balance();
+
+		match T::CoreStaking::stake(who) {
+			// already bonded
+			Ok(_) => T::CoreStaking::bond_extra(who, amount_to_bond),
+			// first bond
+			Err(_) => T::CoreStaking::bond(who, amount_to_bond, &delegate.payee),
+		}
+	}
+
+	#[transactional]
+	fn delegate_withdraw(
+		delegate: &Self::AccountId,
+		delegator: &Self::AccountId,
+		value: Self::Balance,
+		num_slashing_spans: u32,
+	) -> DispatchResult {
+		// check how much is already unbonded
+		let delegation_register = <Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
+		let unbonded_balance = delegation_register.unbonded_balance();
+
+		if unbonded_balance < value {
+			// fixme(ank4n) handle killing of stash
+			let amount_to_withdraw = value.saturating_sub(unbonded_balance);
+			let _stash_killed: bool =
+				T::CoreStaking::withdraw_exact(delegate, amount_to_withdraw, num_slashing_spans)
+					.map_err(|_| Error::<T>::WithdrawFailed)?;
+		}
+
+		Self::delegation_withdraw(delegator, delegate, value)
+	}
+
+	fn apply_slash(
+		delegate: &Self::AccountId,
+		delegator: &Self::AccountId,
+		value: Self::Balance,
+		maybe_reporter: Option<Self::AccountId>,
+	) -> DispatchResult {
+		let mut delegation_register =
+			<Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
+		let (assigned_delegate, delegate_balance) =
+			<Delegators<T>>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
+
+		ensure!(&assigned_delegate == delegate, Error::<T>::NotDelegate);
+		ensure!(delegate_balance >= value, Error::<T>::NotEnoughFunds);
+
+		let (mut credit, _missing) =
+			T::Currency::slash(&HoldReason::Delegating.into(), &delegator, value);
+		let actual_slash = credit.peek();
+		// remove the slashed amount
+		delegation_register.pending_slash.saturating_reduce(actual_slash);
+		<Delegates<T>>::insert(delegate, delegation_register);
+
+		if let Some(reporter) = maybe_reporter {
+			let reward_payout: BalanceOf<T> =
+				T::CoreStaking::slash_reward_fraction() * actual_slash;
+			let (reporter_reward, rest) = credit.split(reward_payout);
+			credit = rest;
+			// fixme(ank4n): handle error
+			let _ = T::Currency::resolve(&reporter, reporter_reward);
+		}
+
+		T::OnSlash::on_unbalanced(credit);
+		Ok(())
+	}
+
+	/// Move funds from proxy delegator to actual delegator.
+	#[transactional]
+	fn migrate_delegator(
+		delegate: &Self::AccountId,
+		new_delegator: &Self::AccountId,
+		value: Self::Balance,
+	) -> DispatchResult {
+		ensure!(value >= T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
+		// make sure new delegator is not an existing delegator or a delegate
+		ensure!(!<Delegates<T>>::contains_key(new_delegator), Error::<T>::NotAllowed);
+		ensure!(!<Delegators<T>>::contains_key(new_delegator), Error::<T>::NotAllowed);
+		// ensure we are migrating
+		let proxy_delegator =
+			<DelegateMigration<T>>::get(delegate).ok_or(Error::<T>::NotMigrating)?;
+		// proxy delegator must exist
+		let (assigned_delegate, delegate_balance) =
+			<Delegators<T>>::get(&proxy_delegator).ok_or(Error::<T>::BadState)?;
+		ensure!(assigned_delegate == *delegate, Error::<T>::BadState);
+
+		// make sure proxy delegator has enough balance to support this migration.
+		ensure!(delegate_balance >= value, Error::<T>::NotEnoughFunds);
+
+		// remove delegation of `value` from `proxy_delegator`.
+		let updated_delegate_balance = delegate_balance.saturating_sub(value);
+
+		// if all funds are migrated out of proxy delegator, clean up.
+		if updated_delegate_balance == BalanceOf::<T>::zero() {
+			<Delegators<T>>::remove(&proxy_delegator);
+			<DelegateMigration<T>>::remove(delegate);
+		} else {
+			// else update proxy delegator
+			<Delegators<T>>::insert(&proxy_delegator, (delegate, updated_delegate_balance));
+		}
+
+		let released = T::Currency::release(
+			&HoldReason::Delegating.into(),
+			&proxy_delegator,
+			value,
+			Precision::BestEffort,
+		)?;
+
+		defensive_assert!(released == value, "hold should have been released fully");
+
+		// transfer the withdrawn value to `new_delegator`.
+		T::Currency::transfer(&proxy_delegator, new_delegator, value, Preservation::Expendable)
+			.map_err(|_| Error::<T>::BadState)?;
+
+		// add the above removed delegation to `new_delegator`.
+		<Delegators<T>>::insert(new_delegator, (delegate, value));
+		// hold the funds again in the new delegator account.
+		T::Currency::hold(&HoldReason::Delegating.into(), &new_delegator, value)?;
+
+		Ok(())
+	}
+
+	fn delegate(
+		delegator: &Self::AccountId,
+		delegate: &Self::AccountId,
+		value: Self::Balance,
+	) -> DispatchResult {
+		let delegator_balance =
+			T::Currency::reducible_balance(&delegator, Preservation::Expendable, Fortitude::Polite);
+		ensure!(value >= T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
+		ensure!(delegator_balance >= value, Error::<T>::NotEnoughFunds);
+		ensure!(delegate != delegator, Error::<T>::InvalidDelegation);
+
+		let mut delegation_register =
+			<Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
+		ensure!(!delegation_register.blocked, Error::<T>::DelegationsBlocked);
+
+		// A delegate cannot delegate.
+		if <Delegates<T>>::contains_key(delegator) {
+			return Err(Error::<T>::InvalidDelegation.into())
+		}
+
+		let new_delegation_amount =
+			if let Some((current_delegate, current_delegation)) = <Delegators<T>>::get(delegator) {
+				ensure!(&current_delegate == delegate, Error::<T>::InvalidDelegation);
+				value.saturating_add(current_delegation)
+			} else {
+				value
+			};
+
+		delegation_register.total_delegated.saturating_accrue(value);
+
+		<Delegators<T>>::insert(delegator, (delegate, new_delegation_amount));
+		<Delegates<T>>::insert(delegate, delegation_register);
+
+		T::Currency::hold(&HoldReason::Delegating.into(), &delegator, value)?;
+
+		Self::deposit_event(Event::<T>::Delegated {
+			delegate: delegate.clone(),
+			delegator: delegator.clone(),
+			amount: value,
+		});
+
+		Ok(())
+	}
+}
+
+impl<T: Config> StakingDelegationSupport for Pallet<T> {
+    type Balance = BalanceOf<T>;
+    type AccountId = T::AccountId;
+    fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
+        <Delegates<T>>::get(who)
+            .map(|delegate| delegate.delegated_balance())
+            .unwrap_or_default()
+    }
+
+    fn restrict_reward_destination(
+        who: &Self::AccountId,
+        reward_destination: Option<Self::AccountId>,
+    ) -> bool {
+        let maybe_register = <Delegates<T>>::get(who);
+
+        if maybe_register.is_none() {
+            // no restrictions for non delegates.
+            return false;
+        }
+
+        // restrict if reward destination is not set
+        if reward_destination.is_none() {
+            return true;
+        }
+
+        let register = maybe_register.expect("checked above; qed");
+        let reward_acc = reward_destination.expect("checked above; qed");
+
+        // restrict if reward account is not what delegate registered.
+        register.payee != reward_acc
+    }
+
+    fn is_delegate(who: &Self::AccountId) -> bool {
+        Self::is_delegate(who)
+    }
+
+    fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+        ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
+
+        // delegation register should exist since `who` is a delegate.
+        let delegation_register = <Delegates<T>>::get(who).defensive_ok_or(Error::<T>::BadState)?;
+
+        ensure!(delegation_register.total_delegated >= amount, Error::<T>::NotEnoughFunds);
+        ensure!(delegation_register.pending_slash <= amount, Error::<T>::UnappliedSlash);
+        let updated_register = DelegationLedger { hold: amount, ..delegation_register };
+        <Delegates<T>>::insert(who, updated_register);
+
+        Ok(())
+    }
+
+    fn report_slash(who: &Self::AccountId, slash: Self::Balance) {
+        <Delegates<T>>::mutate(who, |maybe_register| match maybe_register {
+            Some(register) => register.pending_slash.saturating_accrue(slash),
+            None => {
+                defensive!("should not be called on non-delegate");
+            },
+        });
+    }
+}
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 2c426dfdec75a..f6b4fff758bfb 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -57,6 +57,9 @@ mod types;
 
 use types::*;
 
+// implementation of public traits.
+mod impls;
+
 #[cfg(feature = "runtime-benchmarks")]
 mod benchmarking;
 
@@ -303,506 +306,7 @@ pub mod pallet {
 	}
 }
 
-impl<T: Config> DelegationInterface for Pallet<T> {
-	type Balance = BalanceOf<T>;
-	type AccountId = T::AccountId;
-
-	fn delegated_balance(who: &Self::AccountId) -> Self::Balance {
-		<Delegates<T>>::get(who)
-			.map_or_else(|| 0u32.into(), |register| register.delegated_balance())
-	}
-
-	fn unbonded_balance(who: &Self::AccountId) -> Self::Balance {
-		<Delegates<T>>::get(who).map_or_else(|| 0u32.into(), |register| register.unbonded_balance())
-	}
-
-	fn accept_delegations(
-		who: &Self::AccountId,
-		reward_destination: &Self::AccountId,
-	) -> DispatchResult {
-		Self::register_as_delegate(
-			RawOrigin::Signed(who.clone()).into(),
-			reward_destination.clone(),
-		)
-	}
-
-	/// Transfers funds from current staked account to `proxy_delegator`. Current staked account
-	/// becomes a `delegate` with `proxy_delegator` delegating stakes to it.
-	fn migrate_accept_delegations(
-		new_delegate: &Self::AccountId,
-		proxy_delegator: &Self::AccountId,
-		payee: &Self::AccountId,
-	) -> DispatchResult {
-		ensure!(new_delegate != proxy_delegator, Error::<T>::InvalidDelegation);
-
-		// ensure proxy delegator has at least minimum balance to keep the account alive.
-		ensure!(
-			T::Currency::reducible_balance(
-				proxy_delegator,
-				Preservation::Expendable,
-				Fortitude::Polite
-			) > Zero::zero(),
-			Error::<T>::NotEnoughFunds
-		);
-
-		// ensure staker is a nominator
-		let status = T::CoreStaking::status(new_delegate)?;
-		match status {
-			StakerStatus::Nominator(_) => (),
-			_ => return Err(Error::<T>::InvalidDelegation.into()),
-		}
-
-		<DelegateMigration<T>>::insert(&new_delegate, &proxy_delegator);
-		let stake = T::CoreStaking::stake(new_delegate)?;
-
-		// unlock funds from staker
-		T::CoreStaking::release_all(new_delegate);
-
-		// try transferring the staked amount. This should never fail but if it does, it indicates
-		// bad state and we abort.
-		T::Currency::transfer(new_delegate, proxy_delegator, stake.total, Preservation::Expendable)
-			.map_err(|_| Error::<T>::BadState)?;
-
-		// delegate from new delegator to staker.
-		// todo(ank4n) : inline this fn and propagate payee to core staking..
-		Self::accept_delegations(new_delegate, payee)?;
-
-		Self::delegate(proxy_delegator, new_delegate, stake.total)?;
-		Self::bond_all(new_delegate)
-	}
-
-	fn block_delegations(delegate: &Self::AccountId) -> DispatchResult {
-		let mut register = <Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-		register.blocked = true;
-		<Delegates<T>>::insert(delegate, register);
-
-		Ok(())
-	}
-
-	fn unblock_delegations(delegate: &Self::AccountId) -> DispatchResult {
-		let mut register = <Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-		register.blocked = false;
-		<Delegates<T>>::insert(delegate, register);
-
-		Ok(())
-	}
-
-	fn kill_delegate(_delegate: &Self::AccountId) -> DispatchResult {
-		todo!()
-	}
-
-	fn bond_all(who: &Self::AccountId) -> DispatchResult {
-		let delegate = <Delegates<T>>::get(who).ok_or(Error::<T>::NotDelegate)?;
-		let amount_to_bond = delegate.unbonded_balance();
-
-		match T::CoreStaking::stake(who) {
-			// already bonded
-			Ok(_) => T::CoreStaking::bond_extra(who, amount_to_bond),
-			// first bond
-			Err(_) => T::CoreStaking::bond(who, amount_to_bond, &delegate.payee),
-		}
-	}
-
-	#[transactional]
-	fn delegate_withdraw(
-		delegate: &Self::AccountId,
-		delegator: &Self::AccountId,
-		value: Self::Balance,
-		num_slashing_spans: u32,
-	) -> DispatchResult {
-		// check how much is already unbonded
-		let delegation_register = <Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-		let unbonded_balance = delegation_register.unbonded_balance();
-
-		if unbonded_balance < value {
-			// fixme(ank4n) handle killing of stash
-			let amount_to_withdraw = value.saturating_sub(unbonded_balance);
-			let _stash_killed: bool =
-				T::CoreStaking::withdraw_exact(delegate, amount_to_withdraw, num_slashing_spans)
-					.map_err(|_| Error::<T>::WithdrawFailed)?;
-		}
-
-		Self::delegation_withdraw(delegator, delegate, value)
-	}
-
-	fn apply_slash(
-		delegate: &Self::AccountId,
-		delegator: &Self::AccountId,
-		value: Self::Balance,
-		maybe_reporter: Option<Self::AccountId>,
-	) -> DispatchResult {
-		let mut delegation_register =
-			<Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-		let (assigned_delegate, delegate_balance) =
-			<Delegators<T>>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
-
-		ensure!(&assigned_delegate == delegate, Error::<T>::NotDelegate);
-		ensure!(delegate_balance >= value, Error::<T>::NotEnoughFunds);
-
-		let (mut credit, _missing) =
-			T::Currency::slash(&HoldReason::Delegating.into(), &delegator, value);
-		let actual_slash = credit.peek();
-		// remove the slashed amount
-		delegation_register.pending_slash.saturating_reduce(actual_slash);
-		<Delegates<T>>::insert(delegate, delegation_register);
-
-		if let Some(reporter) = maybe_reporter {
-			let reward_payout: BalanceOf<T> =
-				T::CoreStaking::slash_reward_fraction() * actual_slash;
-			let (reporter_reward, rest) = credit.split(reward_payout);
-			credit = rest;
-			// fixme(ank4n): handle error
-			let _ = T::Currency::resolve(&reporter, reporter_reward);
-		}
-
-		T::OnSlash::on_unbalanced(credit);
-		Ok(())
-	}
-
-	/// Move funds from proxy delegator to actual delegator.
-	#[transactional]
-	fn migrate_delegator(
-		delegate: &Self::AccountId,
-		new_delegator: &Self::AccountId,
-		value: Self::Balance,
-	) -> DispatchResult {
-		ensure!(value >= T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
-		// make sure new delegator is not an existing delegator or a delegate
-		ensure!(!<Delegates<T>>::contains_key(new_delegator), Error::<T>::NotAllowed);
-		ensure!(!<Delegators<T>>::contains_key(new_delegator), Error::<T>::NotAllowed);
-		// ensure we are migrating
-		let proxy_delegator =
-			<DelegateMigration<T>>::get(delegate).ok_or(Error::<T>::NotMigrating)?;
-		// proxy delegator must exist
-		let (assigned_delegate, delegate_balance) =
-			<Delegators<T>>::get(&proxy_delegator).ok_or(Error::<T>::BadState)?;
-		ensure!(assigned_delegate == *delegate, Error::<T>::BadState);
-
-		// make sure proxy delegator has enough balance to support this migration.
-		ensure!(delegate_balance >= value, Error::<T>::NotEnoughFunds);
-
-		// remove delegation of `value` from `proxy_delegator`.
-		let updated_delegate_balance = delegate_balance.saturating_sub(value);
-
-		// if all funds are migrated out of proxy delegator, clean up.
-		if updated_delegate_balance == BalanceOf::<T>::zero() {
-			<Delegators<T>>::remove(&proxy_delegator);
-			<DelegateMigration<T>>::remove(delegate);
-		} else {
-			// else update proxy delegator
-			<Delegators<T>>::insert(&proxy_delegator, (delegate, updated_delegate_balance));
-		}
-
-		let released = T::Currency::release(
-			&HoldReason::Delegating.into(),
-			&proxy_delegator,
-			value,
-			Precision::BestEffort,
-		)?;
-
-		defensive_assert!(released == value, "hold should have been released fully");
-
-		// transfer the withdrawn value to `new_delegator`.
-		T::Currency::transfer(&proxy_delegator, new_delegator, value, Preservation::Expendable)
-			.map_err(|_| Error::<T>::BadState)?;
-
-		// add the above removed delegation to `new_delegator`.
-		<Delegators<T>>::insert(new_delegator, (delegate, value));
-		// hold the funds again in the new delegator account.
-		T::Currency::hold(&HoldReason::Delegating.into(), &new_delegator, value)?;
-
-		Ok(())
-	}
-
-	fn delegate(
-		delegator: &Self::AccountId,
-		delegate: &Self::AccountId,
-		value: Self::Balance,
-	) -> DispatchResult {
-		let delegator_balance =
-			T::Currency::reducible_balance(&delegator, Preservation::Expendable, Fortitude::Polite);
-		ensure!(value >= T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
-		ensure!(delegator_balance >= value, Error::<T>::NotEnoughFunds);
-		ensure!(delegate != delegator, Error::<T>::InvalidDelegation);
-
-		let mut delegation_register =
-			<Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-		ensure!(!delegation_register.blocked, Error::<T>::DelegationsBlocked);
-
-		// A delegate cannot delegate.
-		if <Delegates<T>>::contains_key(delegator) {
-			return Err(Error::<T>::InvalidDelegation.into())
-		}
-
-		let new_delegation_amount =
-			if let Some((current_delegate, current_delegation)) = <Delegators<T>>::get(delegator) {
-				ensure!(&current_delegate == delegate, Error::<T>::InvalidDelegation);
-				value.saturating_add(current_delegation)
-			} else {
-				value
-			};
-
-		delegation_register.total_delegated.saturating_accrue(value);
-
-		<Delegators<T>>::insert(delegator, (delegate, new_delegation_amount));
-		<Delegates<T>>::insert(delegate, delegation_register);
-
-		T::Currency::hold(&HoldReason::Delegating.into(), &delegator, value)?;
-
-		Self::deposit_event(Event::<T>::Delegated {
-			delegate: delegate.clone(),
-			delegator: delegator.clone(),
-			amount: value,
-		});
-
-		Ok(())
-	}
-}
-
-impl<T: Config> StakingDelegationSupport for Pallet<T> {
-	type Balance = BalanceOf<T>;
-	type AccountId = T::AccountId;
-	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
-		<Delegates<T>>::get(who)
-			.map(|delegate| delegate.delegated_balance())
-			.unwrap_or_default()
-	}
-
-	fn restrict_reward_destination(
-		who: &Self::AccountId,
-		reward_destination: Option<Self::AccountId>,
-	) -> bool {
-		let maybe_register = <Delegates<T>>::get(who);
-
-		if maybe_register.is_none() {
-			// no restrictions for non delegates.
-			return false;
-		}
-
-		// restrict if reward destination is not set
-		if reward_destination.is_none() {
-			return true;
-		}
-
-		let register = maybe_register.expect("checked above; qed");
-		let reward_acc = reward_destination.expect("checked above; qed");
-
-		// restrict if reward account is not what delegate registered.
-		register.payee != reward_acc
-	}
-
-	fn is_delegate(who: &Self::AccountId) -> bool {
-		Self::is_delegate(who)
-	}
-
-	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
-		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
-
-		// delegation register should exist since `who` is a delegate.
-		let delegation_register = <Delegates<T>>::get(who).defensive_ok_or(Error::<T>::BadState)?;
-
-		ensure!(delegation_register.total_delegated >= amount, Error::<T>::NotEnoughFunds);
-		ensure!(delegation_register.pending_slash <= amount, Error::<T>::UnappliedSlash);
-		let updated_register = DelegationLedger { hold: amount, ..delegation_register };
-		<Delegates<T>>::insert(who, updated_register);
-
-		Ok(())
-	}
-
-	fn report_slash(who: &Self::AccountId, slash: Self::Balance) {
-		<Delegates<T>>::mutate(who, |maybe_register| match maybe_register {
-			Some(register) => register.pending_slash.saturating_accrue(slash),
-			None => {
-				defensive!("should not be called on non-delegate");
-			},
-		});
-	}
-}
-
-/// StakingInterface implementation with delegation support.
-///
-/// Only supports Nominators via Delegated Bonds. It is possible for a nominator to migrate and
-/// become a `Delegate`.
-impl<T: Config> StakingInterface for Pallet<T> {
-	type Balance = BalanceOf<T>;
-	type AccountId = T::AccountId;
-	type CurrencyToVote = <T::CoreStaking as StakingInterface>::CurrencyToVote;
-
-	fn minimum_nominator_bond() -> Self::Balance {
-		T::CoreStaking::minimum_nominator_bond()
-	}
-
-	fn minimum_validator_bond() -> Self::Balance {
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
-		T::CoreStaking::minimum_validator_bond()
-	}
-
-	fn stash_by_ctrl(_controller: &Self::AccountId) -> Result<Self::AccountId, DispatchError> {
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
-		// ctrl are deprecated, just return err.
-		Err(Error::<T>::NotSupported.into())
-	}
-
-	fn bonding_duration() -> EraIndex {
-		T::CoreStaking::bonding_duration()
-	}
-
-	fn current_era() -> EraIndex {
-		T::CoreStaking::current_era()
-	}
-
-	fn stake(who: &Self::AccountId) -> Result<Stake<Self::Balance>, DispatchError> {
-		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
-		return T::CoreStaking::stake(who);
-	}
-
-	fn total_stake(who: &Self::AccountId) -> Result<Self::Balance, DispatchError> {
-		if Self::is_delegate(who) {
-			return T::CoreStaking::total_stake(who);
-		}
-
-		if Self::is_delegator(who) {
-			let (_, delegation_amount) =
-				<Delegators<T>>::get(who).defensive_ok_or(Error::<T>::BadState)?;
-			return Ok(delegation_amount)
-		}
-
-		Err(Error::<T>::NotSupported.into())
-	}
-
-	fn active_stake(who: &Self::AccountId) -> Result<Self::Balance, DispatchError> {
-		T::CoreStaking::active_stake(who)
-	}
-
-	fn is_unbonding(who: &Self::AccountId) -> Result<bool, DispatchError> {
-		T::CoreStaking::is_unbonding(who)
-	}
-
-	fn fully_unbond(who: &Self::AccountId) -> DispatchResult {
-		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
-		return T::CoreStaking::fully_unbond(who);
-	}
-
-	fn bond(
-		who: &Self::AccountId,
-		value: Self::Balance,
-		payee: &Self::AccountId,
-	) -> DispatchResult {
-		// ensure who is not already staked
-		ensure!(T::CoreStaking::status(who).is_err(), Error::<T>::NotDelegate);
-		let delegation_register = <Delegates<T>>::get(who).ok_or(Error::<T>::NotDelegate)?;
-
-		ensure!(delegation_register.unbonded_balance() >= value, Error::<T>::NotEnoughFunds);
-		ensure!(delegation_register.payee == *payee, Error::<T>::InvalidRewardDestination);
-
-		T::CoreStaking::bond(who, value, payee)
-	}
-
-	fn nominate(who: &Self::AccountId, validators: Vec<Self::AccountId>) -> DispatchResult {
-		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
-		return T::CoreStaking::nominate(who, validators);
-	}
-
-	fn chill(who: &Self::AccountId) -> DispatchResult {
-		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
-		return T::CoreStaking::chill(who);
-	}
-
-	fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult {
-		let delegation_register = <Delegates<T>>::get(who).ok_or(Error::<T>::NotDelegate)?;
-		ensure!(delegation_register.unbonded_balance() >= extra, Error::<T>::NotEnoughFunds);
-
-		T::CoreStaking::bond_extra(who, extra)
-	}
-
-	fn unbond(stash: &Self::AccountId, value: Self::Balance) -> DispatchResult {
-		let delegation_register = <Delegates<T>>::get(stash).ok_or(Error::<T>::NotDelegate)?;
-		ensure!(delegation_register.hold >= value, Error::<T>::NotEnoughFunds);
-
-		T::CoreStaking::unbond(stash, value)
-	}
-
-	/// Not supported, call [`Delegate::withdraw`]
-	fn withdraw_unbonded(
-		_stash: Self::AccountId,
-		_num_slashing_spans: u32,
-	) -> Result<bool, DispatchError> {
-		// FIXME(ank4n): Support withdrawing to self account.
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
-		Err(Error::<T>::NotSupported.into())
-	}
-
-	/// Not supported, call [`Delegate::withdraw`]
-	fn withdraw_exact(
-		_stash: &Self::AccountId,
-		_amount: Self::Balance,
-		_num_slashing_spans: u32,
-	) -> Result<bool, DispatchError> {
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
-		Err(Error::<T>::NotSupported.into())
-	}
-
-	fn desired_validator_count() -> u32 {
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
-		T::CoreStaking::desired_validator_count()
-	}
-
-	fn election_ongoing() -> bool {
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
-		T::CoreStaking::election_ongoing()
-	}
-
-	fn force_unstake(_who: Self::AccountId) -> DispatchResult {
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
-		Err(Error::<T>::NotSupported.into())
-	}
-
-	fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool {
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
-		T::CoreStaking::is_exposed_in_era(who, era)
-	}
-
-	fn status(who: &Self::AccountId) -> Result<StakerStatus<Self::AccountId>, DispatchError> {
-		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
-		T::CoreStaking::status(who)
-	}
-
-	fn is_validator(who: &Self::AccountId) -> bool {
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
-		T::CoreStaking::is_validator(who)
-	}
 
-	fn nominations(who: &Self::AccountId) -> Option<Vec<Self::AccountId>> {
-		T::CoreStaking::nominations(who)
-	}
-
-	fn slash_reward_fraction() -> Perbill {
-		T::CoreStaking::slash_reward_fraction()
-	}
-
-	fn release_all(_who: &Self::AccountId) {
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
-	}
-
-	#[cfg(feature = "runtime-benchmarks")]
-	fn max_exposure_page_size() -> sp_staking::Page {
-		T::CoreStaking::max_exposure_page_size()
-	}
-
-	#[cfg(feature = "runtime-benchmarks")]
-	fn add_era_stakers(
-		current_era: &EraIndex,
-		stash: &Self::AccountId,
-		exposures: Vec<(Self::AccountId, Self::Balance)>,
-	) {
-		T::CoreStaking::add_era_stakers(current_era, stash, exposures)
-	}
-
-	#[cfg(feature = "runtime-benchmarks")]
-	fn set_current_era(era: EraIndex) {
-		T::CoreStaking::set_current_era(era)
-	}
-}
 impl<T: Config> Pallet<T> {
 	fn sub_account(account_type: AccountType, delegate_account: T::AccountId) -> T::AccountId {
 		T::PalletId::get().into_sub_account_truncating((account_type, delegate_account.clone()))

From 71c9fffdaf30b187b0fa6f1873f7b1021adac5ba Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 17 Feb 2024 18:20:17 +0100
Subject: [PATCH 086/202] add delegation struct

---
 .../frame/delegated-staking/src/impls.rs      | 40 +++++++++++--------
 substrate/frame/delegated-staking/src/lib.rs  | 19 +++++----
 .../frame/delegated-staking/src/types.rs      | 30 +++++++++++++-
 3 files changed, 61 insertions(+), 28 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 03fbe2437b6e9..f6401b7463616 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -64,9 +64,9 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		}
 
 		if Self::is_delegator(who) {
-			let (_, delegation_amount) =
-				<Delegators<T>>::get(who).defensive_ok_or(Error::<T>::BadState)?;
-			return Ok(delegation_amount)
+			let delegation =
+				Delegation::<T>::get(who).defensive_ok_or(Error::<T>::BadState)?;
+			return Ok(delegation.amount)
 		}
 
 		Err(Error::<T>::NotSupported.into())
@@ -336,11 +336,11 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 	) -> DispatchResult {
 		let mut delegation_register =
 			<Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-		let (assigned_delegate, delegate_balance) =
+		let delegation =
 			<Delegators<T>>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
 
-		ensure!(&assigned_delegate == delegate, Error::<T>::NotDelegate);
-		ensure!(delegate_balance >= value, Error::<T>::NotEnoughFunds);
+		ensure!(&delegation.delegate == delegate, Error::<T>::NotDelegate);
+		ensure!(delegation.amount >= value, Error::<T>::NotEnoughFunds);
 
 		let (mut credit, _missing) =
 			T::Currency::slash(&HoldReason::Delegating.into(), &delegator, value);
@@ -377,15 +377,16 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		let proxy_delegator =
 			<DelegateMigration<T>>::get(delegate).ok_or(Error::<T>::NotMigrating)?;
 		// proxy delegator must exist
-		let (assigned_delegate, delegate_balance) =
+		// let (assigned_delegate, delegate_balance) =
+		let delegation =
 			<Delegators<T>>::get(&proxy_delegator).ok_or(Error::<T>::BadState)?;
-		ensure!(assigned_delegate == *delegate, Error::<T>::BadState);
+		ensure!(delegation.delegate == *delegate, Error::<T>::BadState);
 
 		// make sure proxy delegator has enough balance to support this migration.
-		ensure!(delegate_balance >= value, Error::<T>::NotEnoughFunds);
+		ensure!(delegation.amount >= value, Error::<T>::NotEnoughFunds);
 
 		// remove delegation of `value` from `proxy_delegator`.
-		let updated_delegate_balance = delegate_balance.saturating_sub(value);
+		let updated_delegate_balance = delegation.amount.saturating_sub(value);
 
 		// if all funds are migrated out of proxy delegator, clean up.
 		if updated_delegate_balance == BalanceOf::<T>::zero() {
@@ -393,7 +394,14 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 			<DelegateMigration<T>>::remove(delegate);
 		} else {
 			// else update proxy delegator
-			<Delegators<T>>::insert(&proxy_delegator, (delegate, updated_delegate_balance));
+			<Delegators<T>>::insert(
+				&proxy_delegator,
+				Delegation {
+					delegate: delegate.clone(),
+					amount: updated_delegate_balance,
+					delegator: Some(proxy_delegator.clone()),
+				}
+			);
 		}
 
 		let released = T::Currency::release(
@@ -410,7 +418,7 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 			.map_err(|_| Error::<T>::BadState)?;
 
 		// add the above removed delegation to `new_delegator`.
-		<Delegators<T>>::insert(new_delegator, (delegate, value));
+		Delegation::<T>::from(delegate, value).save(new_delegator);
 		// hold the funds again in the new delegator account.
 		T::Currency::hold(&HoldReason::Delegating.into(), &new_delegator, value)?;
 
@@ -438,16 +446,16 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		}
 
 		let new_delegation_amount =
-			if let Some((current_delegate, current_delegation)) = <Delegators<T>>::get(delegator) {
-				ensure!(&current_delegate == delegate, Error::<T>::InvalidDelegation);
-				value.saturating_add(current_delegation)
+			if let Some(current_delegation) = <Delegators<T>>::get(delegator) {
+				ensure!(&current_delegation.delegate == delegate, Error::<T>::InvalidDelegation);
+				value.saturating_add(current_delegation.amount)
 			} else {
 				value
 			};
 
 		delegation_register.total_delegated.saturating_accrue(value);
 
-		<Delegators<T>>::insert(delegator, (delegate, new_delegation_amount));
+		Delegation::<T>::from(delegate, new_delegation_amount).save(delegator);
 		<Delegates<T>>::insert(delegate, delegation_register);
 
 		T::Currency::hold(&HoldReason::Delegating.into(), &delegator, value)?;
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index f6b4fff758bfb..3428f9ff17699 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -186,7 +186,7 @@ pub mod pallet {
 	/// want to restrict delegators to delegate only to one account.
 	#[pallet::storage]
 	pub(crate) type Delegators<T: Config> =
-		CountedStorageMap<_, Twox64Concat, T::AccountId, (T::AccountId, BalanceOf<T>), OptionQuery>;
+		CountedStorageMap<_, Twox64Concat, T::AccountId, Delegation<T>, OptionQuery>;
 
 	/// Map of `Delegate` to their Ledger.
 	#[pallet::storage]
@@ -352,7 +352,7 @@ impl<T: Config> Pallet<T> {
 		T::Currency::transfer(who, &proxy_delegator, stake.total, Preservation::Protect)
 			.map_err(|_| Error::<T>::BadState)?;
 
-		DelegationLedger::<T>::new(&reward_account).save(&who);
+		let ledger = DelegationLedger::<T>::new(&reward_account).save(&who);
 		// FIXME(ank4n) expose set payee in staking interface.
 		// T::CoreStaking::set_payee(who, reward_account)
 
@@ -378,9 +378,8 @@ impl<T: Config> Pallet<T> {
 		delegate: &T::AccountId,
 		amount: BalanceOf<T>,
 	) -> DispatchResult {
-		// let mut delegation_register =
-		// 	<Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-		// ensure!(!delegation_register.blocked, Error::<T>::DelegationsBlocked);
+		// let mut ledger = <Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
+		// ensure!(!ledger.blocked, Error::<T>::DelegationsBlocked);
 		//
 		// let new_delegation_amount =
 		// 	if let Some((current_delegate, current_delegation)) = <Delegators<T>>::get(delegator) {
@@ -419,18 +418,18 @@ impl<T: Config> Pallet<T> {
 		delegation_register.total_delegated.saturating_reduce(value);
 		<Delegates<T>>::insert(delegate, delegation_register);
 
-		let (assigned_delegate, delegate_balance) =
+		let delegation =
 			<Delegators<T>>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
 		// delegator should already be delegating to `delegate`
-		ensure!(&assigned_delegate == delegate, Error::<T>::NotDelegate);
-		ensure!(delegate_balance >= value, Error::<T>::NotEnoughFunds);
-		let updated_delegate_balance = delegate_balance.saturating_sub(value);
+		ensure!(&delegation.delegate == delegate, Error::<T>::NotDelegate);
+		ensure!(delegation.amount >= value, Error::<T>::NotEnoughFunds);
+		let updated_delegate_balance = delegation.amount.saturating_sub(value);
 
 		// remove delegator if nothing delegated anymore
 		if updated_delegate_balance == BalanceOf::<T>::zero() {
 			<Delegators<T>>::remove(delegator);
 		} else {
-			<Delegators<T>>::insert(delegator, (delegate, updated_delegate_balance));
+			<Delegators<T>>::insert(delegator, Delegation::<T>::from(delegate, updated_delegate_balance));
 		}
 
 		let released = T::Currency::release(
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index 6de552d235583..df5141f607a12 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -34,10 +34,36 @@ pub(crate) enum AccountType {
 #[derive(Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
 #[scale_info(skip_type_params(T))]
 pub struct Delegation<T: Config> {
-    // The target of delegation.
+    /// The target of delegation.
     pub delegate: T::AccountId,
-    // The amount delegated.
+    /// The amount delegated.
     pub amount: BalanceOf<T>,
+    /// The `delegator` account who is delegating.
+    #[codec(skip)]
+    pub delegator: Option<T::AccountId>,
+}
+
+impl<T: Config> Delegation<T> {
+    pub(crate) fn get(delegator: &T::AccountId) -> Option<Self> {
+        <Delegators<T>>::get(delegator).map(|d| d.with_key(delegator))
+    }
+
+    /// consumes self and returns a new copy with the key.
+    fn with_key(self, key: &T::AccountId) -> Self {
+        Delegation { delegator: Some(key.clone()), ..self }
+    }
+
+    pub(crate) fn from(delegate: &T::AccountId, amount: BalanceOf<T>) -> Self {
+        Delegation { delegate: delegate.clone(), amount, delegator: None }
+    }
+
+    pub(crate) fn save(self, key: &T::AccountId) -> Self {
+        let new_val = self.with_key(key);
+        <Delegators<T>>::insert(key, &new_val);
+
+        new_val
+    }
+
 }
 
 /// Ledger of all delegations to a `Delegate`.

From 5caba0765d98cb6c1b51c45006820be9f113ec04 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 17 Feb 2024 18:54:14 +0100
Subject: [PATCH 087/202] impl delegate

---
 substrate/frame/delegated-staking/src/lib.rs  | 56 +++++++++----------
 .../frame/delegated-staking/src/types.rs      | 11 ++--
 2 files changed, 33 insertions(+), 34 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 3428f9ff17699..715a9db07f2e7 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -78,8 +78,8 @@ use frame_support::{
 };
 
 use sp_runtime::{
-	traits::{AccountIdConversion, Zero},
-	DispatchResult, Perbill, RuntimeDebug, Saturating,
+	traits::{AccountIdConversion, Zero, CheckedAdd},
+	DispatchResult, Perbill, RuntimeDebug, Saturating, ArithmeticError,
 };
 use sp_staking::{
 	delegation::{DelegationInterface, StakingDelegationSupport},
@@ -378,33 +378,31 @@ impl<T: Config> Pallet<T> {
 		delegate: &T::AccountId,
 		amount: BalanceOf<T>,
 	) -> DispatchResult {
-		// let mut ledger = <Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-		// ensure!(!ledger.blocked, Error::<T>::DelegationsBlocked);
-		//
-		// let new_delegation_amount =
-		// 	if let Some((current_delegate, current_delegation)) = <Delegators<T>>::get(delegator) {
-		// 		ensure!(&current_delegate == delegate, Error::<T>::InvalidDelegation);
-		// 		value.saturating_add(current_delegation)
-		// 	} else {
-		// 		value
-		// 	};
-		//
-		// delegation_register.total_delegated.saturating_accrue(value);
-		//
-		// <Delegators<T>>::insert(delegator, (delegate, new_delegation_amount));
-		// <Delegates<T>>::insert(delegate, delegation_register);
-		//
-		// T::Currency::hold(&HoldReason::Delegating.into(), &delegator, value)?;
-		//
-		// Self::deposit_event(Event::<T>::Delegated {
-		// 	delegate: delegate.clone(),
-		// 	delegator: delegator.clone(),
-		// 	amount: value,
-		// });
-		//
-		// Ok(())
-
-		todo!()
+		let mut ledger = DelegationLedger::<T>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
+		ensure!(!ledger.blocked, Error::<T>::DelegationsBlocked);
+
+		let new_delegation_amount =
+			if let Some(existing_delegation) = Delegation::<T>::get(delegator) {
+				ensure!(&existing_delegation.delegate == delegate, Error::<T>::InvalidDelegation);
+				existing_delegation.amount.checked_add(&amount).ok_or(ArithmeticError::Overflow)?
+			} else {
+				amount
+			};
+
+		Delegation::<T>::from(delegate, new_delegation_amount).save(delegator);
+
+		ledger.total_delegated = ledger.total_delegated.checked_add(&new_delegation_amount).ok_or(ArithmeticError::Overflow)?;
+		ledger.save(delegate);
+
+		T::Currency::hold(&HoldReason::Delegating.into(), &delegator, amount)?;
+
+		Self::deposit_event(Event::<T>::Delegated {
+			delegate: delegate.clone(),
+			delegator: delegator.clone(),
+			amount,
+		});
+
+		Ok(())
 	}
 	fn delegation_withdraw(
 		delegator: &T::AccountId,
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index df5141f607a12..2079ab872313b 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -96,7 +96,7 @@ pub struct DelegationLedger<T: Config> {
 
 
 impl<T: Config> DelegationLedger<T> {
-    pub fn new(reward_destination: &T::AccountId) -> Self {
+    pub(crate) fn new(reward_destination: &T::AccountId) -> Self {
         DelegationLedger {
             payee: reward_destination.clone(),
             total_delegated: Zero::zero(),
@@ -112,12 +112,12 @@ impl<T: Config> DelegationLedger<T> {
         DelegationLedger { delegate: Some(key.clone()), ..self }
     }
 
-    fn get(key: &T::AccountId) -> Option<Self> {
+    pub(crate) fn get(key: &T::AccountId) -> Option<Self> {
         <Delegates<T>>::get(key).map(|d| d.with_key(key))
     }
 
     /// Balance that is stakeable.
-    pub fn delegated_balance(&self) -> BalanceOf<T> {
+    pub(crate) fn delegated_balance(&self) -> BalanceOf<T> {
         // do not allow to stake more than unapplied slash
         self.total_delegated.saturating_sub(self.pending_slash)
     }
@@ -125,11 +125,12 @@ impl<T: Config> DelegationLedger<T> {
     /// Balance that is delegated but not bonded.
     ///
     /// Can be funds that are unbonded but not withdrawn.
-    pub fn unbonded_balance(&self) -> BalanceOf<T> {
+    pub(crate) fn unbonded_balance(&self) -> BalanceOf<T> {
+        // fixme(ank4n) Remove hold and get balance from removing withdrawal_unclaimed.
         self.total_delegated.saturating_sub(self.hold)
     }
 
-    pub fn save(self, key: &T::AccountId) -> Self {
+    pub(crate) fn save(self, key: &T::AccountId) -> Self {
         let new_val = self.with_key(key);
         <Delegates<T>>::insert(key, &new_val);
 

From 0ec296576de312e79e67fc0f511bc9830861ae9e Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 17 Feb 2024 18:58:36 +0100
Subject: [PATCH 088/202] remove the key

---
 .../frame/delegated-staking/src/impls.rs      |  1 -
 .../frame/delegated-staking/src/types.rs      | 36 ++++---------------
 2 files changed, 7 insertions(+), 30 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index f6401b7463616..3fd38f23575fa 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -399,7 +399,6 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 				Delegation {
 					delegate: delegate.clone(),
 					amount: updated_delegate_balance,
-					delegator: Some(proxy_delegator.clone()),
 				}
 			);
 		}
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index 2079ab872313b..303c91b42dbb1 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -38,30 +38,19 @@ pub struct Delegation<T: Config> {
     pub delegate: T::AccountId,
     /// The amount delegated.
     pub amount: BalanceOf<T>,
-    /// The `delegator` account who is delegating.
-    #[codec(skip)]
-    pub delegator: Option<T::AccountId>,
 }
 
 impl<T: Config> Delegation<T> {
     pub(crate) fn get(delegator: &T::AccountId) -> Option<Self> {
-        <Delegators<T>>::get(delegator).map(|d| d.with_key(delegator))
-    }
-
-    /// consumes self and returns a new copy with the key.
-    fn with_key(self, key: &T::AccountId) -> Self {
-        Delegation { delegator: Some(key.clone()), ..self }
+        <Delegators<T>>::get(delegator)
     }
 
     pub(crate) fn from(delegate: &T::AccountId, amount: BalanceOf<T>) -> Self {
-        Delegation { delegate: delegate.clone(), amount, delegator: None }
+        Delegation { delegate: delegate.clone(), amount }
     }
 
-    pub(crate) fn save(self, key: &T::AccountId) -> Self {
-        let new_val = self.with_key(key);
-        <Delegators<T>>::insert(key, &new_val);
-
-        new_val
+    pub(crate) fn save(self, key: &T::AccountId) {
+        <Delegators<T>>::insert(key, self)
     }
 
 }
@@ -88,9 +77,6 @@ pub struct DelegationLedger<T: Config> {
     pub pending_slash: BalanceOf<T>,
     /// Whether this `delegate` is blocked from receiving new delegations.
     pub blocked: bool,
-    /// The `delegate` account associated with the ledger.
-    #[codec(skip)]
-    pub delegate: Option<T::AccountId>,
 }
 
 
@@ -103,17 +89,12 @@ impl<T: Config> DelegationLedger<T> {
             hold: Zero::zero(),
             pending_slash: Zero::zero(),
             blocked: false,
-            delegate: None,
         }
     }
 
-    /// consumes self and returns a new copy with the key.
-    fn with_key(self, key: &T::AccountId) -> Self {
-        DelegationLedger { delegate: Some(key.clone()), ..self }
-    }
 
     pub(crate) fn get(key: &T::AccountId) -> Option<Self> {
-        <Delegates<T>>::get(key).map(|d| d.with_key(key))
+        <Delegates<T>>::get(key)
     }
 
     /// Balance that is stakeable.
@@ -130,10 +111,7 @@ impl<T: Config> DelegationLedger<T> {
         self.total_delegated.saturating_sub(self.hold)
     }
 
-    pub(crate) fn save(self, key: &T::AccountId) -> Self {
-        let new_val = self.with_key(key);
-        <Delegates<T>>::insert(key, &new_val);
-
-        new_val
+    pub(crate) fn save(self, key: &T::AccountId) {
+        <Delegates<T>>::insert(key, self)
     }
 }

From 4a609024af0437a972592763d809535adfd9cbfd Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 17 Feb 2024 20:13:28 +0100
Subject: [PATCH 089/202] fix test

---
 .../frame/delegated-staking/src/impls.rs      | 45 +++----------------
 substrate/frame/delegated-staking/src/lib.rs  | 31 +++++++------
 .../frame/delegated-staking/src/tests.rs      |  9 ++--
 3 files changed, 26 insertions(+), 59 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 3fd38f23575fa..6c4b447c45fb3 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -232,46 +232,13 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 	/// Transfers funds from current staked account to `proxy_delegator`. Current staked account
 	/// becomes a `delegate` with `proxy_delegator` delegating stakes to it.
 	fn migrate_accept_delegations(
-		new_delegate: &Self::AccountId,
-		proxy_delegator: &Self::AccountId,
-		payee: &Self::AccountId,
+		who: &Self::AccountId,
+		_proxy_delegator: &Self::AccountId,
+		reward_destination: &Self::AccountId,
 	) -> DispatchResult {
-		ensure!(new_delegate != proxy_delegator, Error::<T>::InvalidDelegation);
-
-		// ensure proxy delegator has at least minimum balance to keep the account alive.
-		ensure!(
-			T::Currency::reducible_balance(
-				proxy_delegator,
-				Preservation::Expendable,
-				Fortitude::Polite
-			) > Zero::zero(),
-			Error::<T>::NotEnoughFunds
-		);
-
-		// ensure staker is a nominator
-		let status = T::CoreStaking::status(new_delegate)?;
-		match status {
-			StakerStatus::Nominator(_) => (),
-			_ => return Err(Error::<T>::InvalidDelegation.into()),
-		}
-
-		<DelegateMigration<T>>::insert(&new_delegate, &proxy_delegator);
-		let stake = T::CoreStaking::stake(new_delegate)?;
-
-		// unlock funds from staker
-		T::CoreStaking::release_all(new_delegate);
-
-		// try transferring the staked amount. This should never fail but if it does, it indicates
-		// bad state and we abort.
-		T::Currency::transfer(new_delegate, proxy_delegator, stake.total, Preservation::Expendable)
-			.map_err(|_| Error::<T>::BadState)?;
-
-		// delegate from new delegator to staker.
-		// todo(ank4n) : inline this fn and propagate payee to core staking..
-		Self::accept_delegations(new_delegate, payee)?;
-
-		Self::delegate(proxy_delegator, new_delegate, stake.total)?;
-		Self::bond_all(new_delegate)
+		Self::migrate_to_delegate(RawOrigin::Signed(who.clone()).into(),
+								  reward_destination.clone()
+		)
 	}
 
 	fn block_delegations(delegate: &Self::AccountId) -> DispatchResult {
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 715a9db07f2e7..962e3a649d3b5 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -215,15 +215,15 @@ pub mod pallet {
 		) -> DispatchResult {
 			let who = ensure_signed(origin)?;
 
-			// They cannot be already a direct staker in the staking pallet.
-			ensure!(Self::not_direct_staker(&who), Error::<T>::AlreadyStaker);
-
 			// Existing `delegate` cannot register again.
 			ensure!(!Self::is_delegate(&who), Error::<T>::NotAllowed);
 
 			// A delegator cannot become a `delegate`.
 			ensure!(!Self::is_delegator(&who), Error::<T>::NotAllowed);
 
+			// They cannot be already a direct staker in the staking pallet.
+			ensure!(Self::not_direct_staker(&who), Error::<T>::AlreadyStaker);
+
 			// Reward account cannot be same as `delegate` account.
 			ensure!(reward_account != who, Error::<T>::InvalidRewardDestination);
 
@@ -242,6 +242,9 @@ pub mod pallet {
 			reward_account: T::AccountId,
 		) -> DispatchResult {
 			let who = ensure_signed(origin)?;
+			// Ensure is not already a delegate.
+			ensure!(!Self::is_delegate(&who), Error::<T>::NotAllowed);
+
 			ensure!(Self::is_direct_nominator(&who), Error::<T>::NotAllowed);
 
 			// Reward account cannot be same as `delegate` account.
@@ -308,7 +311,7 @@ pub mod pallet {
 
 
 impl<T: Config> Pallet<T> {
-	fn sub_account(account_type: AccountType, delegate_account: T::AccountId) -> T::AccountId {
+	pub(crate) fn sub_account(account_type: AccountType, delegate_account: T::AccountId) -> T::AccountId {
 		T::PalletId::get().into_sub_account_truncating((account_type, delegate_account.clone()))
 	}
 
@@ -320,10 +323,6 @@ impl<T: Config> Pallet<T> {
 		<Delegators<T>>::contains_key(who)
 	}
 
-	fn is_migrating(delegate: &T::AccountId) -> bool {
-		<DelegateMigration<T>>::contains_key(delegate)
-	}
-
 	/// Returns true if who is not already staking.
 	fn not_direct_staker(who: &T::AccountId) -> bool {
 		T::CoreStaking::status(&who).is_err()
@@ -337,22 +336,26 @@ impl<T: Config> Pallet<T> {
 	}
 
 	fn do_migrate_to_delegate(who: &T::AccountId, reward_account: &T::AccountId) -> DispatchResult {
+		// We create a proxy delegator that will keep all the delegation funds until funds are
+		// transferred to actual delegator.
+		let proxy_delegator = Self::sub_account(AccountType::ProxyDelegator, who.clone());
+
+		// Transfer minimum balance to proxy delegator.
+		T::Currency::transfer(who, &proxy_delegator, T::Currency::minimum_balance(), Preservation::Protect)
+			.map_err(|_| Error::<T>::NotEnoughFunds)?;
+
 		// Get current stake
 		let stake = T::CoreStaking::stake(who)?;
 
 		// release funds from core staking.
 		T::CoreStaking::release_all(who);
 
-		// We create a proxy delegator that will keep all the delegation funds until funds are
-		// transferred to actual delegator.
-		let proxy_delegator = Self::sub_account(AccountType::ProxyDelegator, who.clone());
-
 		// transferring just released staked amount. This should never fail but if it does, it
 		// indicates bad state and we abort.
 		T::Currency::transfer(who, &proxy_delegator, stake.total, Preservation::Protect)
 			.map_err(|_| Error::<T>::BadState)?;
 
-		let ledger = DelegationLedger::<T>::new(&reward_account).save(&who);
+		DelegationLedger::<T>::new(&reward_account).save(&who);
 		// FIXME(ank4n) expose set payee in staking interface.
 		// T::CoreStaking::set_payee(who, reward_account)
 
@@ -394,7 +397,7 @@ impl<T: Config> Pallet<T> {
 		ledger.total_delegated = ledger.total_delegated.checked_add(&new_delegation_amount).ok_or(ArithmeticError::Overflow)?;
 		ledger.save(delegate);
 
-		T::Currency::hold(&HoldReason::Delegating.into(), &delegator, amount)?;
+		T::Currency::hold(&HoldReason::Delegating.into(), delegator, amount)?;
 
 		Self::deposit_event(Event::<T>::Delegated {
 			delegate: delegate.clone(),
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 889d9601564bb..ce66ddbb3ba85 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -448,11 +448,9 @@ mod integration {
 			// to migrate, nominator needs to set an account as a proxy delegator where staked funds
 			// will be moved and delegated back to this old nominator account. This should be funded
 			// with at least ED.
-			let proxy_delegator = 202;
-			fund(&proxy_delegator, ExistentialDeposit::get());
+			let proxy_delegator = DelegatedStaking::sub_account(AccountType::ProxyDelegator, 200);
 
 			assert_ok!(DelegatedStaking::migrate_accept_delegations(&200, &proxy_delegator, &201));
-			assert!(DelegatedStaking::is_migrating(&200));
 
 			// verify all went well
 			let mut expected_proxy_delegated_amount = staked_amount;
@@ -460,7 +458,8 @@ mod integration {
 				Balances::balance_on_hold(&HoldReason::Delegating.into(), &proxy_delegator),
 				expected_proxy_delegated_amount
 			);
-			assert_eq!(Balances::free_balance(200), 5000 - staked_amount);
+			// ED + stake amount is transferred from delegate to proxy delegator account.
+			assert_eq!(Balances::free_balance(200), 5000 - staked_amount - ExistentialDeposit::get());
 			assert_eq!(DelegatedStaking::stake(&200).unwrap(), init_stake);
 			assert_eq!(DelegatedStaking::delegated_balance(&200), 4000);
 			assert_eq!(DelegatedStaking::unbonded_balance(&200), 0);
@@ -489,8 +488,6 @@ mod integration {
 				assert_eq!(DelegatedStaking::unbonded_balance(&200), 0);
 			}
 
-			assert!(!DelegatedStaking::is_migrating(&200));
-
 			// cannot use migrate delegator anymore
 			assert_noop!(
 				DelegatedStaking::migrate_delegator(&200, &305, 1),

From 6eb298cf556d1e01da25b437afa0ec841f3b055f Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 17 Feb 2024 21:10:17 +0100
Subject: [PATCH 090/202] fix unclaim withdraw to be a field and not sub
 account

---
 substrate/frame/delegated-staking/src/lib.rs  |  89 ++++++++++--
 .../frame/delegated-staking/src/types.rs      | 136 +++++++++---------
 2 files changed, 144 insertions(+), 81 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 962e3a649d3b5..e1eb556a92560 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -44,6 +44,16 @@
 //! to apply slash. It is `delegate`'s responsibility to apply slashes for each delegator, one at a
 //! time. Staking pallet ensures the pending slash never exceeds staked amount and would freeze
 //! further withdraws until pending slashes are applied.
+//!
+//!
+//! ### Note about minimum balance
+//!
+//! When registering as `delegate`, a sub account for unclaimed withdrawals are created and funded
+//! with `ExistentialDeposit`. If the `delegate` is migrating from being a `Nominator`, another
+//! sub account is created for managing funds of delegators who have not yet migrated their funds
+//! to won account. These accounts are funded by the `Delegate` and it should have enough free
+//! balance to cover these. When these accounts are not killed (not needed anymore), the funds are
+//! returned to the `Delegate`.
 
 #[cfg(test)]
 mod mock;
@@ -71,15 +81,15 @@ use frame_support::{
 			Balanced, Inspect as FunInspect, Mutate as FunMutate,
 		},
 		tokens::{fungible::Credit, Fortitude, Precision, Preservation},
-		DefensiveOption, Imbalance, OnUnbalanced,
+		Defensive, DefensiveOption, Imbalance, OnUnbalanced,
 	},
 	transactional,
 	weights::Weight,
 };
 
 use sp_runtime::{
-	traits::{AccountIdConversion, Zero, CheckedAdd},
-	DispatchResult, Perbill, RuntimeDebug, Saturating, ArithmeticError,
+	traits::{AccountIdConversion, CheckedAdd, CheckedSub, Zero},
+	ArithmeticError, DispatchResult, Perbill, RuntimeDebug, Saturating,
 };
 use sp_staking::{
 	delegation::{DelegationInterface, StakingDelegationSupport},
@@ -266,7 +276,39 @@ pub mod pallet {
 			amount: BalanceOf<T>,
 			num_slashing_spans: u32,
 		) -> DispatchResult {
-			todo!()
+			let who = ensure_signed(origin)?;
+			let mut ledger = DelegationLedger::<T>::get(&who).ok_or(Error::<T>::NotDelegate)?;
+
+			// if we do not already have enough funds to be claimed, try withdraw some more.
+			if ledger.unclaimed_withdrawals < amount {
+				let pre_total =
+					T::CoreStaking::stake(&who).defensive()?.total;
+				// fixme(ank4n) handle killing of stash
+				let _stash_killed: bool =
+					T::CoreStaking::withdraw_unbonded(who.clone(), num_slashing_spans)
+						.map_err(|_| Error::<T>::WithdrawFailed)?;
+
+				let post_total =
+					T::CoreStaking::stake(&who).defensive()?.total;
+
+				let new_withdrawn =
+					post_total.checked_sub(&pre_total).defensive_ok_or(Error::<T>::BadState)?;
+
+				ledger.unclaimed_withdrawals = ledger
+					.unclaimed_withdrawals
+					.checked_add(&new_withdrawn)
+					.ok_or(ArithmeticError::Overflow)?;
+			}
+
+
+			ensure!(
+				ledger.unclaimed_withdrawals > amount,
+				Error::<T>::NotEnoughFunds
+			);
+
+			ledger.save(&who);
+
+			Self::delegation_withdraw(&delegator, &who, amount)
 		}
 
 		/// Migrate delegated fund.
@@ -309,9 +351,11 @@ pub mod pallet {
 	}
 }
 
-
 impl<T: Config> Pallet<T> {
-	pub(crate) fn sub_account(account_type: AccountType, delegate_account: T::AccountId) -> T::AccountId {
+	pub(crate) fn sub_account(
+		account_type: AccountType,
+		delegate_account: T::AccountId,
+	) -> T::AccountId {
 		T::PalletId::get().into_sub_account_truncating((account_type, delegate_account.clone()))
 	}
 
@@ -341,8 +385,13 @@ impl<T: Config> Pallet<T> {
 		let proxy_delegator = Self::sub_account(AccountType::ProxyDelegator, who.clone());
 
 		// Transfer minimum balance to proxy delegator.
-		T::Currency::transfer(who, &proxy_delegator, T::Currency::minimum_balance(), Preservation::Protect)
-			.map_err(|_| Error::<T>::NotEnoughFunds)?;
+		T::Currency::transfer(
+			who,
+			&proxy_delegator,
+			T::Currency::minimum_balance(),
+			Preservation::Protect,
+		)
+		.map_err(|_| Error::<T>::NotEnoughFunds)?;
 
 		// Get current stake
 		let stake = T::CoreStaking::stake(who)?;
@@ -387,14 +436,20 @@ impl<T: Config> Pallet<T> {
 		let new_delegation_amount =
 			if let Some(existing_delegation) = Delegation::<T>::get(delegator) {
 				ensure!(&existing_delegation.delegate == delegate, Error::<T>::InvalidDelegation);
-				existing_delegation.amount.checked_add(&amount).ok_or(ArithmeticError::Overflow)?
+				existing_delegation
+					.amount
+					.checked_add(&amount)
+					.ok_or(ArithmeticError::Overflow)?
 			} else {
 				amount
 			};
 
 		Delegation::<T>::from(delegate, new_delegation_amount).save(delegator);
 
-		ledger.total_delegated = ledger.total_delegated.checked_add(&new_delegation_amount).ok_or(ArithmeticError::Overflow)?;
+		ledger.total_delegated = ledger
+			.total_delegated
+			.checked_add(&new_delegation_amount)
+			.ok_or(ArithmeticError::Overflow)?;
 		ledger.save(delegate);
 
 		T::Currency::hold(&HoldReason::Delegating.into(), delegator, amount)?;
@@ -407,6 +462,12 @@ impl<T: Config> Pallet<T> {
 
 		Ok(())
 	}
+
+	fn do_release(delegate: &T::AccountId, delegator: &T::AccountId, value: BalanceOf<T>) {
+		// let mut ledger =
+		// 	DelegationLedger::<T>::get(delegate).defensive_ok_or(Error::<T>::NotDelegate)?;
+	}
+	// FIXME(ank4n): remove this
 	fn delegation_withdraw(
 		delegator: &T::AccountId,
 		delegate: &T::AccountId,
@@ -419,8 +480,7 @@ impl<T: Config> Pallet<T> {
 		delegation_register.total_delegated.saturating_reduce(value);
 		<Delegates<T>>::insert(delegate, delegation_register);
 
-		let delegation =
-			<Delegators<T>>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
+		let delegation = <Delegators<T>>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
 		// delegator should already be delegating to `delegate`
 		ensure!(&delegation.delegate == delegate, Error::<T>::NotDelegate);
 		ensure!(delegation.amount >= value, Error::<T>::NotEnoughFunds);
@@ -430,7 +490,10 @@ impl<T: Config> Pallet<T> {
 		if updated_delegate_balance == BalanceOf::<T>::zero() {
 			<Delegators<T>>::remove(delegator);
 		} else {
-			<Delegators<T>>::insert(delegator, Delegation::<T>::from(delegate, updated_delegate_balance));
+			<Delegators<T>>::insert(
+				delegator,
+				Delegation::<T>::from(delegate, updated_delegate_balance),
+			);
 		}
 
 		let released = T::Currency::release(
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index 303c91b42dbb1..6143abded59e0 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -23,36 +23,35 @@ use super::*;
 /// The type of pot account being created.
 #[derive(Encode, Decode)]
 pub(crate) enum AccountType {
-    /// Funds that are withdrawn from the staking ledger but not claimed by the `delegator` yet.
-    UnclaimedWithdrawal,
-    /// A proxy delegator account created for a nominator who migrated to a `delegate` account.
-    ///
-    /// Funds for unmigrated `delegator` accounts of the `delegate` are kept here.
-    ProxyDelegator,
+	/// Funds that are withdrawn from the staking ledger but not claimed by the `delegator` yet.
+	UnclaimedWithdrawal,
+	/// A proxy delegator account created for a nominator who migrated to a `delegate` account.
+	///
+	/// Funds for unmigrated `delegator` accounts of the `delegate` are kept here.
+	ProxyDelegator,
 }
 
 #[derive(Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
 #[scale_info(skip_type_params(T))]
 pub struct Delegation<T: Config> {
-    /// The target of delegation.
-    pub delegate: T::AccountId,
-    /// The amount delegated.
-    pub amount: BalanceOf<T>,
+	/// The target of delegation.
+	pub delegate: T::AccountId,
+	/// The amount delegated.
+	pub amount: BalanceOf<T>,
 }
 
 impl<T: Config> Delegation<T> {
-    pub(crate) fn get(delegator: &T::AccountId) -> Option<Self> {
-        <Delegators<T>>::get(delegator)
-    }
+	pub(crate) fn get(delegator: &T::AccountId) -> Option<Self> {
+		<Delegators<T>>::get(delegator)
+	}
 
-    pub(crate) fn from(delegate: &T::AccountId, amount: BalanceOf<T>) -> Self {
-        Delegation { delegate: delegate.clone(), amount }
-    }
-
-    pub(crate) fn save(self, key: &T::AccountId) {
-        <Delegators<T>>::insert(key, self)
-    }
+	pub(crate) fn from(delegate: &T::AccountId, amount: BalanceOf<T>) -> Self {
+		Delegation { delegate: delegate.clone(), amount }
+	}
 
+	pub(crate) fn save(self, key: &T::AccountId) {
+		<Delegators<T>>::insert(key, self)
+	}
 }
 
 /// Ledger of all delegations to a `Delegate`.
@@ -63,55 +62,56 @@ impl<T: Config> Delegation<T> {
 #[derive(Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
 #[scale_info(skip_type_params(T))]
 pub struct DelegationLedger<T: Config> {
-    /// Where the reward should be paid out.
-    pub payee: T::AccountId,
-    /// Sum of all delegated funds to this `delegate`.
-    #[codec(compact)]
-    pub total_delegated: BalanceOf<T>,
-    /// Amount that is bonded and held.
-    // FIXME(ank4n) (can we remove it)
-    #[codec(compact)]
-    pub hold: BalanceOf<T>,
-    /// Slashes that are not yet applied.
-    #[codec(compact)]
-    pub pending_slash: BalanceOf<T>,
-    /// Whether this `delegate` is blocked from receiving new delegations.
-    pub blocked: bool,
+	/// Where the reward should be paid out.
+	pub payee: T::AccountId,
+	/// Sum of all delegated funds to this `delegate`.
+	#[codec(compact)]
+	pub total_delegated: BalanceOf<T>,
+	/// Amount that is bonded and held.
+	// FIXME(ank4n) (can we remove it)
+	#[codec(compact)]
+	pub hold: BalanceOf<T>,
+	/// Funds that are withdrawn from core staking but not released to delegator/s.
+	#[codec(compact)]
+	pub unclaimed_withdrawals: BalanceOf<T>,
+	/// Slashes that are not yet applied.
+	#[codec(compact)]
+	pub pending_slash: BalanceOf<T>,
+	/// Whether this `delegate` is blocked from receiving new delegations.
+	pub blocked: bool,
 }
 
-
-
 impl<T: Config> DelegationLedger<T> {
-    pub(crate) fn new(reward_destination: &T::AccountId) -> Self {
-        DelegationLedger {
-            payee: reward_destination.clone(),
-            total_delegated: Zero::zero(),
-            hold: Zero::zero(),
-            pending_slash: Zero::zero(),
-            blocked: false,
-        }
-    }
-
-
-    pub(crate) fn get(key: &T::AccountId) -> Option<Self> {
-        <Delegates<T>>::get(key)
-    }
-
-    /// Balance that is stakeable.
-    pub(crate) fn delegated_balance(&self) -> BalanceOf<T> {
-        // do not allow to stake more than unapplied slash
-        self.total_delegated.saturating_sub(self.pending_slash)
-    }
-
-    /// Balance that is delegated but not bonded.
-    ///
-    /// Can be funds that are unbonded but not withdrawn.
-    pub(crate) fn unbonded_balance(&self) -> BalanceOf<T> {
-        // fixme(ank4n) Remove hold and get balance from removing withdrawal_unclaimed.
-        self.total_delegated.saturating_sub(self.hold)
-    }
-
-    pub(crate) fn save(self, key: &T::AccountId) {
-        <Delegates<T>>::insert(key, self)
-    }
+	pub(crate) fn new(reward_destination: &T::AccountId) -> Self {
+		DelegationLedger {
+			payee: reward_destination.clone(),
+			total_delegated: Zero::zero(),
+			hold: Zero::zero(),
+			unclaimed_withdrawals: Zero::zero(),
+			pending_slash: Zero::zero(),
+			blocked: false,
+		}
+	}
+
+	pub(crate) fn get(key: &T::AccountId) -> Option<Self> {
+		<Delegates<T>>::get(key)
+	}
+
+	/// Balance that is stakeable.
+	pub(crate) fn delegated_balance(&self) -> BalanceOf<T> {
+		// do not allow to stake more than unapplied slash
+		self.total_delegated.saturating_sub(self.pending_slash)
+	}
+
+	/// Balance that is delegated but not bonded.
+	///
+	/// Can be funds that are unbonded but not withdrawn.
+	pub(crate) fn unbonded_balance(&self) -> BalanceOf<T> {
+		// fixme(ank4n) Remove hold and get balance from removing withdrawal_unclaimed.
+		self.total_delegated.saturating_sub(self.hold)
+	}
+
+	pub(crate) fn save(self, key: &T::AccountId) {
+		<Delegates<T>>::insert(key, self)
+	}
 }

From ddb79638a1b62fde6c6b8088245124117f262f99 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 17 Feb 2024 21:52:28 +0100
Subject: [PATCH 091/202] impl release

---
 substrate/frame/delegated-staking/src/lib.rs  | 117 ++++++++++++------
 .../frame/delegated-staking/src/types.rs      |   2 +-
 2 files changed, 83 insertions(+), 36 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index e1eb556a92560..2b73ba7d33506 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -277,38 +277,7 @@ pub mod pallet {
 			num_slashing_spans: u32,
 		) -> DispatchResult {
 			let who = ensure_signed(origin)?;
-			let mut ledger = DelegationLedger::<T>::get(&who).ok_or(Error::<T>::NotDelegate)?;
-
-			// if we do not already have enough funds to be claimed, try withdraw some more.
-			if ledger.unclaimed_withdrawals < amount {
-				let pre_total =
-					T::CoreStaking::stake(&who).defensive()?.total;
-				// fixme(ank4n) handle killing of stash
-				let _stash_killed: bool =
-					T::CoreStaking::withdraw_unbonded(who.clone(), num_slashing_spans)
-						.map_err(|_| Error::<T>::WithdrawFailed)?;
-
-				let post_total =
-					T::CoreStaking::stake(&who).defensive()?.total;
-
-				let new_withdrawn =
-					post_total.checked_sub(&pre_total).defensive_ok_or(Error::<T>::BadState)?;
-
-				ledger.unclaimed_withdrawals = ledger
-					.unclaimed_withdrawals
-					.checked_add(&new_withdrawn)
-					.ok_or(ArithmeticError::Overflow)?;
-			}
-
-
-			ensure!(
-				ledger.unclaimed_withdrawals > amount,
-				Error::<T>::NotEnoughFunds
-			);
-
-			ledger.save(&who);
-
-			Self::delegation_withdraw(&delegator, &who, amount)
+			Self::do_release(&who, &delegator, amount, num_slashing_spans)
 		}
 
 		/// Migrate delegated fund.
@@ -463,9 +432,87 @@ impl<T: Config> Pallet<T> {
 		Ok(())
 	}
 
-	fn do_release(delegate: &T::AccountId, delegator: &T::AccountId, value: BalanceOf<T>) {
-		// let mut ledger =
-		// 	DelegationLedger::<T>::get(delegate).defensive_ok_or(Error::<T>::NotDelegate)?;
+	fn do_release(
+		who: &T::AccountId,
+		delegator: &T::AccountId,
+		amount: BalanceOf<T>,
+		num_slashing_spans: u32,
+	) -> DispatchResult {
+		let mut ledger = DelegationLedger::<T>::get(who).ok_or(Error::<T>::NotDelegate)?;
+		let mut delegation = Delegation::<T>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
+
+		// make sure delegation to be released is sound.
+		ensure!(&delegation.delegate == who, Error::<T>::NotDelegate);
+		ensure!(delegation.amount >= amount, Error::<T>::NotEnoughFunds);
+
+		// if we do not already have enough funds to be claimed, try withdraw some more.
+		if ledger.unclaimed_withdrawals < amount {
+			ledger = Self::withdraw_unbounded(who, num_slashing_spans)?;
+		}
+
+		// if we still do not have enough funds to release, abort.
+		ensure!(ledger.unclaimed_withdrawals >= amount, Error::<T>::NotEnoughFunds);
+
+		// book keep into ledger
+		ledger.total_delegated = ledger.total_delegated.checked_sub(&amount).defensive_ok_or(ArithmeticError::Overflow)?;
+		ledger.unclaimed_withdrawals =
+			ledger.unclaimed_withdrawals.checked_sub(&amount).defensive_ok_or(ArithmeticError::Overflow)?;
+		ledger.save(who);
+
+		// book keep delegation
+		delegation.amount = delegation.amount.checked_sub(&amount).defensive_ok_or(ArithmeticError::Overflow)?;
+
+		// remove delegator if nothing delegated anymore
+		if delegation.amount == BalanceOf::<T>::zero() {
+			<Delegators<T>>::remove(delegator);
+		} else {
+			delegation.save(delegator);
+		}
+
+		let released = T::Currency::release(
+			&HoldReason::Delegating.into(),
+			&delegator,
+			amount,
+			Precision::BestEffort,
+		)?;
+
+		defensive_assert!(released == amount, "hold should have been released fully");
+
+		Self::deposit_event(Event::<T>::Withdrawn {
+			delegate: who.clone(),
+			delegator: delegator.clone(),
+			amount,
+		});
+
+		Ok(())
+	}
+
+	fn withdraw_unbounded(
+		delegate: &T::AccountId,
+		num_slashing_spans: u32,
+	) -> Result<DelegationLedger<T>, DispatchError> {
+		let mut ledger = DelegationLedger::<T>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
+
+		let pre_total = T::CoreStaking::stake(delegate).defensive()?.total;
+
+		// fixme(ank4n) handle killing of stash
+		let _stash_killed: bool =
+			T::CoreStaking::withdraw_unbonded(delegate.clone(), num_slashing_spans)
+				.map_err(|_| Error::<T>::WithdrawFailed)?;
+
+		let post_total = T::CoreStaking::stake(delegate).defensive()?.total;
+
+		let new_withdrawn =
+			post_total.checked_sub(&pre_total).defensive_ok_or(Error::<T>::BadState)?;
+
+		ledger.unclaimed_withdrawals = ledger
+			.unclaimed_withdrawals
+			.checked_add(&new_withdrawn)
+			.ok_or(ArithmeticError::Overflow)?;
+
+		ledger.clone().save(delegate);
+
+		Ok(ledger)
 	}
 	// FIXME(ank4n): remove this
 	fn delegation_withdraw(
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index 6143abded59e0..14121df2de708 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -59,7 +59,7 @@ impl<T: Config> Delegation<T> {
 /// This keeps track of the active balance of the `delegate` that is made up from the funds that are
 /// currently delegated to this `delegate`. It also tracks the pending slashes yet to be applied
 /// among other things.
-#[derive(Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
+#[derive(Default, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
 #[scale_info(skip_type_params(T))]
 pub struct DelegationLedger<T: Config> {
 	/// Where the reward should be paid out.

From e6656a6122e74883d673e37e9a73d80dfc5a2244 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 17 Feb 2024 21:55:42 +0100
Subject: [PATCH 092/202] cleanup

---
 .../frame/delegated-staking/src/impls.rs      | 151 ++++++++----------
 substrate/frame/delegated-staking/src/lib.rs  |  45 ------
 2 files changed, 68 insertions(+), 128 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 6c4b447c45fb3..fb8a37db6ffe8 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -64,8 +64,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		}
 
 		if Self::is_delegator(who) {
-			let delegation =
-				Delegation::<T>::get(who).defensive_ok_or(Error::<T>::BadState)?;
+			let delegation = Delegation::<T>::get(who).defensive_ok_or(Error::<T>::BadState)?;
 			return Ok(delegation.amount)
 		}
 
@@ -236,9 +235,7 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		_proxy_delegator: &Self::AccountId,
 		reward_destination: &Self::AccountId,
 	) -> DispatchResult {
-		Self::migrate_to_delegate(RawOrigin::Signed(who.clone()).into(),
-								  reward_destination.clone()
-		)
+		Self::migrate_to_delegate(RawOrigin::Signed(who.clone()).into(), reward_destination.clone())
 	}
 
 	fn block_delegations(delegate: &Self::AccountId) -> DispatchResult {
@@ -280,19 +277,12 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		value: Self::Balance,
 		num_slashing_spans: u32,
 	) -> DispatchResult {
-		// check how much is already unbonded
-		let delegation_register = <Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-		let unbonded_balance = delegation_register.unbonded_balance();
-
-		if unbonded_balance < value {
-			// fixme(ank4n) handle killing of stash
-			let amount_to_withdraw = value.saturating_sub(unbonded_balance);
-			let _stash_killed: bool =
-				T::CoreStaking::withdraw_exact(delegate, amount_to_withdraw, num_slashing_spans)
-					.map_err(|_| Error::<T>::WithdrawFailed)?;
-		}
-
-		Self::delegation_withdraw(delegator, delegate, value)
+		Self::release(
+			RawOrigin::Signed(delegate.clone()).into(),
+			delegator.clone(),
+			value,
+			num_slashing_spans,
+		)
 	}
 
 	fn apply_slash(
@@ -303,8 +293,7 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 	) -> DispatchResult {
 		let mut delegation_register =
 			<Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-		let delegation =
-			<Delegators<T>>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
+		let delegation = <Delegators<T>>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
 
 		ensure!(&delegation.delegate == delegate, Error::<T>::NotDelegate);
 		ensure!(delegation.amount >= value, Error::<T>::NotEnoughFunds);
@@ -345,8 +334,7 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 			<DelegateMigration<T>>::get(delegate).ok_or(Error::<T>::NotMigrating)?;
 		// proxy delegator must exist
 		// let (assigned_delegate, delegate_balance) =
-		let delegation =
-			<Delegators<T>>::get(&proxy_delegator).ok_or(Error::<T>::BadState)?;
+		let delegation = <Delegators<T>>::get(&proxy_delegator).ok_or(Error::<T>::BadState)?;
 		ensure!(delegation.delegate == *delegate, Error::<T>::BadState);
 
 		// make sure proxy delegator has enough balance to support this migration.
@@ -363,10 +351,7 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 			// else update proxy delegator
 			<Delegators<T>>::insert(
 				&proxy_delegator,
-				Delegation {
-					delegate: delegate.clone(),
-					amount: updated_delegate_balance,
-				}
+				Delegation { delegate: delegate.clone(), amount: updated_delegate_balance },
 			);
 		}
 
@@ -437,61 +422,61 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 }
 
 impl<T: Config> StakingDelegationSupport for Pallet<T> {
-    type Balance = BalanceOf<T>;
-    type AccountId = T::AccountId;
-    fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
-        <Delegates<T>>::get(who)
-            .map(|delegate| delegate.delegated_balance())
-            .unwrap_or_default()
-    }
-
-    fn restrict_reward_destination(
-        who: &Self::AccountId,
-        reward_destination: Option<Self::AccountId>,
-    ) -> bool {
-        let maybe_register = <Delegates<T>>::get(who);
-
-        if maybe_register.is_none() {
-            // no restrictions for non delegates.
-            return false;
-        }
-
-        // restrict if reward destination is not set
-        if reward_destination.is_none() {
-            return true;
-        }
-
-        let register = maybe_register.expect("checked above; qed");
-        let reward_acc = reward_destination.expect("checked above; qed");
-
-        // restrict if reward account is not what delegate registered.
-        register.payee != reward_acc
-    }
-
-    fn is_delegate(who: &Self::AccountId) -> bool {
-        Self::is_delegate(who)
-    }
-
-    fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
-        ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
-
-        // delegation register should exist since `who` is a delegate.
-        let delegation_register = <Delegates<T>>::get(who).defensive_ok_or(Error::<T>::BadState)?;
-
-        ensure!(delegation_register.total_delegated >= amount, Error::<T>::NotEnoughFunds);
-        ensure!(delegation_register.pending_slash <= amount, Error::<T>::UnappliedSlash);
-        let updated_register = DelegationLedger { hold: amount, ..delegation_register };
-        <Delegates<T>>::insert(who, updated_register);
-
-        Ok(())
-    }
-
-    fn report_slash(who: &Self::AccountId, slash: Self::Balance) {
-        <Delegates<T>>::mutate(who, |maybe_register| match maybe_register {
-            Some(register) => register.pending_slash.saturating_accrue(slash),
-            None => {
-                defensive!("should not be called on non-delegate");
-            },
-        });
-    }
+	type Balance = BalanceOf<T>;
+	type AccountId = T::AccountId;
+	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
+		<Delegates<T>>::get(who)
+			.map(|delegate| delegate.delegated_balance())
+			.unwrap_or_default()
+	}
+
+	fn restrict_reward_destination(
+		who: &Self::AccountId,
+		reward_destination: Option<Self::AccountId>,
+	) -> bool {
+		let maybe_register = <Delegates<T>>::get(who);
+
+		if maybe_register.is_none() {
+			// no restrictions for non delegates.
+			return false;
+		}
+
+		// restrict if reward destination is not set
+		if reward_destination.is_none() {
+			return true;
+		}
+
+		let register = maybe_register.expect("checked above; qed");
+		let reward_acc = reward_destination.expect("checked above; qed");
+
+		// restrict if reward account is not what delegate registered.
+		register.payee != reward_acc
+	}
+
+	fn is_delegate(who: &Self::AccountId) -> bool {
+		Self::is_delegate(who)
+	}
+
+	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
+
+		// delegation register should exist since `who` is a delegate.
+		let delegation_register = <Delegates<T>>::get(who).defensive_ok_or(Error::<T>::BadState)?;
+
+		ensure!(delegation_register.total_delegated >= amount, Error::<T>::NotEnoughFunds);
+		ensure!(delegation_register.pending_slash <= amount, Error::<T>::UnappliedSlash);
+		let updated_register = DelegationLedger { hold: amount, ..delegation_register };
+		<Delegates<T>>::insert(who, updated_register);
+
+		Ok(())
+	}
+
+	fn report_slash(who: &Self::AccountId, slash: Self::Balance) {
+		<Delegates<T>>::mutate(who, |maybe_register| match maybe_register {
+			Some(register) => register.pending_slash.saturating_accrue(slash),
+			None => {
+				defensive!("should not be called on non-delegate");
+			},
+		});
+	}
 }
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 2b73ba7d33506..1e31e5c344452 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -514,51 +514,6 @@ impl<T: Config> Pallet<T> {
 
 		Ok(ledger)
 	}
-	// FIXME(ank4n): remove this
-	fn delegation_withdraw(
-		delegator: &T::AccountId,
-		delegate: &T::AccountId,
-		value: BalanceOf<T>,
-	) -> DispatchResult {
-		let mut delegation_register =
-			<Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-		ensure!(delegation_register.unbonded_balance() >= value, Error::<T>::BadState);
-
-		delegation_register.total_delegated.saturating_reduce(value);
-		<Delegates<T>>::insert(delegate, delegation_register);
-
-		let delegation = <Delegators<T>>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
-		// delegator should already be delegating to `delegate`
-		ensure!(&delegation.delegate == delegate, Error::<T>::NotDelegate);
-		ensure!(delegation.amount >= value, Error::<T>::NotEnoughFunds);
-		let updated_delegate_balance = delegation.amount.saturating_sub(value);
-
-		// remove delegator if nothing delegated anymore
-		if updated_delegate_balance == BalanceOf::<T>::zero() {
-			<Delegators<T>>::remove(delegator);
-		} else {
-			<Delegators<T>>::insert(
-				delegator,
-				Delegation::<T>::from(delegate, updated_delegate_balance),
-			);
-		}
-
-		let released = T::Currency::release(
-			&HoldReason::Delegating.into(),
-			&delegator,
-			value,
-			Precision::BestEffort,
-		)?;
-
-		defensive_assert!(released == value, "hold should have been released fully");
-		Self::deposit_event(Event::<T>::Withdrawn {
-			delegate: delegate.clone(),
-			delegator: delegator.clone(),
-			amount: value,
-		});
-
-		Ok(())
-	}
 }
 
 #[cfg(any(test, feature = "try-runtime"))]

From 8002ef0c149abfd83ff710f4c67e83f085b3a289 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 17 Feb 2024 21:56:03 +0100
Subject: [PATCH 093/202] cargo fmt

---
 substrate/frame/delegated-staking/src/lib.rs  | 16 +++++++++++----
 .../frame/delegated-staking/src/tests.rs      |  5 ++++-
 substrate/frame/nomination-pools/src/lib.rs   | 20 +++++++++++--------
 substrate/frame/staking/src/lib.rs            |  1 -
 4 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 1e31e5c344452..98909b0e39fe3 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -454,13 +454,21 @@ impl<T: Config> Pallet<T> {
 		ensure!(ledger.unclaimed_withdrawals >= amount, Error::<T>::NotEnoughFunds);
 
 		// book keep into ledger
-		ledger.total_delegated = ledger.total_delegated.checked_sub(&amount).defensive_ok_or(ArithmeticError::Overflow)?;
-		ledger.unclaimed_withdrawals =
-			ledger.unclaimed_withdrawals.checked_sub(&amount).defensive_ok_or(ArithmeticError::Overflow)?;
+		ledger.total_delegated = ledger
+			.total_delegated
+			.checked_sub(&amount)
+			.defensive_ok_or(ArithmeticError::Overflow)?;
+		ledger.unclaimed_withdrawals = ledger
+			.unclaimed_withdrawals
+			.checked_sub(&amount)
+			.defensive_ok_or(ArithmeticError::Overflow)?;
 		ledger.save(who);
 
 		// book keep delegation
-		delegation.amount = delegation.amount.checked_sub(&amount).defensive_ok_or(ArithmeticError::Overflow)?;
+		delegation.amount = delegation
+			.amount
+			.checked_sub(&amount)
+			.defensive_ok_or(ArithmeticError::Overflow)?;
 
 		// remove delegator if nothing delegated anymore
 		if delegation.amount == BalanceOf::<T>::zero() {
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index ce66ddbb3ba85..611c9cd3a8fd7 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -459,7 +459,10 @@ mod integration {
 				expected_proxy_delegated_amount
 			);
 			// ED + stake amount is transferred from delegate to proxy delegator account.
-			assert_eq!(Balances::free_balance(200), 5000 - staked_amount - ExistentialDeposit::get());
+			assert_eq!(
+				Balances::free_balance(200),
+				5000 - staked_amount - ExistentialDeposit::get()
+			);
 			assert_eq!(DelegatedStaking::stake(&200).unwrap(), init_stake);
 			assert_eq!(DelegatedStaking::delegated_balance(&200), 4000);
 			assert_eq!(DelegatedStaking::unbonded_balance(&200), 0);
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index fef5cfaccf5b4..dfb0cefa542be 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -373,7 +373,7 @@ use sp_runtime::{
 	},
 	FixedPointNumber, Perbill,
 };
-use sp_staking::{EraIndex, StakingInterface, delegation::DelegationInterface};
+use sp_staking::{delegation::DelegationInterface, EraIndex, StakingInterface};
 use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, ops::Div, vec::Vec};
 
 #[cfg(any(feature = "try-runtime", feature = "fuzzing", test, debug_assertions))]
@@ -2264,9 +2264,9 @@ pub mod pallet {
 			ensure!(!withdrawn_points.is_empty(), Error::<T>::CannotWithdrawAny);
 
 			let mut sum_unlocked_points: BalanceOf<T> = Zero::zero();
-			let balance_to_unbond = withdrawn_points
-				.iter()
-				.fold(BalanceOf::<T>::zero(), |accumulator, (era, unlocked_points)| {
+			let balance_to_unbond = withdrawn_points.iter().fold(
+				BalanceOf::<T>::zero(),
+				|accumulator, (era, unlocked_points)| {
 					sum_unlocked_points = sum_unlocked_points.saturating_add(*unlocked_points);
 					if let Some(era_pool) = sub_pools.with_era.get_mut(era) {
 						let balance_to_unbond = era_pool.dissolve(*unlocked_points);
@@ -2279,15 +2279,20 @@ pub mod pallet {
 						// era-less pool.
 						accumulator.saturating_add(sub_pools.no_era.dissolve(*unlocked_points))
 					}
-				});
+				},
+			);
 			// fixme(ank4n): Transfer whatever is minimum transferable.
 			// Withdraw upto limit and return the amount withdrawn and whether stash killed.
 
 			// Before calculating the `balance_to_unbond`, we call withdraw unbonded to ensure the
 			// `transferrable_balance` is correct.
 			// fixme(ank4n): Handle result.
-			let _withdraw_result =
-				T::Staking::delegate_withdraw(&bonded_pool.bonded_account(), &member_account, balance_to_unbond, num_slashing_spans)?;
+			let _withdraw_result = T::Staking::delegate_withdraw(
+				&bonded_pool.bonded_account(),
+				&member_account,
+				balance_to_unbond,
+				num_slashing_spans,
+			)?;
 
 			// defensive-only: the depositor puts enough funds into the stash so that it will only
 			// be destroyed when they are leaving.
@@ -2296,7 +2301,6 @@ pub mod pallet {
 			// 	Error::<T>::Defensive(DefensiveError::BondedStashKilledPrematurely)
 			// );
 
-
 			Self::deposit_event(Event::<T>::Withdrawn {
 				member: member_account.clone(),
 				pool_id: member.pool_id,
diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs
index 15ded13ef745e..4815607283a9f 100644
--- a/substrate/frame/staking/src/lib.rs
+++ b/substrate/frame/staking/src/lib.rs
@@ -420,7 +420,6 @@ impl<AccountId: Clone> RewardDestination<AccountId> {
 			},
 		}
 	}
-
 }
 
 /// Preference of what happens regarding validation.

From 4e42c6c97512eac02ec5a79f44a4b2f3ac8ac943 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 17 Feb 2024 21:58:57 +0100
Subject: [PATCH 094/202] remove transactional

---
 substrate/frame/delegated-staking/src/impls.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index fb8a37db6ffe8..0db1ee50e6156 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -270,7 +270,6 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		}
 	}
 
-	#[transactional]
 	fn delegate_withdraw(
 		delegate: &Self::AccountId,
 		delegator: &Self::AccountId,

From a4e0ee24f8b9c2f0f5ebed19de1641eab3dc079e Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 18 Feb 2024 09:09:13 +0100
Subject: [PATCH 095/202] refactor but some test failing

---
 substrate/frame/delegated-staking/src/lib.rs  | 93 ++++++++++++++++---
 .../frame/delegated-staking/src/types.rs      | 18 ++++
 2 files changed, 98 insertions(+), 13 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 98909b0e39fe3..6154746a43185 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -44,17 +44,6 @@
 //! to apply slash. It is `delegate`'s responsibility to apply slashes for each delegator, one at a
 //! time. Staking pallet ensures the pending slash never exceeds staked amount and would freeze
 //! further withdraws until pending slashes are applied.
-//!
-//!
-//! ### Note about minimum balance
-//!
-//! When registering as `delegate`, a sub account for unclaimed withdrawals are created and funded
-//! with `ExistentialDeposit`. If the `delegate` is migrating from being a `Nominator`, another
-//! sub account is created for managing funds of delegators who have not yet migrated their funds
-//! to won account. These accounts are funded by the `Delegate` and it should have enough free
-//! balance to cover these. When these accounts are not killed (not needed anymore), the funds are
-//! returned to the `Delegate`.
-
 #[cfg(test)]
 mod mock;
 
@@ -77,7 +66,9 @@ use frame_support::{
 	pallet_prelude::*,
 	traits::{
 		fungible::{
-			hold::{Balanced as FunHoldBalanced, Mutate as FunHoldMutate},
+			hold::{
+				Balanced as FunHoldBalanced, Inspect as FunHoldInspect, Mutate as FunHoldMutate,
+			},
 			Balanced, Inspect as FunInspect, Mutate as FunMutate,
 		},
 		tokens::{fungible::Credit, Fortitude, Precision, Preservation},
@@ -292,7 +283,25 @@ pub mod pallet {
 			delegator: T::AccountId,
 			amount: BalanceOf<T>,
 		) -> DispatchResult {
-			todo!()
+			let delegate = ensure_signed(origin)?;
+
+			// Ensure they have minimum delegation.
+			ensure!(amount >= T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
+
+			// Ensure delegator is sane.
+			ensure!(!Self::is_delegate(&delegator), Error::<T>::NotAllowed);
+			ensure!(!Self::is_delegator(&delegator), Error::<T>::NotAllowed);
+			ensure!(Self::not_direct_staker(&delegator), Error::<T>::AlreadyStaker);
+
+			// ensure delegate is sane.
+			ensure!(Self::is_delegate(&delegate), Error::<T>::NotDelegate);
+
+			// and has some delegated balance to migrate.
+			let proxy_delegator = Self::sub_account(AccountType::ProxyDelegator, delegate);
+			let balance_remaining = Self::held_balance_of(&proxy_delegator);
+			ensure!(balance_remaining >= amount, Error::<T>::NotEnoughFunds);
+
+			Self::do_migrate_delegation(&proxy_delegator, &delegator, amount)
 		}
 
 		/// Delegate funds to a `Delegate` account.
@@ -328,6 +337,10 @@ impl<T: Config> Pallet<T> {
 		T::PalletId::get().into_sub_account_truncating((account_type, delegate_account.clone()))
 	}
 
+	/// Balance of a delegator that is delegated.
+	pub(crate) fn held_balance_of(who: &T::AccountId) -> BalanceOf<T> {
+		T::Currency::balance_on_hold(&HoldReason::Delegating.into(), who)
+	}
 	fn is_delegate(who: &T::AccountId) -> bool {
 		<Delegates<T>>::contains_key(who)
 	}
@@ -522,6 +535,60 @@ impl<T: Config> Pallet<T> {
 
 		Ok(ledger)
 	}
+
+	/// Migrates delegation of `amount` from `source` account to `destination` account.
+	fn do_migrate_delegation(
+		source_delegator: &T::AccountId,
+		destination_delegator: &T::AccountId,
+		amount: BalanceOf<T>,
+	) -> DispatchResult {
+		let mut source_delegation =
+			Delegators::<T>::get(&source_delegator).defensive_ok_or(Error::<T>::BadState)?;
+
+		// some checks that must have already been checked before.
+		ensure!(source_delegation.amount >= amount, Error::<T>::NotEnoughFunds);
+		debug_assert!(
+			!Self::is_delegator(destination_delegator) && !Self::is_delegate(destination_delegator)
+		);
+
+		// update delegations
+		Delegation::<T>::from(&source_delegation.delegate, amount)
+			.save(destination_delegator);
+
+		source_delegation
+			.decrease_delegation(amount)
+			.defensive_ok_or(Error::<T>::BadState)?
+			.save(source_delegator);
+
+		// FIXME(ank4n): If all funds are migrated from source, it can be cleaned up and ED returned
+		// to delegate or alternatively whoever cleans it up. This could be a permission-less
+		// extrinsic.
+
+		// release funds from source
+		let released = T::Currency::release(
+			&HoldReason::Delegating.into(),
+			&source_delegator,
+			amount,
+			Precision::BestEffort,
+		)?;
+
+		defensive_assert!(released == amount, "hold should have been released fully");
+
+		// transfer the released value to `destination_delegator`.
+		// Note: The source should have been funded ED in the beginning so it should not be dusted.
+		T::Currency::transfer(
+			&source_delegator,
+			destination_delegator,
+			amount,
+			Preservation::Preserve,
+		)
+		.map_err(|_| Error::<T>::BadState)?;
+
+		// hold the funds again in the new delegator account.
+		T::Currency::hold(&HoldReason::Delegating.into(), &destination_delegator, amount)?;
+
+		Ok(())
+	}
 }
 
 #[cfg(any(test, feature = "try-runtime"))]
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index 14121df2de708..a52cf7a760f9d 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -49,7 +49,25 @@ impl<T: Config> Delegation<T> {
 		Delegation { delegate: delegate.clone(), amount }
 	}
 
+	/// Checked decrease of delegation amount. Consumes self and returns a new copy.
+	pub(crate) fn decrease_delegation(self, amount: BalanceOf<T>) -> Option<Self> {
+		let updated_delegation = self.amount.checked_sub(&amount)?;
+		Some(Delegation::from(&self.delegate, updated_delegation))
+	}
+
+	/// Checked increase of delegation amount. Consumes self and returns a new copy.
+	pub(crate) fn increase_delegation(self, amount: BalanceOf<T>) -> Option<Self> {
+		let updated_delegation = self.amount.checked_add(&amount)?;
+		Some(Delegation::from(&self.delegate, updated_delegation))
+	}
+
 	pub(crate) fn save(self, key: &T::AccountId) {
+		// Clean up if no delegation left.
+		if self.amount == Zero::zero() {
+			<Delegators<T>>::remove(key);
+			return;
+		}
+
 		<Delegators<T>>::insert(key, self)
 	}
 }

From 20c3fceddd566269aa013b658f9395d982378301 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 18 Feb 2024 09:25:06 +0100
Subject: [PATCH 096/202] fix migration test

---
 .../frame/delegated-staking/src/impls.rs      | 53 ++-----------------
 .../frame/delegated-staking/src/tests.rs      |  2 +-
 2 files changed, 5 insertions(+), 50 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 0db1ee50e6156..be76e6a20ecf8 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -318,61 +318,16 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 	}
 
 	/// Move funds from proxy delegator to actual delegator.
-	#[transactional]
 	fn migrate_delegator(
 		delegate: &Self::AccountId,
 		new_delegator: &Self::AccountId,
 		value: Self::Balance,
 	) -> DispatchResult {
-		ensure!(value >= T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
-		// make sure new delegator is not an existing delegator or a delegate
-		ensure!(!<Delegates<T>>::contains_key(new_delegator), Error::<T>::NotAllowed);
-		ensure!(!<Delegators<T>>::contains_key(new_delegator), Error::<T>::NotAllowed);
-		// ensure we are migrating
-		let proxy_delegator =
-			<DelegateMigration<T>>::get(delegate).ok_or(Error::<T>::NotMigrating)?;
-		// proxy delegator must exist
-		// let (assigned_delegate, delegate_balance) =
-		let delegation = <Delegators<T>>::get(&proxy_delegator).ok_or(Error::<T>::BadState)?;
-		ensure!(delegation.delegate == *delegate, Error::<T>::BadState);
-
-		// make sure proxy delegator has enough balance to support this migration.
-		ensure!(delegation.amount >= value, Error::<T>::NotEnoughFunds);
-
-		// remove delegation of `value` from `proxy_delegator`.
-		let updated_delegate_balance = delegation.amount.saturating_sub(value);
-
-		// if all funds are migrated out of proxy delegator, clean up.
-		if updated_delegate_balance == BalanceOf::<T>::zero() {
-			<Delegators<T>>::remove(&proxy_delegator);
-			<DelegateMigration<T>>::remove(delegate);
-		} else {
-			// else update proxy delegator
-			<Delegators<T>>::insert(
-				&proxy_delegator,
-				Delegation { delegate: delegate.clone(), amount: updated_delegate_balance },
-			);
-		}
-
-		let released = T::Currency::release(
-			&HoldReason::Delegating.into(),
-			&proxy_delegator,
+		Self::migrate_delegation(
+			RawOrigin::Signed(delegate.clone()).into(),
+			new_delegator.clone(),
 			value,
-			Precision::BestEffort,
-		)?;
-
-		defensive_assert!(released == value, "hold should have been released fully");
-
-		// transfer the withdrawn value to `new_delegator`.
-		T::Currency::transfer(&proxy_delegator, new_delegator, value, Preservation::Expendable)
-			.map_err(|_| Error::<T>::BadState)?;
-
-		// add the above removed delegation to `new_delegator`.
-		Delegation::<T>::from(delegate, value).save(new_delegator);
-		// hold the funds again in the new delegator account.
-		T::Currency::hold(&HoldReason::Delegating.into(), &new_delegator, value)?;
-
-		Ok(())
+		)
 	}
 
 	fn delegate(
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 611c9cd3a8fd7..1a74f61371757 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -494,7 +494,7 @@ mod integration {
 			// cannot use migrate delegator anymore
 			assert_noop!(
 				DelegatedStaking::migrate_delegator(&200, &305, 1),
-				Error::<T>::NotMigrating
+				Error::<T>::NotEnoughFunds
 			);
 		});
 	}

From bbc39b673bad44bdf074318d6b4ff8152b430399 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 18 Feb 2024 10:50:03 +0100
Subject: [PATCH 097/202] impl delegation

---
 .../frame/delegated-staking/src/impls.rs      | 42 +++----------------
 substrate/frame/delegated-staking/src/lib.rs  | 41 ++++++++++--------
 .../frame/delegated-staking/src/tests.rs      |  6 +--
 .../frame/delegated-staking/src/types.rs      | 18 +++++++-
 4 files changed, 48 insertions(+), 59 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index be76e6a20ecf8..50915e09f5275 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -335,43 +335,11 @@ impl<T: Config> DelegationInterface for Pallet<T> {
 		delegate: &Self::AccountId,
 		value: Self::Balance,
 	) -> DispatchResult {
-		let delegator_balance =
-			T::Currency::reducible_balance(&delegator, Preservation::Expendable, Fortitude::Polite);
-		ensure!(value >= T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
-		ensure!(delegator_balance >= value, Error::<T>::NotEnoughFunds);
-		ensure!(delegate != delegator, Error::<T>::InvalidDelegation);
-
-		let mut delegation_register =
-			<Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-		ensure!(!delegation_register.blocked, Error::<T>::DelegationsBlocked);
-
-		// A delegate cannot delegate.
-		if <Delegates<T>>::contains_key(delegator) {
-			return Err(Error::<T>::InvalidDelegation.into())
-		}
-
-		let new_delegation_amount =
-			if let Some(current_delegation) = <Delegators<T>>::get(delegator) {
-				ensure!(&current_delegation.delegate == delegate, Error::<T>::InvalidDelegation);
-				value.saturating_add(current_delegation.amount)
-			} else {
-				value
-			};
-
-		delegation_register.total_delegated.saturating_accrue(value);
-
-		Delegation::<T>::from(delegate, new_delegation_amount).save(delegator);
-		<Delegates<T>>::insert(delegate, delegation_register);
-
-		T::Currency::hold(&HoldReason::Delegating.into(), &delegator, value)?;
-
-		Self::deposit_event(Event::<T>::Delegated {
-			delegate: delegate.clone(),
-			delegator: delegator.clone(),
-			amount: value,
-		});
-
-		Ok(())
+		Self::delegate_funds(
+			RawOrigin::Signed(delegator.clone()).into(),
+			delegate.clone(),
+			value,
+		)
 	}
 }
 
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 6154746a43185..78b4617e7033b 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -153,8 +153,8 @@ pub mod pallet {
 		NotSupported,
 		/// This `delegate` is not set as a migrating account.
 		NotMigrating,
-		/// Delegate no longer accepting new delegations.
-		DelegationsBlocked,
+		/// Account does not accept delegations.
+		NotAcceptingDelegations,
 	}
 
 	/// A reason for placing a hold on funds.
@@ -305,26 +305,32 @@ pub mod pallet {
 		}
 
 		/// Delegate funds to a `Delegate` account.
+		///
+		/// If delegation already exists, it increases the delegation by `amount`.
 		#[pallet::call_index(4)]
 		#[pallet::weight(Weight::default())]
-		// FIXME(ank4n): rename to `delegate`
 		pub fn delegate_funds(
 			origin: OriginFor<T>,
 			delegate: T::AccountId,
 			amount: BalanceOf<T>,
 		) -> DispatchResult {
-			todo!()
-		}
+			let who = ensure_signed(origin)?;
 
-		/// Add funds to an existing delegation.
-		#[pallet::call_index(5)]
-		#[pallet::weight(Weight::default())]
-		pub fn delegate_extra(
-			origin: OriginFor<T>,
-			delegate: T::AccountId,
-			amount: BalanceOf<T>,
-		) -> DispatchResult {
-			todo!()
+			// ensure amount is over minimum to delegate
+			ensure!(amount > T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
+
+			// ensure delegator is sane.
+			ensure!(Delegation::<T>::can_delegate(&who, &delegate), Error::<T>::InvalidDelegation);
+			ensure!(Self::not_direct_staker(&who), Error::<T>::AlreadyStaker);
+
+			// ensure delegate is sane.
+			ensure!(DelegationLedger::<T>::can_accept_delegation(&delegate), Error::<T>::NotAcceptingDelegations);
+
+			let delegator_balance =
+				T::Currency::reducible_balance(&who, Preservation::Preserve, Fortitude::Polite);
+			ensure!(delegator_balance >= amount, Error::<T>::NotEnoughFunds);
+
+			Self::do_delegate(&who, &delegate, amount)
 		}
 	}
 }
@@ -413,7 +419,7 @@ impl<T: Config> Pallet<T> {
 		amount: BalanceOf<T>,
 	) -> DispatchResult {
 		let mut ledger = DelegationLedger::<T>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-		ensure!(!ledger.blocked, Error::<T>::DelegationsBlocked);
+		debug_assert!(!ledger.blocked);
 
 		let new_delegation_amount =
 			if let Some(existing_delegation) = Delegation::<T>::get(delegator) {
@@ -552,8 +558,7 @@ impl<T: Config> Pallet<T> {
 		);
 
 		// update delegations
-		Delegation::<T>::from(&source_delegation.delegate, amount)
-			.save(destination_delegator);
+		Delegation::<T>::from(&source_delegation.delegate, amount).save(destination_delegator);
 
 		source_delegation
 			.decrease_delegation(amount)
@@ -574,7 +579,7 @@ impl<T: Config> Pallet<T> {
 
 		defensive_assert!(released == amount, "hold should have been released fully");
 
-		// transfer the released value to `destination_delegator`.
+		// transfer the released amount to `destination_delegator`.
 		// Note: The source should have been funded ED in the beginning so it should not be dusted.
 		T::Currency::transfer(
 			&source_delegator,
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 1a74f61371757..7935b856b695d 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -127,11 +127,11 @@ fn delegate_restrictions() {
 		// delegate one tries to delegate to a delegator
 		assert_noop!(
 			DelegatedStaking::delegate(&delegate_one, &delegator_one, 10),
-			Error::<T>::NotDelegate
+			Error::<T>::InvalidDelegation
 		);
 		assert_noop!(
 			DelegatedStaking::delegate(&delegate_one, &delegator_two, 10),
-			Error::<T>::NotDelegate
+			Error::<T>::InvalidDelegation
 		);
 
 		// delegator one tries to delegate to delegate 2 as well (it already delegates to delegate
@@ -403,7 +403,7 @@ mod integration {
 			// cannot delegate to it anymore
 			assert_noop!(
 				DelegatedStaking::delegate(&300, &200, 100),
-				Error::<T>::DelegationsBlocked
+				Error::<T>::NotAcceptingDelegations
 			);
 
 			// delegate can unblock delegation
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index a52cf7a760f9d..3f620386318a2 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -49,6 +49,15 @@ impl<T: Config> Delegation<T> {
 		Delegation { delegate: delegate.clone(), amount }
 	}
 
+	pub(crate) fn can_delegate(delegator: &T::AccountId, delegate: &T::AccountId) -> bool {
+		Delegation::<T>::get(delegator)
+			.map(|delegation| delegation.delegate == delegate.clone())
+			.unwrap_or(
+				// all good if its a new delegator expect it should not am existing delegate.
+				!<Delegates::<T>>::contains_key(delegator)
+			)
+	}
+
 	/// Checked decrease of delegation amount. Consumes self and returns a new copy.
 	pub(crate) fn decrease_delegation(self, amount: BalanceOf<T>) -> Option<Self> {
 		let updated_delegation = self.amount.checked_sub(&amount)?;
@@ -77,6 +86,7 @@ impl<T: Config> Delegation<T> {
 /// This keeps track of the active balance of the `delegate` that is made up from the funds that are
 /// currently delegated to this `delegate`. It also tracks the pending slashes yet to be applied
 /// among other things.
+// FIXME(ank4n): Break up into two storage items - bookkeeping stuff and settings stuff.
 #[derive(Default, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
 #[scale_info(skip_type_params(T))]
 pub struct DelegationLedger<T: Config> {
@@ -115,6 +125,12 @@ impl<T: Config> DelegationLedger<T> {
 		<Delegates<T>>::get(key)
 	}
 
+	pub(crate) fn can_accept_delegation(delegate: &T::AccountId) -> bool {
+		DelegationLedger::<T>::get(delegate)
+			.map(|ledger| !ledger.blocked)
+			.unwrap_or(false)
+	}
+
 	/// Balance that is stakeable.
 	pub(crate) fn delegated_balance(&self) -> BalanceOf<T> {
 		// do not allow to stake more than unapplied slash
@@ -132,4 +148,4 @@ impl<T: Config> DelegationLedger<T> {
 	pub(crate) fn save(self, key: &T::AccountId) {
 		<Delegates<T>>::insert(key, self)
 	}
-}
+}
\ No newline at end of file

From 7634a58d75a40a1cc7a0c29d9838c718b08f728c Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 18 Feb 2024 11:34:26 +0100
Subject: [PATCH 098/202] fix one test and leave a todo note for the other

---
 substrate/frame/delegated-staking/src/lib.rs  | 12 +------
 .../frame/delegated-staking/src/tests.rs      | 34 +++++++++++--------
 2 files changed, 20 insertions(+), 26 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 78b4617e7033b..007c889a2b4e1 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -151,8 +151,6 @@ pub mod pallet {
 		WithdrawFailed,
 		/// This operation is not supported with Delegation Staking.
 		NotSupported,
-		/// This `delegate` is not set as a migrating account.
-		NotMigrating,
 		/// Account does not accept delegations.
 		NotAcceptingDelegations,
 	}
@@ -194,14 +192,6 @@ pub mod pallet {
 	pub(crate) type Delegates<T: Config> =
 		CountedStorageMap<_, Twox64Concat, T::AccountId, DelegationLedger<T>, OptionQuery>;
 
-	/// Map of Delegate and its proxy delegator account while its actual delegators are migrating.
-	///
-	/// Helps ensure correctness of ongoing migration of a direct nominator to a `delegate`. If a
-	/// `delegate` does not exist, it implies it is not going through migration.
-	#[pallet::storage]
-	pub(crate) type DelegateMigration<T: Config> =
-		CountedStorageMap<_, Twox64Concat, T::AccountId, T::AccountId, OptionQuery>;
-
 	#[pallet::call]
 	impl<T: Config> Pallet<T> {
 		/// Register an account to be a `Delegate`.
@@ -530,7 +520,7 @@ impl<T: Config> Pallet<T> {
 		let post_total = T::CoreStaking::stake(delegate).defensive()?.total;
 
 		let new_withdrawn =
-			post_total.checked_sub(&pre_total).defensive_ok_or(Error::<T>::BadState)?;
+			pre_total.checked_sub(&post_total).defensive_ok_or(Error::<T>::BadState)?;
 
 		ledger.unclaimed_withdrawals = ledger
 			.unclaimed_withdrawals
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 7935b856b695d..54cd92b53891c 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -210,8 +210,8 @@ mod integration {
 			assert!(eq_stake(delegate, total_staked, total_staked));
 			// Withdrawing without unbonding would fail.
 			assert_noop!(
-				DelegatedStaking::delegate_withdraw(&delegate, &300, 50, 0),
-				Error::<T>::WithdrawFailed
+				DelegatedStaking::delegate_withdraw(&delegate, &301, 50, 0),
+				Error::<T>::NotEnoughFunds
 			);
 			// assert_noop!(DelegatedStaking::delegate_withdraw(&delegate, &200, 50, 0),
 			// Error::<T>::NotAllowed); active and total stake remains same
@@ -233,7 +233,7 @@ mod integration {
 			// nothing to withdraw at era 4
 			assert_noop!(
 				DelegatedStaking::delegate_withdraw(&delegate, &305, 50, 0),
-				Error::<T>::WithdrawFailed
+				Error::<T>::NotEnoughFunds
 			);
 
 			assert!(eq_stake(delegate, total_staked, expected_active));
@@ -245,7 +245,7 @@ mod integration {
 			// at era 5, 50 tokens are withdrawable, cannot withdraw more.
 			assert_noop!(
 				DelegatedStaking::delegate_withdraw(&delegate, &305, 51, 0),
-				Error::<T>::WithdrawFailed
+				Error::<T>::NotEnoughFunds
 			);
 			// less is possible
 			assert_ok!(DelegatedStaking::delegate_withdraw(&delegate, &305, 30, 0));
@@ -277,11 +277,11 @@ mod integration {
 			// cannot withdraw anything more..
 			assert_noop!(
 				DelegatedStaking::delegate_withdraw(&delegate, &301, 1, 0),
-				Error::<T>::WithdrawFailed
+				Error::<T>::NotEnoughFunds
 			);
 			assert_noop!(
 				DelegatedStaking::delegate_withdraw(&delegate, &350, 1, 0),
-				Error::<T>::WithdrawFailed
+				Error::<T>::NotEnoughFunds
 			);
 		});
 	}
@@ -295,19 +295,23 @@ mod integration {
 			// verify withdraw not possible yet
 			assert_noop!(
 				DelegatedStaking::delegate_withdraw(&delegate, &300, 100, 0),
-				Error::<T>::WithdrawFailed
+				Error::<T>::NotEnoughFunds
 			);
 
 			// add new delegation that is not staked
-			fund(&300, 1000);
-			assert_ok!(DelegatedStaking::delegate(&300, &delegate, 100));
 
-			// verify unbonded balance
-			assert_eq!(DelegatedStaking::unbonded_balance(&delegate), 100);
-
-			// withdraw works now without unbonding
-			assert_ok!(DelegatedStaking::delegate_withdraw(&delegate, &300, 100, 0));
-			assert_eq!(DelegatedStaking::unbonded_balance(&delegate), 0);
+			// FIXME(ank4n): add scenario where staked funds are withdrawn from ledger but not
+			// withdrawn and test its claimed from there first.
+
+			// fund(&300, 1000);
+			// assert_ok!(DelegatedStaking::delegate(&300, &delegate, 100));
+			//
+			// // verify unbonded balance
+			// assert_eq!(DelegatedStaking::unbonded_balance(&delegate), 100);
+			//
+			// // withdraw works now without unbonding
+			// assert_ok!(DelegatedStaking::delegate_withdraw(&delegate, &300, 100, 0));
+			// assert_eq!(DelegatedStaking::unbonded_balance(&delegate), 0);
 		});
 	}
 

From b05ff807c6d1605e31efaa348685311e66fb1ebc Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 18 Feb 2024 11:53:15 +0100
Subject: [PATCH 099/202] moved some to use dispatch fn directly

---
 .../frame/delegated-staking/src/tests.rs      | 92 +++++++++----------
 1 file changed, 46 insertions(+), 46 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 54cd92b53891c..5bb65e3210f6d 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -32,11 +32,11 @@ fn create_a_delegate_with_first_delegator() {
 
 		// set intention to accept delegation.
 		fund(&delegate, 1000);
-		assert_ok!(DelegatedStaking::accept_delegations(&delegate, &reward_account));
+		assert_ok!(DelegatedStaking::register_as_delegate(RawOrigin::Signed(delegate).into(), reward_account));
 
 		// delegate to this account
 		fund(&delegator, 1000);
-		assert_ok!(DelegatedStaking::delegate(&delegator, &delegate, 100));
+		assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(delegator).into(), delegate, 100));
 
 		// verify
 		assert!(DelegatedStaking::is_delegate(&delegate));
@@ -50,23 +50,23 @@ fn cannot_become_delegate() {
 	ExtBuilder::default().build_and_execute(|| {
 		// cannot set reward account same as delegate account
 		assert_noop!(
-			DelegatedStaking::accept_delegations(&100, &100),
+			DelegatedStaking::register_as_delegate(RawOrigin::Signed(100).into(), 100),
 			Error::<T>::InvalidRewardDestination
 		);
 
 		// an existing validator cannot become delegate
 		assert_noop!(
-			DelegatedStaking::accept_delegations(&mock::GENESIS_VALIDATOR, &100),
+			DelegatedStaking::register_as_delegate(RawOrigin::Signed(mock::GENESIS_VALIDATOR).into(), 100),
 			Error::<T>::AlreadyStaker
 		);
 
 		// an existing nominator cannot become delegate
 		assert_noop!(
-			DelegatedStaking::accept_delegations(&mock::GENESIS_NOMINATOR_ONE, &100),
+			DelegatedStaking::register_as_delegate(RawOrigin::Signed(mock::GENESIS_NOMINATOR_ONE).into(), 100),
 			Error::<T>::AlreadyStaker
 		);
 		assert_noop!(
-			DelegatedStaking::accept_delegations(&mock::GENESIS_NOMINATOR_TWO, &100),
+			DelegatedStaking::register_as_delegate(RawOrigin::Signed(mock::GENESIS_NOMINATOR_TWO).into(), 100),
 			Error::<T>::AlreadyStaker
 		);
 	});
@@ -84,12 +84,12 @@ fn create_multiple_delegators() {
 		assert_eq!(DelegatedStaking::stakeable_balance(&delegate), 0);
 
 		// set intention to accept delegation.
-		assert_ok!(DelegatedStaking::accept_delegations(&delegate, &reward_account));
+		assert_ok!(DelegatedStaking::register_as_delegate(RawOrigin::Signed(delegate).into(), reward_account));
 
 		// create 100 delegators
 		for i in 202..302 {
 			fund(&i, 100 + ExistentialDeposit::get());
-			assert_ok!(DelegatedStaking::delegate(&i, &delegate, 100));
+			assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(i).into(), delegate, 100));
 			// Balance of 100 held on delegator account for delegating to the delegate.
 			assert_eq!(Balances::balance_on_hold(&HoldReason::Delegating.into(), &i), 100);
 		}
@@ -107,37 +107,37 @@ fn delegate_restrictions() {
 		let delegate_one = 200;
 		let delegator_one = 210;
 		fund(&delegate_one, 100);
-		assert_ok!(DelegatedStaking::accept_delegations(&delegate_one, &(delegate_one + 1)));
+		assert_ok!(DelegatedStaking::register_as_delegate(RawOrigin::Signed(delegate_one).into(), delegate_one + 1));
 		fund(&delegator_one, 200);
-		assert_ok!(DelegatedStaking::delegate(&delegator_one, &delegate_one, 100));
+		assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(delegator_one).into(), delegate_one, 100));
 
 		let delegate_two = 300;
 		let delegator_two = 310;
 		fund(&delegate_two, 100);
-		assert_ok!(DelegatedStaking::accept_delegations(&delegate_two, &(delegate_two + 1)));
+		assert_ok!(DelegatedStaking::register_as_delegate(RawOrigin::Signed(delegate_two).into(), delegate_two + 1));
 		fund(&delegator_two, 200);
-		assert_ok!(DelegatedStaking::delegate(&delegator_two, &delegate_two, 100));
+		assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(delegator_two).into(), delegate_two, 100));
 
 		// delegate one tries to delegate to delegate 2
 		assert_noop!(
-			DelegatedStaking::delegate(&delegate_one, &delegate_two, 10),
+			DelegatedStaking::delegate_funds(RawOrigin::Signed(delegate_one).into(), delegate_two, 10),
 			Error::<T>::InvalidDelegation
 		);
 
 		// delegate one tries to delegate to a delegator
 		assert_noop!(
-			DelegatedStaking::delegate(&delegate_one, &delegator_one, 10),
+			DelegatedStaking::delegate_funds(RawOrigin::Signed(delegate_one).into(), delegator_one, 10),
 			Error::<T>::InvalidDelegation
 		);
 		assert_noop!(
-			DelegatedStaking::delegate(&delegate_one, &delegator_two, 10),
+			DelegatedStaking::delegate_funds(RawOrigin::Signed(delegate_one).into(), delegator_two, 10),
 			Error::<T>::InvalidDelegation
 		);
 
 		// delegator one tries to delegate to delegate 2 as well (it already delegates to delegate
 		// 1)
 		assert_noop!(
-			DelegatedStaking::delegate(&delegator_one, &delegate_two, 10),
+			DelegatedStaking::delegate_funds(RawOrigin::Signed(delegator_one).into(), delegate_two, 10),
 			Error::<T>::InvalidDelegation
 		);
 	});
@@ -163,14 +163,14 @@ mod integration {
 
 			// set intention to become a delegate
 			fund(&delegate, 100);
-			assert_ok!(DelegatedStaking::accept_delegations(&delegate, &reward_acc));
+			assert_ok!(DelegatedStaking::register_as_delegate(RawOrigin::Signed(delegate).into(), reward_acc));
 			assert_eq!(DelegatedStaking::stakeable_balance(&delegate), 0);
 
 			let mut delegated_balance: Balance = 0;
 			// set some delegations
 			for delegator in 200..250 {
 				fund(&delegator, 200);
-				assert_ok!(DelegatedStaking::delegate(&delegator, &delegate, 100));
+				assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(delegator).into(), delegate, 100));
 				delegated_balance += 100;
 				assert_eq!(
 					Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator),
@@ -210,10 +210,10 @@ mod integration {
 			assert!(eq_stake(delegate, total_staked, total_staked));
 			// Withdrawing without unbonding would fail.
 			assert_noop!(
-				DelegatedStaking::delegate_withdraw(&delegate, &301, 50, 0),
+				DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 301, 50, 0),
 				Error::<T>::NotEnoughFunds
 			);
-			// assert_noop!(DelegatedStaking::delegate_withdraw(&delegate, &200, 50, 0),
+			// assert_noop!(DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 200, 50, 0),
 			// Error::<T>::NotAllowed); active and total stake remains same
 			assert!(eq_stake(delegate, total_staked, total_staked));
 
@@ -232,7 +232,7 @@ mod integration {
 
 			// nothing to withdraw at era 4
 			assert_noop!(
-				DelegatedStaking::delegate_withdraw(&delegate, &305, 50, 0),
+				DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 305, 50, 0),
 				Error::<T>::NotEnoughFunds
 			);
 
@@ -244,43 +244,43 @@ mod integration {
 			start_era(5);
 			// at era 5, 50 tokens are withdrawable, cannot withdraw more.
 			assert_noop!(
-				DelegatedStaking::delegate_withdraw(&delegate, &305, 51, 0),
+				DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 305, 51, 0),
 				Error::<T>::NotEnoughFunds
 			);
 			// less is possible
-			assert_ok!(DelegatedStaking::delegate_withdraw(&delegate, &305, 30, 0));
-			assert_ok!(DelegatedStaking::delegate_withdraw(&delegate, &305, 20, 0));
+			assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 305, 30, 0));
+			assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 305, 20, 0));
 
 			// Lets go to future era where everything is unbonded. Withdrawable amount: 100 + 200
 			start_era(7);
 			// 305 has no more amount delegated so it cannot withdraw.
 			assert_noop!(
-				DelegatedStaking::delegate_withdraw(&delegate, &305, 5, 0),
+				DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 305, 5, 0),
 				Error::<T>::NotDelegator
 			);
 			// 309 is an active delegator but has total delegation of 90, so it cannot withdraw more
 			// than that.
 			assert_noop!(
-				DelegatedStaking::delegate_withdraw(&delegate, &309, 91, 0),
+				DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 309, 91, 0),
 				Error::<T>::NotEnoughFunds
 			);
 			// 310 cannot withdraw more than delegated funds.
 			assert_noop!(
-				DelegatedStaking::delegate_withdraw(&delegate, &310, 101, 0),
+				DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 310, 101, 0),
 				Error::<T>::NotEnoughFunds
 			);
 			// but can withdraw all its delegation amount.
-			assert_ok!(DelegatedStaking::delegate_withdraw(&delegate, &310, 100, 0));
+			assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 310, 100, 0));
 			// 320 can withdraw all its delegation amount.
-			assert_ok!(DelegatedStaking::delegate_withdraw(&delegate, &320, 200, 0));
+			assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 320, 200, 0));
 
 			// cannot withdraw anything more..
 			assert_noop!(
-				DelegatedStaking::delegate_withdraw(&delegate, &301, 1, 0),
+				DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 301, 1, 0),
 				Error::<T>::NotEnoughFunds
 			);
 			assert_noop!(
-				DelegatedStaking::delegate_withdraw(&delegate, &350, 1, 0),
+				DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 350, 1, 0),
 				Error::<T>::NotEnoughFunds
 			);
 		});
@@ -294,7 +294,7 @@ mod integration {
 
 			// verify withdraw not possible yet
 			assert_noop!(
-				DelegatedStaking::delegate_withdraw(&delegate, &300, 100, 0),
+				DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 300, 100, 0),
 				Error::<T>::NotEnoughFunds
 			);
 
@@ -304,13 +304,13 @@ mod integration {
 			// withdrawn and test its claimed from there first.
 
 			// fund(&300, 1000);
-			// assert_ok!(DelegatedStaking::delegate(&300, &delegate, 100));
+			// assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(300.into()), delegate, 100));
 			//
 			// // verify unbonded balance
 			// assert_eq!(DelegatedStaking::unbonded_balance(&delegate), 100);
 			//
 			// // withdraw works now without unbonding
-			// assert_ok!(DelegatedStaking::delegate_withdraw(&delegate, &300, 100, 0));
+			// assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 300, 100, 0));
 			// assert_eq!(DelegatedStaking::unbonded_balance(&delegate), 0);
 		});
 	}
@@ -324,15 +324,15 @@ mod integration {
 
 			// `delegate` account cannot be reward destination
 			assert_noop!(
-				DelegatedStaking::accept_delegations(&200, &200),
+				DelegatedStaking::register_as_delegate(RawOrigin::Signed(200).into(), 200),
 				Error::<T>::InvalidRewardDestination
 			);
 
 			// different reward account works
-			assert_ok!(DelegatedStaking::accept_delegations(&200, &201));
+			assert_ok!(DelegatedStaking::register_as_delegate(RawOrigin::Signed(200).into(), 201));
 			// add some delegations to it
 			fund(&300, 1000);
-			assert_ok!(DelegatedStaking::delegate(&300, &200, 100));
+			assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(300).into(), 200, 100));
 
 			// if delegate calls Staking pallet directly with a different reward destination, it
 			// fails.
@@ -377,16 +377,16 @@ mod integration {
 			setup_delegation_stake(200, 201, (202..203).collect(), 100, 0);
 
 			// Registering again is noop
-			assert_noop!(DelegatedStaking::accept_delegations(&200, &201), Error::<T>::NotAllowed);
+			assert_noop!(DelegatedStaking::register_as_delegate(RawOrigin::Signed(200).into(), 201), Error::<T>::NotAllowed);
 			// a delegator cannot become delegate
-			assert_noop!(DelegatedStaking::accept_delegations(&202, &203), Error::<T>::NotAllowed);
+			assert_noop!(DelegatedStaking::register_as_delegate(RawOrigin::Signed(202).into(), 203), Error::<T>::NotAllowed);
 			// existing staker cannot become a delegate
 			assert_noop!(
-				DelegatedStaking::accept_delegations(&GENESIS_NOMINATOR_ONE, &201),
+				DelegatedStaking::register_as_delegate(RawOrigin::Signed(GENESIS_NOMINATOR_ONE).into(), 201),
 				Error::<T>::AlreadyStaker
 			);
 			assert_noop!(
-				DelegatedStaking::accept_delegations(&GENESIS_VALIDATOR, &201),
+				DelegatedStaking::register_as_delegate(RawOrigin::Signed(GENESIS_VALIDATOR).into(), 201),
 				Error::<T>::AlreadyStaker
 			);
 		});
@@ -395,18 +395,18 @@ mod integration {
 	#[test]
 	fn block_delegations() {
 		ExtBuilder::default().build_and_execute(|| {
-			assert_ok!(DelegatedStaking::accept_delegations(&200, &201));
+			assert_ok!(DelegatedStaking::register_as_delegate(RawOrigin::Signed(200).into(), 201));
 
 			// delegation works
 			fund(&300, 1000);
-			assert_ok!(DelegatedStaking::delegate(&300, &200, 100));
+			assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(300).into(), 200, 100));
 
 			// delegate blocks delegation
 			assert_ok!(DelegatedStaking::block_delegations(&200));
 
 			// cannot delegate to it anymore
 			assert_noop!(
-				DelegatedStaking::delegate(&300, &200, 100),
+				DelegatedStaking::delegate_funds(RawOrigin::Signed(300).into(), 200, 100),
 				Error::<T>::NotAcceptingDelegations
 			);
 
@@ -414,7 +414,7 @@ mod integration {
 			assert_ok!(DelegatedStaking::unblock_delegations(&200));
 
 			// delegation works again
-			assert_ok!(DelegatedStaking::delegate(&300, &200, 100));
+			assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(300).into(), 200, 100));
 		});
 	}
 
@@ -454,7 +454,7 @@ mod integration {
 			// with at least ED.
 			let proxy_delegator = DelegatedStaking::sub_account(AccountType::ProxyDelegator, 200);
 
-			assert_ok!(DelegatedStaking::migrate_accept_delegations(&200, &proxy_delegator, &201));
+			assert_ok!(DelegatedStaking::migrate_to_delegate(RawOrigin::Signed(200).into(), 201));
 
 			// verify all went well
 			let mut expected_proxy_delegated_amount = staked_amount;

From cf18750ec8a4a78d7f1886ac839f3a4b8589db30 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 18 Feb 2024 17:53:13 +0100
Subject: [PATCH 100/202] add Delegator type

---
 .../frame/delegated-staking/src/types.rs      | 58 +++++++++++++------
 1 file changed, 40 insertions(+), 18 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index 3f620386318a2..d316cbe2b784b 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -19,6 +19,7 @@
 //! Basic types used in delegated staking.
 
 use super::*;
+use std::num::FpCategory::Zero;
 
 /// The type of pot account being created.
 #[derive(Encode, Decode)]
@@ -54,7 +55,7 @@ impl<T: Config> Delegation<T> {
 			.map(|delegation| delegation.delegate == delegate.clone())
 			.unwrap_or(
 				// all good if its a new delegator expect it should not am existing delegate.
-				!<Delegates::<T>>::contains_key(delegator)
+				!<Delegates<T>>::contains_key(delegator),
 			)
 	}
 
@@ -95,10 +96,6 @@ pub struct DelegationLedger<T: Config> {
 	/// Sum of all delegated funds to this `delegate`.
 	#[codec(compact)]
 	pub total_delegated: BalanceOf<T>,
-	/// Amount that is bonded and held.
-	// FIXME(ank4n) (can we remove it)
-	#[codec(compact)]
-	pub hold: BalanceOf<T>,
 	/// Funds that are withdrawn from core staking but not released to delegator/s.
 	#[codec(compact)]
 	pub unclaimed_withdrawals: BalanceOf<T>,
@@ -114,7 +111,6 @@ impl<T: Config> DelegationLedger<T> {
 		DelegationLedger {
 			payee: reward_destination.clone(),
 			total_delegated: Zero::zero(),
-			hold: Zero::zero(),
 			unclaimed_withdrawals: Zero::zero(),
 			pending_slash: Zero::zero(),
 			blocked: false,
@@ -131,21 +127,47 @@ impl<T: Config> DelegationLedger<T> {
 			.unwrap_or(false)
 	}
 
-	/// Balance that is stakeable.
-	pub(crate) fn delegated_balance(&self) -> BalanceOf<T> {
-		// do not allow to stake more than unapplied slash
+	pub(crate) fn save(self, key: &T::AccountId) {
+		<Delegates<T>>::insert(key, self)
+	}
+
+	/// Effective total balance of the `delegate`.
+	pub(crate) fn effective_balance(&self) -> BalanceOf<T> {
+		defensive_assert!(
+			self.total_delegated > self.pending_slash,
+			"slash cannot be higher than actual balance of delegator"
+		);
+
+		// pending slash needs to be burned and cannot be used for stake.
 		self.total_delegated.saturating_sub(self.pending_slash)
 	}
 
-	/// Balance that is delegated but not bonded.
-	///
-	/// Can be funds that are unbonded but not withdrawn.
-	pub(crate) fn unbonded_balance(&self) -> BalanceOf<T> {
-		// fixme(ank4n) Remove hold and get balance from removing withdrawal_unclaimed.
-		self.total_delegated.saturating_sub(self.hold)
+	/// Balance that can be bonded in [`T::CoreStaking`].
+	pub(crate) fn balance_available_to_bond(&self) -> BalanceOf<T> {
+		self.effective_balance().saturating_sub(self.unclaimed_withdrawals)
 	}
+}
 
-	pub(crate) fn save(self, key: &T::AccountId) {
-		<Delegates<T>>::insert(key, self)
+pub struct Delegate<T: Config>(T::AccountId);
+
+impl<T: Config> Delegate<T> {
+	fn available_to_bond(&self) -> BalanceOf<T> {
+		let exposed_stake = self.exposed_stake();
+
+		let bondable = self.ledger().map(|ledger| {
+			ledger.balance_available_to_bond()
+		}).unwrap_or(Zero::zero());
+
+		defensive_assert!(bondable >= exposed_stake, "cannot expose more than delegate balance");
+
+		bondable.saturating_sub(exposed_stake)
 	}
-}
\ No newline at end of file
+
+	fn ledger(&self) -> Option<DelegationLedger<T>> {
+		DelegationLedger::<T>::get(&self.0)
+	}
+
+	fn exposed_stake(&self) -> BalanceOf<T> {
+		T::CoreStaking::total_stake(&self.0).unwrap_or(Zero::zero())
+	}
+}

From 2f9819af16ff4c58b671b5060f0142890c27b9c6 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 18 Feb 2024 19:04:09 +0100
Subject: [PATCH 101/202] compiles

---
 .../frame/delegated-staking/src/impls.rs      | 305 +++++++++---------
 substrate/frame/delegated-staking/src/lib.rs  |  32 +-
 substrate/frame/delegated-staking/src/mock.rs |  36 ++-
 .../frame/delegated-staking/src/tests.rs      |  34 +-
 .../frame/delegated-staking/src/types.rs      |  51 ++-
 5 files changed, 255 insertions(+), 203 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 50915e09f5275..258685226b2df 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -91,10 +91,10 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	) -> DispatchResult {
 		// ensure who is not already staked
 		ensure!(T::CoreStaking::status(who).is_err(), Error::<T>::NotDelegate);
-		let delegation_register = <Delegates<T>>::get(who).ok_or(Error::<T>::NotDelegate)?;
+		let delegate = Delegate::<T>::from(who)?;
 
-		ensure!(delegation_register.unbonded_balance() >= value, Error::<T>::NotEnoughFunds);
-		ensure!(delegation_register.payee == *payee, Error::<T>::InvalidRewardDestination);
+		ensure!(delegate.available_to_bond() >= value, Error::<T>::NotEnoughFunds);
+		ensure!(delegate.ledger.payee == *payee, Error::<T>::InvalidRewardDestination);
 
 		T::CoreStaking::bond(who, value, payee)
 	}
@@ -111,19 +111,19 @@ impl<T: Config> StakingInterface for Pallet<T> {
 
 	fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult {
 		let delegation_register = <Delegates<T>>::get(who).ok_or(Error::<T>::NotDelegate)?;
-		ensure!(delegation_register.unbonded_balance() >= extra, Error::<T>::NotEnoughFunds);
+		ensure!(delegation_register.stakeable_balance() >= extra, Error::<T>::NotEnoughFunds);
 
 		T::CoreStaking::bond_extra(who, extra)
 	}
 
 	fn unbond(stash: &Self::AccountId, value: Self::Balance) -> DispatchResult {
-		let delegation_register = <Delegates<T>>::get(stash).ok_or(Error::<T>::NotDelegate)?;
-		ensure!(delegation_register.hold >= value, Error::<T>::NotEnoughFunds);
+		let delegate = Delegate::<T>::from(stash)?;
+		ensure!(delegate.exposed_stake() >= value, Error::<T>::NotEnoughFunds);
 
 		T::CoreStaking::unbond(stash, value)
 	}
 
-	/// Not supported, call [`Delegate::withdraw`]
+	/// Not supported, call [`DelegationInterface::delegate_withdraw`]
 	fn withdraw_unbonded(
 		_stash: Self::AccountId,
 		_num_slashing_spans: u32,
@@ -133,7 +133,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		Err(Error::<T>::NotSupported.into())
 	}
 
-	/// Not supported, call [`Delegate::withdraw`]
+	/// Not supported, call [`DelegationInterface::delegate_withdraw`]
 	fn withdraw_exact(
 		_stash: &Self::AccountId,
 		_amount: Self::Balance,
@@ -205,150 +205,150 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 }
 
-impl<T: Config> DelegationInterface for Pallet<T> {
-	type Balance = BalanceOf<T>;
-	type AccountId = T::AccountId;
-
-	fn delegated_balance(who: &Self::AccountId) -> Self::Balance {
-		<Delegates<T>>::get(who)
-			.map_or_else(|| 0u32.into(), |register| register.delegated_balance())
-	}
-
-	fn unbonded_balance(who: &Self::AccountId) -> Self::Balance {
-		<Delegates<T>>::get(who).map_or_else(|| 0u32.into(), |register| register.unbonded_balance())
-	}
-
-	fn accept_delegations(
-		who: &Self::AccountId,
-		reward_destination: &Self::AccountId,
-	) -> DispatchResult {
-		Self::register_as_delegate(
-			RawOrigin::Signed(who.clone()).into(),
-			reward_destination.clone(),
-		)
-	}
-
-	/// Transfers funds from current staked account to `proxy_delegator`. Current staked account
-	/// becomes a `delegate` with `proxy_delegator` delegating stakes to it.
-	fn migrate_accept_delegations(
-		who: &Self::AccountId,
-		_proxy_delegator: &Self::AccountId,
-		reward_destination: &Self::AccountId,
-	) -> DispatchResult {
-		Self::migrate_to_delegate(RawOrigin::Signed(who.clone()).into(), reward_destination.clone())
-	}
-
-	fn block_delegations(delegate: &Self::AccountId) -> DispatchResult {
-		let mut register = <Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-		register.blocked = true;
-		<Delegates<T>>::insert(delegate, register);
-
-		Ok(())
-	}
-
-	fn unblock_delegations(delegate: &Self::AccountId) -> DispatchResult {
-		let mut register = <Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-		register.blocked = false;
-		<Delegates<T>>::insert(delegate, register);
-
-		Ok(())
-	}
-
-	fn kill_delegate(_delegate: &Self::AccountId) -> DispatchResult {
-		todo!()
-	}
-
-	fn bond_all(who: &Self::AccountId) -> DispatchResult {
-		let delegate = <Delegates<T>>::get(who).ok_or(Error::<T>::NotDelegate)?;
-		let amount_to_bond = delegate.unbonded_balance();
-
-		match T::CoreStaking::stake(who) {
-			// already bonded
-			Ok(_) => T::CoreStaking::bond_extra(who, amount_to_bond),
-			// first bond
-			Err(_) => T::CoreStaking::bond(who, amount_to_bond, &delegate.payee),
-		}
-	}
-
-	fn delegate_withdraw(
-		delegate: &Self::AccountId,
-		delegator: &Self::AccountId,
-		value: Self::Balance,
-		num_slashing_spans: u32,
-	) -> DispatchResult {
-		Self::release(
-			RawOrigin::Signed(delegate.clone()).into(),
-			delegator.clone(),
-			value,
-			num_slashing_spans,
-		)
-	}
-
-	fn apply_slash(
-		delegate: &Self::AccountId,
-		delegator: &Self::AccountId,
-		value: Self::Balance,
-		maybe_reporter: Option<Self::AccountId>,
-	) -> DispatchResult {
-		let mut delegation_register =
-			<Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-		let delegation = <Delegators<T>>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
-
-		ensure!(&delegation.delegate == delegate, Error::<T>::NotDelegate);
-		ensure!(delegation.amount >= value, Error::<T>::NotEnoughFunds);
-
-		let (mut credit, _missing) =
-			T::Currency::slash(&HoldReason::Delegating.into(), &delegator, value);
-		let actual_slash = credit.peek();
-		// remove the slashed amount
-		delegation_register.pending_slash.saturating_reduce(actual_slash);
-		<Delegates<T>>::insert(delegate, delegation_register);
-
-		if let Some(reporter) = maybe_reporter {
-			let reward_payout: BalanceOf<T> =
-				T::CoreStaking::slash_reward_fraction() * actual_slash;
-			let (reporter_reward, rest) = credit.split(reward_payout);
-			credit = rest;
-			// fixme(ank4n): handle error
-			let _ = T::Currency::resolve(&reporter, reporter_reward);
-		}
-
-		T::OnSlash::on_unbalanced(credit);
-		Ok(())
-	}
-
-	/// Move funds from proxy delegator to actual delegator.
-	fn migrate_delegator(
-		delegate: &Self::AccountId,
-		new_delegator: &Self::AccountId,
-		value: Self::Balance,
-	) -> DispatchResult {
-		Self::migrate_delegation(
-			RawOrigin::Signed(delegate.clone()).into(),
-			new_delegator.clone(),
-			value,
-		)
-	}
-
-	fn delegate(
-		delegator: &Self::AccountId,
-		delegate: &Self::AccountId,
-		value: Self::Balance,
-	) -> DispatchResult {
-		Self::delegate_funds(
-			RawOrigin::Signed(delegator.clone()).into(),
-			delegate.clone(),
-			value,
-		)
-	}
-}
+// impl<T: Config> DelegationInterface for Pallet<T> {
+// 	type Balance = BalanceOf<T>;
+// 	type AccountId = T::AccountId;
+//
+// 	fn delegated_balance(who: &Self::AccountId) -> Self::Balance {
+// 		<Delegates<T>>::get(who)
+// 			.map_or_else(|| 0u32.into(), |register| register.delegated_balance())
+// 	}
+//
+// 	fn unbonded_balance(who: &Self::AccountId) -> Self::Balance {
+// 		<Delegates<T>>::get(who).map_or_else(|| 0u32.into(), |register| register.stakeable_balance())
+// 	}
+//
+// 	fn accept_delegations(
+// 		who: &Self::AccountId,
+// 		reward_destination: &Self::AccountId,
+// 	) -> DispatchResult {
+// 		Self::register_as_delegate(
+// 			RawOrigin::Signed(who.clone()).into(),
+// 			reward_destination.clone(),
+// 		)
+// 	}
+//
+// 	/// Transfers funds from current staked account to `proxy_delegator`. Current staked account
+// 	/// becomes a `delegate` with `proxy_delegator` delegating stakes to it.
+// 	fn migrate_accept_delegations(
+// 		who: &Self::AccountId,
+// 		_proxy_delegator: &Self::AccountId,
+// 		reward_destination: &Self::AccountId,
+// 	) -> DispatchResult {
+// 		Self::migrate_to_delegate(RawOrigin::Signed(who.clone()).into(), reward_destination.clone())
+// 	}
+//
+// 	fn block_delegations(delegate: &Self::AccountId) -> DispatchResult {
+// 		let mut register = <Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
+// 		register.blocked = true;
+// 		<Delegates<T>>::insert(delegate, register);
+//
+// 		Ok(())
+// 	}
+//
+// 	fn unblock_delegations(delegate: &Self::AccountId) -> DispatchResult {
+// 		let mut register = <Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
+// 		register.blocked = false;
+// 		<Delegates<T>>::insert(delegate, register);
+//
+// 		Ok(())
+// 	}
+//
+// 	fn kill_delegate(_delegate: &Self::AccountId) -> DispatchResult {
+// 		todo!()
+// 	}
+//
+// 	fn bond_all(who: &Self::AccountId) -> DispatchResult {
+// 		let delegate = <Delegates<T>>::get(who).ok_or(Error::<T>::NotDelegate)?;
+// 		let amount_to_bond = delegate.stakeable_balance();
+//
+// 		match T::CoreStaking::stake(who) {
+// 			// already bonded
+// 			Ok(_) => T::CoreStaking::bond_extra(who, amount_to_bond),
+// 			// first bond
+// 			Err(_) => T::CoreStaking::bond(who, amount_to_bond, &delegate.payee),
+// 		}
+// 	}
+//
+// 	fn delegate_withdraw(
+// 		delegate: &Self::AccountId,
+// 		delegator: &Self::AccountId,
+// 		value: Self::Balance,
+// 		num_slashing_spans: u32,
+// 	) -> DispatchResult {
+// 		Self::release(
+// 			RawOrigin::Signed(delegate.clone()).into(),
+// 			delegator.clone(),
+// 			value,
+// 			num_slashing_spans,
+// 		)
+// 	}
+//
+// 	fn apply_slash(
+// 		delegate: &Self::AccountId,
+// 		delegator: &Self::AccountId,
+// 		value: Self::Balance,
+// 		maybe_reporter: Option<Self::AccountId>,
+// 	) -> DispatchResult {
+// 		let mut delegation_register =
+// 			<Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
+// 		let delegation = <Delegators<T>>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
+//
+// 		ensure!(&delegation.delegate == delegate, Error::<T>::NotDelegate);
+// 		ensure!(delegation.amount >= value, Error::<T>::NotEnoughFunds);
+//
+// 		let (mut credit, _missing) =
+// 			T::Currency::slash(&HoldReason::Delegating.into(), &delegator, value);
+// 		let actual_slash = credit.peek();
+// 		// remove the slashed amount
+// 		delegation_register.pending_slash.saturating_reduce(actual_slash);
+// 		<Delegates<T>>::insert(delegate, delegation_register);
+//
+// 		if let Some(reporter) = maybe_reporter {
+// 			let reward_payout: BalanceOf<T> =
+// 				T::CoreStaking::slash_reward_fraction() * actual_slash;
+// 			let (reporter_reward, rest) = credit.split(reward_payout);
+// 			credit = rest;
+// 			// fixme(ank4n): handle error
+// 			let _ = T::Currency::resolve(&reporter, reporter_reward);
+// 		}
+//
+// 		T::OnSlash::on_unbalanced(credit);
+// 		Ok(())
+// 	}
+//
+// 	/// Move funds from proxy delegator to actual delegator.
+// 	fn migrate_delegator(
+// 		delegate: &Self::AccountId,
+// 		new_delegator: &Self::AccountId,
+// 		value: Self::Balance,
+// 	) -> DispatchResult {
+// 		Self::migrate_delegation(
+// 			RawOrigin::Signed(delegate.clone()).into(),
+// 			new_delegator.clone(),
+// 			value,
+// 		)
+// 	}
+//
+// 	fn delegate(
+// 		delegator: &Self::AccountId,
+// 		delegate: &Self::AccountId,
+// 		value: Self::Balance,
+// 	) -> DispatchResult {
+// 		Self::delegate_funds(
+// 			RawOrigin::Signed(delegator.clone()).into(),
+// 			delegate.clone(),
+// 			value,
+// 		)
+// 	}
+// }
 
 impl<T: Config> StakingDelegationSupport for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
-		<Delegates<T>>::get(who)
-			.map(|delegate| delegate.delegated_balance())
+		Delegate::<T>::from(who)
+			.map(|delegate| delegate.available_to_bond())
 			.unwrap_or_default()
 	}
 
@@ -380,16 +380,7 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 	}
 
 	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
-		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
-
-		// delegation register should exist since `who` is a delegate.
-		let delegation_register = <Delegates<T>>::get(who).defensive_ok_or(Error::<T>::BadState)?;
-
-		ensure!(delegation_register.total_delegated >= amount, Error::<T>::NotEnoughFunds);
-		ensure!(delegation_register.pending_slash <= amount, Error::<T>::UnappliedSlash);
-		let updated_register = DelegationLedger { hold: amount, ..delegation_register };
-		<Delegates<T>>::insert(who, updated_register);
-
+	 	// fixme(ank4n): Do I really need this?
 		Ok(())
 	}
 
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 007c889a2b4e1..5e9ba4b67be21 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -322,6 +322,23 @@ pub mod pallet {
 
 			Self::do_delegate(&who, &delegate, amount)
 		}
+
+		/// Stop accepting new delegation.
+		///
+		/// To unblock, pass false.
+		#[pallet::call_index(5)]
+		#[pallet::weight(Weight::default())]
+		pub fn block_delegations(
+			origin: OriginFor<T>,
+			block: bool,
+		) -> DispatchResult {
+			let who = ensure_signed(origin)?;
+
+			let delegate = Delegate::<T>::from(&who)?;
+			delegate.update_status(block).save();
+
+			Ok(())
+		}
 	}
 }
 
@@ -390,16 +407,15 @@ impl<T: Config> Pallet<T> {
 		Self::do_bond(who, stake.total)
 	}
 
-	fn do_bond(delegate: &T::AccountId, amount: BalanceOf<T>) -> DispatchResult {
-		let ledger = <Delegates<T>>::get(delegate).defensive_ok_or(Error::<T>::NotDelegate)?;
+	fn do_bond(delegate_acc: &T::AccountId, amount: BalanceOf<T>) -> DispatchResult {
+		let delegate = Delegate::<T>::from(delegate_acc)?;
 
-		debug_assert!(amount == ledger.unbonded_balance());
+		debug_assert!(amount == delegate.available_to_bond());
 
-		match T::CoreStaking::stake(delegate) {
-			// already bonded
-			Ok(_) => T::CoreStaking::bond_extra(delegate, amount),
-			// first bond
-			Err(_) => T::CoreStaking::bond(delegate, amount, &ledger.payee),
+		if delegate.is_exposed() {
+			T::CoreStaking::bond_extra(&delegate.key, amount)
+		} else {
+			T::CoreStaking::bond(&delegate.key, amount, &delegate.reward_account())
 		}
 	}
 
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index f17c0cb2522d6..978ff38dda050 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -15,7 +15,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use crate::{self as delegated_staking};
+use crate::{self as delegated_staking, types::Delegate};
 use frame_support::{
 	assert_ok, derive_impl,
 	pallet_prelude::*,
@@ -30,8 +30,9 @@ use frame_election_provider_support::{
 	bounds::{ElectionBounds, ElectionBoundsBuilder},
 	onchain, SequentialPhragmen,
 };
+use frame_support::dispatch::RawOrigin;
 use pallet_staking::CurrentEra;
-use sp_staking::delegation::{DelegationInterface, StakingDelegationSupport};
+use sp_staking::{delegation::StakingDelegationSupport, StakingInterface, Stake};
 
 pub type T = Runtime;
 type Block = frame_system::mocking::MockBlock<Runtime>;
@@ -250,20 +251,31 @@ pub(crate) fn setup_delegation_stake(
 	increment: Balance,
 ) -> Balance {
 	fund(&delegate, 100);
-	assert_ok!(DelegatedStaking::accept_delegations(&delegate, &reward_acc));
+	assert_ok!(DelegatedStaking::register_as_delegate(
+		RawOrigin::Signed(delegate).into(),
+		reward_acc
+	));
 	let mut delegated_amount: Balance = 0;
 	for (index, delegator) in delegators.iter().enumerate() {
 		let amount_to_delegate = base_delegate_amount + increment * index as Balance;
 		delegated_amount += amount_to_delegate;
 
 		fund(delegator, amount_to_delegate + ExistentialDeposit::get());
-		assert_ok!(DelegatedStaking::delegate(delegator, &delegate, amount_to_delegate));
-		assert_ok!(DelegatedStaking::bond_all(&delegate));
+		assert_ok!(DelegatedStaking::delegate_funds(
+			RawOrigin::Signed(delegator.clone()).into(),
+			delegate,
+			amount_to_delegate
+		));
+		if index == 0 {
+			assert_ok!(DelegatedStaking::bond(&delegate, amount_to_delegate, &reward_acc));
+		} else {
+			assert_ok!(DelegatedStaking::bond_extra(&delegate, amount_to_delegate));
+		}
 	}
 
 	// sanity checks
 	assert_eq!(DelegatedStaking::stakeable_balance(&delegate), delegated_amount);
-	assert_eq!(DelegatedStaking::unbonded_balance(&delegate), 0);
+	assert_eq!(Delegate::<T>::from(&delegate).unwrap().available_to_bond(), 0);
 
 	delegated_amount
 }
@@ -273,6 +285,16 @@ pub(crate) fn start_era(era: sp_staking::EraIndex) {
 }
 
 pub(crate) fn eq_stake(who: AccountId, total: Balance, active: Balance) -> bool {
-	use sp_staking::{Stake, StakingInterface};
 	Staking::stake(&who).unwrap() == Stake { total, active }
 }
+
+pub(crate) fn delegate_available_to_bond(delegate: &AccountId) -> Balance {
+	let delegate = Delegate::<T>::from(delegate).expect("delegate should exist");
+	delegate.available_to_bond()
+}
+
+
+pub(crate) fn delegate_effective_balance(delegate: &AccountId) -> Balance {
+	let delegate = Delegate::<T>::from(delegate).expect("delegate should exist");
+	delegate.ledger.effective_balance()
+}
\ No newline at end of file
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 5bb65e3210f6d..aac6326bab191 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -180,10 +180,10 @@ mod integration {
 				assert_eq!(DelegatedStaking::stakeable_balance(&delegate), delegated_balance);
 
 				// unbonded balance is the newly delegated 100
-				assert_eq!(DelegatedStaking::unbonded_balance(&delegate), 100);
-				assert_ok!(DelegatedStaking::bond_all(&delegate));
+				assert_eq!(delegate_available_to_bond(&delegate), 100);
+				assert_ok!(DelegatedStaking::bond_extra(&delegate, 100));
 				// after bond, unbonded balance is 0
-				assert_eq!(DelegatedStaking::unbonded_balance(&delegate), 0);
+				assert_eq!(delegate_available_to_bond(&delegate), 0);
 			}
 
 			assert_eq!(
@@ -237,9 +237,9 @@ mod integration {
 			);
 
 			assert!(eq_stake(delegate, total_staked, expected_active));
-			assert_eq!(DelegatedStaking::unbonded_balance(&delegate), 0);
+			assert_eq!(delegate_available_to_bond(&delegate), 0);
 			// full amount is still delegated
-			assert_eq!(DelegatedStaking::delegated_balance(&delegate), total_staked);
+			assert_eq!(delegate_effective_balance(&delegate), total_staked);
 
 			start_era(5);
 			// at era 5, 50 tokens are withdrawable, cannot withdraw more.
@@ -307,11 +307,11 @@ mod integration {
 			// assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(300.into()), delegate, 100));
 			//
 			// // verify unbonded balance
-			// assert_eq!(DelegatedStaking::unbonded_balance(&delegate), 100);
+			// assert_eq!(delegate_available_to_bond(&delegate), 100);
 			//
 			// // withdraw works now without unbonding
 			// assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 300, 100, 0));
-			// assert_eq!(DelegatedStaking::unbonded_balance(&delegate), 0);
+			// assert_eq!(delegate_available_to_bond(&delegate), 0);
 		});
 	}
 
@@ -353,8 +353,8 @@ mod integration {
 			));
 			// amount is staked correctly
 			assert!(eq_stake(200, 100, 100));
-			assert_eq!(DelegatedStaking::unbonded_balance(&200), 0);
-			assert_eq!(DelegatedStaking::delegated_balance(&200), 100);
+			assert_eq!(delegate_available_to_bond(&200), 0);
+			assert_eq!(delegate_effective_balance(&200), 100);
 
 			// free balance of delegate is untouched
 			assert_eq!(Balances::free_balance(200), balance_200);
@@ -402,7 +402,7 @@ mod integration {
 			assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(300).into(), 200, 100));
 
 			// delegate blocks delegation
-			assert_ok!(DelegatedStaking::block_delegations(&200));
+			assert_ok!(DelegatedStaking::block_delegations(RawOrigin::Signed(200).into(), true));
 
 			// cannot delegate to it anymore
 			assert_noop!(
@@ -411,7 +411,7 @@ mod integration {
 			);
 
 			// delegate can unblock delegation
-			assert_ok!(DelegatedStaking::unblock_delegations(&200));
+			assert_ok!(DelegatedStaking::block_delegations(RawOrigin::Signed(200).into(), false));
 
 			// delegation works again
 			assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(300).into(), 200, 100));
@@ -468,8 +468,8 @@ mod integration {
 				5000 - staked_amount - ExistentialDeposit::get()
 			);
 			assert_eq!(DelegatedStaking::stake(&200).unwrap(), init_stake);
-			assert_eq!(DelegatedStaking::delegated_balance(&200), 4000);
-			assert_eq!(DelegatedStaking::unbonded_balance(&200), 0);
+			assert_eq!(delegate_effective_balance(&200), 4000);
+			assert_eq!(delegate_available_to_bond(&200), 0);
 
 			// now lets migrate the delegators
 			let delegator_share = staked_amount / 4;
@@ -478,7 +478,7 @@ mod integration {
 				// fund them with ED
 				fund(&delegator, ExistentialDeposit::get());
 				// migrate 1/4th amount into each delegator
-				assert_ok!(DelegatedStaking::migrate_delegator(&200, &delegator, delegator_share));
+				assert_ok!(DelegatedStaking::migrate_delegation(RawOrigin::Signed(200).into(), delegator, delegator_share));
 				assert_eq!(
 					Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator),
 					delegator_share
@@ -491,13 +491,13 @@ mod integration {
 
 				// delegate stake is unchanged.
 				assert_eq!(DelegatedStaking::stake(&200).unwrap(), init_stake);
-				assert_eq!(DelegatedStaking::delegated_balance(&200), 4000);
-				assert_eq!(DelegatedStaking::unbonded_balance(&200), 0);
+				assert_eq!(delegate_effective_balance(&200), 4000);
+				assert_eq!(delegate_available_to_bond(&200), 0);
 			}
 
 			// cannot use migrate delegator anymore
 			assert_noop!(
-				DelegatedStaking::migrate_delegator(&200, &305, 1),
+				DelegatedStaking::migrate_delegation(RawOrigin::Signed(200).into(), 305, 1),
 				Error::<T>::NotEnoughFunds
 			);
 		});
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index d316cbe2b784b..4248cecc9ab35 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -19,7 +19,6 @@
 //! Basic types used in delegated staking.
 
 use super::*;
-use std::num::FpCategory::Zero;
 
 /// The type of pot account being created.
 #[derive(Encode, Decode)]
@@ -134,7 +133,7 @@ impl<T: Config> DelegationLedger<T> {
 	/// Effective total balance of the `delegate`.
 	pub(crate) fn effective_balance(&self) -> BalanceOf<T> {
 		defensive_assert!(
-			self.total_delegated > self.pending_slash,
+			self.total_delegated >= self.pending_slash,
 			"slash cannot be higher than actual balance of delegator"
 		);
 
@@ -143,31 +142,55 @@ impl<T: Config> DelegationLedger<T> {
 	}
 
 	/// Balance that can be bonded in [`T::CoreStaking`].
-	pub(crate) fn balance_available_to_bond(&self) -> BalanceOf<T> {
+	pub(crate) fn stakeable_balance(&self) -> BalanceOf<T> {
 		self.effective_balance().saturating_sub(self.unclaimed_withdrawals)
 	}
 }
 
-pub struct Delegate<T: Config>(T::AccountId);
+pub struct Delegate<T: Config> {
+	pub key: T::AccountId,
+	pub ledger: DelegationLedger<T>,
+}
 
 impl<T: Config> Delegate<T> {
-	fn available_to_bond(&self) -> BalanceOf<T> {
+	pub(crate) fn from(delegate: &T::AccountId) -> Result<Delegate<T>, DispatchError> {
+		let ledger = DelegationLedger::<T>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
+		Ok(Delegate { key: delegate.clone(), ledger })
+	}
+
+	pub(crate) fn available_to_bond(&self) -> BalanceOf<T> {
 		let exposed_stake = self.exposed_stake();
 
-		let bondable = self.ledger().map(|ledger| {
-			ledger.balance_available_to_bond()
-		}).unwrap_or(Zero::zero());
+		let stakeable =
+			self.ledger().map(|ledger| ledger.stakeable_balance()).unwrap_or(Zero::zero());
+
+		defensive_assert!(stakeable >= exposed_stake, "cannot expose more than delegate balance");
+
+		stakeable.saturating_sub(exposed_stake)
+	}
 
-		defensive_assert!(bondable >= exposed_stake, "cannot expose more than delegate balance");
+	pub(crate) fn ledger(&self) -> Option<DelegationLedger<T>> {
+		DelegationLedger::<T>::get(&self.key)
+	}
+
+	pub(crate) fn exposed_stake(&self) -> BalanceOf<T> {
+		T::CoreStaking::total_stake(&self.key).unwrap_or(Zero::zero())
+	}
+
+	pub(crate) fn is_exposed(&self) -> bool {
+		T::CoreStaking::stake(&self.key).is_ok()
+	}
 
-		bondable.saturating_sub(exposed_stake)
+	pub(crate) fn reward_account(&self) -> &T::AccountId {
+		&self.ledger.payee
 	}
 
-	fn ledger(&self) -> Option<DelegationLedger<T>> {
-		DelegationLedger::<T>::get(&self.0)
+	pub(crate) fn update_status(self, block: bool) -> Self {
+		Delegate { ledger: DelegationLedger { blocked: block, ..self.ledger }, ..self }
 	}
 
-	fn exposed_stake(&self) -> BalanceOf<T> {
-		T::CoreStaking::total_stake(&self.0).unwrap_or(Zero::zero())
+	pub(crate) fn save(self) {
+		let key = self.key;
+		self.ledger.save(&key)
 	}
 }

From 50da2acc4e90900235d4283de55ec4251e357152 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 18 Feb 2024 19:20:24 +0100
Subject: [PATCH 102/202] test passes

---
 .../frame/delegated-staking/src/impls.rs      |   9 +-
 substrate/frame/delegated-staking/src/lib.rs  |  18 +--
 substrate/frame/delegated-staking/src/mock.rs |  10 +-
 .../frame/delegated-staking/src/tests.rs      | 139 ++++++++++++++----
 .../frame/delegated-staking/src/types.rs      |   6 +-
 5 files changed, 136 insertions(+), 46 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 258685226b2df..1a0e9ac5a592c 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -118,7 +118,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 
 	fn unbond(stash: &Self::AccountId, value: Self::Balance) -> DispatchResult {
 		let delegate = Delegate::<T>::from(stash)?;
-		ensure!(delegate.exposed_stake() >= value, Error::<T>::NotEnoughFunds);
+		ensure!(delegate.bonded_stake() >= value, Error::<T>::NotEnoughFunds);
 
 		T::CoreStaking::unbond(stash, value)
 	}
@@ -346,9 +346,12 @@ impl<T: Config> StakingInterface for Pallet<T> {
 impl<T: Config> StakingDelegationSupport for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
+
+	/// this balance is total delegator that can be staked, and importantly not extra balance that
+	/// is delegated but not bonded yet.
 	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
 		Delegate::<T>::from(who)
-			.map(|delegate| delegate.available_to_bond())
+			.map(|delegate| delegate.ledger.stakeable_balance())
 			.unwrap_or_default()
 	}
 
@@ -380,7 +383,7 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 	}
 
 	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
-	 	// fixme(ank4n): Do I really need this?
+		// fixme(ank4n): Do I really need this?
 		Ok(())
 	}
 
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 5e9ba4b67be21..c97369db6359a 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -314,7 +314,10 @@ pub mod pallet {
 			ensure!(Self::not_direct_staker(&who), Error::<T>::AlreadyStaker);
 
 			// ensure delegate is sane.
-			ensure!(DelegationLedger::<T>::can_accept_delegation(&delegate), Error::<T>::NotAcceptingDelegations);
+			ensure!(
+				DelegationLedger::<T>::can_accept_delegation(&delegate),
+				Error::<T>::NotAcceptingDelegations
+			);
 
 			let delegator_balance =
 				T::Currency::reducible_balance(&who, Preservation::Preserve, Fortitude::Polite);
@@ -328,10 +331,7 @@ pub mod pallet {
 		/// To unblock, pass false.
 		#[pallet::call_index(5)]
 		#[pallet::weight(Weight::default())]
-		pub fn block_delegations(
-			origin: OriginFor<T>,
-			block: bool,
-		) -> DispatchResult {
+		pub fn block_delegations(origin: OriginFor<T>, block: bool) -> DispatchResult {
 			let who = ensure_signed(origin)?;
 
 			let delegate = Delegate::<T>::from(&who)?;
@@ -403,16 +403,16 @@ impl<T: Config> Pallet<T> {
 		// FIXME(ank4n) expose set payee in staking interface.
 		// T::CoreStaking::set_payee(who, reward_account)
 
-		Self::do_delegate(&proxy_delegator, who, stake.total)?;
-		Self::do_bond(who, stake.total)
+		Self::do_delegate(&proxy_delegator, who, stake.total)
 	}
 
 	fn do_bond(delegate_acc: &T::AccountId, amount: BalanceOf<T>) -> DispatchResult {
 		let delegate = Delegate::<T>::from(delegate_acc)?;
 
-		debug_assert!(amount == delegate.available_to_bond());
+		let available_to_bond = delegate.available_to_bond();
+		defensive_assert!(amount == available_to_bond, "not expected value to bond");
 
-		if delegate.is_exposed() {
+		if delegate.is_bonded() {
 			T::CoreStaking::bond_extra(&delegate.key, amount)
 		} else {
 			T::CoreStaking::bond(&delegate.key, amount, &delegate.reward_account())
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 978ff38dda050..c3a98e82354ff 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -32,7 +32,7 @@ use frame_election_provider_support::{
 };
 use frame_support::dispatch::RawOrigin;
 use pallet_staking::CurrentEra;
-use sp_staking::{delegation::StakingDelegationSupport, StakingInterface, Stake};
+use sp_staking::{delegation::StakingDelegationSupport, Stake, StakingInterface};
 
 pub type T = Runtime;
 type Block = frame_system::mocking::MockBlock<Runtime>;
@@ -293,8 +293,12 @@ pub(crate) fn delegate_available_to_bond(delegate: &AccountId) -> Balance {
 	delegate.available_to_bond()
 }
 
-
 pub(crate) fn delegate_effective_balance(delegate: &AccountId) -> Balance {
 	let delegate = Delegate::<T>::from(delegate).expect("delegate should exist");
 	delegate.ledger.effective_balance()
-}
\ No newline at end of file
+}
+
+pub(crate) fn delegate_bonded(delegate: &AccountId) -> bool {
+	let delegate = Delegate::<T>::from(delegate).expect("delegate should exist");
+	delegate.is_bonded()
+}
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index aac6326bab191..535ddf619a031 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -32,11 +32,18 @@ fn create_a_delegate_with_first_delegator() {
 
 		// set intention to accept delegation.
 		fund(&delegate, 1000);
-		assert_ok!(DelegatedStaking::register_as_delegate(RawOrigin::Signed(delegate).into(), reward_account));
+		assert_ok!(DelegatedStaking::register_as_delegate(
+			RawOrigin::Signed(delegate).into(),
+			reward_account
+		));
 
 		// delegate to this account
 		fund(&delegator, 1000);
-		assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(delegator).into(), delegate, 100));
+		assert_ok!(DelegatedStaking::delegate_funds(
+			RawOrigin::Signed(delegator).into(),
+			delegate,
+			100
+		));
 
 		// verify
 		assert!(DelegatedStaking::is_delegate(&delegate));
@@ -56,17 +63,26 @@ fn cannot_become_delegate() {
 
 		// an existing validator cannot become delegate
 		assert_noop!(
-			DelegatedStaking::register_as_delegate(RawOrigin::Signed(mock::GENESIS_VALIDATOR).into(), 100),
+			DelegatedStaking::register_as_delegate(
+				RawOrigin::Signed(mock::GENESIS_VALIDATOR).into(),
+				100
+			),
 			Error::<T>::AlreadyStaker
 		);
 
 		// an existing nominator cannot become delegate
 		assert_noop!(
-			DelegatedStaking::register_as_delegate(RawOrigin::Signed(mock::GENESIS_NOMINATOR_ONE).into(), 100),
+			DelegatedStaking::register_as_delegate(
+				RawOrigin::Signed(mock::GENESIS_NOMINATOR_ONE).into(),
+				100
+			),
 			Error::<T>::AlreadyStaker
 		);
 		assert_noop!(
-			DelegatedStaking::register_as_delegate(RawOrigin::Signed(mock::GENESIS_NOMINATOR_TWO).into(), 100),
+			DelegatedStaking::register_as_delegate(
+				RawOrigin::Signed(mock::GENESIS_NOMINATOR_TWO).into(),
+				100
+			),
 			Error::<T>::AlreadyStaker
 		);
 	});
@@ -84,12 +100,19 @@ fn create_multiple_delegators() {
 		assert_eq!(DelegatedStaking::stakeable_balance(&delegate), 0);
 
 		// set intention to accept delegation.
-		assert_ok!(DelegatedStaking::register_as_delegate(RawOrigin::Signed(delegate).into(), reward_account));
+		assert_ok!(DelegatedStaking::register_as_delegate(
+			RawOrigin::Signed(delegate).into(),
+			reward_account
+		));
 
 		// create 100 delegators
 		for i in 202..302 {
 			fund(&i, 100 + ExistentialDeposit::get());
-			assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(i).into(), delegate, 100));
+			assert_ok!(DelegatedStaking::delegate_funds(
+				RawOrigin::Signed(i).into(),
+				delegate,
+				100
+			));
 			// Balance of 100 held on delegator account for delegating to the delegate.
 			assert_eq!(Balances::balance_on_hold(&HoldReason::Delegating.into(), &i), 100);
 		}
@@ -107,37 +130,67 @@ fn delegate_restrictions() {
 		let delegate_one = 200;
 		let delegator_one = 210;
 		fund(&delegate_one, 100);
-		assert_ok!(DelegatedStaking::register_as_delegate(RawOrigin::Signed(delegate_one).into(), delegate_one + 1));
+		assert_ok!(DelegatedStaking::register_as_delegate(
+			RawOrigin::Signed(delegate_one).into(),
+			delegate_one + 1
+		));
 		fund(&delegator_one, 200);
-		assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(delegator_one).into(), delegate_one, 100));
+		assert_ok!(DelegatedStaking::delegate_funds(
+			RawOrigin::Signed(delegator_one).into(),
+			delegate_one,
+			100
+		));
 
 		let delegate_two = 300;
 		let delegator_two = 310;
 		fund(&delegate_two, 100);
-		assert_ok!(DelegatedStaking::register_as_delegate(RawOrigin::Signed(delegate_two).into(), delegate_two + 1));
+		assert_ok!(DelegatedStaking::register_as_delegate(
+			RawOrigin::Signed(delegate_two).into(),
+			delegate_two + 1
+		));
 		fund(&delegator_two, 200);
-		assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(delegator_two).into(), delegate_two, 100));
+		assert_ok!(DelegatedStaking::delegate_funds(
+			RawOrigin::Signed(delegator_two).into(),
+			delegate_two,
+			100
+		));
 
 		// delegate one tries to delegate to delegate 2
 		assert_noop!(
-			DelegatedStaking::delegate_funds(RawOrigin::Signed(delegate_one).into(), delegate_two, 10),
+			DelegatedStaking::delegate_funds(
+				RawOrigin::Signed(delegate_one).into(),
+				delegate_two,
+				10
+			),
 			Error::<T>::InvalidDelegation
 		);
 
 		// delegate one tries to delegate to a delegator
 		assert_noop!(
-			DelegatedStaking::delegate_funds(RawOrigin::Signed(delegate_one).into(), delegator_one, 10),
+			DelegatedStaking::delegate_funds(
+				RawOrigin::Signed(delegate_one).into(),
+				delegator_one,
+				10
+			),
 			Error::<T>::InvalidDelegation
 		);
 		assert_noop!(
-			DelegatedStaking::delegate_funds(RawOrigin::Signed(delegate_one).into(), delegator_two, 10),
+			DelegatedStaking::delegate_funds(
+				RawOrigin::Signed(delegate_one).into(),
+				delegator_two,
+				10
+			),
 			Error::<T>::InvalidDelegation
 		);
 
 		// delegator one tries to delegate to delegate 2 as well (it already delegates to delegate
 		// 1)
 		assert_noop!(
-			DelegatedStaking::delegate_funds(RawOrigin::Signed(delegator_one).into(), delegate_two, 10),
+			DelegatedStaking::delegate_funds(
+				RawOrigin::Signed(delegator_one).into(),
+				delegate_two,
+				10
+			),
 			Error::<T>::InvalidDelegation
 		);
 	});
@@ -163,14 +216,22 @@ mod integration {
 
 			// set intention to become a delegate
 			fund(&delegate, 100);
-			assert_ok!(DelegatedStaking::register_as_delegate(RawOrigin::Signed(delegate).into(), reward_acc));
+			assert_ok!(DelegatedStaking::register_as_delegate(
+				RawOrigin::Signed(delegate).into(),
+				reward_acc
+			));
 			assert_eq!(DelegatedStaking::stakeable_balance(&delegate), 0);
 
 			let mut delegated_balance: Balance = 0;
+
 			// set some delegations
 			for delegator in 200..250 {
 				fund(&delegator, 200);
-				assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(delegator).into(), delegate, 100));
+				assert_ok!(DelegatedStaking::delegate_funds(
+					RawOrigin::Signed(delegator).into(),
+					delegate,
+					100
+				));
 				delegated_balance += 100;
 				assert_eq!(
 					Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator),
@@ -181,7 +242,12 @@ mod integration {
 
 				// unbonded balance is the newly delegated 100
 				assert_eq!(delegate_available_to_bond(&delegate), 100);
-				assert_ok!(DelegatedStaking::bond_extra(&delegate, 100));
+				if delegate_bonded(&delegate) {
+					assert_ok!(DelegatedStaking::bond_extra(&delegate, 100));
+				} else {
+					assert_ok!(DelegatedStaking::bond(&delegate, 100, &reward_acc));
+				}
+
 				// after bond, unbonded balance is 0
 				assert_eq!(delegate_available_to_bond(&delegate), 0);
 			}
@@ -213,8 +279,8 @@ mod integration {
 				DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 301, 50, 0),
 				Error::<T>::NotEnoughFunds
 			);
-			// assert_noop!(DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 200, 50, 0),
-			// Error::<T>::NotAllowed); active and total stake remains same
+			// assert_noop!(DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 200, 50,
+			// 0), Error::<T>::NotAllowed); active and total stake remains same
 			assert!(eq_stake(delegate, total_staked, total_staked));
 
 			// 305 wants to unbond 50 in era 2, withdrawable in era 5.
@@ -304,14 +370,15 @@ mod integration {
 			// withdrawn and test its claimed from there first.
 
 			// fund(&300, 1000);
-			// assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(300.into()), delegate, 100));
+			// assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(300.into()), delegate,
+			// 100));
 			//
 			// // verify unbonded balance
 			// assert_eq!(delegate_available_to_bond(&delegate), 100);
 			//
 			// // withdraw works now without unbonding
-			// assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 300, 100, 0));
-			// assert_eq!(delegate_available_to_bond(&delegate), 0);
+			// assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 300, 100,
+			// 0)); assert_eq!(delegate_available_to_bond(&delegate), 0);
 		});
 	}
 
@@ -377,16 +444,28 @@ mod integration {
 			setup_delegation_stake(200, 201, (202..203).collect(), 100, 0);
 
 			// Registering again is noop
-			assert_noop!(DelegatedStaking::register_as_delegate(RawOrigin::Signed(200).into(), 201), Error::<T>::NotAllowed);
+			assert_noop!(
+				DelegatedStaking::register_as_delegate(RawOrigin::Signed(200).into(), 201),
+				Error::<T>::NotAllowed
+			);
 			// a delegator cannot become delegate
-			assert_noop!(DelegatedStaking::register_as_delegate(RawOrigin::Signed(202).into(), 203), Error::<T>::NotAllowed);
+			assert_noop!(
+				DelegatedStaking::register_as_delegate(RawOrigin::Signed(202).into(), 203),
+				Error::<T>::NotAllowed
+			);
 			// existing staker cannot become a delegate
 			assert_noop!(
-				DelegatedStaking::register_as_delegate(RawOrigin::Signed(GENESIS_NOMINATOR_ONE).into(), 201),
+				DelegatedStaking::register_as_delegate(
+					RawOrigin::Signed(GENESIS_NOMINATOR_ONE).into(),
+					201
+				),
 				Error::<T>::AlreadyStaker
 			);
 			assert_noop!(
-				DelegatedStaking::register_as_delegate(RawOrigin::Signed(GENESIS_VALIDATOR).into(), 201),
+				DelegatedStaking::register_as_delegate(
+					RawOrigin::Signed(GENESIS_VALIDATOR).into(),
+					201
+				),
 				Error::<T>::AlreadyStaker
 			);
 		});
@@ -478,7 +557,11 @@ mod integration {
 				// fund them with ED
 				fund(&delegator, ExistentialDeposit::get());
 				// migrate 1/4th amount into each delegator
-				assert_ok!(DelegatedStaking::migrate_delegation(RawOrigin::Signed(200).into(), delegator, delegator_share));
+				assert_ok!(DelegatedStaking::migrate_delegation(
+					RawOrigin::Signed(200).into(),
+					delegator,
+					delegator_share
+				));
 				assert_eq!(
 					Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator),
 					delegator_share
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index 4248cecc9ab35..5999d4b9a977e 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -159,7 +159,7 @@ impl<T: Config> Delegate<T> {
 	}
 
 	pub(crate) fn available_to_bond(&self) -> BalanceOf<T> {
-		let exposed_stake = self.exposed_stake();
+		let exposed_stake = self.bonded_stake();
 
 		let stakeable =
 			self.ledger().map(|ledger| ledger.stakeable_balance()).unwrap_or(Zero::zero());
@@ -173,11 +173,11 @@ impl<T: Config> Delegate<T> {
 		DelegationLedger::<T>::get(&self.key)
 	}
 
-	pub(crate) fn exposed_stake(&self) -> BalanceOf<T> {
+	pub(crate) fn bonded_stake(&self) -> BalanceOf<T> {
 		T::CoreStaking::total_stake(&self.key).unwrap_or(Zero::zero())
 	}
 
-	pub(crate) fn is_exposed(&self) -> bool {
+	pub(crate) fn is_bonded(&self) -> bool {
 		T::CoreStaking::stake(&self.key).is_ok()
 	}
 

From 2f00fb07cb7d436af9962e88f234ea24a36bbf0e Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 18 Feb 2024 19:29:55 +0100
Subject: [PATCH 103/202] remove update hold

---
 substrate/frame/delegated-staking/src/impls.rs |  5 -----
 substrate/frame/staking/src/pallet/impls.rs    | 11 +++--------
 substrate/primitives/staking/src/delegation.rs |  4 +---
 3 files changed, 4 insertions(+), 16 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 1a0e9ac5a592c..1e4a9df8294b9 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -382,11 +382,6 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 		Self::is_delegate(who)
 	}
 
-	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
-		// fixme(ank4n): Do I really need this?
-		Ok(())
-	}
-
 	fn report_slash(who: &Self::AccountId, slash: Self::Balance) {
 		<Delegates<T>>::mutate(who, |maybe_register| match maybe_register {
 			Some(register) => register.pending_slash.saturating_accrue(slash),
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 3c6c24136a862..8d6e1c243b22b 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1120,11 +1120,11 @@ impl<T: Config> Pallet<T> {
 		who: &T::AccountId,
 		amount: BalanceOf<T>,
 	) -> sp_runtime::DispatchResult {
-		if T::DelegationSupport::is_delegate(who) {
-			return T::DelegationSupport::update_hold(who, amount);
+		// only apply lock if it is not a delegate. Delegate accounts are already locked/held.
+		if !T::DelegationSupport::is_delegate(who) {
+			T::Currency::set_lock(crate::STAKING_ID, who, amount, WithdrawReasons::all());
 		}
 
-		T::Currency::set_lock(crate::STAKING_ID, who, amount, WithdrawReasons::all());
 		Ok(())
 	}
 }
@@ -1885,11 +1885,6 @@ impl<T: Config> StakingDelegationSupport for NoDelegation<T> {
 	fn is_delegate(_who: &Self::AccountId) -> bool {
 		false
 	}
-	fn update_hold(_who: &Self::AccountId, _amount: Self::Balance) -> sp_runtime::DispatchResult {
-		defensive!("delegation update_hold should not be have been called for NoDelegation");
-		Err(Error::<T>::BadState.into())
-	}
-
 	fn report_slash(_who: &Self::AccountId, _slash: Self::Balance) {
 		defensive!("delegation report_slash should not be have been called for NoDelegation");
 	}
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 6aa4befa339d2..af8cca9bb091a 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -21,6 +21,7 @@ use sp_runtime::{DispatchResult, Saturating};
 use sp_std::ops::Sub;
 
 /// Allows an account to accept stake delegations and manage its operations.
+// FIXME(ank4n): Remove this and add a new trait (in delegation pallet) for NP adapter.
 pub trait DelegationInterface {
 	/// Balance type used by the staking system.
 	type Balance: Sub<Output = Self::Balance>
@@ -154,9 +155,6 @@ pub trait StakingDelegationSupport {
 	/// Returns true if `who` accepts delegations for stake.
 	fn is_delegate(who: &Self::AccountId) -> bool;
 
-	/// Update amount held for bonded stake.
-	fn update_hold(who: &Self::AccountId, amount: Self::Balance) -> DispatchResult;
-
 	/// Reports an ongoing slash to the `delegate` account that would be applied lazily.
 	fn report_slash(who: &Self::AccountId, slash: Self::Balance);
 }

From 833eadb6a8fd071c07f3d3f1e0b0f66dbb81b6dd Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 18 Feb 2024 20:04:51 +0100
Subject: [PATCH 104/202] remove commented code

---
 .../frame/delegated-staking/src/impls.rs      | 103 +-----------------
 1 file changed, 1 insertion(+), 102 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 1e4a9df8294b9..c7ef966ce43e9 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -206,84 +206,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 }
 
 // impl<T: Config> DelegationInterface for Pallet<T> {
-// 	type Balance = BalanceOf<T>;
-// 	type AccountId = T::AccountId;
-//
-// 	fn delegated_balance(who: &Self::AccountId) -> Self::Balance {
-// 		<Delegates<T>>::get(who)
-// 			.map_or_else(|| 0u32.into(), |register| register.delegated_balance())
-// 	}
-//
-// 	fn unbonded_balance(who: &Self::AccountId) -> Self::Balance {
-// 		<Delegates<T>>::get(who).map_or_else(|| 0u32.into(), |register| register.stakeable_balance())
-// 	}
-//
-// 	fn accept_delegations(
-// 		who: &Self::AccountId,
-// 		reward_destination: &Self::AccountId,
-// 	) -> DispatchResult {
-// 		Self::register_as_delegate(
-// 			RawOrigin::Signed(who.clone()).into(),
-// 			reward_destination.clone(),
-// 		)
-// 	}
-//
-// 	/// Transfers funds from current staked account to `proxy_delegator`. Current staked account
-// 	/// becomes a `delegate` with `proxy_delegator` delegating stakes to it.
-// 	fn migrate_accept_delegations(
-// 		who: &Self::AccountId,
-// 		_proxy_delegator: &Self::AccountId,
-// 		reward_destination: &Self::AccountId,
-// 	) -> DispatchResult {
-// 		Self::migrate_to_delegate(RawOrigin::Signed(who.clone()).into(), reward_destination.clone())
-// 	}
-//
-// 	fn block_delegations(delegate: &Self::AccountId) -> DispatchResult {
-// 		let mut register = <Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-// 		register.blocked = true;
-// 		<Delegates<T>>::insert(delegate, register);
-//
-// 		Ok(())
-// 	}
-//
-// 	fn unblock_delegations(delegate: &Self::AccountId) -> DispatchResult {
-// 		let mut register = <Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-// 		register.blocked = false;
-// 		<Delegates<T>>::insert(delegate, register);
-//
-// 		Ok(())
-// 	}
-//
-// 	fn kill_delegate(_delegate: &Self::AccountId) -> DispatchResult {
-// 		todo!()
-// 	}
-//
-// 	fn bond_all(who: &Self::AccountId) -> DispatchResult {
-// 		let delegate = <Delegates<T>>::get(who).ok_or(Error::<T>::NotDelegate)?;
-// 		let amount_to_bond = delegate.stakeable_balance();
-//
-// 		match T::CoreStaking::stake(who) {
-// 			// already bonded
-// 			Ok(_) => T::CoreStaking::bond_extra(who, amount_to_bond),
-// 			// first bond
-// 			Err(_) => T::CoreStaking::bond(who, amount_to_bond, &delegate.payee),
-// 		}
-// 	}
-//
-// 	fn delegate_withdraw(
-// 		delegate: &Self::AccountId,
-// 		delegator: &Self::AccountId,
-// 		value: Self::Balance,
-// 		num_slashing_spans: u32,
-// 	) -> DispatchResult {
-// 		Self::release(
-// 			RawOrigin::Signed(delegate.clone()).into(),
-// 			delegator.clone(),
-// 			value,
-// 			num_slashing_spans,
-// 		)
-// 	}
-//
+// FIXME(ank4n): Should be part of NP Adapter.
 // 	fn apply_slash(
 // 		delegate: &Self::AccountId,
 // 		delegator: &Self::AccountId,
@@ -317,30 +240,6 @@ impl<T: Config> StakingInterface for Pallet<T> {
 // 		Ok(())
 // 	}
 //
-// 	/// Move funds from proxy delegator to actual delegator.
-// 	fn migrate_delegator(
-// 		delegate: &Self::AccountId,
-// 		new_delegator: &Self::AccountId,
-// 		value: Self::Balance,
-// 	) -> DispatchResult {
-// 		Self::migrate_delegation(
-// 			RawOrigin::Signed(delegate.clone()).into(),
-// 			new_delegator.clone(),
-// 			value,
-// 		)
-// 	}
-//
-// 	fn delegate(
-// 		delegator: &Self::AccountId,
-// 		delegate: &Self::AccountId,
-// 		value: Self::Balance,
-// 	) -> DispatchResult {
-// 		Self::delegate_funds(
-// 			RawOrigin::Signed(delegator.clone()).into(),
-// 			delegate.clone(),
-// 			value,
-// 		)
-// 	}
 // }
 
 impl<T: Config> StakingDelegationSupport for Pallet<T> {

From 9fe70fe9ee66fe1bf2a817d52de578b0b0c46ead Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 18 Feb 2024 21:13:29 +0100
Subject: [PATCH 105/202] nomination pool revert

---
 .../nomination-pools/benchmarking/Cargo.toml  |   3 -
 substrate/frame/nomination-pools/src/lib.rs   |  70 ++++----
 .../nomination-pools/test-staking/Cargo.toml  |   1 -
 .../nomination-pools/test-staking/src/lib.rs  | 163 ------------------
 .../nomination-pools/test-staking/src/mock.rs |  18 +-
 5 files changed, 39 insertions(+), 216 deletions(-)

diff --git a/substrate/frame/nomination-pools/benchmarking/Cargo.toml b/substrate/frame/nomination-pools/benchmarking/Cargo.toml
index c6f2743409741..3693ad1866dd4 100644
--- a/substrate/frame/nomination-pools/benchmarking/Cargo.toml
+++ b/substrate/frame/nomination-pools/benchmarking/Cargo.toml
@@ -27,7 +27,6 @@ frame-support = { path = "../../support", default-features = false }
 frame-system = { path = "../../system", default-features = false }
 pallet-bags-list = { path = "../../bags-list", default-features = false }
 pallet-staking = { path = "../../staking", default-features = false }
-pallet-delegated-staking = { path = "../../delegated-staking", default-features = false }
 pallet-nomination-pools = { path = "..", default-features = false }
 
 # Substrate Primitives
@@ -56,7 +55,6 @@ std = [
 	"pallet-balances/std",
 	"pallet-nomination-pools/std",
 	"pallet-staking/std",
-	"pallet-delegated-staking/std",
 	"pallet-timestamp/std",
 	"scale-info/std",
 	"sp-core/std",
@@ -76,7 +74,6 @@ runtime-benchmarks = [
 	"pallet-balances/runtime-benchmarks",
 	"pallet-nomination-pools/runtime-benchmarks",
 	"pallet-staking/runtime-benchmarks",
-	"pallet-delegated-staking/runtime-benchmarks",
 	"pallet-timestamp/runtime-benchmarks",
 	"sp-runtime/runtime-benchmarks",
 	"sp-staking/runtime-benchmarks",
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index dfb0cefa542be..2777e7b6052e6 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -373,7 +373,7 @@ use sp_runtime::{
 	},
 	FixedPointNumber, Perbill,
 };
-use sp_staking::{delegation::DelegationInterface, EraIndex, StakingInterface};
+use sp_staking::{EraIndex, StakingInterface};
 use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, ops::Div, vec::Vec};
 
 #[cfg(any(feature = "try-runtime", feature = "fuzzing", test, debug_assertions))]
@@ -1259,7 +1259,7 @@ impl<T: Config> BondedPool<T> {
 		T::Currency::transfer(
 			who,
 			&bonded_account,
-			T::Currency::minimum_balance(),
+			amount,
 			match ty {
 				BondType::Create => Preservation::Expendable,
 				BondType::Later => Preservation::Preserve,
@@ -1271,19 +1271,11 @@ impl<T: Config> BondedPool<T> {
 
 		match ty {
 			// TODO(ank4n): When type create, also do accept delegation call..
-			BondType::Create => {
-				T::Staking::accept_delegations(&bonded_account, &self.reward_account())?;
-				T::Staking::delegate(&who, &bonded_account, amount)?;
-				T::Staking::bond(&bonded_account, amount, &self.reward_account())?
-			},
-
+			BondType::Create => T::Staking::bond(&bonded_account, amount, &self.reward_account())?,
 			// The pool should always be created in such a way its in a state to bond extra, but if
 			// the active balance is slashed below the minimum bonded or the account cannot be
 			// found, we exit early.
-			BondType::Later => {
-				T::Staking::delegate(&who, &bonded_account, amount)?;
-				T::Staking::bond_extra(&bonded_account, amount)?
-			},
+			BondType::Later => T::Staking::bond_extra(&bonded_account, amount)?,
 		}
 		TotalValueLocked::<T>::mutate(|tvl| {
 			tvl.saturating_accrue(amount);
@@ -1652,8 +1644,7 @@ pub mod pallet {
 		type U256ToBalance: Convert<U256, BalanceOf<Self>>;
 
 		/// The interface for nominating.
-		type Staking: StakingInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId>
-			+ DelegationInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
+		type Staking: StakingInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
 
 		/// The amount of eras a `SubPools::with_era` pool can exist before it gets merged into the
 		/// `SubPools::no_era` pool. In other words, this is the amount of eras a member will be
@@ -2263,10 +2254,22 @@ pub mod pallet {
 			let withdrawn_points = member.withdraw_unlocked(current_era);
 			ensure!(!withdrawn_points.is_empty(), Error::<T>::CannotWithdrawAny);
 
+			// Before calculating the `balance_to_unbond`, we call withdraw unbonded to ensure the
+			// `transferrable_balance` is correct.
+			let stash_killed =
+				T::Staking::withdraw_unbonded(bonded_pool.bonded_account(), num_slashing_spans)?;
+
+			// defensive-only: the depositor puts enough funds into the stash so that it will only
+			// be destroyed when they are leaving.
+			ensure!(
+				!stash_killed || caller == bonded_pool.roles.depositor,
+				Error::<T>::Defensive(DefensiveError::BondedStashKilledPrematurely)
+			);
+
 			let mut sum_unlocked_points: BalanceOf<T> = Zero::zero();
-			let balance_to_unbond = withdrawn_points.iter().fold(
-				BalanceOf::<T>::zero(),
-				|accumulator, (era, unlocked_points)| {
+			let balance_to_unbond = withdrawn_points
+				.iter()
+				.fold(BalanceOf::<T>::zero(), |accumulator, (era, unlocked_points)| {
 					sum_unlocked_points = sum_unlocked_points.saturating_add(*unlocked_points);
 					if let Some(era_pool) = sub_pools.with_era.get_mut(era) {
 						let balance_to_unbond = era_pool.dissolve(*unlocked_points);
@@ -2279,27 +2282,24 @@ pub mod pallet {
 						// era-less pool.
 						accumulator.saturating_add(sub_pools.no_era.dissolve(*unlocked_points))
 					}
-				},
-			);
-			// fixme(ank4n): Transfer whatever is minimum transferable.
-			// Withdraw upto limit and return the amount withdrawn and whether stash killed.
-
-			// Before calculating the `balance_to_unbond`, we call withdraw unbonded to ensure the
-			// `transferrable_balance` is correct.
-			// fixme(ank4n): Handle result.
-			let _withdraw_result = T::Staking::delegate_withdraw(
+				})
+				// A call to this transaction may cause the pool's stash to get dusted. If this
+				// happens before the last member has withdrawn, then all subsequent withdraws will
+				// be 0. However the unbond pools do no get updated to reflect this. In the
+				// aforementioned scenario, this check ensures we don't try to withdraw funds that
+				// don't exist. This check is also defensive in cases where the unbond pool does not
+				// update its balance (e.g. a bug in the slashing hook.) We gracefully proceed in
+				// order to ensure members can leave the pool and it can be destroyed.
+				.min(bonded_pool.transferable_balance());
+
+			// fixme(ank4n): Fix for delegated
+			T::Currency::transfer(
 				&bonded_pool.bonded_account(),
 				&member_account,
 				balance_to_unbond,
-				num_slashing_spans,
-			)?;
-
-			// defensive-only: the depositor puts enough funds into the stash so that it will only
-			// be destroyed when they are leaving.
-			// ensure!(
-			// 	!stash_killed || caller == bonded_pool.roles.depositor,
-			// 	Error::<T>::Defensive(DefensiveError::BondedStashKilledPrematurely)
-			// );
+				Preservation::Expendable,
+			)
+			.defensive()?;
 
 			Self::deposit_event(Event::<T>::Withdrawn {
 				member: member_account.clone(),
diff --git a/substrate/frame/nomination-pools/test-staking/Cargo.toml b/substrate/frame/nomination-pools/test-staking/Cargo.toml
index 12c358b7e1614..9c7b12e4c6345 100644
--- a/substrate/frame/nomination-pools/test-staking/Cargo.toml
+++ b/substrate/frame/nomination-pools/test-staking/Cargo.toml
@@ -32,7 +32,6 @@ frame-election-provider-support = { path = "../../election-provider-support" }
 pallet-timestamp = { path = "../../timestamp" }
 pallet-balances = { path = "../../balances" }
 pallet-staking = { path = "../../staking" }
-pallet-delegated-staking = { path = "../../delegated-staking" }
 pallet-bags-list = { path = "../../bags-list" }
 pallet-staking-reward-curve = { path = "../../staking/reward-curve" }
 pallet-nomination-pools = { path = ".." }
diff --git a/substrate/frame/nomination-pools/test-staking/src/lib.rs b/substrate/frame/nomination-pools/test-staking/src/lib.rs
index e960d027f3e07..865b7a71e6884 100644
--- a/substrate/frame/nomination-pools/test-staking/src/lib.rs
+++ b/substrate/frame/nomination-pools/test-staking/src/lib.rs
@@ -191,169 +191,6 @@ fn pool_lifecycle_e2e() {
 	})
 }
 
-#[test]
-fn pool_migration_to_delegation_e2e() {
-	new_test_ext().execute_with(|| {
-		assert_eq!(Balances::minimum_balance(), 5);
-		assert_eq!(Staking::current_era(), None);
-
-		// create the pool, we know this has id 1.
-		assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10));
-		assert_eq!(LastPoolId::<Runtime>::get(), 1);
-
-		// have the pool nominate.
-		assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]));
-
-		assert_eq!(
-			staking_events_since_last_call(),
-			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }]
-		);
-		assert_eq!(
-			pool_events_since_last_call(),
-			vec![
-				PoolsEvent::Created { depositor: 10, pool_id: 1 },
-				PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true },
-			]
-		);
-
-		// have two members join
-		assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1));
-		assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1));
-
-		assert_eq!(
-			staking_events_since_last_call(),
-			vec![
-				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 },
-				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 },
-			]
-		);
-		assert_eq!(
-			pool_events_since_last_call(),
-			vec![
-				PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true },
-				PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true },
-			]
-		);
-
-		// pool goes into destroying
-		assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying));
-
-		// depositor cannot unbond yet.
-		assert_noop!(
-			Pools::unbond(RuntimeOrigin::signed(10), 10, 50),
-			PoolsError::<Runtime>::MinimumBondNotMet,
-		);
-
-		// now the members want to unbond.
-		assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10));
-		assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10));
-
-		assert_eq!(PoolMembers::<Runtime>::get(20).unwrap().unbonding_eras.len(), 1);
-		assert_eq!(PoolMembers::<Runtime>::get(20).unwrap().points, 0);
-		assert_eq!(PoolMembers::<Runtime>::get(21).unwrap().unbonding_eras.len(), 1);
-		assert_eq!(PoolMembers::<Runtime>::get(21).unwrap().points, 0);
-
-		assert_eq!(
-			staking_events_since_last_call(),
-			vec![
-				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
-				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
-			]
-		);
-		assert_eq!(
-			pool_events_since_last_call(),
-			vec![
-				PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying },
-				PoolsEvent::Unbonded { member: 20, pool_id: 1, points: 10, balance: 10, era: 3 },
-				PoolsEvent::Unbonded { member: 21, pool_id: 1, points: 10, balance: 10, era: 3 },
-			]
-		);
-
-		// depositor cannot still unbond
-		assert_noop!(
-			Pools::unbond(RuntimeOrigin::signed(10), 10, 50),
-			PoolsError::<Runtime>::MinimumBondNotMet,
-		);
-
-		for e in 1..BondingDuration::get() {
-			CurrentEra::<Runtime>::set(Some(e));
-			assert_noop!(
-				Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0),
-				PoolsError::<Runtime>::CannotWithdrawAny
-			);
-		}
-
-		// members are now unlocked.
-		CurrentEra::<Runtime>::set(Some(BondingDuration::get()));
-
-		// depositor cannot still unbond
-		assert_noop!(
-			Pools::unbond(RuntimeOrigin::signed(10), 10, 50),
-			PoolsError::<Runtime>::MinimumBondNotMet,
-		);
-
-		// but members can now withdraw.
-		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0));
-		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0));
-		assert!(PoolMembers::<Runtime>::get(20).is_none());
-		assert!(PoolMembers::<Runtime>::get(21).is_none());
-
-		assert_eq!(
-			staking_events_since_last_call(),
-			vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 },]
-		);
-		assert_eq!(
-			pool_events_since_last_call(),
-			vec![
-				PoolsEvent::Withdrawn { member: 20, pool_id: 1, points: 10, balance: 10 },
-				PoolsEvent::MemberRemoved { pool_id: 1, member: 20 },
-				PoolsEvent::Withdrawn { member: 21, pool_id: 1, points: 10, balance: 10 },
-				PoolsEvent::MemberRemoved { pool_id: 1, member: 21 },
-			]
-		);
-
-		// as soon as all members have left, the depositor can try to unbond, but since the
-		// min-nominator intention is set, they must chill first.
-		assert_noop!(
-			Pools::unbond(RuntimeOrigin::signed(10), 10, 50),
-			pallet_staking::Error::<Runtime>::InsufficientBond
-		);
-
-		assert_ok!(Pools::chill(RuntimeOrigin::signed(10), 1));
-		assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 50));
-
-		assert_eq!(
-			staking_events_since_last_call(),
-			vec![
-				StakingEvent::Chilled { stash: POOL1_BONDED },
-				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 50 },
-			]
-		);
-		assert_eq!(
-			pool_events_since_last_call(),
-			vec![PoolsEvent::Unbonded { member: 10, pool_id: 1, points: 50, balance: 50, era: 6 }]
-		);
-
-		// waiting another bonding duration:
-		CurrentEra::<Runtime>::set(Some(BondingDuration::get() * 2));
-		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 1));
-
-		// pools is fully destroyed now.
-		assert_eq!(
-			staking_events_since_last_call(),
-			vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 50 },]
-		);
-		assert_eq!(
-			pool_events_since_last_call(),
-			vec![
-				PoolsEvent::Withdrawn { member: 10, pool_id: 1, points: 50, balance: 50 },
-				PoolsEvent::MemberRemoved { pool_id: 1, member: 10 },
-				PoolsEvent::Destroyed { pool_id: 1 }
-			]
-		);
-	})
-}
-
 #[test]
 fn pool_slash_e2e() {
 	new_test_ext().execute_with(|| {
diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs
index 751baedc7557e..ce97e13d640b6 100644
--- a/substrate/frame/nomination-pools/test-staking/src/mock.rs
+++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs
@@ -88,8 +88,8 @@ impl pallet_balances::Config for Runtime {
 	type WeightInfo = ();
 	type FreezeIdentifier = RuntimeFreezeReason;
 	type MaxFreezes = ConstU32<1>;
-	type RuntimeHoldReason = RuntimeHoldReason;
-	type RuntimeFreezeReason = RuntimeFreezeReason;
+	type RuntimeHoldReason = ();
+	type RuntimeFreezeReason = ();
 }
 
 pallet_staking_reward_curve::build! {
@@ -111,7 +111,6 @@ parameter_types! {
 impl pallet_staking::Config for Runtime {
 	type Currency = Balances;
 	type CurrencyBalance = Balance;
-	type DelegationSupport = DelegatedStaking;
 	type UnixTime = pallet_timestamp::Pallet<Self>;
 	type CurrencyToVote = ();
 	type RewardRemainder = ();
@@ -168,14 +167,6 @@ impl Convert<sp_core::U256, Balance> for U256ToBalance {
 	}
 }
 
-impl pallet_delegated_staking::Config for Runtime {
-	type RuntimeEvent = RuntimeEvent;
-	type Currency = Balances;
-	type OnSlash = ();
-	type RuntimeHoldReason = RuntimeHoldReason;
-	type CoreStaking = Staking;
-}
-
 parameter_types! {
 	pub const PostUnbondingPoolsWindow: u32 = 10;
 	pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls");
@@ -189,7 +180,7 @@ impl pallet_nomination_pools::Config for Runtime {
 	type RewardCounter = FixedU128;
 	type BalanceToU256 = BalanceToU256;
 	type U256ToBalance = U256ToBalance;
-	type Staking = DelegatedStaking;
+	type Staking = Staking;
 	type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow;
 	type MaxMetadataLen = ConstU32<256>;
 	type MaxUnbonding = ConstU32<8>;
@@ -200,14 +191,13 @@ impl pallet_nomination_pools::Config for Runtime {
 type Block = frame_system::mocking::MockBlock<Runtime>;
 
 frame_support::construct_runtime!(
-pub enum Runtime {
+	pub enum Runtime {
 		System: frame_system,
 		Timestamp: pallet_timestamp,
 		Balances: pallet_balances,
 		Staking: pallet_staking,
 		VoterList: pallet_bags_list::<Instance1>,
 		Pools: pallet_nomination_pools,
-		DelegatedStaking: pallet_delegated_staking::{Pallet, Storage, Event<T>, HoldReason},
 	}
 );
 

From bdc3b12d7f8903d48d71121c693924ace4277ec5 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 18 Feb 2024 21:19:48 +0100
Subject: [PATCH 106/202] fix np tests

---
 Cargo.lock                                             |  2 --
 substrate/frame/delegated-staking/src/impls.rs         | 10 ----------
 substrate/frame/nomination-pools/src/mock.rs           |  8 ++++++++
 .../frame/nomination-pools/test-staking/src/mock.rs    |  1 +
 substrate/frame/staking/src/pallet/impls.rs            | 10 ----------
 substrate/primitives/staking/src/lib.rs                |  9 ---------
 6 files changed, 9 insertions(+), 31 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 778c0ba3b11af..09a70664d1fd2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -10372,7 +10372,6 @@ dependencies = [
  "frame-system",
  "pallet-bags-list",
  "pallet-balances",
- "pallet-delegated-staking",
  "pallet-nomination-pools",
  "pallet-staking",
  "pallet-staking-reward-curve",
@@ -10422,7 +10421,6 @@ dependencies = [
  "log",
  "pallet-bags-list",
  "pallet-balances",
- "pallet-delegated-staking",
  "pallet-nomination-pools",
  "pallet-staking",
  "pallet-staking-reward-curve",
diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index c7ef966ce43e9..f8cc15f597d75 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -133,16 +133,6 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		Err(Error::<T>::NotSupported.into())
 	}
 
-	/// Not supported, call [`DelegationInterface::delegate_withdraw`]
-	fn withdraw_exact(
-		_stash: &Self::AccountId,
-		_amount: Self::Balance,
-		_num_slashing_spans: u32,
-	) -> Result<bool, DispatchError> {
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
-		Err(Error::<T>::NotSupported.into())
-	}
-
 	fn desired_validator_count() -> u32 {
 		defensive_assert!(false, "not supported for delegated impl of staking interface");
 		T::CoreStaking::desired_validator_count()
diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs
index f982b72c63564..8110b4e7fd06b 100644
--- a/substrate/frame/nomination-pools/src/mock.rs
+++ b/substrate/frame/nomination-pools/src/mock.rs
@@ -220,6 +220,14 @@ impl sp_staking::StakingInterface for StakingMock {
 	fn max_exposure_page_size() -> sp_staking::Page {
 		unimplemented!("method currently not used in testing")
 	}
+
+	fn slash_reward_fraction() -> Perbill {
+		unimplemented!("method currently not used in testing")
+	}
+
+	fn release_all(_who: &Self::AccountId) {
+		unimplemented!("method currently not used in testing")
+	}
 }
 
 #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs
index ce97e13d640b6..87ce77f9733a6 100644
--- a/substrate/frame/nomination-pools/test-staking/src/mock.rs
+++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs
@@ -111,6 +111,7 @@ parameter_types! {
 impl pallet_staking::Config for Runtime {
 	type Currency = Balances;
 	type CurrencyBalance = Balance;
+	type DelegationSupport = pallet_staking::NoDelegation<Self>;
 	type UnixTime = pallet_timestamp::Pallet<Self>;
 	type CurrencyToVote = ();
 	type RewardRemainder = ();
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 242ccd0bd605f..08ab7c81afb13 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1769,16 +1769,6 @@ impl<T: Config> StakingInterface for Pallet<T> {
 			.map_err(|with_post| with_post.error)
 	}
 
-	fn withdraw_exact(
-		who: &Self::AccountId,
-		amount: BalanceOf<T>,
-		num_slashing_spans: u32,
-	) -> Result<bool, DispatchError> {
-		let ctrl = Self::bonded(who).ok_or(Error::<T>::NotStash)?;
-		Self::do_withdraw_unbonded(&ctrl, num_slashing_spans, Some(amount))
-			.map(|_| !Ledger::<T>::contains_key(&ctrl))
-	}
-
 	fn bond(
 		who: &Self::AccountId,
 		value: Self::Balance,
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 4819ea583a27d..46825775fd625 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -251,15 +251,6 @@ pub trait StakingInterface {
 		num_slashing_spans: u32,
 	) -> Result<bool, DispatchError>;
 
-	/// Unlock any funds schedule to unlock before or at the current era upto a provided limit.
-	///
-	/// Returns whether the stash was killed because of this withdraw or not.
-	fn withdraw_exact(
-		stash: &Self::AccountId,
-		amount: Self::Balance,
-		num_slashing_spans: u32,
-	) -> Result<bool, DispatchError>;
-
 	/// The ideal number of active validators.
 	fn desired_validator_count() -> u32;
 

From 949c5d512728be1bbba940714777e1a9cf016e13 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 18 Feb 2024 21:25:38 +0100
Subject: [PATCH 107/202] refactor test

---
 substrate/frame/delegated-staking/src/mock.rs | 14 +++-------
 .../frame/delegated-staking/src/tests.rs      | 26 +++++++++----------
 2 files changed, 17 insertions(+), 23 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index c3a98e82354ff..e001444b5fce0 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -288,17 +288,11 @@ pub(crate) fn eq_stake(who: AccountId, total: Balance, active: Balance) -> bool
 	Staking::stake(&who).unwrap() == Stake { total, active }
 }
 
-pub(crate) fn delegate_available_to_bond(delegate: &AccountId) -> Balance {
-	let delegate = Delegate::<T>::from(delegate).expect("delegate should exist");
-	delegate.available_to_bond()
-}
-
-pub(crate) fn delegate_effective_balance(delegate: &AccountId) -> Balance {
-	let delegate = Delegate::<T>::from(delegate).expect("delegate should exist");
-	delegate.ledger.effective_balance()
-}
-
 pub(crate) fn delegate_bonded(delegate: &AccountId) -> bool {
 	let delegate = Delegate::<T>::from(delegate).expect("delegate should exist");
 	delegate.is_bonded()
 }
+
+pub(crate) fn get_delegate(delegate: &AccountId) -> Delegate<T> {
+	Delegate::<T>::from(delegate).expect("delegate should exist")
+}
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 535ddf619a031..69264bfec036b 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -241,15 +241,15 @@ mod integration {
 				assert_eq!(DelegatedStaking::stakeable_balance(&delegate), delegated_balance);
 
 				// unbonded balance is the newly delegated 100
-				assert_eq!(delegate_available_to_bond(&delegate), 100);
-				if delegate_bonded(&delegate) {
+				assert_eq!(get_delegate(&delegate).available_to_bond(), 100);
+				if get_delegate(&delegate).is_bonded() {
 					assert_ok!(DelegatedStaking::bond_extra(&delegate, 100));
 				} else {
 					assert_ok!(DelegatedStaking::bond(&delegate, 100, &reward_acc));
 				}
 
 				// after bond, unbonded balance is 0
-				assert_eq!(delegate_available_to_bond(&delegate), 0);
+				assert_eq!(get_delegate(&delegate).available_to_bond(), 0);
 			}
 
 			assert_eq!(
@@ -303,9 +303,9 @@ mod integration {
 			);
 
 			assert!(eq_stake(delegate, total_staked, expected_active));
-			assert_eq!(delegate_available_to_bond(&delegate), 0);
+			assert_eq!(get_delegate(&delegate).available_to_bond(), 0);
 			// full amount is still delegated
-			assert_eq!(delegate_effective_balance(&delegate), total_staked);
+			assert_eq!(get_delegate(&delegate).ledger.effective_balance(), total_staked);
 
 			start_era(5);
 			// at era 5, 50 tokens are withdrawable, cannot withdraw more.
@@ -374,11 +374,11 @@ mod integration {
 			// 100));
 			//
 			// // verify unbonded balance
-			// assert_eq!(delegate_available_to_bond(&delegate), 100);
+			// assert_eq!(get_delegate(&delegate).available_to_bond(), 100);
 			//
 			// // withdraw works now without unbonding
 			// assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 300, 100,
-			// 0)); assert_eq!(delegate_available_to_bond(&delegate), 0);
+			// 0)); assert_eq!(get_delegate(&delegate).available_to_bond(), 0);
 		});
 	}
 
@@ -420,8 +420,8 @@ mod integration {
 			));
 			// amount is staked correctly
 			assert!(eq_stake(200, 100, 100));
-			assert_eq!(delegate_available_to_bond(&200), 0);
-			assert_eq!(delegate_effective_balance(&200), 100);
+			assert_eq!(get_delegate(&200).available_to_bond(), 0);
+			assert_eq!(get_delegate(&200).ledger.effective_balance(), 100);
 
 			// free balance of delegate is untouched
 			assert_eq!(Balances::free_balance(200), balance_200);
@@ -547,8 +547,8 @@ mod integration {
 				5000 - staked_amount - ExistentialDeposit::get()
 			);
 			assert_eq!(DelegatedStaking::stake(&200).unwrap(), init_stake);
-			assert_eq!(delegate_effective_balance(&200), 4000);
-			assert_eq!(delegate_available_to_bond(&200), 0);
+			assert_eq!(get_delegate(&200).ledger.effective_balance(), 4000);
+			assert_eq!(get_delegate(&200).available_to_bond(), 0);
 
 			// now lets migrate the delegators
 			let delegator_share = staked_amount / 4;
@@ -574,8 +574,8 @@ mod integration {
 
 				// delegate stake is unchanged.
 				assert_eq!(DelegatedStaking::stake(&200).unwrap(), init_stake);
-				assert_eq!(delegate_effective_balance(&200), 4000);
-				assert_eq!(delegate_available_to_bond(&200), 0);
+				assert_eq!(get_delegate(&200).ledger.effective_balance(), 4000);
+				assert_eq!(get_delegate(&200).available_to_bond(), 0);
 			}
 
 			// cannot use migrate delegator anymore

From f31cee29bc5a0cddde3f14c162137a9b468d9247 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 18 Feb 2024 22:25:43 +0100
Subject: [PATCH 108/202] create np direct stake adapter

---
 .../frame/delegated-staking/src/impls.rs      |  4 +-
 substrate/frame/delegated-staking/src/lib.rs  |  1 +
 .../frame/nomination-pools/src/adapter.rs     | 81 +++++++++++++++++++
 substrate/frame/nomination-pools/src/lib.rs   | 20 +++--
 substrate/frame/nomination-pools/src/mock.rs  |  1 +
 5 files changed, 97 insertions(+), 10 deletions(-)
 create mode 100644 substrate/frame/nomination-pools/src/adapter.rs

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index f8cc15f597d75..5db6bbb333ee9 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -16,8 +16,7 @@
 // You should have received a copy of the GNU General Public License
 // along with this program. If not, see <https://www.gnu.org/licenses/>.
 
-//! Implementations of public traits, namely [StakingInterface], [DelegationInterface] and
-//! [StakingDelegationSupport].
+//! Implementations of public traits, namely [StakingInterface], and [StakingDelegationSupport].
 
 use super::*;
 
@@ -124,6 +123,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	/// Not supported, call [`DelegationInterface::delegate_withdraw`]
+	/// FIXME(ank4n): Support it!!
 	fn withdraw_unbonded(
 		_stash: Self::AccountId,
 		_num_slashing_spans: u32,
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index c97369db6359a..5527187f20ad1 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -18,6 +18,7 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 #![deny(rustdoc::broken_intra_doc_links)]
 
+// FIXME(ank4n): fix docs
 //! An implementation of a delegation system for staking that can be utilised using
 //! [`DelegationInterface`]. In future, if exposed via extrinsic, these primitives could also be
 //! used by off-chain entities, or by foreign multi-locations (via xcm).
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
new file mode 100644
index 0000000000000..1fa02379496ba
--- /dev/null
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -0,0 +1,81 @@
+// This file is part of Substrate.
+
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use crate::*;
+use frame_support::traits::tokens::Balance;
+
+/// Pool adapter trait that can support multiple modes of staking: i.e. Delegated or Direct.
+pub trait PoolAdapter {
+    type Balance: Balance;
+    type AccountId: Clone + Debug;
+
+    /// Similar to [Inspect::balance].
+    fn balance(who: &Self::AccountId) -> Self::Balance;
+
+    /// Similar to [Inspect::total_balance].
+    fn total_balance(who: &Self::AccountId) -> Self::Balance;
+
+    /// Delegates stake from delegator to pool account.
+    ///
+    /// Similar to [Mutate::transfer] for Direct Stake.
+    fn delegate(who: &Self::AccountId, pool_account: &Self::AccountId, amount: Self::Balance, preservation: Preservation) -> DispatchResult;
+
+    /// Revoke delegation to pool account.
+    ///
+    /// Similar to [Mutate::transfer] for Direct Stake but in reverse direction to [Self::delegate].
+    fn release_delegation(who: &Self::AccountId, pool_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult;
+
+}
+
+
+/// Pool adapter that supports DirectStake.
+pub struct DirectStake<T: Config>(PhantomData<T>);
+
+impl<T: Config> PoolAdapter for DirectStake<T> {
+    type Balance = BalanceOf<T>;
+    type AccountId = T::AccountId;
+
+    fn balance(who: &Self::AccountId) -> Self::Balance {
+        T::Currency::balance(who)
+    }
+
+    fn total_balance(who: &Self::AccountId) -> Self::Balance {
+        T::Currency::total_balance(who)
+    }
+
+    fn delegate(who: &Self::AccountId, pool_account: &Self::AccountId, amount: Self::Balance, preservation: Preservation) -> DispatchResult {
+        T::Currency::transfer(
+            who,
+            &pool_account,
+            amount,
+            preservation,
+        )?;
+
+        Ok(())
+    }
+
+    fn release_delegation(who: &Self::AccountId, pool_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+        T::Currency::transfer(
+            &pool_account,
+            &who,
+            amount,
+            Preservation::Expendable,
+        )?;
+
+        Ok(())
+    }
+}
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index 2777e7b6052e6..b8848dea969d7 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -378,6 +378,7 @@ use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, ops::Div, vec::Vec};
 
 #[cfg(any(feature = "try-runtime", feature = "fuzzing", test, debug_assertions))]
 use sp_runtime::TryRuntimeError;
+use adapter::PoolAdapter;
 
 /// The log target of this pallet.
 pub const LOG_TARGET: &str = "runtime::nomination-pools";
@@ -399,6 +400,7 @@ mod tests;
 
 pub mod migration;
 pub mod weights;
+mod adapter;
 
 pub use pallet::*;
 pub use weights::WeightInfo;
@@ -1056,7 +1058,7 @@ impl<T: Config> BondedPool<T> {
 		// `pallet-nomination-pool`. This means reducible balance always returns balance preserving
 		// ED in the account. What we want though is transferable balance given the account can be
 		// dusted.
-		T::Currency::balance(&account)
+		T::PoolAdapter::balance(&account)
 			.saturating_sub(T::Staking::active_stake(&account).unwrap_or_default())
 	}
 
@@ -1256,7 +1258,7 @@ impl<T: Config> BondedPool<T> {
 		// Cache the value
 		let bonded_account = self.bonded_account();
 		// TODO(ank4n) joining a pool: delegate funds to pool account..
-		T::Currency::transfer(
+		T::PoolAdapter::delegate(
 			who,
 			&bonded_account,
 			amount,
@@ -1655,6 +1657,9 @@ pub mod pallet {
 
 		/// The maximum length, in bytes, that a pools metadata maybe.
 		type MaxMetadataLen: Get<u32>;
+
+		/// An adapter to support delegated to direct staking.
+		type PoolAdapter: PoolAdapter<AccountId = Self::AccountId, Balance = BalanceOf<Self>>;
 	}
 
 	/// The sum of funds across all pools.
@@ -2292,12 +2297,10 @@ pub mod pallet {
 				// order to ensure members can leave the pool and it can be destroyed.
 				.min(bonded_pool.transferable_balance());
 
-			// fixme(ank4n): Fix for delegated
-			T::Currency::transfer(
-				&bonded_pool.bonded_account(),
+			T::PoolAdapter::release_delegation(
 				&member_account,
+				&bonded_pool.bonded_account(),
 				balance_to_unbond,
-				Preservation::Expendable,
 			)
 			.defensive()?;
 
@@ -2879,11 +2882,12 @@ impl<T: Config> Pallet<T> {
 			"could not transfer all amount to depositor while dissolving pool"
 		);
 		defensive_assert!(
-			T::Currency::total_balance(&bonded_pool.bonded_account()) == Zero::zero(),
+			T::PoolAdapter::total_balance(&bonded_pool.bonded_account()) == Zero::zero(),
 			"dissolving pool should not have any balance"
 		);
 		// NOTE: Defensively force set balance to zero.
 		T::Currency::set_balance(&reward_account, Zero::zero());
+		// fixme(ank4n): Can't do this with delegated?
 		T::Currency::set_balance(&bonded_pool.bonded_account(), Zero::zero());
 
 		Self::deposit_event(Event::<T>::Destroyed { pool_id: bonded_pool.id });
@@ -3460,7 +3464,7 @@ impl<T: Config> Pallet<T> {
 
 			let sum_unbonding_balance = subs.sum_unbonding_balance();
 			let bonded_balance = T::Staking::active_stake(&pool_account).unwrap_or_default();
-			let total_balance = T::Currency::total_balance(&pool_account);
+			let total_balance = T::PoolAdapter::total_balance(&pool_account);
 
 			assert!(
 				total_balance >= bonded_balance + sum_unbonding_balance,
diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs
index 8110b4e7fd06b..b60f4a26b3aca 100644
--- a/substrate/frame/nomination-pools/src/mock.rs
+++ b/substrate/frame/nomination-pools/src/mock.rs
@@ -311,6 +311,7 @@ impl pools::Config for Runtime {
 	type MaxMetadataLen = MaxMetadataLen;
 	type MaxUnbonding = MaxUnbonding;
 	type MaxPointsToBalance = frame_support::traits::ConstU8<10>;
+	type PoolAdapter = adapter::DirectStake<Self>;
 }
 
 type Block = frame_system::mocking::MockBlock<Runtime>;

From 141004f302c890893913124ce0e9be09c9a786ef Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Mon, 19 Feb 2024 09:29:51 +0100
Subject: [PATCH 109/202] all test pass

---
 .../frame/nomination-pools/src/adapter.rs     | 41 ++++++---------
 substrate/frame/nomination-pools/src/lib.rs   | 26 ++++------
 .../nomination-pools/test-staking/src/mock.rs |  1 +
 .../primitives/staking/src/delegation.rs      | 50 +++++++++++++++++++
 4 files changed, 75 insertions(+), 43 deletions(-)

diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index 1fa02379496ba..335a238500675 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -18,34 +18,10 @@
 use crate::*;
 use frame_support::traits::tokens::Balance;
 
-/// Pool adapter trait that can support multiple modes of staking: i.e. Delegated or Direct.
-pub trait PoolAdapter {
-    type Balance: Balance;
-    type AccountId: Clone + Debug;
-
-    /// Similar to [Inspect::balance].
-    fn balance(who: &Self::AccountId) -> Self::Balance;
-
-    /// Similar to [Inspect::total_balance].
-    fn total_balance(who: &Self::AccountId) -> Self::Balance;
-
-    /// Delegates stake from delegator to pool account.
-    ///
-    /// Similar to [Mutate::transfer] for Direct Stake.
-    fn delegate(who: &Self::AccountId, pool_account: &Self::AccountId, amount: Self::Balance, preservation: Preservation) -> DispatchResult;
-
-    /// Revoke delegation to pool account.
-    ///
-    /// Similar to [Mutate::transfer] for Direct Stake but in reverse direction to [Self::delegate].
-    fn release_delegation(who: &Self::AccountId, pool_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult;
-
-}
-
-
 /// Pool adapter that supports DirectStake.
 pub struct DirectStake<T: Config>(PhantomData<T>);
 
-impl<T: Config> PoolAdapter for DirectStake<T> {
+impl<T: Config> sp_staking::delegation::PoolAdapter for DirectStake<T> {
     type Balance = BalanceOf<T>;
     type AccountId = T::AccountId;
 
@@ -57,12 +33,23 @@ impl<T: Config> PoolAdapter for DirectStake<T> {
         T::Currency::total_balance(who)
     }
 
-    fn delegate(who: &Self::AccountId, pool_account: &Self::AccountId, amount: Self::Balance, preservation: Preservation) -> DispatchResult {
+    fn delegate(who: &Self::AccountId, pool_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+        T::Currency::transfer(
+            who,
+            &pool_account,
+            amount,
+            Preservation::Expendable,
+        )?;
+
+        Ok(())
+    }
+
+    fn delegate_extra(who: &Self::AccountId, pool_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
         T::Currency::transfer(
             who,
             &pool_account,
             amount,
-            preservation,
+            Preservation::Preserve,
         )?;
 
         Ok(())
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index b8848dea969d7..4566494dfb565 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -373,12 +373,11 @@ use sp_runtime::{
 	},
 	FixedPointNumber, Perbill,
 };
-use sp_staking::{EraIndex, StakingInterface};
+use sp_staking::{EraIndex, StakingInterface, delegation::PoolAdapter};
 use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, ops::Div, vec::Vec};
 
 #[cfg(any(feature = "try-runtime", feature = "fuzzing", test, debug_assertions))]
 use sp_runtime::TryRuntimeError;
-use adapter::PoolAdapter;
 
 /// The log target of this pallet.
 pub const LOG_TARGET: &str = "runtime::nomination-pools";
@@ -400,7 +399,7 @@ mod tests;
 
 pub mod migration;
 pub mod weights;
-mod adapter;
+pub mod adapter;
 
 pub use pallet::*;
 pub use weights::WeightInfo;
@@ -1257,27 +1256,22 @@ impl<T: Config> BondedPool<T> {
 	) -> Result<BalanceOf<T>, DispatchError> {
 		// Cache the value
 		let bonded_account = self.bonded_account();
-		// TODO(ank4n) joining a pool: delegate funds to pool account..
-		T::PoolAdapter::delegate(
-			who,
-			&bonded_account,
-			amount,
-			match ty {
-				BondType::Create => Preservation::Expendable,
-				BondType::Later => Preservation::Preserve,
-			},
-		)?;
+
 		// We must calculate the points issued *before* we bond who's funds, else points:balance
 		// ratio will be wrong.
 		let points_issued = self.issue(amount);
 
 		match ty {
-			// TODO(ank4n): When type create, also do accept delegation call..
-			BondType::Create => T::Staking::bond(&bonded_account, amount, &self.reward_account())?,
+			BondType::Create => {
+				T::PoolAdapter::delegate(who, &bonded_account, amount)?;
+				T::Staking::bond(&bonded_account, amount, &self.reward_account())?
+			},
 			// The pool should always be created in such a way its in a state to bond extra, but if
 			// the active balance is slashed below the minimum bonded or the account cannot be
 			// found, we exit early.
-			BondType::Later => T::Staking::bond_extra(&bonded_account, amount)?,
+			BondType::Later => {
+				T::PoolAdapter::delegate_extra(who, &bonded_account, amount)?;
+				T::Staking::bond_extra(&bonded_account, amount)? },
 		}
 		TotalValueLocked::<T>::mutate(|tvl| {
 			tvl.saturating_accrue(amount);
diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs
index 87ce77f9733a6..6b327ba5bb27d 100644
--- a/substrate/frame/nomination-pools/test-staking/src/mock.rs
+++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs
@@ -187,6 +187,7 @@ impl pallet_nomination_pools::Config for Runtime {
 	type MaxUnbonding = ConstU32<8>;
 	type MaxPointsToBalance = ConstU8<10>;
 	type PalletId = PoolsPalletId;
+	type PoolAdapter = pallet_nomination_pools::adapter::DirectStake<Self>;
 }
 
 type Block = frame_system::mocking::MockBlock<Runtime>;
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index af8cca9bb091a..75d6d728a5128 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -158,3 +158,53 @@ pub trait StakingDelegationSupport {
 	/// Reports an ongoing slash to the `delegate` account that would be applied lazily.
 	fn report_slash(who: &Self::AccountId, slash: Self::Balance);
 }
+
+/// Pool adapter trait that can support multiple modes of staking: i.e. Delegated or Direct.
+pub trait PoolAdapter {
+	type Balance: Sub<Output = Self::Balance>
+		+ Ord
+		+ PartialEq
+		+ Default
+		+ Copy
+		+ MaxEncodedLen
+		+ FullCodec
+		+ TypeInfo
+		+ Saturating;
+	type AccountId: Clone + sp_std::fmt::Debug;
+
+	/// Similar to [Inspect::balance].
+	fn balance(who: &Self::AccountId) -> Self::Balance;
+
+	/// Similar to [Inspect::total_balance].
+	fn total_balance(who: &Self::AccountId) -> Self::Balance;
+
+	/// Start delegation to the pool account.
+	///
+	/// Similar to [Mutate::transfer] for Direct Stake.
+	fn delegate(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
+
+	/// Add more delegation to the pool account.
+	///
+	/// Similar to [Mutate::transfer] for Direct Stake.
+	///
+	/// We need this along with [Self::delegate] as NominationPool has a slight different behaviour
+	/// for the first delegation and the subsequent ones.
+	fn delegate_extra(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
+
+	/// Revoke delegation to pool account.
+	///
+	/// Similar to [Mutate::transfer] for Direct Stake but in reverse direction to [Self::delegate].
+	fn release_delegation(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
+}

From 13b4a8262e7ca0e381782f615884689fbc5908f5 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Mon, 19 Feb 2024 09:39:53 +0100
Subject: [PATCH 110/202] rename DirectStake to NoDelegation to keep its name
 similar to Staking support impl

---
 .../frame/delegated-staking/src/impls.rs      | 26 +++++++
 .../frame/nomination-pools/src/adapter.rs     | 77 +++++++++----------
 substrate/frame/nomination-pools/src/mock.rs  |  2 +-
 .../nomination-pools/test-staking/src/mock.rs |  2 +-
 4 files changed, 66 insertions(+), 41 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 5db6bbb333ee9..b779c7bf96a79 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -18,6 +18,7 @@
 
 //! Implementations of public traits, namely [StakingInterface], and [StakingDelegationSupport].
 
+use sp_staking::delegation::PoolAdapter;
 use super::*;
 
 /// StakingInterface implementation with delegation support.
@@ -280,3 +281,28 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 		});
 	}
 }
+
+impl<T: Config> PoolAdapter for Pallet<T> {
+	type Balance = BalanceOf<T>;
+	type AccountId = T::AccountId;
+
+	fn balance(who: &Self::AccountId) -> Self::Balance {
+		todo!()
+	}
+
+	fn total_balance(who: &Self::AccountId) -> Self::Balance {
+		todo!()
+	}
+
+	fn delegate(who: &Self::AccountId, pool_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+		todo!()
+	}
+
+	fn delegate_extra(who: &Self::AccountId, pool_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+		todo!()
+	}
+
+	fn release_delegation(who: &Self::AccountId, pool_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+		todo!()
+	}
+}
\ No newline at end of file
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index 335a238500675..7562b11ff2588 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -16,53 +16,52 @@
 // limitations under the License.
 
 use crate::*;
-use frame_support::traits::tokens::Balance;
 
-/// Pool adapter that supports DirectStake.
-pub struct DirectStake<T: Config>(PhantomData<T>);
+/// Basic pool adapter that only supports Direct Staking.
+///
+/// When delegating, tokens are moved between the delegator and pool account as opposed to holding
+/// tokens in delegator's accounts.
+pub struct NoDelegation<T: Config>(PhantomData<T>);
 
-impl<T: Config> sp_staking::delegation::PoolAdapter for DirectStake<T> {
-    type Balance = BalanceOf<T>;
-    type AccountId = T::AccountId;
+impl<T: Config> PoolAdapter for NoDelegation<T> {
+	type Balance = BalanceOf<T>;
+	type AccountId = T::AccountId;
 
-    fn balance(who: &Self::AccountId) -> Self::Balance {
-        T::Currency::balance(who)
-    }
+	fn balance(who: &Self::AccountId) -> Self::Balance {
+		T::Currency::balance(who)
+	}
 
-    fn total_balance(who: &Self::AccountId) -> Self::Balance {
-        T::Currency::total_balance(who)
-    }
+	fn total_balance(who: &Self::AccountId) -> Self::Balance {
+		T::Currency::total_balance(who)
+	}
 
-    fn delegate(who: &Self::AccountId, pool_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
-        T::Currency::transfer(
-            who,
-            &pool_account,
-            amount,
-            Preservation::Expendable,
-        )?;
+	fn delegate(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
+		T::Currency::transfer(who, &pool_account, amount, Preservation::Expendable)?;
 
-        Ok(())
-    }
+		Ok(())
+	}
 
-    fn delegate_extra(who: &Self::AccountId, pool_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
-        T::Currency::transfer(
-            who,
-            &pool_account,
-            amount,
-            Preservation::Preserve,
-        )?;
+	fn delegate_extra(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
+		T::Currency::transfer(who, &pool_account, amount, Preservation::Preserve)?;
 
-        Ok(())
-    }
+		Ok(())
+	}
 
-    fn release_delegation(who: &Self::AccountId, pool_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
-        T::Currency::transfer(
-            &pool_account,
-            &who,
-            amount,
-            Preservation::Expendable,
-        )?;
+	fn release_delegation(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
+		T::Currency::transfer(&pool_account, &who, amount, Preservation::Expendable)?;
 
-        Ok(())
-    }
+		Ok(())
+	}
 }
diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs
index b60f4a26b3aca..85b8c3b644055 100644
--- a/substrate/frame/nomination-pools/src/mock.rs
+++ b/substrate/frame/nomination-pools/src/mock.rs
@@ -311,7 +311,7 @@ impl pools::Config for Runtime {
 	type MaxMetadataLen = MaxMetadataLen;
 	type MaxUnbonding = MaxUnbonding;
 	type MaxPointsToBalance = frame_support::traits::ConstU8<10>;
-	type PoolAdapter = adapter::DirectStake<Self>;
+	type PoolAdapter = adapter::NoDelegation<Self>;
 }
 
 type Block = frame_system::mocking::MockBlock<Runtime>;
diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs
index 6b327ba5bb27d..60b782d5b9ac2 100644
--- a/substrate/frame/nomination-pools/test-staking/src/mock.rs
+++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs
@@ -187,7 +187,7 @@ impl pallet_nomination_pools::Config for Runtime {
 	type MaxUnbonding = ConstU32<8>;
 	type MaxPointsToBalance = ConstU8<10>;
 	type PalletId = PoolsPalletId;
-	type PoolAdapter = pallet_nomination_pools::adapter::DirectStake<Self>;
+	type PoolAdapter = pallet_nomination_pools::adapter::NoDelegation<Self>;
 }
 
 type Block = frame_system::mocking::MockBlock<Runtime>;

From bed9c4cafc54a3cbe1d3acf59c80dd2197cb1a2f Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Mon, 19 Feb 2024 09:40:15 +0100
Subject: [PATCH 111/202] fmt

---
 .../frame/delegated-staking/src/impls.rs      | 22 ++++++++++++++-----
 substrate/frame/delegated-staking/src/lib.rs  |  1 -
 substrate/frame/nomination-pools/src/lib.rs   |  7 +++---
 3 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index b779c7bf96a79..34dbce708aa17 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -18,8 +18,8 @@
 
 //! Implementations of public traits, namely [StakingInterface], and [StakingDelegationSupport].
 
-use sp_staking::delegation::PoolAdapter;
 use super::*;
+use sp_staking::delegation::PoolAdapter;
 
 /// StakingInterface implementation with delegation support.
 ///
@@ -294,15 +294,27 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 		todo!()
 	}
 
-	fn delegate(who: &Self::AccountId, pool_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+	fn delegate(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
 		todo!()
 	}
 
-	fn delegate_extra(who: &Self::AccountId, pool_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+	fn delegate_extra(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
 		todo!()
 	}
 
-	fn release_delegation(who: &Self::AccountId, pool_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+	fn release_delegation(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
 		todo!()
 	}
-}
\ No newline at end of file
+}
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 5527187f20ad1..d0bdd67384e29 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -17,7 +17,6 @@
 
 #![cfg_attr(not(feature = "std"), no_std)]
 #![deny(rustdoc::broken_intra_doc_links)]
-
 // FIXME(ank4n): fix docs
 //! An implementation of a delegation system for staking that can be utilised using
 //! [`DelegationInterface`]. In future, if exposed via extrinsic, these primitives could also be
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index 4566494dfb565..d021961bced39 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -373,7 +373,7 @@ use sp_runtime::{
 	},
 	FixedPointNumber, Perbill,
 };
-use sp_staking::{EraIndex, StakingInterface, delegation::PoolAdapter};
+use sp_staking::{delegation::PoolAdapter, EraIndex, StakingInterface};
 use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, ops::Div, vec::Vec};
 
 #[cfg(any(feature = "try-runtime", feature = "fuzzing", test, debug_assertions))]
@@ -397,9 +397,9 @@ pub mod mock;
 #[cfg(test)]
 mod tests;
 
+pub mod adapter;
 pub mod migration;
 pub mod weights;
-pub mod adapter;
 
 pub use pallet::*;
 pub use weights::WeightInfo;
@@ -1271,7 +1271,8 @@ impl<T: Config> BondedPool<T> {
 			// found, we exit early.
 			BondType::Later => {
 				T::PoolAdapter::delegate_extra(who, &bonded_account, amount)?;
-				T::Staking::bond_extra(&bonded_account, amount)? },
+				T::Staking::bond_extra(&bonded_account, amount)?
+			},
 		}
 		TotalValueLocked::<T>::mutate(|tvl| {
 			tvl.saturating_accrue(amount);

From 54acfb71faf5ab80bdf46e97791d4f50a15423dc Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Mon, 19 Feb 2024 11:05:31 +0100
Subject: [PATCH 112/202] move adapter logic local to pool

---
 .../frame/delegated-staking/src/impls.rs      | 38 ---------
 .../frame/nomination-pools/src/adapter.rs     | 82 ++++++++++++++++++-
 substrate/frame/nomination-pools/src/lib.rs   | 18 ++--
 substrate/frame/nomination-pools/src/mock.rs  |  2 +-
 .../nomination-pools/test-staking/src/mock.rs |  2 +-
 .../primitives/staking/src/delegation.rs      | 50 -----------
 6 files changed, 93 insertions(+), 99 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 34dbce708aa17..5db6bbb333ee9 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -19,7 +19,6 @@
 //! Implementations of public traits, namely [StakingInterface], and [StakingDelegationSupport].
 
 use super::*;
-use sp_staking::delegation::PoolAdapter;
 
 /// StakingInterface implementation with delegation support.
 ///
@@ -281,40 +280,3 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 		});
 	}
 }
-
-impl<T: Config> PoolAdapter for Pallet<T> {
-	type Balance = BalanceOf<T>;
-	type AccountId = T::AccountId;
-
-	fn balance(who: &Self::AccountId) -> Self::Balance {
-		todo!()
-	}
-
-	fn total_balance(who: &Self::AccountId) -> Self::Balance {
-		todo!()
-	}
-
-	fn delegate(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult {
-		todo!()
-	}
-
-	fn delegate_extra(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult {
-		todo!()
-	}
-
-	fn release_delegation(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult {
-		todo!()
-	}
-}
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index 7562b11ff2588..b569573819ac1 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -16,6 +16,49 @@
 // limitations under the License.
 
 use crate::*;
+use frame_support::traits::tokens::Balance;
+
+/// Staking adapter trait that can support multiple modes of staking: i.e. Delegated or Direct.
+pub trait StakingAdapter {
+	type Balance: Balance;
+	type AccountId: Clone + Debug;
+
+	/// Similar to [Inspect::balance].
+	fn balance(who: &Self::AccountId) -> Self::Balance;
+
+	/// Similar to [Inspect::total_balance].
+	fn total_balance(who: &Self::AccountId) -> Self::Balance;
+
+	/// Start delegation to the pool account.
+	///
+	/// Similar to [Mutate::transfer] for Direct Stake.
+	fn delegate(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
+
+	/// Add more delegation to the pool account.
+	///
+	/// Similar to [Mutate::transfer] for Direct Stake.
+	///
+	/// We need this along with [Self::delegate] as NominationPool has a slight different behaviour
+	/// for the first delegation and the subsequent ones.
+	fn delegate_extra(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
+
+	/// Revoke delegation to pool account.
+	///
+	/// Similar to [Mutate::transfer] for Direct Stake but in reverse direction to [Self::delegate].
+	fn release_delegation(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
+}
 
 /// Basic pool adapter that only supports Direct Staking.
 ///
@@ -23,7 +66,7 @@ use crate::*;
 /// tokens in delegator's accounts.
 pub struct NoDelegation<T: Config>(PhantomData<T>);
 
-impl<T: Config> PoolAdapter for NoDelegation<T> {
+impl<T: Config> StakingAdapter for NoDelegation<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
@@ -65,3 +108,40 @@ impl<T: Config> PoolAdapter for NoDelegation<T> {
 		Ok(())
 	}
 }
+
+impl<T: Config> StakingAdapter for Pallet<T> {
+	type Balance = BalanceOf<T>;
+	type AccountId = T::AccountId;
+
+	fn balance(who: &Self::AccountId) -> Self::Balance {
+		todo!()
+	}
+
+	fn total_balance(who: &Self::AccountId) -> Self::Balance {
+		todo!()
+	}
+
+	fn delegate(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
+		todo!()
+	}
+
+	fn delegate_extra(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
+		todo!()
+	}
+
+	fn release_delegation(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
+		todo!()
+	}
+}
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index d021961bced39..3c823e3cdb568 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -373,7 +373,7 @@ use sp_runtime::{
 	},
 	FixedPointNumber, Perbill,
 };
-use sp_staking::{delegation::PoolAdapter, EraIndex, StakingInterface};
+use sp_staking::{EraIndex, StakingInterface};
 use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, ops::Div, vec::Vec};
 
 #[cfg(any(feature = "try-runtime", feature = "fuzzing", test, debug_assertions))]
@@ -398,6 +398,8 @@ pub mod mock;
 mod tests;
 
 pub mod adapter;
+use adapter::StakingAdapter;
+
 pub mod migration;
 pub mod weights;
 
@@ -1057,7 +1059,7 @@ impl<T: Config> BondedPool<T> {
 		// `pallet-nomination-pool`. This means reducible balance always returns balance preserving
 		// ED in the account. What we want though is transferable balance given the account can be
 		// dusted.
-		T::PoolAdapter::balance(&account)
+		T::StakingAdapter::balance(&account)
 			.saturating_sub(T::Staking::active_stake(&account).unwrap_or_default())
 	}
 
@@ -1263,14 +1265,14 @@ impl<T: Config> BondedPool<T> {
 
 		match ty {
 			BondType::Create => {
-				T::PoolAdapter::delegate(who, &bonded_account, amount)?;
+				T::StakingAdapter::delegate(who, &bonded_account, amount)?;
 				T::Staking::bond(&bonded_account, amount, &self.reward_account())?
 			},
 			// The pool should always be created in such a way its in a state to bond extra, but if
 			// the active balance is slashed below the minimum bonded or the account cannot be
 			// found, we exit early.
 			BondType::Later => {
-				T::PoolAdapter::delegate_extra(who, &bonded_account, amount)?;
+				T::StakingAdapter::delegate_extra(who, &bonded_account, amount)?;
 				T::Staking::bond_extra(&bonded_account, amount)?
 			},
 		}
@@ -1654,7 +1656,7 @@ pub mod pallet {
 		type MaxMetadataLen: Get<u32>;
 
 		/// An adapter to support delegated to direct staking.
-		type PoolAdapter: PoolAdapter<AccountId = Self::AccountId, Balance = BalanceOf<Self>>;
+		type StakingAdapter: StakingAdapter<AccountId = Self::AccountId, Balance = BalanceOf<Self>>;
 	}
 
 	/// The sum of funds across all pools.
@@ -2292,7 +2294,7 @@ pub mod pallet {
 				// order to ensure members can leave the pool and it can be destroyed.
 				.min(bonded_pool.transferable_balance());
 
-			T::PoolAdapter::release_delegation(
+			T::StakingAdapter::release_delegation(
 				&member_account,
 				&bonded_pool.bonded_account(),
 				balance_to_unbond,
@@ -2877,7 +2879,7 @@ impl<T: Config> Pallet<T> {
 			"could not transfer all amount to depositor while dissolving pool"
 		);
 		defensive_assert!(
-			T::PoolAdapter::total_balance(&bonded_pool.bonded_account()) == Zero::zero(),
+			T::StakingAdapter::total_balance(&bonded_pool.bonded_account()) == Zero::zero(),
 			"dissolving pool should not have any balance"
 		);
 		// NOTE: Defensively force set balance to zero.
@@ -3459,7 +3461,7 @@ impl<T: Config> Pallet<T> {
 
 			let sum_unbonding_balance = subs.sum_unbonding_balance();
 			let bonded_balance = T::Staking::active_stake(&pool_account).unwrap_or_default();
-			let total_balance = T::PoolAdapter::total_balance(&pool_account);
+			let total_balance = T::StakingAdapter::total_balance(&pool_account);
 
 			assert!(
 				total_balance >= bonded_balance + sum_unbonding_balance,
diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs
index 85b8c3b644055..8fb2bd89668e3 100644
--- a/substrate/frame/nomination-pools/src/mock.rs
+++ b/substrate/frame/nomination-pools/src/mock.rs
@@ -311,7 +311,7 @@ impl pools::Config for Runtime {
 	type MaxMetadataLen = MaxMetadataLen;
 	type MaxUnbonding = MaxUnbonding;
 	type MaxPointsToBalance = frame_support::traits::ConstU8<10>;
-	type PoolAdapter = adapter::NoDelegation<Self>;
+	type StakingAdapter = adapter::NoDelegation<Self>;
 }
 
 type Block = frame_system::mocking::MockBlock<Runtime>;
diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs
index 60b782d5b9ac2..30933171e6056 100644
--- a/substrate/frame/nomination-pools/test-staking/src/mock.rs
+++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs
@@ -187,7 +187,7 @@ impl pallet_nomination_pools::Config for Runtime {
 	type MaxUnbonding = ConstU32<8>;
 	type MaxPointsToBalance = ConstU8<10>;
 	type PalletId = PoolsPalletId;
-	type PoolAdapter = pallet_nomination_pools::adapter::NoDelegation<Self>;
+	type StakingAdapter = pallet_nomination_pools::adapter::NoDelegation<Self>;
 }
 
 type Block = frame_system::mocking::MockBlock<Runtime>;
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 75d6d728a5128..af8cca9bb091a 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -158,53 +158,3 @@ pub trait StakingDelegationSupport {
 	/// Reports an ongoing slash to the `delegate` account that would be applied lazily.
 	fn report_slash(who: &Self::AccountId, slash: Self::Balance);
 }
-
-/// Pool adapter trait that can support multiple modes of staking: i.e. Delegated or Direct.
-pub trait PoolAdapter {
-	type Balance: Sub<Output = Self::Balance>
-		+ Ord
-		+ PartialEq
-		+ Default
-		+ Copy
-		+ MaxEncodedLen
-		+ FullCodec
-		+ TypeInfo
-		+ Saturating;
-	type AccountId: Clone + sp_std::fmt::Debug;
-
-	/// Similar to [Inspect::balance].
-	fn balance(who: &Self::AccountId) -> Self::Balance;
-
-	/// Similar to [Inspect::total_balance].
-	fn total_balance(who: &Self::AccountId) -> Self::Balance;
-
-	/// Start delegation to the pool account.
-	///
-	/// Similar to [Mutate::transfer] for Direct Stake.
-	fn delegate(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult;
-
-	/// Add more delegation to the pool account.
-	///
-	/// Similar to [Mutate::transfer] for Direct Stake.
-	///
-	/// We need this along with [Self::delegate] as NominationPool has a slight different behaviour
-	/// for the first delegation and the subsequent ones.
-	fn delegate_extra(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult;
-
-	/// Revoke delegation to pool account.
-	///
-	/// Similar to [Mutate::transfer] for Direct Stake but in reverse direction to [Self::delegate].
-	fn release_delegation(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult;
-}

From ea78f168d02632c887af6a187cf8730d83c6a1f4 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Mon, 19 Feb 2024 11:17:56 +0100
Subject: [PATCH 113/202] Revert "move adapter logic local to pool"

This reverts commit 54acfb71faf5ab80bdf46e97791d4f50a15423dc.
---
 .../frame/delegated-staking/src/impls.rs      | 38 +++++++++
 .../frame/nomination-pools/src/adapter.rs     | 82 +------------------
 substrate/frame/nomination-pools/src/lib.rs   | 18 ++--
 substrate/frame/nomination-pools/src/mock.rs  |  2 +-
 .../nomination-pools/test-staking/src/mock.rs |  2 +-
 .../primitives/staking/src/delegation.rs      | 50 +++++++++++
 6 files changed, 99 insertions(+), 93 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 5db6bbb333ee9..34dbce708aa17 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -19,6 +19,7 @@
 //! Implementations of public traits, namely [StakingInterface], and [StakingDelegationSupport].
 
 use super::*;
+use sp_staking::delegation::PoolAdapter;
 
 /// StakingInterface implementation with delegation support.
 ///
@@ -280,3 +281,40 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 		});
 	}
 }
+
+impl<T: Config> PoolAdapter for Pallet<T> {
+	type Balance = BalanceOf<T>;
+	type AccountId = T::AccountId;
+
+	fn balance(who: &Self::AccountId) -> Self::Balance {
+		todo!()
+	}
+
+	fn total_balance(who: &Self::AccountId) -> Self::Balance {
+		todo!()
+	}
+
+	fn delegate(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
+		todo!()
+	}
+
+	fn delegate_extra(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
+		todo!()
+	}
+
+	fn release_delegation(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
+		todo!()
+	}
+}
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index b569573819ac1..7562b11ff2588 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -16,49 +16,6 @@
 // limitations under the License.
 
 use crate::*;
-use frame_support::traits::tokens::Balance;
-
-/// Staking adapter trait that can support multiple modes of staking: i.e. Delegated or Direct.
-pub trait StakingAdapter {
-	type Balance: Balance;
-	type AccountId: Clone + Debug;
-
-	/// Similar to [Inspect::balance].
-	fn balance(who: &Self::AccountId) -> Self::Balance;
-
-	/// Similar to [Inspect::total_balance].
-	fn total_balance(who: &Self::AccountId) -> Self::Balance;
-
-	/// Start delegation to the pool account.
-	///
-	/// Similar to [Mutate::transfer] for Direct Stake.
-	fn delegate(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult;
-
-	/// Add more delegation to the pool account.
-	///
-	/// Similar to [Mutate::transfer] for Direct Stake.
-	///
-	/// We need this along with [Self::delegate] as NominationPool has a slight different behaviour
-	/// for the first delegation and the subsequent ones.
-	fn delegate_extra(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult;
-
-	/// Revoke delegation to pool account.
-	///
-	/// Similar to [Mutate::transfer] for Direct Stake but in reverse direction to [Self::delegate].
-	fn release_delegation(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult;
-}
 
 /// Basic pool adapter that only supports Direct Staking.
 ///
@@ -66,7 +23,7 @@ pub trait StakingAdapter {
 /// tokens in delegator's accounts.
 pub struct NoDelegation<T: Config>(PhantomData<T>);
 
-impl<T: Config> StakingAdapter for NoDelegation<T> {
+impl<T: Config> PoolAdapter for NoDelegation<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
@@ -108,40 +65,3 @@ impl<T: Config> StakingAdapter for NoDelegation<T> {
 		Ok(())
 	}
 }
-
-impl<T: Config> StakingAdapter for Pallet<T> {
-	type Balance = BalanceOf<T>;
-	type AccountId = T::AccountId;
-
-	fn balance(who: &Self::AccountId) -> Self::Balance {
-		todo!()
-	}
-
-	fn total_balance(who: &Self::AccountId) -> Self::Balance {
-		todo!()
-	}
-
-	fn delegate(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult {
-		todo!()
-	}
-
-	fn delegate_extra(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult {
-		todo!()
-	}
-
-	fn release_delegation(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult {
-		todo!()
-	}
-}
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index 3c823e3cdb568..d021961bced39 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -373,7 +373,7 @@ use sp_runtime::{
 	},
 	FixedPointNumber, Perbill,
 };
-use sp_staking::{EraIndex, StakingInterface};
+use sp_staking::{delegation::PoolAdapter, EraIndex, StakingInterface};
 use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, ops::Div, vec::Vec};
 
 #[cfg(any(feature = "try-runtime", feature = "fuzzing", test, debug_assertions))]
@@ -398,8 +398,6 @@ pub mod mock;
 mod tests;
 
 pub mod adapter;
-use adapter::StakingAdapter;
-
 pub mod migration;
 pub mod weights;
 
@@ -1059,7 +1057,7 @@ impl<T: Config> BondedPool<T> {
 		// `pallet-nomination-pool`. This means reducible balance always returns balance preserving
 		// ED in the account. What we want though is transferable balance given the account can be
 		// dusted.
-		T::StakingAdapter::balance(&account)
+		T::PoolAdapter::balance(&account)
 			.saturating_sub(T::Staking::active_stake(&account).unwrap_or_default())
 	}
 
@@ -1265,14 +1263,14 @@ impl<T: Config> BondedPool<T> {
 
 		match ty {
 			BondType::Create => {
-				T::StakingAdapter::delegate(who, &bonded_account, amount)?;
+				T::PoolAdapter::delegate(who, &bonded_account, amount)?;
 				T::Staking::bond(&bonded_account, amount, &self.reward_account())?
 			},
 			// The pool should always be created in such a way its in a state to bond extra, but if
 			// the active balance is slashed below the minimum bonded or the account cannot be
 			// found, we exit early.
 			BondType::Later => {
-				T::StakingAdapter::delegate_extra(who, &bonded_account, amount)?;
+				T::PoolAdapter::delegate_extra(who, &bonded_account, amount)?;
 				T::Staking::bond_extra(&bonded_account, amount)?
 			},
 		}
@@ -1656,7 +1654,7 @@ pub mod pallet {
 		type MaxMetadataLen: Get<u32>;
 
 		/// An adapter to support delegated to direct staking.
-		type StakingAdapter: StakingAdapter<AccountId = Self::AccountId, Balance = BalanceOf<Self>>;
+		type PoolAdapter: PoolAdapter<AccountId = Self::AccountId, Balance = BalanceOf<Self>>;
 	}
 
 	/// The sum of funds across all pools.
@@ -2294,7 +2292,7 @@ pub mod pallet {
 				// order to ensure members can leave the pool and it can be destroyed.
 				.min(bonded_pool.transferable_balance());
 
-			T::StakingAdapter::release_delegation(
+			T::PoolAdapter::release_delegation(
 				&member_account,
 				&bonded_pool.bonded_account(),
 				balance_to_unbond,
@@ -2879,7 +2877,7 @@ impl<T: Config> Pallet<T> {
 			"could not transfer all amount to depositor while dissolving pool"
 		);
 		defensive_assert!(
-			T::StakingAdapter::total_balance(&bonded_pool.bonded_account()) == Zero::zero(),
+			T::PoolAdapter::total_balance(&bonded_pool.bonded_account()) == Zero::zero(),
 			"dissolving pool should not have any balance"
 		);
 		// NOTE: Defensively force set balance to zero.
@@ -3461,7 +3459,7 @@ impl<T: Config> Pallet<T> {
 
 			let sum_unbonding_balance = subs.sum_unbonding_balance();
 			let bonded_balance = T::Staking::active_stake(&pool_account).unwrap_or_default();
-			let total_balance = T::StakingAdapter::total_balance(&pool_account);
+			let total_balance = T::PoolAdapter::total_balance(&pool_account);
 
 			assert!(
 				total_balance >= bonded_balance + sum_unbonding_balance,
diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs
index 8fb2bd89668e3..85b8c3b644055 100644
--- a/substrate/frame/nomination-pools/src/mock.rs
+++ b/substrate/frame/nomination-pools/src/mock.rs
@@ -311,7 +311,7 @@ impl pools::Config for Runtime {
 	type MaxMetadataLen = MaxMetadataLen;
 	type MaxUnbonding = MaxUnbonding;
 	type MaxPointsToBalance = frame_support::traits::ConstU8<10>;
-	type StakingAdapter = adapter::NoDelegation<Self>;
+	type PoolAdapter = adapter::NoDelegation<Self>;
 }
 
 type Block = frame_system::mocking::MockBlock<Runtime>;
diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs
index 30933171e6056..60b782d5b9ac2 100644
--- a/substrate/frame/nomination-pools/test-staking/src/mock.rs
+++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs
@@ -187,7 +187,7 @@ impl pallet_nomination_pools::Config for Runtime {
 	type MaxUnbonding = ConstU32<8>;
 	type MaxPointsToBalance = ConstU8<10>;
 	type PalletId = PoolsPalletId;
-	type StakingAdapter = pallet_nomination_pools::adapter::NoDelegation<Self>;
+	type PoolAdapter = pallet_nomination_pools::adapter::NoDelegation<Self>;
 }
 
 type Block = frame_system::mocking::MockBlock<Runtime>;
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index af8cca9bb091a..75d6d728a5128 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -158,3 +158,53 @@ pub trait StakingDelegationSupport {
 	/// Reports an ongoing slash to the `delegate` account that would be applied lazily.
 	fn report_slash(who: &Self::AccountId, slash: Self::Balance);
 }
+
+/// Pool adapter trait that can support multiple modes of staking: i.e. Delegated or Direct.
+pub trait PoolAdapter {
+	type Balance: Sub<Output = Self::Balance>
+		+ Ord
+		+ PartialEq
+		+ Default
+		+ Copy
+		+ MaxEncodedLen
+		+ FullCodec
+		+ TypeInfo
+		+ Saturating;
+	type AccountId: Clone + sp_std::fmt::Debug;
+
+	/// Similar to [Inspect::balance].
+	fn balance(who: &Self::AccountId) -> Self::Balance;
+
+	/// Similar to [Inspect::total_balance].
+	fn total_balance(who: &Self::AccountId) -> Self::Balance;
+
+	/// Start delegation to the pool account.
+	///
+	/// Similar to [Mutate::transfer] for Direct Stake.
+	fn delegate(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
+
+	/// Add more delegation to the pool account.
+	///
+	/// Similar to [Mutate::transfer] for Direct Stake.
+	///
+	/// We need this along with [Self::delegate] as NominationPool has a slight different behaviour
+	/// for the first delegation and the subsequent ones.
+	fn delegate_extra(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
+
+	/// Revoke delegation to pool account.
+	///
+	/// Similar to [Mutate::transfer] for Direct Stake but in reverse direction to [Self::delegate].
+	fn release_delegation(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
+}

From a32444252ae9b095adfe4348701872c2193811e2 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Mon, 19 Feb 2024 11:40:45 +0100
Subject: [PATCH 114/202] quick basic impl of Delegation adapter for pool

---
 .../frame/delegated-staking/src/impls.rs      | 24 +++++++++++++++----
 .../frame/delegated-staking/src/types.rs      | 19 ++++++++++++---
 2 files changed, 35 insertions(+), 8 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 34dbce708aa17..67e42e6f3dce0 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -286,20 +286,33 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
+	/// Return balance of the `Delegate` (pool account) that is not bonded.
+	///
+	/// Equivalent to [FunInspect::balance] for non delegate accounts.
 	fn balance(who: &Self::AccountId) -> Self::Balance {
-		todo!()
+		Delegate::<T>::from(who)
+			.map(|delegate| delegate.unbonded())
+			.unwrap_or(Zero::zero())
 	}
 
+	/// Returns balance of `Delegate` account including the held balances.
+	///
+	/// Equivalent to [FunInspect::total_balance] for non delegate accounts.
 	fn total_balance(who: &Self::AccountId) -> Self::Balance {
-		todo!()
+		Delegate::<T>::from(who)
+			.map(|delegate| delegate.ledger.effective_balance())
+			.unwrap_or(Zero::zero())
 	}
 
+	/// Add initial delegation to the pool account.
+	///
+	/// Equivalent to [FunMutate::transfer] for Direct Staking.
 	fn delegate(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult {
-		todo!()
+		Pallet::<T>::delegate_funds(RawOrigin::Signed(who.clone()).into(), pool_account.clone(), amount)
 	}
 
 	fn delegate_extra(
@@ -307,7 +320,7 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult {
-		todo!()
+		Self::delegate(who, pool_account, amount)
 	}
 
 	fn release_delegation(
@@ -315,6 +328,7 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult {
-		todo!()
+		// fixme(ank4n): This should not require slashing spans.
+		Pallet::<T>::release(RawOrigin::Signed(pool_account.clone()).into(), who.clone(), amount, 0)
 	}
 }
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index 5999d4b9a977e..5de79e0fb2286 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -159,14 +159,27 @@ impl<T: Config> Delegate<T> {
 	}
 
 	pub(crate) fn available_to_bond(&self) -> BalanceOf<T> {
-		let exposed_stake = self.bonded_stake();
+		let bonded_stake = self.bonded_stake();
 
 		let stakeable =
 			self.ledger().map(|ledger| ledger.stakeable_balance()).unwrap_or(Zero::zero());
 
-		defensive_assert!(stakeable >= exposed_stake, "cannot expose more than delegate balance");
+		defensive_assert!(stakeable >= bonded_stake, "cannot expose more than delegate balance");
 
-		stakeable.saturating_sub(exposed_stake)
+		stakeable.saturating_sub(bonded_stake)
+	}
+
+	/// Similar to [`Self::available_to_bond`] but includes `DelegationLedger.unclaimed_withdrawals`
+	/// as well.
+	pub(crate) fn unbonded(&self) -> BalanceOf<T> {
+		let bonded_stake = self.bonded_stake();
+
+		let net_balance =
+			self.ledger().map(|ledger| ledger.effective_balance()).unwrap_or(Zero::zero());
+
+		defensive_assert!(net_balance >= bonded_stake, "cannot expose more than delegate balance");
+
+		net_balance.saturating_sub(bonded_stake)
 	}
 
 	pub(crate) fn ledger(&self) -> Option<DelegationLedger<T>> {

From 10fadcdbee8fe7dd4acb3d58c90bf848a8c52a15 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Wed, 21 Feb 2024 15:34:52 +0100
Subject: [PATCH 115/202] add np to delegate pallet mock runtime

---
 Cargo.lock                                    |  1 +
 substrate/frame/delegated-staking/Cargo.toml  |  1 +
 substrate/frame/delegated-staking/src/mock.rs | 43 +++++++++++++++++--
 substrate/frame/nomination-pools/src/lib.rs   |  2 +-
 4 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 09a70664d1fd2..1277f68730cd1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -9767,6 +9767,7 @@ dependencies = [
  "frame-support",
  "frame-system",
  "pallet-balances",
+ "pallet-nomination-pools",
  "pallet-staking",
  "pallet-staking-reward-curve",
  "pallet-timestamp",
diff --git a/substrate/frame/delegated-staking/Cargo.toml b/substrate/frame/delegated-staking/Cargo.toml
index 735b2794d5eab..4b278af64cf3a 100644
--- a/substrate/frame/delegated-staking/Cargo.toml
+++ b/substrate/frame/delegated-staking/Cargo.toml
@@ -26,6 +26,7 @@ sp-io = { path = "../../primitives/io" }
 substrate-test-utils = { path = "../../test-utils" }
 sp-tracing = { path = "../../primitives/tracing" }
 pallet-staking = { path = "../staking" }
+pallet-nomination-pools = { path = "../nomination-pools" }
 pallet-balances = { path = "../balances" }
 pallet-timestamp = { path = "../timestamp" }
 pallet-staking-reward-curve = { path = "../staking/reward-curve" }
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index e001444b5fce0..ad69680ecdc6d 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -32,6 +32,8 @@ use frame_election_provider_support::{
 };
 use frame_support::dispatch::RawOrigin;
 use pallet_staking::CurrentEra;
+use sp_core::U256;
+use sp_runtime::traits::Convert;
 use sp_staking::{delegation::StakingDelegationSupport, Stake, StakingInterface};
 
 pub type T = Runtime;
@@ -72,10 +74,10 @@ impl pallet_balances::Config for Runtime {
 	type ExistentialDeposit = ExistentialDeposit;
 	type AccountStore = System;
 	type WeightInfo = ();
-	type FreezeIdentifier = ();
-	type MaxFreezes = ();
+	type FreezeIdentifier = RuntimeFreezeReason;
+	type MaxFreezes = ConstU32<1>;
 	type RuntimeHoldReason = RuntimeHoldReason;
-	type RuntimeFreezeReason = ();
+	type RuntimeFreezeReason = RuntimeFreezeReason;
 }
 
 pallet_staking_reward_curve::build! {
@@ -148,6 +150,40 @@ impl delegated_staking::Config for Runtime {
 	type CoreStaking = Staking;
 }
 
+pub struct BalanceToU256;
+impl Convert<Balance, U256> for BalanceToU256 {
+	fn convert(n: Balance) -> U256 {
+		n.into()
+	}
+}
+pub struct U256ToBalance;
+impl Convert<U256, Balance> for U256ToBalance {
+	fn convert(n: U256) -> Balance {
+		n.try_into().unwrap()
+	}
+}
+
+parameter_types! {
+	pub static MaxUnbonding: u32 = 8;
+	pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls");
+}
+impl pallet_nomination_pools::Config for Runtime {
+	type RuntimeEvent = RuntimeEvent;
+	type WeightInfo = ();
+	type Currency = Balances;
+	type RuntimeFreezeReason = RuntimeFreezeReason;
+	type RewardCounter = sp_runtime::FixedU128;
+	type BalanceToU256 = BalanceToU256;
+	type U256ToBalance = U256ToBalance;
+	type Staking = DelegatedStaking;
+	type PostUnbondingPoolsWindow = ConstU32<2>;
+	type PalletId = PoolsPalletId;
+	type MaxMetadataLen = ConstU32<256>;
+	type MaxUnbonding = MaxUnbonding;
+	type MaxPointsToBalance = frame_support::traits::ConstU8<10>;
+	type PoolAdapter = DelegatedStaking;
+}
+
 frame_support::construct_runtime!(
 	pub enum Runtime {
 		System: frame_system,
@@ -155,6 +191,7 @@ frame_support::construct_runtime!(
 		Balances: pallet_balances,
 		Staking: pallet_staking,
 		DelegatedStaking: delegated_staking,
+		NominationPools: pallet_nomination_pools,
 	}
 );
 
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index d021961bced39..d75fc774d3908 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -3117,7 +3117,7 @@ impl<T: Config> Pallet<T> {
 	) -> DispatchResult {
 		if signer != member_account {
 			ensure!(
-				ClaimPermissions::<T>::get(&member_account).can_bond_extra(),
+					ClaimPermissions::<T>::get(&member_account).can_bond_extra(),
 				Error::<T>::DoesNotHavePermission
 			);
 			ensure!(extra == BondExtra::Rewards, Error::<T>::BondExtraRestricted);

From 9cafa0e6a05218b9fdb31ec7fd3ed2095433e993 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Wed, 21 Feb 2024 15:39:07 +0100
Subject: [PATCH 116/202] fmt

---
 substrate/frame/delegated-staking/src/impls.rs | 6 +++++-
 substrate/frame/nomination-pools/src/lib.rs    | 2 +-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 67e42e6f3dce0..5ee361ffa4436 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -312,7 +312,11 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult {
-		Pallet::<T>::delegate_funds(RawOrigin::Signed(who.clone()).into(), pool_account.clone(), amount)
+		Pallet::<T>::delegate_funds(
+			RawOrigin::Signed(who.clone()).into(),
+			pool_account.clone(),
+			amount,
+		)
 	}
 
 	fn delegate_extra(
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index d75fc774d3908..d021961bced39 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -3117,7 +3117,7 @@ impl<T: Config> Pallet<T> {
 	) -> DispatchResult {
 		if signer != member_account {
 			ensure!(
-					ClaimPermissions::<T>::get(&member_account).can_bond_extra(),
+				ClaimPermissions::<T>::get(&member_account).can_bond_extra(),
 				Error::<T>::DoesNotHavePermission
 			);
 			ensure!(extra == BondExtra::Rewards, Error::<T>::BondExtraRestricted);

From f10e589bee8d68fac2e1b671e135eb04e21e32b6 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Wed, 21 Feb 2024 15:53:58 +0100
Subject: [PATCH 117/202] tests skeleton

---
 .../frame/delegated-staking/src/tests.rs      | 65 ++++++++++++++++++-
 1 file changed, 64 insertions(+), 1 deletion(-)

diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 69264bfec036b..10324502c0b00 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -202,7 +202,7 @@ fn apply_pending_slash() {
 }
 
 /// Integration tests with pallet-staking.
-mod integration {
+mod staking_integration {
 	use super::*;
 	use pallet_staking::RewardDestination;
 	use sp_staking::Stake;
@@ -586,3 +586,66 @@ mod integration {
 		});
 	}
 }
+
+mod pool_integration {
+
+	#[test]
+	fn create_pool() {
+
+	}
+
+	#[test]
+	fn join_pool() {
+
+	}
+
+	#[test]
+	fn bond_extra_to_pool() {
+
+	}
+
+	#[test]
+	fn claim_pool_rewards() {
+
+	}
+
+	#[test]
+	fn unbond_delegation_from_pool() {
+
+	}
+
+	#[test]
+	fn pool_withdraw_unbonded() {
+
+	}
+
+	#[test]
+	fn delegator_withdraw_unbonded() {
+
+	}
+
+	#[test]
+	fn update_nominations() {
+
+	}
+
+	#[test]
+	fn destroy_pool() {
+
+	}
+
+	#[test]
+	fn chill_pool() {
+
+	}
+
+	#[test]
+	fn claim_commission_pool_operator() {
+
+	}
+
+	#[test]
+	fn pool_slashed() {
+
+	}
+}

From b11ea7a8b941ea66adf598659485759213099891 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Wed, 21 Feb 2024 17:38:05 +0100
Subject: [PATCH 118/202] use balance type u128 so np pot accounts are unique

---
 .../frame/delegated-staking/src/impls.rs      |  9 ++++++++-
 substrate/frame/delegated-staking/src/mock.rs | 16 +++++++++------
 .../frame/delegated-staking/src/tests.rs      | 20 ++++++++++++++++++-
 .../frame/nomination-pools/src/adapter.rs     |  9 ++++-----
 substrate/frame/nomination-pools/src/lib.rs   | 12 ++++-------
 .../primitives/staking/src/delegation.rs      | 10 ++--------
 6 files changed, 47 insertions(+), 29 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 5ee361ffa4436..1565d0a5ffdcd 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -310,8 +310,11 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 	fn delegate(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
+		reward_account: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult {
+		Pallet::<T>::register_as_delegate(RawOrigin::Signed(pool_account.clone()).into(), reward_account.clone())?;
+
 		Pallet::<T>::delegate_funds(
 			RawOrigin::Signed(who.clone()).into(),
 			pool_account.clone(),
@@ -324,7 +327,11 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult {
-		Self::delegate(who, pool_account, amount)
+		Pallet::<T>::delegate_funds(
+			RawOrigin::Signed(who.clone()).into(),
+			pool_account.clone(),
+			amount,
+		)
 	}
 
 	fn release_delegation(
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index ad69680ecdc6d..26a3556e9f6e0 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -15,12 +15,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use crate::{self as delegated_staking, types::Delegate};
+use crate::{self as delegated_staking, types::Delegate, HoldReason};
 use frame_support::{
-	assert_ok, derive_impl,
+	assert_noop, assert_ok, derive_impl,
 	pallet_prelude::*,
 	parameter_types,
-	traits::{ConstU64, Currency},
+	traits::{fungible::InspectHold, ConstU64, Currency},
 	PalletId,
 };
 
@@ -38,7 +38,7 @@ use sp_staking::{delegation::StakingDelegationSupport, Stake, StakingInterface};
 
 pub type T = Runtime;
 type Block = frame_system::mocking::MockBlock<Runtime>;
-pub type AccountId = u64;
+pub type AccountId = u128;
 
 pub const GENESIS_VALIDATOR: AccountId = 1;
 pub const GENESIS_NOMINATOR_ONE: AccountId = 101;
@@ -99,7 +99,7 @@ parameter_types! {
 pub struct OnChainSeqPhragmen;
 impl onchain::Config for OnChainSeqPhragmen {
 	type System = Runtime;
-	type Solver = SequentialPhragmen<u64, sp_runtime::Perbill>;
+	type Solver = SequentialPhragmen<Balance, sp_runtime::Perbill>;
 	type DataProvider = Staking;
 	type WeightInfo = ();
 	type MaxWinners = ConstU32<100>;
@@ -191,7 +191,7 @@ frame_support::construct_runtime!(
 		Balances: pallet_balances,
 		Staking: pallet_staking,
 		DelegatedStaking: delegated_staking,
-		NominationPools: pallet_nomination_pools,
+		Pools: pallet_nomination_pools,
 	}
 );
 
@@ -333,3 +333,7 @@ pub(crate) fn delegate_bonded(delegate: &AccountId) -> bool {
 pub(crate) fn get_delegate(delegate: &AccountId) -> Delegate<T> {
 	Delegate::<T>::from(delegate).expect("delegate should exist")
 }
+
+pub(crate) fn held_balance(who: &AccountId) -> Balance {
+	Balances::balance_on_hold(&HoldReason::Delegating.into(), &who)
+}
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 10324502c0b00..3cfc3de3954c0 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -588,15 +588,33 @@ mod staking_integration {
 }
 
 mod pool_integration {
-
+	use super::*;
 	#[test]
 	fn create_pool() {
+		ExtBuilder::default().build_and_execute(|| {
+			let creator: AccountId = 100;
+			fund(&creator, 500);
+			let delegate_amount = 200;
+
+			assert_ok!(Pools::create(RawOrigin::Signed(creator).into(), delegate_amount, creator, creator, creator));
+			assert_eq!(held_balance(&creator), delegate_amount);
 
+			let pool_account = Pools::create_bonded_account(1);
+			let delegate = get_delegate(&pool_account);
+		});
 	}
 
 	#[test]
 	fn join_pool() {
+		for i in 1..10000000 {
+			let bonded = Pools::create_bonded_account(i);
+			let reward = Pools::create_reward_account(i);
 
+			if bonded != reward {
+				println!("Index: {:?}, Bonded: {:?}, Reward: {:?}",i, bonded, reward);
+				break
+			}
+		}
 	}
 
 	#[test]
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index 7562b11ff2588..bc33e32f80f2f 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -38,11 +38,11 @@ impl<T: Config> PoolAdapter for NoDelegation<T> {
 	fn delegate(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
+		reward_account: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult {
 		T::Currency::transfer(who, &pool_account, amount, Preservation::Expendable)?;
-
-		Ok(())
+		T::Staking::bond(pool_account, amount, reward_account)
 	}
 
 	fn delegate_extra(
@@ -50,9 +50,8 @@ impl<T: Config> PoolAdapter for NoDelegation<T> {
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult {
-		T::Currency::transfer(who, &pool_account, amount, Preservation::Preserve)?;
-
-		Ok(())
+		T::Currency::transfer(who, pool_account, amount, Preservation::Preserve)?;
+		T::Staking::bond_extra(pool_account, amount)
 	}
 
 	fn release_delegation(
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index d021961bced39..579b470514752 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -1260,19 +1260,15 @@ impl<T: Config> BondedPool<T> {
 		// We must calculate the points issued *before* we bond who's funds, else points:balance
 		// ratio will be wrong.
 		let points_issued = self.issue(amount);
+		let reward_account = self.reward_account();
 
 		match ty {
-			BondType::Create => {
-				T::PoolAdapter::delegate(who, &bonded_account, amount)?;
-				T::Staking::bond(&bonded_account, amount, &self.reward_account())?
-			},
+			BondType::Create =>
+				T::PoolAdapter::delegate(who, &bonded_account, &reward_account, amount)?,
 			// The pool should always be created in such a way its in a state to bond extra, but if
 			// the active balance is slashed below the minimum bonded or the account cannot be
 			// found, we exit early.
-			BondType::Later => {
-				T::PoolAdapter::delegate_extra(who, &bonded_account, amount)?;
-				T::Staking::bond_extra(&bonded_account, amount)?
-			},
+			BondType::Later => T::PoolAdapter::delegate_extra(who, &bonded_account, amount)?,
 		}
 		TotalValueLocked::<T>::mutate(|tvl| {
 			tvl.saturating_accrue(amount);
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 75d6d728a5128..e1d1120684fe3 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -178,21 +178,15 @@ pub trait PoolAdapter {
 	/// Similar to [Inspect::total_balance].
 	fn total_balance(who: &Self::AccountId) -> Self::Balance;
 
-	/// Start delegation to the pool account.
-	///
-	/// Similar to [Mutate::transfer] for Direct Stake.
+	/// Initiate delegation to the pool account.
 	fn delegate(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
+		reward_account: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult;
 
 	/// Add more delegation to the pool account.
-	///
-	/// Similar to [Mutate::transfer] for Direct Stake.
-	///
-	/// We need this along with [Self::delegate] as NominationPool has a slight different behaviour
-	/// for the first delegation and the subsequent ones.
 	fn delegate_extra(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,

From 8029e2e8f3fa4294a313f54e22d2657df60db353 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Wed, 21 Feb 2024 17:46:31 +0100
Subject: [PATCH 119/202] create pool

---
 .../frame/delegated-staking/src/impls.rs      | 17 ++++++--
 .../frame/delegated-staking/src/tests.rs      | 42 ++++++++++---------
 2 files changed, 36 insertions(+), 23 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 1565d0a5ffdcd..f4c3e455ae48c 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -313,13 +313,21 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 		reward_account: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult {
-		Pallet::<T>::register_as_delegate(RawOrigin::Signed(pool_account.clone()).into(), reward_account.clone())?;
+		// First delegation so we needs to register the pool account as delegate.
+		Pallet::<T>::register_as_delegate(
+			RawOrigin::Signed(pool_account.clone()).into(),
+			reward_account.clone(),
+		)?;
 
+		// Delegate the funds from who to the pool account.
 		Pallet::<T>::delegate_funds(
 			RawOrigin::Signed(who.clone()).into(),
 			pool_account.clone(),
 			amount,
-		)
+		)?;
+
+		// Bond the funds to staking.
+		Pallet::<T>::bond(pool_account, amount, reward_account)
 	}
 
 	fn delegate_extra(
@@ -331,7 +339,10 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 			RawOrigin::Signed(who.clone()).into(),
 			pool_account.clone(),
 			amount,
-		)
+		)?;
+
+		// Bond the funds to staking.
+		Pallet::<T>::bond_extra(pool_account, amount)
 	}
 
 	fn release_delegation(
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 3cfc3de3954c0..812770a2b2bd3 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -596,74 +596,76 @@ mod pool_integration {
 			fund(&creator, 500);
 			let delegate_amount = 200;
 
-			assert_ok!(Pools::create(RawOrigin::Signed(creator).into(), delegate_amount, creator, creator, creator));
+			assert_ok!(Pools::create(
+				RawOrigin::Signed(creator).into(),
+				delegate_amount,
+				creator,
+				creator,
+				creator
+			));
 			assert_eq!(held_balance(&creator), delegate_amount);
 
 			let pool_account = Pools::create_bonded_account(1);
 			let delegate = get_delegate(&pool_account);
+
+			assert_eq!(delegate.ledger.effective_balance(), delegate_amount);
+			assert_eq!(delegate.available_to_bond(), 0);
+			assert_eq!(delegate.unbonded(), 0);
 		});
 	}
 
 	#[test]
 	fn join_pool() {
-		for i in 1..10000000 {
-			let bonded = Pools::create_bonded_account(i);
-			let reward = Pools::create_reward_account(i);
-
-			if bonded != reward {
-				println!("Index: {:?}, Bonded: {:?}, Reward: {:?}",i, bonded, reward);
-				break
-			}
-		}
+		ExtBuilder::default().build_and_execute(|| {});
 	}
 
 	#[test]
 	fn bond_extra_to_pool() {
-
+		ExtBuilder::default().build_and_execute(|| {});
 	}
 
 	#[test]
 	fn claim_pool_rewards() {
-
+		ExtBuilder::default().build_and_execute(|| {});
 	}
 
 	#[test]
 	fn unbond_delegation_from_pool() {
-
+		ExtBuilder::default().build_and_execute(|| {});
 	}
 
 	#[test]
 	fn pool_withdraw_unbonded() {
-
+		ExtBuilder::default().build_and_execute(|| {});
 	}
 
 	#[test]
 	fn delegator_withdraw_unbonded() {
-
+		ExtBuilder::default().build_and_execute(|| {});
 	}
 
 	#[test]
 	fn update_nominations() {
-
+		ExtBuilder::default().build_and_execute(|| {});
 	}
 
 	#[test]
 	fn destroy_pool() {
-
+		ExtBuilder::default().build_and_execute(|| {});
 	}
 
 	#[test]
 	fn chill_pool() {
-
+		ExtBuilder::default().build_and_execute(|| {});
 	}
 
 	#[test]
 	fn claim_commission_pool_operator() {
-
+		ExtBuilder::default().build_and_execute(|| {});
 	}
 
 	#[test]
 	fn pool_slashed() {
-
+		ExtBuilder::default().build_and_execute(|| {});
 	}
 }

From f283207da68f291b779edc91d950145efc240092 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Wed, 21 Feb 2024 18:04:39 +0100
Subject: [PATCH 120/202] increment provider on pool account

---
 substrate/frame/delegated-staking/src/impls.rs |  2 +-
 substrate/frame/delegated-staking/src/lib.rs   | 14 +++++++++++---
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index f4c3e455ae48c..e6c86968287a3 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -313,7 +313,7 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 		reward_account: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult {
-		// First delegation so we needs to register the pool account as delegate.
+		// This is the first delegation so we needs to register the pool account as a `delegate`.
 		Pallet::<T>::register_as_delegate(
 			RawOrigin::Signed(pool_account.clone()).into(),
 			reward_account.clone(),
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index d0bdd67384e29..0942641e52ee7 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -218,8 +218,7 @@ pub mod pallet {
 			// Reward account cannot be same as `delegate` account.
 			ensure!(reward_account != who, Error::<T>::InvalidRewardDestination);
 
-			DelegationLedger::<T>::new(&reward_account).save(&who);
-
+			Self::do_register_delegator(&who, &reward_account);
 			Ok(())
 		}
 
@@ -374,6 +373,15 @@ impl<T: Config> Pallet<T> {
 			.unwrap_or(false)
 	}
 
+	fn do_register_delegator(who: &T::AccountId, reward_account: &T::AccountId) {
+		DelegationLedger::<T>::new(reward_account).save(who);
+
+		// Pool account is a virtual account. Make this account exist.
+		// TODO: Someday if we expose these calls in a runtime, we should take a deposit for
+		// being a delegator.
+		frame_system::Pallet::<T>::inc_providers(who);
+	}
+
 	fn do_migrate_to_delegate(who: &T::AccountId, reward_account: &T::AccountId) -> DispatchResult {
 		// We create a proxy delegator that will keep all the delegation funds until funds are
 		// transferred to actual delegator.
@@ -399,7 +407,7 @@ impl<T: Config> Pallet<T> {
 		T::Currency::transfer(who, &proxy_delegator, stake.total, Preservation::Protect)
 			.map_err(|_| Error::<T>::BadState)?;
 
-		DelegationLedger::<T>::new(&reward_account).save(&who);
+		Self::do_register_delegator(who, reward_account);
 		// FIXME(ank4n) expose set payee in staking interface.
 		// T::CoreStaking::set_payee(who, reward_account)
 

From a30d3c3efb54093e15d01b39b64410cde7964571 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 22 Feb 2024 00:12:42 +0100
Subject: [PATCH 121/202] join pool works

---
 .../frame/delegated-staking/src/impls.rs      |  2 +-
 .../frame/delegated-staking/src/tests.rs      | 63 ++++++++++++++++++-
 .../frame/delegated-staking/src/types.rs      |  5 ++
 3 files changed, 67 insertions(+), 3 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index e6c86968287a3..21aa212a22e90 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -65,7 +65,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 
 		if Self::is_delegator(who) {
 			let delegation = Delegation::<T>::get(who).defensive_ok_or(Error::<T>::BadState)?;
-			return Ok(delegation.amount)
+			return Ok(delegation.amount);
 		}
 
 		Err(Error::<T>::NotSupported.into())
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 812770a2b2bd3..9d2716891aa65 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -590,12 +590,16 @@ mod staking_integration {
 mod pool_integration {
 	use super::*;
 	#[test]
-	fn create_pool() {
+	fn create_pool_test() {
 		ExtBuilder::default().build_and_execute(|| {
 			let creator: AccountId = 100;
 			fund(&creator, 500);
 			let delegate_amount = 200;
 
+			// nothing held initially
+			assert_eq!(held_balance(&creator), 0);
+
+			// create pool
 			assert_ok!(Pools::create(
 				RawOrigin::Signed(creator).into(),
 				delegate_amount,
@@ -603,11 +607,14 @@ mod pool_integration {
 				creator,
 				creator
 			));
+
+			// correct amount is locked in depositor's account.
 			assert_eq!(held_balance(&creator), delegate_amount);
 
 			let pool_account = Pools::create_bonded_account(1);
 			let delegate = get_delegate(&pool_account);
 
+			// verify state
 			assert_eq!(delegate.ledger.effective_balance(), delegate_amount);
 			assert_eq!(delegate.available_to_bond(), 0);
 			assert_eq!(delegate.unbonded(), 0);
@@ -616,7 +623,48 @@ mod pool_integration {
 
 	#[test]
 	fn join_pool() {
-		ExtBuilder::default().build_and_execute(|| {});
+		ExtBuilder::default().build_and_execute(|| {
+			// create a pool
+			create_pool(100, 200);
+			// keep track of staked amount.
+			let mut staked_amount: Balance = 200;
+
+			// fund delegator
+			let delegator: AccountId = 300;
+			fund(&delegator, 500);
+			// nothing held initially
+			assert_eq!(held_balance(&delegator), 0);
+
+			// delegator joins pool
+			assert_ok!(Pools::join(RawOrigin::Signed(delegator).into(), 100, 1));
+			staked_amount += 100;
+
+			// correct amount is locked in depositor's account.
+			assert_eq!(held_balance(&delegator), 100);
+
+			// delegator is not actively exposed to core staking.
+			assert_eq!(Staking::status(&delegator), Err(StakingError::<T>::NotStash.into()));
+
+			let pool_delegate = get_delegate(&Pools::create_bonded_account(1));
+			// verify state
+			assert_eq!(pool_delegate.ledger.effective_balance(), staked_amount);
+			assert_eq!(pool_delegate.bonded_stake(), staked_amount);
+			assert_eq!(pool_delegate.available_to_bond(), 0);
+			assert_eq!(pool_delegate.unbonded(), 0);
+
+			// let a bunch of delegators join this pool
+			for i in 301..350 {
+				fund(&i, 500);
+				assert_ok!(Pools::join(RawOrigin::Signed(i).into(), (100 + i).into(), 1));
+				staked_amount += 100 + i;
+				assert_eq!(held_balance(&i), 100 + i);
+			}
+
+			assert_eq!(pool_delegate.refresh().unwrap().ledger.effective_balance(), staked_amount);
+			assert_eq!(pool_delegate.bonded_stake(), staked_amount);
+			assert_eq!(pool_delegate.available_to_bond(), 0);
+			assert_eq!(pool_delegate.unbonded(), 0);
+		});
 	}
 
 	#[test]
@@ -668,4 +716,15 @@ mod pool_integration {
 	fn pool_slashed() {
 		ExtBuilder::default().build_and_execute(|| {});
 	}
+
+	fn create_pool(creator: AccountId, amount: Balance) {
+		fund(&creator, amount * 2);
+		assert_ok!(Pools::create(
+			RawOrigin::Signed(creator).into(),
+			amount,
+			creator,
+			creator,
+			creator
+		));
+	}
 }
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index 5de79e0fb2286..05de7ad21274d 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -158,6 +158,11 @@ impl<T: Config> Delegate<T> {
 		Ok(Delegate { key: delegate.clone(), ledger })
 	}
 
+	// re-reads the delegate from database and returns a new instance.
+	pub(crate) fn refresh(&self) -> Result<Delegate<T>, DispatchError> {
+		Self::from(&self.key)
+	}
+
 	pub(crate) fn available_to_bond(&self) -> BalanceOf<T> {
 		let bonded_stake = self.bonded_stake();
 

From 7e09ebed21f72181e200de5b8bc80ffd3ea4911f Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 22 Feb 2024 00:40:14 +0100
Subject: [PATCH 122/202] get actual pool id

---
 .../frame/delegated-staking/src/tests.rs      | 22 ++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 9d2716891aa65..3e452c575f896 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -625,7 +625,7 @@ mod pool_integration {
 	fn join_pool() {
 		ExtBuilder::default().build_and_execute(|| {
 			// create a pool
-			create_pool(100, 200);
+			let pool_id = create_pool(100, 200);
 			// keep track of staked amount.
 			let mut staked_amount: Balance = 200;
 
@@ -636,7 +636,7 @@ mod pool_integration {
 			assert_eq!(held_balance(&delegator), 0);
 
 			// delegator joins pool
-			assert_ok!(Pools::join(RawOrigin::Signed(delegator).into(), 100, 1));
+			assert_ok!(Pools::join(RawOrigin::Signed(delegator).into(), 100, pool_id));
 			staked_amount += 100;
 
 			// correct amount is locked in depositor's account.
@@ -655,7 +655,7 @@ mod pool_integration {
 			// let a bunch of delegators join this pool
 			for i in 301..350 {
 				fund(&i, 500);
-				assert_ok!(Pools::join(RawOrigin::Signed(i).into(), (100 + i).into(), 1));
+				assert_ok!(Pools::join(RawOrigin::Signed(i).into(), (100 + i).into(), pool_id));
 				staked_amount += 100 + i;
 				assert_eq!(held_balance(&i), 100 + i);
 			}
@@ -669,7 +669,10 @@ mod pool_integration {
 
 	#[test]
 	fn bond_extra_to_pool() {
-		ExtBuilder::default().build_and_execute(|| {});
+		ExtBuilder::default().build_and_execute(|| {
+			let pool_id = create_pool(100, 200);
+			add_delegators(pool_id, 100, (300..350).collect(), 100);
+		});
 	}
 
 	#[test]
@@ -717,7 +720,7 @@ mod pool_integration {
 		ExtBuilder::default().build_and_execute(|| {});
 	}
 
-	fn create_pool(creator: AccountId, amount: Balance) {
+	fn create_pool(creator: AccountId, amount: Balance) -> u32 {
 		fund(&creator, amount * 2);
 		assert_ok!(Pools::create(
 			RawOrigin::Signed(creator).into(),
@@ -726,5 +729,14 @@ mod pool_integration {
 			creator,
 			creator
 		));
+
+		pallet_nomination_pools::LastPoolId::<T>::get()
+	}
+
+	fn add_delegators(pool_id: u32, creator: AccountId, delegators: Vec<AccountId>, amount: Balance) {
+		for delegator in delegators {
+			fund(&delegator, amount * 2);
+			assert_ok!(Pools::join(RawOrigin::Signed(delegator).into(), creator, pool_id));
+		}
 	}
 }

From e9819949f74790eb6b22e5852c9954803d49bd79 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 22 Feb 2024 00:53:16 +0100
Subject: [PATCH 123/202] bond extra test

---
 substrate/frame/delegated-staking/src/tests.rs | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 3e452c575f896..5f07e337460e5 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -588,6 +588,7 @@ mod staking_integration {
 }
 
 mod pool_integration {
+	use pallet_nomination_pools::BondExtra;
 	use super::*;
 	#[test]
 	fn create_pool_test() {
@@ -671,7 +672,16 @@ mod pool_integration {
 	fn bond_extra_to_pool() {
 		ExtBuilder::default().build_and_execute(|| {
 			let pool_id = create_pool(100, 200);
-			add_delegators(pool_id, 100, (300..350).collect(), 100);
+			add_delegators(pool_id, 100, (300..310).collect(), 100);
+			let mut staked_amount = 200 + 100 * 10;
+			assert_eq!(get_pool_delegate(pool_id).bonded_stake(), staked_amount);
+
+			// bond extra to pool
+			for i in 300..310 {
+				assert_ok!(Pools::bond_extra(RawOrigin::Signed(i).into(), BondExtra::FreeBalance(50)));
+				staked_amount += 50;
+				assert_eq!(get_pool_delegate(pool_id).bonded_stake(), staked_amount);
+			}
 		});
 	}
 
@@ -739,4 +749,8 @@ mod pool_integration {
 			assert_ok!(Pools::join(RawOrigin::Signed(delegator).into(), creator, pool_id));
 		}
 	}
+
+	fn get_pool_delegate(pool_id: u32) -> Delegate<T> {
+		get_delegate(&Pools::create_bonded_account(pool_id))
+	}
 }

From 8b0d4ae327cfe03edbc7f77698aa601b5053a4a2 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 22 Feb 2024 09:29:11 +0100
Subject: [PATCH 124/202] fix bug of adding surplus amount to delegate

---
 substrate/frame/delegated-staking/src/lib.rs  | 74 ++++++++++++++++++-
 .../frame/delegated-staking/src/types.rs      |  2 +-
 2 files changed, 71 insertions(+), 5 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 0942641e52ee7..4a60f254a72e7 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -80,7 +80,7 @@ use frame_support::{
 
 use sp_runtime::{
 	traits::{AccountIdConversion, CheckedAdd, CheckedSub, Zero},
-	ArithmeticError, DispatchResult, Perbill, RuntimeDebug, Saturating,
+	ArithmeticError, DispatchResult, Perbill, RuntimeDebug, Saturating, TryRuntimeError,
 };
 use sp_staking::{
 	delegation::{DelegationInterface, StakingDelegationSupport},
@@ -173,7 +173,7 @@ pub mod pallet {
 	// }
 
 	#[pallet::event]
-	#[pallet::generate_deposit(pub(super) fn deposit_event)]
+	#[pallet::generate_deposit(pub (super) fn deposit_event)]
 	pub enum Event<T: Config> {
 		Delegated { delegate: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
 		Withdrawn { delegate: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
@@ -339,6 +339,16 @@ pub mod pallet {
 			Ok(())
 		}
 	}
+
+	#[pallet::hooks]
+	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
+		#[cfg(feature = "try-runtime")]
+		fn try_state(_n: BlockNumberFor<T>) -> Result<(), TryRuntimeError> {
+			Self::do_try_state()
+		}
+
+		fn integrity_test() {}
+	}
 }
 
 impl<T: Config> Pallet<T> {
@@ -450,7 +460,7 @@ impl<T: Config> Pallet<T> {
 
 		ledger.total_delegated = ledger
 			.total_delegated
-			.checked_add(&new_delegation_amount)
+			.checked_add(&amount)
 			.ok_or(ArithmeticError::Overflow)?;
 		ledger.save(delegate);
 
@@ -610,9 +620,65 @@ impl<T: Config> Pallet<T> {
 	}
 }
 
+#[cfg(any(test, feature = "try-runtime"))]
+use sp_std::collections::btree_map::BTreeMap;
 #[cfg(any(test, feature = "try-runtime"))]
 impl<T: Config> Pallet<T> {
-	pub(crate) fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> {
+	pub(crate) fn do_try_state() -> Result<(), TryRuntimeError> {
+
+		// build map to avoid reading storage multiple times.
+		let delegation_map = Delegators::<T>::iter().collect::<BTreeMap<_, _>>();
+		let ledger_map = Delegates::<T>::iter().collect::<BTreeMap<_, _>>();
+
+		Self::check_delegates(ledger_map.clone())?;
+		Self::check_delegators(delegation_map, ledger_map)?;
+
+		Ok(())
+	}
+
+	fn check_delegates(
+		ledgers: BTreeMap<T::AccountId, DelegationLedger<T>>,
+	) -> Result<(), TryRuntimeError> {
+		for (delegate, ledger) in ledgers {
+			ensure!(
+				matches!(
+					T::CoreStaking::status(&delegate).expect("delegate should be bonded"),
+					StakerStatus::Nominator(_) | StakerStatus::Idle
+				),
+				"delegate should be bonded and not validator"
+			);
+
+			ensure!(
+				ledger.stakeable_balance() >=
+					T::CoreStaking::total_stake(&delegate)
+						.expect("delegate should exist as a nominator"),
+				"all delegated balance is staked"
+			);
+		}
+
+		Ok(())
+	}
+
+	fn check_delegators(
+		delegations: BTreeMap<T::AccountId, Delegation<T>>,
+		ledger: BTreeMap<T::AccountId, DelegationLedger<T>>,
+	) -> Result<(), TryRuntimeError> {
+		let mut delegation_aggregation = BTreeMap::<T::AccountId, BalanceOf<T>>::new();
+		delegations.iter().for_each(|(delegator, delegation)| {
+			delegation_aggregation
+				.entry(delegation.delegate.clone())
+				.and_modify(|e| *e += delegation.amount)
+				.or_insert(delegation.amount);
+		});
+
+        for (delegate, total_delegated) in delegation_aggregation {
+            let ledger = ledger.get(&delegate).expect("ledger should exist");
+            ensure!(
+                ledger.total_delegated == total_delegated,
+                "ledger total delegated should match delegations"
+            );
+        }
+
 		Ok(())
 	}
 }
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index 05de7ad21274d..1a90d762dcfd0 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -31,7 +31,7 @@ pub(crate) enum AccountType {
 	ProxyDelegator,
 }
 
-#[derive(Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
+#[derive(Default, Encode, Clone, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
 #[scale_info(skip_type_params(T))]
 pub struct Delegation<T: Config> {
 	/// The target of delegation.

From f0cbafe0ead3950400f61adfecaa0eef0932f464 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 22 Feb 2024 10:48:25 +0100
Subject: [PATCH 125/202] claim reward incomplete

---
 substrate/frame/delegated-staking/src/tests.rs | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 5f07e337460e5..f800adbcd57d9 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -687,7 +687,21 @@ mod pool_integration {
 
 	#[test]
 	fn claim_pool_rewards() {
-		ExtBuilder::default().build_and_execute(|| {});
+		ExtBuilder::default().build_and_execute(|| {
+			let pool_id = create_pool(100, 200);
+			add_delegators(pool_id, 100, (300..310).collect(), 100);
+			add_delegators(pool_id, 100, (310..320).collect(), 200);
+
+			// distribute rewards
+
+			// claim rewards
+			for i in 300..320 {
+				let pre_balance = Balances::free_balance(i);
+				assert_ok!(Pools::claim_payout(RawOrigin::Signed(i).into()));
+				assert!(Balances::free_balance(i) >= pre_balance);
+				println!("reward for {}: {}", i, Balances::free_balance(i) - pre_balance);
+			}
+		});
 	}
 
 	#[test]

From 8a83abdf09d084f786807db50f45de371a70a9a3 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 22 Feb 2024 11:37:33 +0100
Subject: [PATCH 126/202] more checks in try state. Some old test fails, to be
 fixed

---
 substrate/frame/delegated-staking/src/lib.rs  |  9 +++-
 .../frame/delegated-staking/src/tests.rs      | 52 ++++++++++++++-----
 2 files changed, 47 insertions(+), 14 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 4a60f254a72e7..7277dde6690b2 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -664,14 +664,19 @@ impl<T: Config> Pallet<T> {
 		ledger: BTreeMap<T::AccountId, DelegationLedger<T>>,
 	) -> Result<(), TryRuntimeError> {
 		let mut delegation_aggregation = BTreeMap::<T::AccountId, BalanceOf<T>>::new();
-		delegations.iter().for_each(|(delegator, delegation)| {
+		for (delegator, delegation) in delegations.iter() {
+			ensure!(T::CoreStaking::status(delegator).is_err(), "delegator should not be directly staked");
+			ensure!(!Self::is_delegate(delegator), "delegator cannot be delegate");
+
 			delegation_aggregation
 				.entry(delegation.delegate.clone())
 				.and_modify(|e| *e += delegation.amount)
 				.or_insert(delegation.amount);
-		});
+		}
 
         for (delegate, total_delegated) in delegation_aggregation {
+			ensure!(!Self::is_delegator(&delegate), "delegate cannot be delegator");
+
             let ledger = ledger.get(&delegate).expect("ledger should exist");
             ensure!(
                 ledger.total_delegated == total_delegated,
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index f800adbcd57d9..9cf4ddbd4f1be 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -588,8 +588,10 @@ mod staking_integration {
 }
 
 mod pool_integration {
-	use pallet_nomination_pools::BondExtra;
 	use super::*;
+	use pallet_nomination_pools::BondExtra;
+	use sp_runtime::print;
+
 	#[test]
 	fn create_pool_test() {
 		ExtBuilder::default().build_and_execute(|| {
@@ -672,13 +674,16 @@ mod pool_integration {
 	fn bond_extra_to_pool() {
 		ExtBuilder::default().build_and_execute(|| {
 			let pool_id = create_pool(100, 200);
-			add_delegators(pool_id, 100, (300..310).collect(), 100);
+			add_delegators(pool_id, (300..310).collect(), 100);
 			let mut staked_amount = 200 + 100 * 10;
 			assert_eq!(get_pool_delegate(pool_id).bonded_stake(), staked_amount);
 
 			// bond extra to pool
 			for i in 300..310 {
-				assert_ok!(Pools::bond_extra(RawOrigin::Signed(i).into(), BondExtra::FreeBalance(50)));
+				assert_ok!(Pools::bond_extra(
+					RawOrigin::Signed(i).into(),
+					BondExtra::FreeBalance(50)
+				));
 				staked_amount += 50;
 				assert_eq!(get_pool_delegate(pool_id).bonded_stake(), staked_amount);
 			}
@@ -688,19 +693,38 @@ mod pool_integration {
 	#[test]
 	fn claim_pool_rewards() {
 		ExtBuilder::default().build_and_execute(|| {
-			let pool_id = create_pool(100, 200);
-			add_delegators(pool_id, 100, (300..310).collect(), 100);
-			add_delegators(pool_id, 100, (310..320).collect(), 200);
-
-			// distribute rewards
+            let creator = 100;
+            let creator_stake = 1000;
+			let pool_id = create_pool(creator, creator_stake);
+			add_delegators(pool_id, (300..310).collect(), 100);
+			add_delegators(pool_id, (310..320).collect(), 200);
+			let total_staked = creator_stake + 100 * 10 + 200 * 10;
+
+			// give some rewards
+			let reward_acc = Pools::create_reward_account(pool_id);
+            let reward_amount = 1000;
+			fund(&reward_acc, reward_amount);
 
 			// claim rewards
 			for i in 300..320 {
 				let pre_balance = Balances::free_balance(i);
+				let delegator_staked_balance = held_balance(&i);
+				// payout reward
 				assert_ok!(Pools::claim_payout(RawOrigin::Signed(i).into()));
-				assert!(Balances::free_balance(i) >= pre_balance);
-				println!("reward for {}: {}", i, Balances::free_balance(i) - pre_balance);
+
+				let reward = Balances::free_balance(i) - pre_balance;
+				assert_eq!(reward, delegator_staked_balance * reward_amount/total_staked);
 			}
+
+            // payout creator
+            let pre_balance = Balances::free_balance(creator);
+            assert_ok!(Pools::claim_payout(RawOrigin::Signed(creator).into()));
+            // verify they are paid out correctly
+            let reward = Balances::free_balance(creator) - pre_balance;
+            assert_eq!(reward, creator_stake * reward_amount/total_staked);
+
+            // reward account should only have left minimum balance after paying out everyone.
+			assert_eq!(Balances::free_balance(reward_acc), ExistentialDeposit::get());
 		});
 	}
 
@@ -757,10 +781,14 @@ mod pool_integration {
 		pallet_nomination_pools::LastPoolId::<T>::get()
 	}
 
-	fn add_delegators(pool_id: u32, creator: AccountId, delegators: Vec<AccountId>, amount: Balance) {
+	fn add_delegators(
+		pool_id: u32,
+		delegators: Vec<AccountId>,
+		amount: Balance,
+	) {
 		for delegator in delegators {
 			fund(&delegator, amount * 2);
-			assert_ok!(Pools::join(RawOrigin::Signed(delegator).into(), creator, pool_id));
+			assert_ok!(Pools::join(RawOrigin::Signed(delegator).into(), amount, pool_id));
 		}
 	}
 

From bf6916b12be7fac5aa72a62be28cc6baf6b2101c Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 22 Feb 2024 11:37:57 +0100
Subject: [PATCH 127/202] fmt

---
 substrate/frame/delegated-staking/src/lib.rs  | 26 ++++++++---------
 .../frame/delegated-staking/src/tests.rs      | 28 ++++++++-----------
 2 files changed, 25 insertions(+), 29 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 7277dde6690b2..1d96de51ffd80 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -458,10 +458,8 @@ impl<T: Config> Pallet<T> {
 
 		Delegation::<T>::from(delegate, new_delegation_amount).save(delegator);
 
-		ledger.total_delegated = ledger
-			.total_delegated
-			.checked_add(&amount)
-			.ok_or(ArithmeticError::Overflow)?;
+		ledger.total_delegated =
+			ledger.total_delegated.checked_add(&amount).ok_or(ArithmeticError::Overflow)?;
 		ledger.save(delegate);
 
 		T::Currency::hold(&HoldReason::Delegating.into(), delegator, amount)?;
@@ -625,7 +623,6 @@ use sp_std::collections::btree_map::BTreeMap;
 #[cfg(any(test, feature = "try-runtime"))]
 impl<T: Config> Pallet<T> {
 	pub(crate) fn do_try_state() -> Result<(), TryRuntimeError> {
-
 		// build map to avoid reading storage multiple times.
 		let delegation_map = Delegators::<T>::iter().collect::<BTreeMap<_, _>>();
 		let ledger_map = Delegates::<T>::iter().collect::<BTreeMap<_, _>>();
@@ -665,7 +662,10 @@ impl<T: Config> Pallet<T> {
 	) -> Result<(), TryRuntimeError> {
 		let mut delegation_aggregation = BTreeMap::<T::AccountId, BalanceOf<T>>::new();
 		for (delegator, delegation) in delegations.iter() {
-			ensure!(T::CoreStaking::status(delegator).is_err(), "delegator should not be directly staked");
+			ensure!(
+				T::CoreStaking::status(delegator).is_err(),
+				"delegator should not be directly staked"
+			);
 			ensure!(!Self::is_delegate(delegator), "delegator cannot be delegate");
 
 			delegation_aggregation
@@ -674,15 +674,15 @@ impl<T: Config> Pallet<T> {
 				.or_insert(delegation.amount);
 		}
 
-        for (delegate, total_delegated) in delegation_aggregation {
+		for (delegate, total_delegated) in delegation_aggregation {
 			ensure!(!Self::is_delegator(&delegate), "delegate cannot be delegator");
 
-            let ledger = ledger.get(&delegate).expect("ledger should exist");
-            ensure!(
-                ledger.total_delegated == total_delegated,
-                "ledger total delegated should match delegations"
-            );
-        }
+			let ledger = ledger.get(&delegate).expect("ledger should exist");
+			ensure!(
+				ledger.total_delegated == total_delegated,
+				"ledger total delegated should match delegations"
+			);
+		}
 
 		Ok(())
 	}
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 9cf4ddbd4f1be..cbcf502c916bc 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -693,8 +693,8 @@ mod pool_integration {
 	#[test]
 	fn claim_pool_rewards() {
 		ExtBuilder::default().build_and_execute(|| {
-            let creator = 100;
-            let creator_stake = 1000;
+			let creator = 100;
+			let creator_stake = 1000;
 			let pool_id = create_pool(creator, creator_stake);
 			add_delegators(pool_id, (300..310).collect(), 100);
 			add_delegators(pool_id, (310..320).collect(), 200);
@@ -702,7 +702,7 @@ mod pool_integration {
 
 			// give some rewards
 			let reward_acc = Pools::create_reward_account(pool_id);
-            let reward_amount = 1000;
+			let reward_amount = 1000;
 			fund(&reward_acc, reward_amount);
 
 			// claim rewards
@@ -713,17 +713,17 @@ mod pool_integration {
 				assert_ok!(Pools::claim_payout(RawOrigin::Signed(i).into()));
 
 				let reward = Balances::free_balance(i) - pre_balance;
-				assert_eq!(reward, delegator_staked_balance * reward_amount/total_staked);
+				assert_eq!(reward, delegator_staked_balance * reward_amount / total_staked);
 			}
 
-            // payout creator
-            let pre_balance = Balances::free_balance(creator);
-            assert_ok!(Pools::claim_payout(RawOrigin::Signed(creator).into()));
-            // verify they are paid out correctly
-            let reward = Balances::free_balance(creator) - pre_balance;
-            assert_eq!(reward, creator_stake * reward_amount/total_staked);
+			// payout creator
+			let pre_balance = Balances::free_balance(creator);
+			assert_ok!(Pools::claim_payout(RawOrigin::Signed(creator).into()));
+			// verify they are paid out correctly
+			let reward = Balances::free_balance(creator) - pre_balance;
+			assert_eq!(reward, creator_stake * reward_amount / total_staked);
 
-            // reward account should only have left minimum balance after paying out everyone.
+			// reward account should only have left minimum balance after paying out everyone.
 			assert_eq!(Balances::free_balance(reward_acc), ExistentialDeposit::get());
 		});
 	}
@@ -781,11 +781,7 @@ mod pool_integration {
 		pallet_nomination_pools::LastPoolId::<T>::get()
 	}
 
-	fn add_delegators(
-		pool_id: u32,
-		delegators: Vec<AccountId>,
-		amount: Balance,
-	) {
+	fn add_delegators(pool_id: u32, delegators: Vec<AccountId>, amount: Balance) {
 		for delegator in delegators {
 			fund(&delegator, amount * 2);
 			assert_ok!(Pools::join(RawOrigin::Signed(delegator).into(), amount, pool_id));

From bdc8c28993536d6409e2c9b840ad9ac03614f5c3 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 22 Feb 2024 11:39:46 +0100
Subject: [PATCH 128/202] remove unused fn

---
 substrate/frame/delegated-staking/src/mock.rs | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 26a3556e9f6e0..cef5d375aa847 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -325,11 +325,6 @@ pub(crate) fn eq_stake(who: AccountId, total: Balance, active: Balance) -> bool
 	Staking::stake(&who).unwrap() == Stake { total, active }
 }
 
-pub(crate) fn delegate_bonded(delegate: &AccountId) -> bool {
-	let delegate = Delegate::<T>::from(delegate).expect("delegate should exist");
-	delegate.is_bonded()
-}
-
 pub(crate) fn get_delegate(delegate: &AccountId) -> Delegate<T> {
 	Delegate::<T>::from(delegate).expect("delegate should exist")
 }

From 6edaf752d198865094e4831dc1c0527eac877e59 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 22 Feb 2024 12:30:19 +0100
Subject: [PATCH 129/202] fix tests

---
 .../frame/delegated-staking/src/impls.rs      | 10 +----
 substrate/frame/delegated-staking/src/lib.rs  |  5 ++-
 substrate/frame/delegated-staking/src/mock.rs |  5 ---
 .../frame/delegated-staking/src/tests.rs      | 37 ++++++-------------
 4 files changed, 16 insertions(+), 41 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 21aa212a22e90..c7d7f8cb12ed1 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -324,10 +324,7 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 			RawOrigin::Signed(who.clone()).into(),
 			pool_account.clone(),
 			amount,
-		)?;
-
-		// Bond the funds to staking.
-		Pallet::<T>::bond(pool_account, amount, reward_account)
+		)
 	}
 
 	fn delegate_extra(
@@ -339,10 +336,7 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 			RawOrigin::Signed(who.clone()).into(),
 			pool_account.clone(),
 			amount,
-		)?;
-
-		// Bond the funds to staking.
-		Pallet::<T>::bond_extra(pool_account, amount)
+		)
 	}
 
 	fn release_delegation(
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 1d96de51ffd80..9486313537e47 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -293,7 +293,7 @@ pub mod pallet {
 			Self::do_migrate_delegation(&proxy_delegator, &delegator, amount)
 		}
 
-		/// Delegate funds to a `Delegate` account.
+		/// Delegate funds to a `Delegate` account and bonds it to [T::CoreStaking].
 		///
 		/// If delegation already exists, it increases the delegation by `amount`.
 		#[pallet::call_index(4)]
@@ -322,7 +322,8 @@ pub mod pallet {
 				T::Currency::reducible_balance(&who, Preservation::Preserve, Fortitude::Polite);
 			ensure!(delegator_balance >= amount, Error::<T>::NotEnoughFunds);
 
-			Self::do_delegate(&who, &delegate, amount)
+			Self::do_delegate(&who, &delegate, amount)?;
+			Self::do_bond(&delegate, amount)
 		}
 
 		/// Stop accepting new delegation.
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index cef5d375aa847..2a8fd49d38eb7 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -303,11 +303,6 @@ pub(crate) fn setup_delegation_stake(
 			delegate,
 			amount_to_delegate
 		));
-		if index == 0 {
-			assert_ok!(DelegatedStaking::bond(&delegate, amount_to_delegate, &reward_acc));
-		} else {
-			assert_ok!(DelegatedStaking::bond_extra(&delegate, amount_to_delegate));
-		}
 	}
 
 	// sanity checks
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index cbcf502c916bc..79a8d948973ec 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -238,18 +238,11 @@ mod staking_integration {
 					100
 				);
 
-				assert_eq!(DelegatedStaking::stakeable_balance(&delegate), delegated_balance);
-
-				// unbonded balance is the newly delegated 100
-				assert_eq!(get_delegate(&delegate).available_to_bond(), 100);
-				if get_delegate(&delegate).is_bonded() {
-					assert_ok!(DelegatedStaking::bond_extra(&delegate, 100));
-				} else {
-					assert_ok!(DelegatedStaking::bond(&delegate, 100, &reward_acc));
-				}
-
-				// after bond, unbonded balance is 0
-				assert_eq!(get_delegate(&delegate).available_to_bond(), 0);
+				let delegate_obj = get_delegate(&delegate);
+				assert_eq!(delegate_obj.ledger.stakeable_balance(), delegated_balance);
+				assert_eq!(delegate_obj.available_to_bond(), 0);
+				assert_eq!(delegate_obj.available_to_bond(), 0);
+				assert_eq!(delegate_obj.bonded_stake(), delegated_balance);
 			}
 
 			assert_eq!(
@@ -404,20 +397,22 @@ mod staking_integration {
 			// if delegate calls Staking pallet directly with a different reward destination, it
 			// fails.
 			assert_noop!(
-				Staking::bond(RuntimeOrigin::signed(200), 100, RewardDestination::Stash),
+				Staking::set_payee(RuntimeOrigin::signed(200), RewardDestination::Stash),
 				StakingError::<T>::RewardDestinationRestricted
 			);
+
 			// non stash account different than one passed to DelegatedStaking also does not work..
 			assert_noop!(
-				Staking::bond(RuntimeOrigin::signed(200), 100, RewardDestination::Account(202)),
+				Staking::set_payee(RuntimeOrigin::signed(200), RewardDestination::Account(202)),
 				StakingError::<T>::RewardDestinationRestricted
 			);
+
 			// passing correct reward destination works
-			assert_ok!(Staking::bond(
+			assert_ok!(Staking::set_payee(
 				RuntimeOrigin::signed(200),
-				100,
 				RewardDestination::Account(201)
 			));
+
 			// amount is staked correctly
 			assert!(eq_stake(200, 100, 100));
 			assert_eq!(get_delegate(&200).available_to_bond(), 0);
@@ -425,16 +420,6 @@ mod staking_integration {
 
 			// free balance of delegate is untouched
 			assert_eq!(Balances::free_balance(200), balance_200);
-
-			// trying to change reward destination later directly via staking does not work.
-			assert_noop!(
-				Staking::set_payee(RuntimeOrigin::signed(200), RewardDestination::Staked),
-				StakingError::<T>::RewardDestinationRestricted
-			);
-			assert_noop!(
-				Staking::set_payee(RuntimeOrigin::signed(200), RewardDestination::Account(300)),
-				StakingError::<T>::RewardDestinationRestricted
-			);
 		});
 	}
 

From 74ec97d5602ca7b5ef08e24a2946b7f3e6941309 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 23 Feb 2024 13:43:00 +0100
Subject: [PATCH 130/202] withdraw test passes

---
 .../frame/delegated-staking/src/impls.rs      | 16 ++--
 substrate/frame/delegated-staking/src/lib.rs  |  4 +-
 substrate/frame/delegated-staking/src/mock.rs | 30 +++++-
 .../frame/delegated-staking/src/tests.rs      | 95 ++++++++++++++++++-
 .../frame/nomination-pools/src/adapter.rs     |  9 +-
 substrate/frame/nomination-pools/src/lib.rs   |  9 +-
 .../primitives/staking/src/delegation.rs      |  4 +-
 7 files changed, 139 insertions(+), 28 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index c7d7f8cb12ed1..9edb59b2d9199 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -123,15 +123,15 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		T::CoreStaking::unbond(stash, value)
 	}
 
-	/// Not supported, call [`DelegationInterface::delegate_withdraw`]
-	/// FIXME(ank4n): Support it!!
+	/// Withdraw unbonding funds until current era.
+	///
+	/// Funds are moved to unclaimed_withdrawals register of the [`DelegationLedger`].
 	fn withdraw_unbonded(
-		_stash: Self::AccountId,
-		_num_slashing_spans: u32,
+		pool_acc: Self::AccountId,
+		num_slashing_spans: u32,
 	) -> Result<bool, DispatchError> {
-		// FIXME(ank4n): Support withdrawing to self account.
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
-		Err(Error::<T>::NotSupported.into())
+		Pallet::<T>::withdraw_unbonded(&pool_acc, num_slashing_spans)
+			.map(|ledger| ledger.total_delegated.is_zero())
 	}
 
 	fn desired_validator_count() -> u32 {
@@ -289,7 +289,7 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 	/// Return balance of the `Delegate` (pool account) that is not bonded.
 	///
 	/// Equivalent to [FunInspect::balance] for non delegate accounts.
-	fn balance(who: &Self::AccountId) -> Self::Balance {
+	fn releasable_balance(who: &Self::AccountId) -> Self::Balance {
 		Delegate::<T>::from(who)
 			.map(|delegate| delegate.unbonded())
 			.unwrap_or(Zero::zero())
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 9486313537e47..67a41fa878195 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -489,7 +489,7 @@ impl<T: Config> Pallet<T> {
 
 		// if we do not already have enough funds to be claimed, try withdraw some more.
 		if ledger.unclaimed_withdrawals < amount {
-			ledger = Self::withdraw_unbounded(who, num_slashing_spans)?;
+			ledger = Self::withdraw_unbonded(who, num_slashing_spans)?;
 		}
 
 		// if we still do not have enough funds to release, abort.
@@ -537,7 +537,7 @@ impl<T: Config> Pallet<T> {
 		Ok(())
 	}
 
-	fn withdraw_unbounded(
+	fn withdraw_unbonded(
 		delegate: &T::AccountId,
 		num_slashing_spans: u32,
 	) -> Result<DelegationLedger<T>, DispatchError> {
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 2a8fd49d38eb7..f3bdfe0b16425 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -317,7 +317,8 @@ pub(crate) fn start_era(era: sp_staking::EraIndex) {
 }
 
 pub(crate) fn eq_stake(who: AccountId, total: Balance, active: Balance) -> bool {
-	Staking::stake(&who).unwrap() == Stake { total, active }
+	Staking::stake(&who).unwrap() == Stake { total, active } &&
+		get_delegate(&who).ledger.stakeable_balance() == total
 }
 
 pub(crate) fn get_delegate(delegate: &AccountId) -> Delegate<T> {
@@ -327,3 +328,30 @@ pub(crate) fn get_delegate(delegate: &AccountId) -> Delegate<T> {
 pub(crate) fn held_balance(who: &AccountId) -> Balance {
 	Balances::balance_on_hold(&HoldReason::Delegating.into(), &who)
 }
+
+parameter_types! {
+	static ObservedEventsPools: usize = 0;
+	static ObservedEventsDelegatedStaking: usize = 0;
+}
+
+pub(crate) fn pool_events_since_last_call() -> Vec<pallet_nomination_pools::Event<Runtime>> {
+	let events = System::events()
+		.into_iter()
+		.map(|r| r.event)
+		.filter_map(|e| if let RuntimeEvent::Pools(inner) = e { Some(inner) } else { None })
+		.collect::<Vec<_>>();
+	let already_seen = ObservedEventsPools::get();
+	ObservedEventsPools::set(events.len());
+	events.into_iter().skip(already_seen).collect()
+}
+
+pub(crate) fn events_since_last_call() -> Vec<crate::Event<Runtime>> {
+	let events = System::events()
+		.into_iter()
+		.map(|r| r.event)
+		.filter_map(|e| if let RuntimeEvent::DelegatedStaking(inner) = e { Some(inner) } else { None })
+		.collect::<Vec<_>>();
+	let already_seen = ObservedEventsDelegatedStaking::get();
+	ObservedEventsDelegatedStaking::set(events.len());
+	events.into_iter().skip(already_seen).collect()
+}
\ No newline at end of file
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 79a8d948973ec..8e7bc36f2a89b 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -20,6 +20,7 @@
 use super::*;
 use crate::mock::*;
 use frame_support::{assert_noop, assert_ok, traits::fungible::InspectHold};
+use pallet_nomination_pools::{Error as PoolsError, Event as PoolsEvent};
 use pallet_staking::Error as StakingError;
 use sp_staking::delegation::StakingDelegationSupport;
 
@@ -659,7 +660,7 @@ mod pool_integration {
 	fn bond_extra_to_pool() {
 		ExtBuilder::default().build_and_execute(|| {
 			let pool_id = create_pool(100, 200);
-			add_delegators(pool_id, (300..310).collect(), 100);
+			add_delegators_to_pool(pool_id, (300..310).collect(), 100);
 			let mut staked_amount = 200 + 100 * 10;
 			assert_eq!(get_pool_delegate(pool_id).bonded_stake(), staked_amount);
 
@@ -681,8 +682,8 @@ mod pool_integration {
 			let creator = 100;
 			let creator_stake = 1000;
 			let pool_id = create_pool(creator, creator_stake);
-			add_delegators(pool_id, (300..310).collect(), 100);
-			add_delegators(pool_id, (310..320).collect(), 200);
+			add_delegators_to_pool(pool_id, (300..310).collect(), 100);
+			add_delegators_to_pool(pool_id, (310..320).collect(), 200);
 			let total_staked = creator_stake + 100 * 10 + 200 * 10;
 
 			// give some rewards
@@ -715,7 +716,91 @@ mod pool_integration {
 
 	#[test]
 	fn unbond_delegation_from_pool() {
-		ExtBuilder::default().build_and_execute(|| {});
+		ExtBuilder::default().build_and_execute(|| {
+			// initial era
+			start_era(1);
+
+			let pool_id = create_pool(100, 1000);
+			let bond_amount = 200;
+			add_delegators_to_pool(pool_id, (300..310).collect(), bond_amount);
+			let total_staked = 1000 + bond_amount * 10;
+			let pool_acc = Pools::create_bonded_account(pool_id);
+
+			start_era(2);
+			// nothing to release yet.
+			assert_noop!(
+				Pools::withdraw_unbonded(RawOrigin::Signed(301).into(), 301, 0),
+				PoolsError::<T>::SubPoolsNotFound
+			);
+
+			// 301 wants to unbond 50 in era 2, withdrawable in era 5.
+			assert_ok!(Pools::unbond(RawOrigin::Signed(301).into(), 301, 50));
+
+			// 302 wants to unbond 100 in era 3, withdrawable in era 6.
+			start_era(3);
+			assert_ok!(Pools::unbond(RawOrigin::Signed(302).into(), 302, 100));
+
+			// 303 wants to unbond 200 in era 4, withdrawable in era 7.
+			start_era(4);
+			assert_ok!(Pools::unbond(RawOrigin::Signed(303).into(), 303, 200));
+
+			// active stake is now reduced..
+			let expected_active = total_staked - (50 + 100 + 200);
+			assert!(eq_stake(pool_acc, total_staked, expected_active));
+
+			// nothing to withdraw at era 4
+			for i in 301..310 {
+				assert_noop!(
+					Pools::withdraw_unbonded(RawOrigin::Signed(i).into(), i, 0),
+					PoolsError::<T>::CannotWithdrawAny
+				);
+			}
+
+			assert!(eq_stake(pool_acc, total_staked, expected_active));
+
+			start_era(5);
+			// at era 5, 301 can withdraw.
+
+			System::reset_events();
+			let held_301 = held_balance(&301);
+			let free_301 = Balances::free_balance(301);
+
+			assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(301).into(), 301, 0));
+			assert_eq!(
+				events_since_last_call(),
+				vec![Event::Withdrawn { delegate: pool_acc, delegator: 301, amount: 50 },]
+			);
+			assert_eq!(
+				pool_events_since_last_call(),
+				vec![PoolsEvent::Withdrawn { member: 301, pool_id, balance: 50, points: 50 },]
+			);
+			assert_eq!(held_balance(&301), held_301 - 50);
+			assert_eq!(Balances::free_balance(301), free_301 + 50);
+
+			start_era(7);
+			// era 7 both delegators can withdraw
+			assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(302).into(), 302, 0));
+			assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(303).into(), 303, 0));
+
+			assert_eq!(
+				events_since_last_call(),
+				vec![
+					Event::Withdrawn { delegate: pool_acc, delegator: 302, amount: 100 },
+					Event::Withdrawn { delegate: pool_acc, delegator: 303, amount: 200 },
+				]
+			);
+			assert_eq!(
+				pool_events_since_last_call(),
+				vec![
+					PoolsEvent::Withdrawn { member: 302, pool_id, balance: 100, points: 100 },
+					PoolsEvent::Withdrawn { member: 303, pool_id, balance: 200, points: 200 },
+					PoolsEvent::MemberRemoved { pool_id: 1, member: 303 },
+				]
+			);
+
+			// 303 is killed
+			assert!(!Delegators::<T>::contains_key(303));
+		});
 	}
 
 	#[test]
@@ -766,7 +851,7 @@ mod pool_integration {
 		pallet_nomination_pools::LastPoolId::<T>::get()
 	}
 
-	fn add_delegators(pool_id: u32, delegators: Vec<AccountId>, amount: Balance) {
+	fn add_delegators_to_pool(pool_id: u32, delegators: Vec<AccountId>, amount: Balance) {
 		for delegator in delegators {
 			fund(&delegator, amount * 2);
 			assert_ok!(Pools::join(RawOrigin::Signed(delegator).into(), amount, pool_id));
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index bc33e32f80f2f..3208576d2eeec 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -27,8 +27,13 @@ impl<T: Config> PoolAdapter for NoDelegation<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
-	fn balance(who: &Self::AccountId) -> Self::Balance {
-		T::Currency::balance(who)
+	fn releasable_balance(who: &Self::AccountId) -> Self::Balance {
+		// Note on why we can't use `Currency::reducible_balance`: Since pooled account has a
+		// provider (staking pallet), the account can not be set expendable by
+		// `pallet-nomination-pool`. This means reducible balance always returns balance preserving
+		// ED in the account. What we want though is transferable balance given the account can be
+		// dusted.
+		T::Currency::balance(who).saturating_sub(T::Staking::active_stake(who).unwrap_or_default())
 	}
 
 	fn total_balance(who: &Self::AccountId) -> Self::Balance {
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index 579b470514752..08de180e2d8e0 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -1051,14 +1051,7 @@ impl<T: Config> BondedPool<T> {
 
 	/// The pools balance that is transferable provided it is expendable by staking pallet.
 	fn transferable_balance(&self) -> BalanceOf<T> {
-		let account = self.bonded_account();
-		// Note on why we can't use `Currency::reducible_balance`: Since pooled account has a
-		// provider (staking pallet), the account can not be set expendable by
-		// `pallet-nomination-pool`. This means reducible balance always returns balance preserving
-		// ED in the account. What we want though is transferable balance given the account can be
-		// dusted.
-		T::PoolAdapter::balance(&account)
-			.saturating_sub(T::Staking::active_stake(&account).unwrap_or_default())
+		T::PoolAdapter::releasable_balance(&self.bonded_account())
 	}
 
 	fn is_root(&self, who: &T::AccountId) -> bool {
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index e1d1120684fe3..683e89836317a 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -172,8 +172,8 @@ pub trait PoolAdapter {
 		+ Saturating;
 	type AccountId: Clone + sp_std::fmt::Debug;
 
-	/// Similar to [Inspect::balance].
-	fn balance(who: &Self::AccountId) -> Self::Balance;
+	/// Balance that is free and can be released to delegator.
+	fn releasable_balance(who: &Self::AccountId) -> Self::Balance;
 
 	/// Similar to [Inspect::total_balance].
 	fn total_balance(who: &Self::AccountId) -> Self::Balance;

From e33cc202de74aa8692cfb5a9aeb9782ccc86142f Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 23 Feb 2024 13:58:53 +0100
Subject: [PATCH 131/202] withdraw pool works

---
 .../frame/delegated-staking/src/tests.rs      | 38 +++++++++++++++----
 .../frame/delegated-staking/src/types.rs      |  3 +-
 2 files changed, 31 insertions(+), 10 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 8e7bc36f2a89b..c530bad726d55 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -715,7 +715,7 @@ mod pool_integration {
 	}
 
 	#[test]
-	fn unbond_delegation_from_pool() {
+	fn withdraw_from_pool() {
 		ExtBuilder::default().build_and_execute(|| {
 			// initial era
 			start_era(1);
@@ -768,11 +768,11 @@ mod pool_integration {
 			assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(301).into(), 301, 0));
 			assert_eq!(
 				events_since_last_call(),
-				vec![Event::Withdrawn { delegate: pool_acc, delegator: 301, amount: 50 },]
+				vec![Event::Withdrawn { delegate: pool_acc, delegator: 301, amount: 50 }]
 			);
 			assert_eq!(
 				pool_events_since_last_call(),
-				vec![PoolsEvent::Withdrawn { member: 301, pool_id, balance: 50, points: 50 },]
+				vec![PoolsEvent::Withdrawn { member: 301, pool_id, balance: 50, points: 50 }]
 			);
 			assert_eq!(held_balance(&301), held_301 - 50);
 			assert_eq!(Balances::free_balance(301), free_301 + 50);
@@ -805,12 +805,34 @@ mod pool_integration {
 
 	#[test]
 	fn pool_withdraw_unbonded() {
-		ExtBuilder::default().build_and_execute(|| {});
-	}
+		ExtBuilder::default().build_and_execute(|| {
+			// initial era
+			start_era(1);
+			let pool_id = create_pool(100, 1000);
+			add_delegators_to_pool(pool_id, (300..310).collect(), 200);
 
-	#[test]
-	fn delegator_withdraw_unbonded() {
-		ExtBuilder::default().build_and_execute(|| {});
+			start_era(2);
+			// 1000 tokens to be unbonded in era 5.
+			for i in 300..310 {
+				assert_ok!(Pools::unbond(RawOrigin::Signed(i).into(), i, 100));
+			}
+
+			start_era(3);
+			// 500 tokens to be unbonded in era 6.
+			for i in 300..310 {
+				assert_ok!(Pools::unbond(RawOrigin::Signed(i).into(), i, 50));
+			}
+
+			start_era(5);
+			// withdraw pool should withdraw 1000 tokens
+			assert_ok!(Pools::pool_withdraw_unbonded(RawOrigin::Signed(100).into(), pool_id, 0));
+			assert_eq!(get_pool_delegate(pool_id).unbonded(), 1000);
+
+            start_era(6);
+            // should withdraw 500 more
+            assert_ok!(Pools::pool_withdraw_unbonded(RawOrigin::Signed(100).into(), pool_id, 0));
+            assert_eq!(get_pool_delegate(pool_id).unbonded(), 1000 + 500);
+		});
 	}
 
 	#[test]
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index 1a90d762dcfd0..fbc29a08a2dfe 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -23,8 +23,6 @@ use super::*;
 /// The type of pot account being created.
 #[derive(Encode, Decode)]
 pub(crate) enum AccountType {
-	/// Funds that are withdrawn from the staking ledger but not claimed by the `delegator` yet.
-	UnclaimedWithdrawal,
 	/// A proxy delegator account created for a nominator who migrated to a `delegate` account.
 	///
 	/// Funds for unmigrated `delegator` accounts of the `delegate` are kept here.
@@ -96,6 +94,7 @@ pub struct DelegationLedger<T: Config> {
 	#[codec(compact)]
 	pub total_delegated: BalanceOf<T>,
 	/// Funds that are withdrawn from core staking but not released to delegator/s.
+	// FIXME(ank4n): Check/test about rebond: where delegator rebond what is unlocking.
 	#[codec(compact)]
 	pub unclaimed_withdrawals: BalanceOf<T>,
 	/// Slashes that are not yet applied.

From 24e7cf3da80558385d8b3475810c9a5e6401ac06 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 23 Feb 2024 16:40:15 +0100
Subject: [PATCH 132/202] updated tests

---
 substrate/frame/delegated-staking/src/mock.rs |  6 +-
 .../frame/delegated-staking/src/tests.rs      | 59 +++++++++++++++++--
 .../frame/delegated-staking/src/types.rs      | 39 ++++++++++++
 3 files changed, 96 insertions(+), 8 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index f3bdfe0b16425..ca184d344149b 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -349,9 +349,11 @@ pub(crate) fn events_since_last_call() -> Vec<crate::Event<Runtime>> {
 	let events = System::events()
 		.into_iter()
 		.map(|r| r.event)
-		.filter_map(|e| if let RuntimeEvent::DelegatedStaking(inner) = e { Some(inner) } else { None })
+		.filter_map(
+			|e| if let RuntimeEvent::DelegatedStaking(inner) = e { Some(inner) } else { None },
+		)
 		.collect::<Vec<_>>();
 	let already_seen = ObservedEventsDelegatedStaking::get();
 	ObservedEventsDelegatedStaking::set(events.len());
 	events.into_iter().skip(already_seen).collect()
-}
\ No newline at end of file
+}
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index c530bad726d55..77199635743bf 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -575,7 +575,7 @@ mod staking_integration {
 
 mod pool_integration {
 	use super::*;
-	use pallet_nomination_pools::BondExtra;
+	use pallet_nomination_pools::{BondExtra, PoolState};
 	use sp_runtime::print;
 
 	#[test]
@@ -828,21 +828,68 @@ mod pool_integration {
 			assert_ok!(Pools::pool_withdraw_unbonded(RawOrigin::Signed(100).into(), pool_id, 0));
 			assert_eq!(get_pool_delegate(pool_id).unbonded(), 1000);
 
-            start_era(6);
-            // should withdraw 500 more
+			start_era(6);
+			// should withdraw 500 more
+			assert_ok!(Pools::pool_withdraw_unbonded(RawOrigin::Signed(100).into(), pool_id, 0));
+			assert_eq!(get_pool_delegate(pool_id).unbonded(), 1000 + 500);
+
+            start_era(7);
+            // Nothing to withdraw, still at 1500.
             assert_ok!(Pools::pool_withdraw_unbonded(RawOrigin::Signed(100).into(), pool_id, 0));
-            assert_eq!(get_pool_delegate(pool_id).unbonded(), 1000 + 500);
+            assert_eq!(get_pool_delegate(pool_id).unbonded(), 1500);
 		});
 	}
 
 	#[test]
 	fn update_nominations() {
-		ExtBuilder::default().build_and_execute(|| {});
+		ExtBuilder::default().build_and_execute(|| {
+            start_era(1);
+			// can't nominate for non-existent pool
+			assert_noop!(Pools::nominate(RawOrigin::Signed(100).into(), 1, vec![99]), PoolsError::<T>::PoolNotFound);
+
+			let pool_id = create_pool(100, 1000);
+			let pool_acc = Pools::create_bonded_account(pool_id);
+			assert_ok!(Pools::nominate(RawOrigin::Signed(100).into(), 1, vec![20, 21, 22]));
+			assert!(Staking::status(&pool_acc) == Ok(StakerStatus::Nominator(vec![20, 21, 22])));
+
+			start_era(3);
+			assert_ok!(Pools::nominate(RawOrigin::Signed(100).into(), 1, vec![18, 19, 22]));
+			assert!(Staking::status(&pool_acc) == Ok(StakerStatus::Nominator(vec![18, 19, 22])));
+        });
 	}
 
 	#[test]
 	fn destroy_pool() {
-		ExtBuilder::default().build_and_execute(|| {});
+		ExtBuilder::default().build_and_execute(|| {
+			start_era(1);
+			let creator = 100;
+			let pool_id = create_pool(creator, 1000);
+			add_delegators_to_pool(pool_id, (300..310).collect(), 200);
+
+			start_era(3);
+			// lets destroy the pool
+			assert_ok!(Pools::set_state(RawOrigin::Signed(creator).into(), pool_id, PoolState::Destroying));
+			assert_ok!(Pools::chill(RawOrigin::Signed(creator).into(), pool_id));
+
+			// unbond all members by the creator/admin
+			for i in 300..310 {
+				assert_ok!(Pools::unbond(RawOrigin::Signed(creator).into(), i, 200));
+			}
+
+
+			start_era(6);
+			// withdraw all members by the creator/admin
+			for i in 300..310 {
+				assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(creator).into(), i, 0));
+			}
+
+			// unbond creator
+			assert_ok!(Pools::unbond(RawOrigin::Signed(creator).into(), creator, 1000));
+
+			start_era(9);
+			// Withdraw self
+			assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(creator).into(), creator, 0));
+		});
 	}
 
 	#[test]
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index fbc29a08a2dfe..fb889106d4d92 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -146,6 +146,7 @@ impl<T: Config> DelegationLedger<T> {
 	}
 }
 
+#[derive(Clone)]
 pub struct Delegate<T: Config> {
 	pub key: T::AccountId,
 	pub ledger: DelegationLedger<T>,
@@ -157,6 +158,44 @@ impl<T: Config> Delegate<T> {
 		Ok(Delegate { key: delegate.clone(), ledger })
 	}
 
+	pub(crate) fn claim_withdraw(self, amount: BalanceOf<T>) -> Result<Self, DispatchError> {
+		let new_total_delegated = self
+			.ledger
+			.total_delegated
+			.checked_sub(&amount)
+			.defensive_ok_or(ArithmeticError::Overflow)?;
+		let new_unclaimed_withdrawals = self
+			.ledger
+			.unclaimed_withdrawals
+			.checked_sub(&amount)
+			.defensive_ok_or(ArithmeticError::Overflow)?;
+
+		Ok(Delegate {
+			ledger: DelegationLedger {
+				total_delegated: new_total_delegated,
+				unclaimed_withdrawals: new_unclaimed_withdrawals,
+				..self.ledger
+			},
+			..self
+		})
+	}
+
+	pub(crate) fn add_to_unclaimed_withdraw(&mut self, amount: BalanceOf<T>) -> Result<Self, DispatchError> {
+		let new_unclaimed_withdrawals = self
+			.ledger
+			.unclaimed_withdrawals
+			.checked_add(&amount)
+			.defensive_ok_or(ArithmeticError::Overflow)?;
+
+		Ok(Delegate {
+			ledger: DelegationLedger {
+				unclaimed_withdrawals: new_unclaimed_withdrawals,
+				payee: self.ledger.payee.clone(),
+				..self.ledger
+			},
+			..self.clone()
+		})
+	}
 	// re-reads the delegate from database and returns a new instance.
 	pub(crate) fn refresh(&self) -> Result<Delegate<T>, DispatchError> {
 		Self::from(&self.key)

From cc365e798f935eb99d65ada33ffccd528f02c51e Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 23 Feb 2024 16:50:57 +0100
Subject: [PATCH 133/202] update withdraw unbonded signature

---
 .../frame/delegated-staking/src/impls.rs      |  2 +-
 substrate/frame/delegated-staking/src/lib.rs  | 24 +++++++---------
 .../frame/delegated-staking/src/tests.rs      |  3 +-
 .../frame/delegated-staking/src/types.rs      | 28 +++++--------------
 4 files changed, 19 insertions(+), 38 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 9edb59b2d9199..6185c1f0797d5 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -131,7 +131,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		num_slashing_spans: u32,
 	) -> Result<bool, DispatchError> {
 		Pallet::<T>::withdraw_unbonded(&pool_acc, num_slashing_spans)
-			.map(|ledger| ledger.total_delegated.is_zero())
+			.map(|delegate| delegate.ledger.total_delegated.is_zero())
 	}
 
 	fn desired_validator_count() -> u32 {
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 67a41fa878195..a1461dd07032c 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -489,7 +489,7 @@ impl<T: Config> Pallet<T> {
 
 		// if we do not already have enough funds to be claimed, try withdraw some more.
 		if ledger.unclaimed_withdrawals < amount {
-			ledger = Self::withdraw_unbonded(who, num_slashing_spans)?;
+			ledger = Self::withdraw_unbonded(who, num_slashing_spans)?.ledger;
 		}
 
 		// if we still do not have enough funds to release, abort.
@@ -538,31 +538,27 @@ impl<T: Config> Pallet<T> {
 	}
 
 	fn withdraw_unbonded(
-		delegate: &T::AccountId,
+		delegate_acc: &T::AccountId,
 		num_slashing_spans: u32,
-	) -> Result<DelegationLedger<T>, DispatchError> {
-		let mut ledger = DelegationLedger::<T>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-
-		let pre_total = T::CoreStaking::stake(delegate).defensive()?.total;
+	) -> Result<Delegate<T>, DispatchError> {
+		let mut delegate = Delegate::<T>::from(delegate_acc)?;
+		let pre_total = T::CoreStaking::stake(delegate_acc).defensive()?.total;
 
 		// fixme(ank4n) handle killing of stash
 		let _stash_killed: bool =
-			T::CoreStaking::withdraw_unbonded(delegate.clone(), num_slashing_spans)
+			T::CoreStaking::withdraw_unbonded(delegate_acc.clone(), num_slashing_spans)
 				.map_err(|_| Error::<T>::WithdrawFailed)?;
 
-		let post_total = T::CoreStaking::stake(delegate).defensive()?.total;
+		let post_total = T::CoreStaking::stake(delegate_acc).defensive()?.total;
 
 		let new_withdrawn =
 			pre_total.checked_sub(&post_total).defensive_ok_or(Error::<T>::BadState)?;
 
-		ledger.unclaimed_withdrawals = ledger
-			.unclaimed_withdrawals
-			.checked_add(&new_withdrawn)
-			.ok_or(ArithmeticError::Overflow)?;
+		delegate.try_add_unclaimed_withdraw(new_withdrawn)?;
 
-		ledger.clone().save(delegate);
+		delegate.clone().save();
 
-		Ok(ledger)
+		Ok(delegate)
 	}
 
 	/// Migrates delegation of `amount` from `source` account to `destination` account.
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 77199635743bf..9573ba6816004 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -199,7 +199,7 @@ fn delegate_restrictions() {
 
 #[test]
 fn apply_pending_slash() {
-	ExtBuilder::default().build_and_execute(|| todo!());
+	ExtBuilder::default().build_and_execute(|| ());
 }
 
 /// Integration tests with pallet-staking.
@@ -490,7 +490,6 @@ mod staking_integration {
 			start_era(1);
 
 			// delegate is slashed
-			todo!()
 		});
 	}
 
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index fb889106d4d92..bed2e0edf0113 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -158,43 +158,29 @@ impl<T: Config> Delegate<T> {
 		Ok(Delegate { key: delegate.clone(), ledger })
 	}
 
-	pub(crate) fn claim_withdraw(self, amount: BalanceOf<T>) -> Result<Self, DispatchError> {
-		let new_total_delegated = self
+	pub(crate) fn try_withdraw(&mut self, amount: BalanceOf<T>) -> Result<(), DispatchError> {
+		self.ledger.total_delegated = self
 			.ledger
 			.total_delegated
 			.checked_sub(&amount)
 			.defensive_ok_or(ArithmeticError::Overflow)?;
-		let new_unclaimed_withdrawals = self
+		self.ledger.unclaimed_withdrawals = self
 			.ledger
 			.unclaimed_withdrawals
 			.checked_sub(&amount)
 			.defensive_ok_or(ArithmeticError::Overflow)?;
 
-		Ok(Delegate {
-			ledger: DelegationLedger {
-				total_delegated: new_total_delegated,
-				unclaimed_withdrawals: new_unclaimed_withdrawals,
-				..self.ledger
-			},
-			..self
-		})
+		Ok(())
 	}
 
-	pub(crate) fn add_to_unclaimed_withdraw(&mut self, amount: BalanceOf<T>) -> Result<Self, DispatchError> {
-		let new_unclaimed_withdrawals = self
+	pub(crate) fn try_add_unclaimed_withdraw(&mut self, amount: BalanceOf<T>) -> Result<(), DispatchError> {
+		self.ledger.unclaimed_withdrawals = self
 			.ledger
 			.unclaimed_withdrawals
 			.checked_add(&amount)
 			.defensive_ok_or(ArithmeticError::Overflow)?;
 
-		Ok(Delegate {
-			ledger: DelegationLedger {
-				unclaimed_withdrawals: new_unclaimed_withdrawals,
-				payee: self.ledger.payee.clone(),
-				..self.ledger
-			},
-			..self.clone()
-		})
+		Ok(())
 	}
 	// re-reads the delegate from database and returns a new instance.
 	pub(crate) fn refresh(&self) -> Result<Delegate<T>, DispatchError> {

From 83fa01b5a093ed2a290543a112349c10771e9cdf Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 23 Feb 2024 16:54:05 +0100
Subject: [PATCH 134/202] refactored release

---
 substrate/frame/delegated-staking/src/lib.rs | 22 +++++++-------------
 1 file changed, 7 insertions(+), 15 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index a1461dd07032c..5b7182745fc6a 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -480,7 +480,7 @@ impl<T: Config> Pallet<T> {
 		amount: BalanceOf<T>,
 		num_slashing_spans: u32,
 	) -> DispatchResult {
-		let mut ledger = DelegationLedger::<T>::get(who).ok_or(Error::<T>::NotDelegate)?;
+		let mut delegate = Delegate::<T>::from(who)?;
 		let mut delegation = Delegation::<T>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
 
 		// make sure delegation to be released is sound.
@@ -488,24 +488,17 @@ impl<T: Config> Pallet<T> {
 		ensure!(delegation.amount >= amount, Error::<T>::NotEnoughFunds);
 
 		// if we do not already have enough funds to be claimed, try withdraw some more.
-		if ledger.unclaimed_withdrawals < amount {
-			ledger = Self::withdraw_unbonded(who, num_slashing_spans)?.ledger;
+		if delegate.ledger.unclaimed_withdrawals < amount {
+			// get the updated delegate
+			delegate = Self::withdraw_unbonded(who, num_slashing_spans)?;
 		}
 
 		// if we still do not have enough funds to release, abort.
-		ensure!(ledger.unclaimed_withdrawals >= amount, Error::<T>::NotEnoughFunds);
+		ensure!(delegate.ledger.unclaimed_withdrawals >= amount, Error::<T>::NotEnoughFunds);
 
 		// book keep into ledger
-		ledger.total_delegated = ledger
-			.total_delegated
-			.checked_sub(&amount)
-			.defensive_ok_or(ArithmeticError::Overflow)?;
-		ledger.unclaimed_withdrawals = ledger
-			.unclaimed_withdrawals
-			.checked_sub(&amount)
-			.defensive_ok_or(ArithmeticError::Overflow)?;
-		ledger.save(who);
-
+		delegate.try_withdraw(amount)?;
+		delegate.save();
 		// book keep delegation
 		delegation.amount = delegation
 			.amount
@@ -544,7 +537,6 @@ impl<T: Config> Pallet<T> {
 		let mut delegate = Delegate::<T>::from(delegate_acc)?;
 		let pre_total = T::CoreStaking::stake(delegate_acc).defensive()?.total;
 
-		// fixme(ank4n) handle killing of stash
 		let _stash_killed: bool =
 			T::CoreStaking::withdraw_unbonded(delegate_acc.clone(), num_slashing_spans)
 				.map_err(|_| Error::<T>::WithdrawFailed)?;

From e953cc32a8dfd6e48ee92865c4f43e656ccd3272 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 23 Feb 2024 16:57:47 +0100
Subject: [PATCH 135/202] stash killed managed while withdraw

---
 substrate/frame/delegated-staking/src/lib.rs | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 5b7182745fc6a..69b9e19e471bc 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -537,11 +537,15 @@ impl<T: Config> Pallet<T> {
 		let mut delegate = Delegate::<T>::from(delegate_acc)?;
 		let pre_total = T::CoreStaking::stake(delegate_acc).defensive()?.total;
 
-		let _stash_killed: bool =
+		let stash_killed: bool =
 			T::CoreStaking::withdraw_unbonded(delegate_acc.clone(), num_slashing_spans)
 				.map_err(|_| Error::<T>::WithdrawFailed)?;
 
-		let post_total = T::CoreStaking::stake(delegate_acc).defensive()?.total;
+		let maybe_post_total = T::CoreStaking::stake(delegate_acc);
+		// One of them should be true
+		defensive_assert!(!(stash_killed && maybe_post_total.is_ok()), "something horrible happened while withdrawing");
+
+		let post_total = maybe_post_total.map_or(Zero::zero(), |s| s.total);
 
 		let new_withdrawn =
 			pre_total.checked_sub(&post_total).defensive_ok_or(Error::<T>::BadState)?;

From 8bac693bb840700caf7be56f80de151da20aea1c Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 23 Feb 2024 17:07:25 +0100
Subject: [PATCH 136/202] all test pass

---
 substrate/frame/delegated-staking/src/lib.rs  | 10 ++++++--
 .../frame/delegated-staking/src/tests.rs      | 24 ++++++++++++-------
 .../frame/delegated-staking/src/types.rs      | 22 ++++++++++++++++-
 3 files changed, 44 insertions(+), 12 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 69b9e19e471bc..2aab64109e1c8 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -498,7 +498,10 @@ impl<T: Config> Pallet<T> {
 
 		// book keep into ledger
 		delegate.try_withdraw(amount)?;
-		delegate.save();
+
+		// kill delegate if not delegated and nothing to claim anymore.
+		delegate.save_or_kill()?;
+
 		// book keep delegation
 		delegation.amount = delegation
 			.amount
@@ -543,7 +546,10 @@ impl<T: Config> Pallet<T> {
 
 		let maybe_post_total = T::CoreStaking::stake(delegate_acc);
 		// One of them should be true
-		defensive_assert!(!(stash_killed && maybe_post_total.is_ok()), "something horrible happened while withdrawing");
+		defensive_assert!(
+			!(stash_killed && maybe_post_total.is_ok()),
+			"something horrible happened while withdrawing"
+		);
 
 		let post_total = maybe_post_total.map_or(Zero::zero(), |s| s.total);
 
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 9573ba6816004..45ddbd1dae2af 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -832,19 +832,22 @@ mod pool_integration {
 			assert_ok!(Pools::pool_withdraw_unbonded(RawOrigin::Signed(100).into(), pool_id, 0));
 			assert_eq!(get_pool_delegate(pool_id).unbonded(), 1000 + 500);
 
-            start_era(7);
-            // Nothing to withdraw, still at 1500.
-            assert_ok!(Pools::pool_withdraw_unbonded(RawOrigin::Signed(100).into(), pool_id, 0));
-            assert_eq!(get_pool_delegate(pool_id).unbonded(), 1500);
+			start_era(7);
+			// Nothing to withdraw, still at 1500.
+			assert_ok!(Pools::pool_withdraw_unbonded(RawOrigin::Signed(100).into(), pool_id, 0));
+			assert_eq!(get_pool_delegate(pool_id).unbonded(), 1500);
 		});
 	}
 
 	#[test]
 	fn update_nominations() {
 		ExtBuilder::default().build_and_execute(|| {
-            start_era(1);
+			start_era(1);
 			// can't nominate for non-existent pool
-			assert_noop!(Pools::nominate(RawOrigin::Signed(100).into(), 1, vec![99]), PoolsError::<T>::PoolNotFound);
+			assert_noop!(
+				Pools::nominate(RawOrigin::Signed(100).into(), 1, vec![99]),
+				PoolsError::<T>::PoolNotFound
+			);
 
 			let pool_id = create_pool(100, 1000);
 			let pool_acc = Pools::create_bonded_account(pool_id);
@@ -854,7 +857,7 @@ mod pool_integration {
 			start_era(3);
 			assert_ok!(Pools::nominate(RawOrigin::Signed(100).into(), 1, vec![18, 19, 22]));
 			assert!(Staking::status(&pool_acc) == Ok(StakerStatus::Nominator(vec![18, 19, 22])));
-        });
+		});
 	}
 
 	#[test]
@@ -867,7 +870,11 @@ mod pool_integration {
 
 			start_era(3);
 			// lets destroy the pool
-			assert_ok!(Pools::set_state(RawOrigin::Signed(creator).into(), pool_id, PoolState::Destroying));
+			assert_ok!(Pools::set_state(
+				RawOrigin::Signed(creator).into(),
+				pool_id,
+				PoolState::Destroying
+			));
 			assert_ok!(Pools::chill(RawOrigin::Signed(creator).into(), pool_id));
 
 			// unbond all members by the creator/admin
@@ -875,7 +882,6 @@ mod pool_integration {
 				assert_ok!(Pools::unbond(RawOrigin::Signed(creator).into(), i, 200));
 			}
 
-
 			start_era(6);
 			// withdraw all members by the creator/admin
 			for i in 300..310 {
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index bed2e0edf0113..6d68f4af62f22 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -173,7 +173,10 @@ impl<T: Config> Delegate<T> {
 		Ok(())
 	}
 
-	pub(crate) fn try_add_unclaimed_withdraw(&mut self, amount: BalanceOf<T>) -> Result<(), DispatchError> {
+	pub(crate) fn try_add_unclaimed_withdraw(
+		&mut self,
+		amount: BalanceOf<T>,
+	) -> Result<(), DispatchError> {
 		self.ledger.unclaimed_withdrawals = self
 			.ledger
 			.unclaimed_withdrawals
@@ -235,4 +238,21 @@ impl<T: Config> Delegate<T> {
 		let key = self.key;
 		self.ledger.save(&key)
 	}
+
+	pub(crate) fn save_or_kill(self) -> Result<(), DispatchError> {
+		let key = self.key;
+		// see if delegate can be killed
+		if self.ledger.total_delegated == Zero::zero() {
+			ensure!(
+				self.ledger.unclaimed_withdrawals == Zero::zero() &&
+					self.ledger.pending_slash == Zero::zero(),
+				Error::<T>::BadState
+			);
+			<Delegates<T>>::remove(key);
+		} else {
+			self.ledger.save(&key)
+		}
+
+		Ok(())
+	}
 }

From 9bc3040f6a1df448573aa56c11d7f091e066eea5 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 23 Feb 2024 17:11:48 +0100
Subject: [PATCH 137/202] small test refactor

---
 substrate/frame/delegated-staking/src/tests.rs | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 45ddbd1dae2af..10ae7d0c6f747 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -865,7 +865,8 @@ mod pool_integration {
 		ExtBuilder::default().build_and_execute(|| {
 			start_era(1);
 			let creator = 100;
-			let pool_id = create_pool(creator, 1000);
+			let creator_stake = 1000;
+			let pool_id = create_pool(creator, creator_stake);
 			add_delegators_to_pool(pool_id, (300..310).collect(), 200);
 
 			start_era(3);
@@ -889,11 +890,20 @@ mod pool_integration {
 			}
 
 			// unbond creator
-			assert_ok!(Pools::unbond(RawOrigin::Signed(creator).into(), creator, 1000));
+			assert_ok!(Pools::unbond(RawOrigin::Signed(creator).into(), creator, creator_stake));
 
 			start_era(9);
+			System::reset_events();
 			// Withdraw self
 			assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(creator).into(), creator, 0));
+			assert_eq!(
+				pool_events_since_last_call(),
+				vec![
+					PoolsEvent::Withdrawn { member: creator, pool_id, balance: creator_stake, points: creator_stake },
+					PoolsEvent::MemberRemoved { pool_id, member: creator },
+					PoolsEvent::Destroyed { pool_id },
+				]
+			);
 		});
 	}
 

From f3a3e6284bc5668b158a2672d617fb4681437395 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 23 Feb 2024 19:25:41 +0100
Subject: [PATCH 138/202] slash is posted correctly

---
 substrate/frame/delegated-staking/src/lib.rs  |  4 +-
 substrate/frame/delegated-staking/src/mock.rs |  2 +-
 .../frame/delegated-staking/src/tests.rs      | 66 +++++++++++++++----
 substrate/frame/staking/src/slashing.rs       | 25 ++++---
 4 files changed, 68 insertions(+), 29 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 2aab64109e1c8..c9ae4d7160281 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -644,11 +644,13 @@ impl<T: Config> Pallet<T> {
 				"delegate should be bonded and not validator"
 			);
 
+			println!("stakeable_balance: {:?}", ledger.stakeable_balance());
+			println!("stake: {:?}", T::CoreStaking::stake(&delegate).unwrap());
 			ensure!(
 				ledger.stakeable_balance() >=
 					T::CoreStaking::total_stake(&delegate)
 						.expect("delegate should exist as a nominator"),
-				"all delegated balance is staked"
+				"Cannot stake more than balance"
 			);
 		}
 
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index ca184d344149b..8c5113a5e6b03 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -133,7 +133,7 @@ impl pallet_staking::Config for Runtime {
 	type NominationsQuota = pallet_staking::FixedNominationsQuota<16>;
 	type MaxUnlockingChunks = ConstU32<32>;
 	type MaxControllersInDeprecationBatch = ConstU32<100>;
-	type EventListeners = ();
+	type EventListeners = Pools;
 	type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
 	type WeightInfo = ();
 }
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 10ae7d0c6f747..ea69dbc465ba8 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -574,7 +574,7 @@ mod staking_integration {
 
 mod pool_integration {
 	use super::*;
-	use pallet_nomination_pools::{BondExtra, PoolState};
+	use pallet_nomination_pools::{BondExtra, BondedPools, PoolState};
 	use sp_runtime::print;
 
 	#[test]
@@ -899,7 +899,12 @@ mod pool_integration {
 			assert_eq!(
 				pool_events_since_last_call(),
 				vec![
-					PoolsEvent::Withdrawn { member: creator, pool_id, balance: creator_stake, points: creator_stake },
+					PoolsEvent::Withdrawn {
+						member: creator,
+						pool_id,
+						balance: creator_stake,
+						points: creator_stake,
+					},
 					PoolsEvent::MemberRemoved { pool_id, member: creator },
 					PoolsEvent::Destroyed { pool_id },
 				]
@@ -907,19 +912,54 @@ mod pool_integration {
 		});
 	}
 
-	#[test]
-	fn chill_pool() {
-		ExtBuilder::default().build_and_execute(|| {});
-	}
-
-	#[test]
-	fn claim_commission_pool_operator() {
-		ExtBuilder::default().build_and_execute(|| {});
-	}
-
 	#[test]
 	fn pool_slashed() {
-		ExtBuilder::default().build_and_execute(|| {});
+		ExtBuilder::default().build_and_execute(|| {
+            start_era(1);
+            let creator = 100;
+            let creator_stake = 500;
+            let pool_id = create_pool(creator, creator_stake);
+            let delegator_stake = 100;
+            add_delegators_to_pool(pool_id, (300..306).collect(), delegator_stake);
+            let pool_acc = Pools::create_bonded_account(pool_id);
+
+            let total_staked = creator_stake + delegator_stake * 6;
+            assert_eq!(Staking::stake(&pool_acc).unwrap().total, total_staked);
+
+            // lets unbond a delegator each in next eras (2, 3, 4).
+            start_era(2);
+            assert_ok!(Pools::unbond(RawOrigin::Signed(300).into(), 300, delegator_stake));
+
+            start_era(3);
+            assert_ok!(Pools::unbond(RawOrigin::Signed(301).into(), 301, delegator_stake));
+
+            start_era(4);
+            assert_ok!(Pools::unbond(RawOrigin::Signed(302).into(), 302, delegator_stake));
+            System::reset_events();
+
+            // slash the pool at era 3
+            assert_eq!(BondedPools::<T>::get(1).unwrap().points, creator_stake + delegator_stake * 6 - delegator_stake * 3);
+            pallet_staking::slashing::do_slash::<T>(
+                &pool_acc,
+                500,
+                &mut Default::default(),
+                &mut Default::default(),
+                3,
+            );
+
+            assert_eq!(
+                pool_events_since_last_call(),
+                vec![
+					// 301 did not get slashed as all as it unbonded in an era before slash.
+					// 302 got slashed 50% of 100 = 50.
+					PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 6, balance: 50 },
+					// 303 got slashed 50% of 100 = 50.
+					PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 7, balance: 50 },
+					// Rest of the pool slashed 50% of 800 = 400.
+					PoolsEvent::PoolSlashed { pool_id: 1, balance: 400 }
+				]
+            );
+        });
 	}
 
 	fn create_pool(creator: AccountId, amount: Balance) -> u32 {
diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs
index b36f66d634d64..bed0b9f621d92 100644
--- a/substrate/frame/staking/src/slashing.rs
+++ b/substrate/frame/staking/src/slashing.rs
@@ -125,7 +125,7 @@ impl SlashingSpans {
 	pub(crate) fn end_span(&mut self, now: EraIndex) -> bool {
 		let next_start = now.defensive_saturating_add(1);
 		if next_start <= self.last_start {
-			return false
+			return false;
 		}
 
 		let last_length = next_start.defensive_saturating_sub(self.last_start);
@@ -242,7 +242,7 @@ pub(crate) fn compute_slash<T: Config>(
 		// kick out the validator even if they won't be slashed,
 		// as long as the misbehavior is from their most recent slashing span.
 		kick_out_if_recent::<T>(params);
-		return None
+		return None;
 	}
 
 	let prior_slash_p = ValidatorSlashInEra::<T>::get(&params.slash_era, params.stash)
@@ -264,7 +264,7 @@ pub(crate) fn compute_slash<T: Config>(
 		// pays out some reward even if the latest report is not max-in-era.
 		// we opt to avoid the nominator lookups and edits and leave more rewards
 		// for more drastic misbehavior.
-		return None
+		return None;
 	}
 
 	// apply slash to validator.
@@ -542,7 +542,7 @@ impl<'a, T: 'a + Config> Drop for InspectingSpans<'a, T> {
 	fn drop(&mut self) {
 		// only update on disk if we slashed this account.
 		if !self.dirty {
-			return
+			return;
 		}
 
 		if let Some((start, end)) = self.spans.prune(self.window_start) {
@@ -626,17 +626,14 @@ pub fn do_slash<T: Config>(
 			// deduct overslash from the reward payout
 			*reward_payout = reward_payout.saturating_sub(missing);
 		}
+	}
 
-		let _ = ledger
-			.update()
-			.defensive_proof("ledger fetched from storage so it exists in storage; qed.");
+	let _ = ledger
+		.update()
+		.defensive_proof("ledger fetched from storage so it exists in storage; qed.");
 
-		// trigger the event
-		<Pallet<T>>::deposit_event(super::Event::<T>::Slashed {
-			staker: stash.clone(),
-			amount: value,
-		});
-	}
+	// trigger the event
+	<Pallet<T>>::deposit_event(super::Event::<T>::Slashed { staker: stash.clone(), amount: value });
 }
 
 /// Apply a previously-unapplied slash.
@@ -678,7 +675,7 @@ fn pay_reporters<T: Config>(
 		// nobody to pay out to or nothing to pay;
 		// just treat the whole value as slashed.
 		T::Slash::on_unbalanced(slashed_imbalance);
-		return
+		return;
 	}
 
 	// take rewards out of the slashed imbalance.

From ff300ef0055ec32cf853e7a7123e710a76d59d7d Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 23 Feb 2024 21:46:26 +0100
Subject: [PATCH 139/202] failing slash test

---
 substrate/frame/delegated-staking/src/lib.rs  |   2 +
 .../frame/delegated-staking/src/tests.rs      | 120 +++++++++++++-----
 2 files changed, 87 insertions(+), 35 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index c9ae4d7160281..4f6b9a8b21e0d 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -177,6 +177,7 @@ pub mod pallet {
 	pub enum Event<T: Config> {
 		Delegated { delegate: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
 		Withdrawn { delegate: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
+		Slashed { delegate: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
 	}
 
 	/// Map of Delegators to their delegation, i.e. (delegate, delegation_amount).
@@ -619,6 +620,7 @@ impl<T: Config> Pallet<T> {
 
 #[cfg(any(test, feature = "try-runtime"))]
 use sp_std::collections::btree_map::BTreeMap;
+
 #[cfg(any(test, feature = "try-runtime"))]
 impl<T: Config> Pallet<T> {
 	pub(crate) fn do_try_state() -> Result<(), TryRuntimeError> {
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index ea69dbc465ba8..e68f018368f48 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -915,51 +915,101 @@ mod pool_integration {
 	#[test]
 	fn pool_slashed() {
 		ExtBuilder::default().build_and_execute(|| {
-            start_era(1);
-            let creator = 100;
-            let creator_stake = 500;
-            let pool_id = create_pool(creator, creator_stake);
-            let delegator_stake = 100;
-            add_delegators_to_pool(pool_id, (300..306).collect(), delegator_stake);
-            let pool_acc = Pools::create_bonded_account(pool_id);
-
-            let total_staked = creator_stake + delegator_stake * 6;
-            assert_eq!(Staking::stake(&pool_acc).unwrap().total, total_staked);
-
-            // lets unbond a delegator each in next eras (2, 3, 4).
-            start_era(2);
-            assert_ok!(Pools::unbond(RawOrigin::Signed(300).into(), 300, delegator_stake));
-
-            start_era(3);
-            assert_ok!(Pools::unbond(RawOrigin::Signed(301).into(), 301, delegator_stake));
-
-            start_era(4);
-            assert_ok!(Pools::unbond(RawOrigin::Signed(302).into(), 302, delegator_stake));
-            System::reset_events();
+			start_era(1);
+			let creator = 100;
+			let creator_stake = 500;
+			let pool_id = create_pool(creator, creator_stake);
+			let delegator_stake = 100;
+			add_delegators_to_pool(pool_id, (300..306).collect(), delegator_stake);
+			let pool_acc = Pools::create_bonded_account(pool_id);
 
-            // slash the pool at era 3
-            assert_eq!(BondedPools::<T>::get(1).unwrap().points, creator_stake + delegator_stake * 6 - delegator_stake * 3);
-            pallet_staking::slashing::do_slash::<T>(
-                &pool_acc,
-                500,
-                &mut Default::default(),
-                &mut Default::default(),
-                3,
-            );
+			let total_staked = creator_stake + delegator_stake * 6;
+			assert_eq!(Staking::stake(&pool_acc).unwrap().total, total_staked);
 
-            assert_eq!(
-                pool_events_since_last_call(),
-                vec![
+			// lets unbond a delegator each in next eras (2, 3, 4).
+			start_era(2);
+			assert_ok!(Pools::unbond(RawOrigin::Signed(300).into(), 300, delegator_stake));
+
+			start_era(3);
+			assert_ok!(Pools::unbond(RawOrigin::Signed(301).into(), 301, delegator_stake));
+
+			start_era(4);
+			assert_ok!(Pools::unbond(RawOrigin::Signed(302).into(), 302, delegator_stake));
+			System::reset_events();
+
+			// slash the pool at era 3
+			assert_eq!(
+				BondedPools::<T>::get(1).unwrap().points,
+				creator_stake + delegator_stake * 6 - delegator_stake * 3
+			);
+			pallet_staking::slashing::do_slash::<T>(
+				&pool_acc,
+				500,
+				&mut Default::default(),
+				&mut Default::default(),
+				3,
+			);
+
+			assert_eq!(
+				pool_events_since_last_call(),
+				vec![
 					// 301 did not get slashed as all as it unbonded in an era before slash.
 					// 302 got slashed 50% of 100 = 50.
 					PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 6, balance: 50 },
 					// 303 got slashed 50% of 100 = 50.
 					PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 7, balance: 50 },
 					// Rest of the pool slashed 50% of 800 = 400.
-					PoolsEvent::PoolSlashed { pool_id: 1, balance: 400 }
+					PoolsEvent::PoolSlashed { pool_id: 1, balance: 400 },
 				]
+			);
+
+			// slash is lazy and balance is still locked in user's accounts.
+			assert_eq!(held_balance(&creator), creator_stake);
+			for i in 300..306 {
+				assert_eq!(held_balance(&i), delegator_stake);
+			}
+			assert_eq!(
+				get_pool_delegate(pool_id).ledger.effective_balance(),
+				Staking::total_stake(&pool_acc).unwrap()
+			);
+
+            // pending slash is book kept.
+			assert_eq!(get_pool_delegate(pool_id).ledger.pending_slash, 500);
+
+            // go in some distant future era.
+            start_era(10);
+            System::reset_events();
+
+            // 300 is not slashed and can withdraw all balance.
+            assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(300).into(), 300, 1));
+            assert_eq!(
+                events_since_last_call(),
+                vec![
+                    Event::Withdrawn { delegate: pool_acc, delegator: 300, amount: 100 },
+                ]
+            );
+            assert_eq!(get_pool_delegate(pool_id).ledger.pending_slash, 500);
+
+			let pre_301 = Balances::free_balance(301);
+            // 301 is slashed and should only be able to withdraw 50.
+            assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(301).into(), 301, 1));
+            assert_eq!(
+                events_since_last_call(),
+                vec![
+					// half amount is slashed first.
+                    Event::Slashed { delegate: pool_acc, delegator: 301, amount: 50 },
+					// rest of it is withdrawn.
+                    Event::Withdrawn { delegate: pool_acc, delegator: 301, amount: 50 },
+                ]
             );
-        });
+            assert_eq!(get_pool_delegate(pool_id).ledger.pending_slash, 450);
+            assert_eq!(held_balance(&301), 0);
+            assert_eq!(Balances::free_balance(301) - pre_301, 50);
+
+			// delegators cannot unbond without applying pending slash on their accounts.
+
+			// when unbonding, should apply slash. Make sure numbers are good.
+		});
 	}
 
 	fn create_pool(creator: AccountId, amount: Balance) -> u32 {

From c19bf20ff8c24abca812aaab54d6f9b76d30ff11 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 23 Feb 2024 22:17:00 +0100
Subject: [PATCH 140/202] add slash call

---
 .../frame/delegated-staking/src/impls.rs      | 51 +++++--------------
 substrate/frame/delegated-staking/src/lib.rs  | 48 +++++++++++++++++
 .../frame/delegated-staking/src/tests.rs      |  8 ++-
 .../frame/nomination-pools/src/adapter.rs     |  5 ++
 .../primitives/staking/src/delegation.rs      |  6 +++
 5 files changed, 80 insertions(+), 38 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 6185c1f0797d5..cc0c102f72825 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -196,43 +196,6 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 }
 
-// impl<T: Config> DelegationInterface for Pallet<T> {
-// FIXME(ank4n): Should be part of NP Adapter.
-// 	fn apply_slash(
-// 		delegate: &Self::AccountId,
-// 		delegator: &Self::AccountId,
-// 		value: Self::Balance,
-// 		maybe_reporter: Option<Self::AccountId>,
-// 	) -> DispatchResult {
-// 		let mut delegation_register =
-// 			<Delegates<T>>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-// 		let delegation = <Delegators<T>>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
-//
-// 		ensure!(&delegation.delegate == delegate, Error::<T>::NotDelegate);
-// 		ensure!(delegation.amount >= value, Error::<T>::NotEnoughFunds);
-//
-// 		let (mut credit, _missing) =
-// 			T::Currency::slash(&HoldReason::Delegating.into(), &delegator, value);
-// 		let actual_slash = credit.peek();
-// 		// remove the slashed amount
-// 		delegation_register.pending_slash.saturating_reduce(actual_slash);
-// 		<Delegates<T>>::insert(delegate, delegation_register);
-//
-// 		if let Some(reporter) = maybe_reporter {
-// 			let reward_payout: BalanceOf<T> =
-// 				T::CoreStaking::slash_reward_fraction() * actual_slash;
-// 			let (reporter_reward, rest) = credit.split(reward_payout);
-// 			credit = rest;
-// 			// fixme(ank4n): handle error
-// 			let _ = T::Currency::resolve(&reporter, reporter_reward);
-// 		}
-//
-// 		T::OnSlash::on_unbalanced(credit);
-// 		Ok(())
-// 	}
-//
-// }
-
 impl<T: Config> StakingDelegationSupport for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
@@ -347,4 +310,18 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 		// fixme(ank4n): This should not require slashing spans.
 		Pallet::<T>::release(RawOrigin::Signed(pool_account.clone()).into(), who.clone(), amount, 0)
 	}
+
+	fn apply_slash(
+		delegate: &Self::AccountId,
+		delegator: &Self::AccountId,
+		value: Self::Balance,
+		maybe_reporter: Option<Self::AccountId>,
+	) -> DispatchResult {
+		Pallet::<T>::slash(
+			RawOrigin::Signed(delegate.clone()).into(),
+			delegator.clone(),
+			value,
+			maybe_reporter,
+		)
+	}
 }
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 4f6b9a8b21e0d..88380f4a3bda4 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -340,6 +340,54 @@ pub mod pallet {
 
 			Ok(())
 		}
+
+		/// Apply a pending slash.
+		///
+		/// Delegate calls this to apply a pending slash to a delegator.
+		#[pallet::call_index(6)]
+		#[pallet::weight(Weight::default())]
+		pub fn slash(
+			origin: OriginFor<T>,
+			delegator: T::AccountId,
+			amount: BalanceOf<T>,
+			maybe_reporter: Option<T::AccountId>,
+		) -> DispatchResult {
+			let who = ensure_signed(origin)?;
+			let mut delegate = Delegate::<T>::from(&who)?;
+			let mut delegation = <Delegators<T>>::get(&delegator).ok_or(Error::<T>::NotDelegator)?;
+
+			ensure!(delegation.delegate == who, Error::<T>::NotDelegate);
+			ensure!(delegation.amount >= amount, Error::<T>::NotEnoughFunds);
+
+			let (mut credit, missing) =
+				T::Currency::slash(&HoldReason::Delegating.into(), &delegator, amount);
+
+			defensive_assert!(missing.is_zero(), "slash should have been fully applied");
+
+			let actual_slash = credit.peek();
+
+			// remove the slashed amount
+			delegate.ledger.pending_slash.saturating_reduce(actual_slash);
+			delegate.save();
+
+			delegation
+				.decrease_delegation(actual_slash)
+				.ok_or(ArithmeticError::Overflow)?
+				.save(&delegator);
+
+			if let Some(reporter) = maybe_reporter {
+				let reward_payout: BalanceOf<T> =
+					T::CoreStaking::slash_reward_fraction() * actual_slash;
+				let (reporter_reward, rest) = credit.split(reward_payout);
+				credit = rest;
+
+				// fixme(ank4n): handle error
+				let _ = T::Currency::resolve(&reporter, reporter_reward);
+			}
+
+			T::OnSlash::on_unbalanced(credit);
+			Ok(())
+		}
 	}
 
 	#[pallet::hooks]
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index e68f018368f48..178a53a605e24 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -575,7 +575,6 @@ mod staking_integration {
 mod pool_integration {
 	use super::*;
 	use pallet_nomination_pools::{BondExtra, BondedPools, PoolState};
-	use sp_runtime::print;
 
 	#[test]
 	fn create_pool_test() {
@@ -909,6 +908,13 @@ mod pool_integration {
 					PoolsEvent::Destroyed { pool_id },
 				]
 			);
+
+			// Make sure all data is cleaned up.
+			assert_eq!(Delegates::<T>::contains_key(Pools::create_bonded_account(pool_id)), false);
+			assert_eq!(Delegators::<T>::contains_key(creator), false);
+			for i in 300..310 {
+				assert_eq!(Delegators::<T>::contains_key(i), false);
+			}
 		});
 	}
 
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index 3208576d2eeec..e798de0d25020 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -68,4 +68,9 @@ impl<T: Config> PoolAdapter for NoDelegation<T> {
 
 		Ok(())
 	}
+
+	fn apply_slash(_delegate: &Self::AccountId, _delegator: &Self::AccountId, _value: Self::Balance, _maybe_reporter: Option<Self::AccountId>) -> sp_runtime::DispatchResult {
+		// for direct staking, slashing is eager, and we don't need to do anything here.
+		Ok(())
+	}
 }
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 683e89836317a..ea59fd3522851 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -201,4 +201,10 @@ pub trait PoolAdapter {
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult;
+	fn apply_slash(
+		delegate: &Self::AccountId,
+		delegator: &Self::AccountId,
+		value: Self::Balance,
+		maybe_reporter: Option<Self::AccountId>,
+	) -> DispatchResult;
 }

From 66c190e88dc04315e8e97c48fb040a9b0ea8f097 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 23 Feb 2024 22:17:18 +0100
Subject: [PATCH 141/202] fmt

---
 substrate/frame/delegated-staking/src/lib.rs  |  3 +-
 .../frame/delegated-staking/src/tests.rs      | 48 +++++++++----------
 .../frame/nomination-pools/src/adapter.rs     |  7 ++-
 3 files changed, 31 insertions(+), 27 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 88380f4a3bda4..eb9b62aa841e3 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -354,7 +354,8 @@ pub mod pallet {
 		) -> DispatchResult {
 			let who = ensure_signed(origin)?;
 			let mut delegate = Delegate::<T>::from(&who)?;
-			let mut delegation = <Delegators<T>>::get(&delegator).ok_or(Error::<T>::NotDelegator)?;
+			let mut delegation =
+				<Delegators<T>>::get(&delegator).ok_or(Error::<T>::NotDelegator)?;
 
 			ensure!(delegation.delegate == who, Error::<T>::NotDelegate);
 			ensure!(delegation.amount >= amount, Error::<T>::NotEnoughFunds);
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 178a53a605e24..14f5e4d46c0da 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -979,38 +979,36 @@ mod pool_integration {
 				Staking::total_stake(&pool_acc).unwrap()
 			);
 
-            // pending slash is book kept.
+			// pending slash is book kept.
 			assert_eq!(get_pool_delegate(pool_id).ledger.pending_slash, 500);
 
-            // go in some distant future era.
-            start_era(10);
-            System::reset_events();
+			// go in some distant future era.
+			start_era(10);
+			System::reset_events();
 
-            // 300 is not slashed and can withdraw all balance.
-            assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(300).into(), 300, 1));
-            assert_eq!(
-                events_since_last_call(),
-                vec![
-                    Event::Withdrawn { delegate: pool_acc, delegator: 300, amount: 100 },
-                ]
-            );
-            assert_eq!(get_pool_delegate(pool_id).ledger.pending_slash, 500);
+			// 300 is not slashed and can withdraw all balance.
+			assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(300).into(), 300, 1));
+			assert_eq!(
+				events_since_last_call(),
+				vec![Event::Withdrawn { delegate: pool_acc, delegator: 300, amount: 100 },]
+			);
+			assert_eq!(get_pool_delegate(pool_id).ledger.pending_slash, 500);
 
 			let pre_301 = Balances::free_balance(301);
-            // 301 is slashed and should only be able to withdraw 50.
-            assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(301).into(), 301, 1));
-            assert_eq!(
-                events_since_last_call(),
-                vec![
+			// 301 is slashed and should only be able to withdraw 50.
+			assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(301).into(), 301, 1));
+			assert_eq!(
+				events_since_last_call(),
+				vec![
 					// half amount is slashed first.
-                    Event::Slashed { delegate: pool_acc, delegator: 301, amount: 50 },
+					Event::Slashed { delegate: pool_acc, delegator: 301, amount: 50 },
 					// rest of it is withdrawn.
-                    Event::Withdrawn { delegate: pool_acc, delegator: 301, amount: 50 },
-                ]
-            );
-            assert_eq!(get_pool_delegate(pool_id).ledger.pending_slash, 450);
-            assert_eq!(held_balance(&301), 0);
-            assert_eq!(Balances::free_balance(301) - pre_301, 50);
+					Event::Withdrawn { delegate: pool_acc, delegator: 301, amount: 50 },
+				]
+			);
+			assert_eq!(get_pool_delegate(pool_id).ledger.pending_slash, 450);
+			assert_eq!(held_balance(&301), 0);
+			assert_eq!(Balances::free_balance(301) - pre_301, 50);
 
 			// delegators cannot unbond without applying pending slash on their accounts.
 
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index e798de0d25020..ad79270c59d3c 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -69,7 +69,12 @@ impl<T: Config> PoolAdapter for NoDelegation<T> {
 		Ok(())
 	}
 
-	fn apply_slash(_delegate: &Self::AccountId, _delegator: &Self::AccountId, _value: Self::Balance, _maybe_reporter: Option<Self::AccountId>) -> sp_runtime::DispatchResult {
+	fn apply_slash(
+		_delegate: &Self::AccountId,
+		_delegator: &Self::AccountId,
+		_value: Self::Balance,
+		_maybe_reporter: Option<Self::AccountId>,
+	) -> sp_runtime::DispatchResult {
 		// for direct staking, slashing is eager, and we don't need to do anything here.
 		Ok(())
 	}

From 9af4ae1dc11141ed90f8153c4ecbfc246346ce28 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 24 Feb 2024 19:42:15 +0100
Subject: [PATCH 142/202] slash extrinsic in np

---
 .../frame/delegated-staking/src/impls.rs      |  15 ++-
 substrate/frame/delegated-staking/src/lib.rs  |  99 +++++++-------
 .../frame/delegated-staking/src/tests.rs      |   1 +
 .../frame/nomination-pools/src/adapter.rs     |   2 +-
 substrate/frame/nomination-pools/src/lib.rs   | 125 ++++++++++++------
 .../primitives/staking/src/delegation.rs      |   8 +-
 6 files changed, 151 insertions(+), 99 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index cc0c102f72825..9f6c5d646a87a 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -258,10 +258,15 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 			.unwrap_or(Zero::zero())
 	}
 
-	/// Returns balance of `Delegate` account including the held balances.
+	/// Returns balance of account that is held.
 	///
-	/// Equivalent to [FunInspect::total_balance] for non delegate accounts.
+	/// - For [Delegate] accounts, this is their total delegation amount.
+	/// - For [Delegators], this is their delegation amount.
 	fn total_balance(who: &Self::AccountId) -> Self::Balance {
+		if Self::is_delegator(who) {
+			return Delegation::<T>::get(who).map(|d| d.amount).unwrap_or(Zero::zero());
+		}
+
 		Delegate::<T>::from(who)
 			.map(|delegate| delegate.ledger.effective_balance())
 			.unwrap_or(Zero::zero())
@@ -311,14 +316,14 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 		Pallet::<T>::release(RawOrigin::Signed(pool_account.clone()).into(), who.clone(), amount, 0)
 	}
 
-	fn apply_slash(
+	fn delegator_slash(
 		delegate: &Self::AccountId,
 		delegator: &Self::AccountId,
 		value: Self::Balance,
 		maybe_reporter: Option<Self::AccountId>,
 	) -> DispatchResult {
-		Pallet::<T>::slash(
-			RawOrigin::Signed(delegate.clone()).into(),
+		Pallet::<T>::do_slash(
+			delegate.clone(),
 			delegator.clone(),
 			value,
 			maybe_reporter,
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index eb9b62aa841e3..735630784f597 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -340,55 +340,6 @@ pub mod pallet {
 
 			Ok(())
 		}
-
-		/// Apply a pending slash.
-		///
-		/// Delegate calls this to apply a pending slash to a delegator.
-		#[pallet::call_index(6)]
-		#[pallet::weight(Weight::default())]
-		pub fn slash(
-			origin: OriginFor<T>,
-			delegator: T::AccountId,
-			amount: BalanceOf<T>,
-			maybe_reporter: Option<T::AccountId>,
-		) -> DispatchResult {
-			let who = ensure_signed(origin)?;
-			let mut delegate = Delegate::<T>::from(&who)?;
-			let mut delegation =
-				<Delegators<T>>::get(&delegator).ok_or(Error::<T>::NotDelegator)?;
-
-			ensure!(delegation.delegate == who, Error::<T>::NotDelegate);
-			ensure!(delegation.amount >= amount, Error::<T>::NotEnoughFunds);
-
-			let (mut credit, missing) =
-				T::Currency::slash(&HoldReason::Delegating.into(), &delegator, amount);
-
-			defensive_assert!(missing.is_zero(), "slash should have been fully applied");
-
-			let actual_slash = credit.peek();
-
-			// remove the slashed amount
-			delegate.ledger.pending_slash.saturating_reduce(actual_slash);
-			delegate.save();
-
-			delegation
-				.decrease_delegation(actual_slash)
-				.ok_or(ArithmeticError::Overflow)?
-				.save(&delegator);
-
-			if let Some(reporter) = maybe_reporter {
-				let reward_payout: BalanceOf<T> =
-					T::CoreStaking::slash_reward_fraction() * actual_slash;
-				let (reporter_reward, rest) = credit.split(reward_payout);
-				credit = rest;
-
-				// fixme(ank4n): handle error
-				let _ = T::Currency::resolve(&reporter, reporter_reward);
-			}
-
-			T::OnSlash::on_unbalanced(credit);
-			Ok(())
-		}
 	}
 
 	#[pallet::hooks]
@@ -665,6 +616,56 @@ impl<T: Config> Pallet<T> {
 
 		Ok(())
 	}
+
+	pub fn do_slash(
+		delegate_acc: T::AccountId,
+		delegator: T::AccountId,
+		amount: BalanceOf<T>,
+		maybe_reporter: Option<T::AccountId>,
+	) -> DispatchResult {
+		let mut delegate = Delegate::<T>::from(&delegate_acc)?;
+		let mut delegation =
+			<Delegators<T>>::get(&delegator).ok_or(Error::<T>::NotDelegator)?;
+
+		ensure!(delegation.delegate == delegate_acc, Error::<T>::NotDelegate);
+		ensure!(delegation.amount >= amount, Error::<T>::NotEnoughFunds);
+
+		let (mut credit, missing) =
+			T::Currency::slash(&HoldReason::Delegating.into(), &delegator, amount);
+
+		defensive_assert!(missing.is_zero(), "slash should have been fully applied");
+
+		let actual_slash = credit.peek();
+
+		// remove the slashed amount
+		delegate.ledger.pending_slash.saturating_reduce(actual_slash);
+		delegate.save();
+
+		delegation
+			.decrease_delegation(actual_slash)
+			.ok_or(ArithmeticError::Overflow)?
+			.save(&delegator);
+
+		if let Some(reporter) = maybe_reporter {
+			let reward_payout: BalanceOf<T> =
+				T::CoreStaking::slash_reward_fraction() * actual_slash;
+			let (reporter_reward, rest) = credit.split(reward_payout);
+			credit = rest;
+
+			// fixme(ank4n): handle error
+			let _ = T::Currency::resolve(&reporter, reporter_reward);
+		}
+
+		T::OnSlash::on_unbalanced(credit);
+
+		Self::deposit_event(Event::<T>::Slashed {
+			delegate: delegate_acc,
+			delegator,
+			amount,
+		});
+
+		Ok(())
+	}
 }
 
 #[cfg(any(test, feature = "try-runtime"))]
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 14f5e4d46c0da..bd5234cbd8103 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -1011,6 +1011,7 @@ mod pool_integration {
 			assert_eq!(Balances::free_balance(301) - pre_301, 50);
 
 			// delegators cannot unbond without applying pending slash on their accounts.
+			// slash_amount = total balance held - (balance from active pool + balance from unbonding pool)
 
 			// when unbonding, should apply slash. Make sure numbers are good.
 		});
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index ad79270c59d3c..19ee78ddd6371 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -69,7 +69,7 @@ impl<T: Config> PoolAdapter for NoDelegation<T> {
 		Ok(())
 	}
 
-	fn apply_slash(
+	fn delegator_slash(
 		_delegate: &Self::AccountId,
 		_delegator: &Self::AccountId,
 		_value: Self::Balance,
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index 08de180e2d8e0..7bffb910f5348 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -546,9 +546,14 @@ impl<T: Config> PoolMember<T> {
 
 	/// Total balance of the member, both active and unbonding.
 	/// Doesn't mutate state.
-	#[cfg(any(feature = "try-runtime", feature = "fuzzing", test, debug_assertions))]
 	fn total_balance(&self) -> BalanceOf<T> {
-		let pool = BondedPool::<T>::get(self.pool_id).unwrap();
+		let maybe_pool = BondedPool::<T>::get(self.pool_id);
+		if maybe_pool.is_none() {
+			defensive!("pool should exist; qed");
+			return Zero::zero();
+		}
+		let pool = maybe_pool.expect("checked pool is not none; qed");
+
 		let active_balance = pool.points_to_balance(self.active_points());
 
 		let sub_pools = match SubPoolsStorage::<T>::get(self.pool_id) {
@@ -737,13 +742,13 @@ impl<T: Config> Commission<T> {
 
 			// do not throttle if `to` is the same or a decrease in commission.
 			if *to <= commission_as_percent {
-				return false
+				return false;
 			}
 			// Test for `max_increase` throttling.
 			//
 			// Throttled if the attempted increase in commission is greater than `max_increase`.
 			if (*to).saturating_sub(commission_as_percent) > t.max_increase {
-				return true
+				return true;
 			}
 
 			// Test for `min_delay` throttling.
@@ -766,7 +771,7 @@ impl<T: Config> Commission<T> {
 						blocks_surpassed < t.min_delay
 					}
 				},
-			)
+			);
 		}
 		false
 	}
@@ -824,7 +829,7 @@ impl<T: Config> Commission<T> {
 		);
 		if let Some(old) = self.max.as_mut() {
 			if new_max > *old {
-				return Err(Error::<T>::MaxCommissionRestricted.into())
+				return Err(Error::<T>::MaxCommissionRestricted.into());
 			}
 			*old = new_max;
 		} else {
@@ -1210,7 +1215,7 @@ impl<T: Config> BondedPool<T> {
 			},
 			(false, true) => {
 				// the depositor can simply not be unbonded permissionlessly, period.
-				return Err(Error::<T>::DoesNotHavePermission.into())
+				return Err(Error::<T>::DoesNotHavePermission.into());
 			},
 		};
 
@@ -1780,7 +1785,7 @@ pub mod pallet {
 
 	/// Events of this pallet.
 	#[pallet::event]
-	#[pallet::generate_deposit(pub(crate) fn deposit_event)]
+	#[pallet::generate_deposit(pub (crate) fn deposit_event)]
 	pub enum Event<T: Config> {
 		/// A pool has been created.
 		Created { depositor: T::AccountId, pool_id: PoolId },
@@ -1934,6 +1939,8 @@ pub mod pallet {
 		BondExtraRestricted,
 		/// No imbalance in the ED deposit for the pool.
 		NothingToAdjust,
+        /// No slash pending that can be applied to the member.
+        NothingToSlash,
 	}
 
 	#[derive(Encode, Decode, PartialEq, TypeInfo, PalletError, RuntimeDebug)]
@@ -2042,9 +2049,9 @@ pub mod pallet {
 		// of just once, in the spirit reusing code.
 		#[pallet::call_index(1)]
 		#[pallet::weight(
-			T::WeightInfo::bond_extra_transfer()
-			.max(T::WeightInfo::bond_extra_other())
-		)]
+        T::WeightInfo::bond_extra_transfer()
+        .max(T::WeightInfo::bond_extra_other())
+        )]
 		pub fn bond_extra(origin: OriginFor<T>, extra: BondExtra<BalanceOf<T>>) -> DispatchResult {
 			let who = ensure_signed(origin)?;
 			Self::do_bond_extra(who.clone(), who, extra)
@@ -2181,7 +2188,7 @@ pub mod pallet {
 		/// would probably see an error like `NoMoreChunks` emitted from the staking system when
 		/// they attempt to unbond.
 		#[pallet::call_index(4)]
-		#[pallet::weight(T::WeightInfo::pool_withdraw_unbonded(*num_slashing_spans))]
+		#[pallet::weight(T::WeightInfo::pool_withdraw_unbonded(* num_slashing_spans))]
 		pub fn pool_withdraw_unbonded(
 			origin: OriginFor<T>,
 			pool_id: PoolId,
@@ -2219,8 +2226,8 @@ pub mod pallet {
 		/// If the target is the depositor, the pool will be destroyed.
 		#[pallet::call_index(5)]
 		#[pallet::weight(
-			T::WeightInfo::withdraw_unbonded_kill(*num_slashing_spans)
-		)]
+        T::WeightInfo::withdraw_unbonded_kill(* num_slashing_spans)
+        )]
 		pub fn withdraw_unbonded(
 			origin: OriginFor<T>,
 			member_account: AccountIdLookupOf<T>,
@@ -2588,9 +2595,9 @@ pub mod pallet {
 		/// `PermissionlessAll` or `PermissionlessCompound`.
 		#[pallet::call_index(14)]
 		#[pallet::weight(
-			T::WeightInfo::bond_extra_transfer()
-			.max(T::WeightInfo::bond_extra_other())
-		)]
+        T::WeightInfo::bond_extra_transfer()
+        .max(T::WeightInfo::bond_extra_other())
+        )]
 		pub fn bond_extra_other(
 			origin: OriginFor<T>,
 			member: AccountIdLookupOf<T>,
@@ -2774,6 +2781,19 @@ pub mod pallet {
 
 			Ok(())
 		}
+
+		/// Apply a pending slash on a member.
+		#[pallet::call_index(23)]
+		// FIXME(ank4n): fix weight info.
+		#[pallet::weight(T::WeightInfo::set_commission_claim_permission())]
+		pub fn apply_slash(
+			origin: OriginFor<T>,
+			member_account: AccountIdLookupOf<T>,
+		) -> DispatchResult {
+			let who = ensure_signed(origin)?;
+			let member_account = T::Lookup::lookup(member_account)?;
+			Self::do_apply_slash(member_account, Some(who))
+		}
 	}
 
 	#[pallet::hooks]
@@ -2962,7 +2982,7 @@ impl<T: Config> Pallet<T> {
 		let balance = T::U256ToBalance::convert;
 		if current_balance.is_zero() || current_points.is_zero() || points.is_zero() {
 			// There is nothing to unbond
-			return Zero::zero()
+			return Zero::zero();
 		}
 
 		// Equivalent of (current_balance / current_points) * points
@@ -2999,7 +3019,7 @@ impl<T: Config> Pallet<T> {
 		// will be zero.
 		let pending_rewards = member.pending_rewards(current_reward_counter)?;
 		if pending_rewards.is_zero() {
-			return Ok(pending_rewards)
+			return Ok(pending_rewards);
 		}
 
 		// IFF the reward is non-zero alter the member and reward pool info.
@@ -3227,7 +3247,7 @@ impl<T: Config> Pallet<T> {
 		let min_balance = T::Currency::minimum_balance();
 
 		if pre_frozen_balance == min_balance {
-			return Err(Error::<T>::NothingToAdjust.into())
+			return Err(Error::<T>::NothingToAdjust.into());
 		}
 
 		// Update frozen amount with current ED.
@@ -3254,6 +3274,25 @@ impl<T: Config> Pallet<T> {
 		Ok(())
 	}
 
+	fn do_apply_slash(member_account: T::AccountId, reporter: Option<T::AccountId>) -> DispatchResult {
+		// calculate points to be slashed.
+		let member =
+			PoolMembers::<T>::get(&member_account).ok_or(Error::<T>::PoolMemberNotFound)?;
+		let bonded_pool = Self::create_bonded_account(member.pool_id);
+
+		let delegated_balance = T::PoolAdapter::total_balance(&member_account);
+		let current_balance = member.total_balance();
+		defensive_assert!(
+			delegated_balance >= current_balance,
+			"delegated balance should always be greater or equal to current balance"
+		);
+
+        // if nothing to slash, return error.
+		ensure!(delegated_balance > current_balance, Error::<T>::NothingToSlash);
+
+		T::PoolAdapter::delegator_slash(&bonded_pool, &member_account, delegated_balance.defensive_saturating_sub(current_balance), reporter)
+	}
+
 	/// Apply freeze on reward account to restrict it from going below ED.
 	pub(crate) fn freeze_pool_deposit(reward_acc: &T::AccountId) -> DispatchResult {
 		T::Currency::set_freeze(
@@ -3306,7 +3345,7 @@ impl<T: Config> Pallet<T> {
 	#[cfg(any(feature = "try-runtime", feature = "fuzzing", test, debug_assertions))]
 	pub fn do_try_state(level: u8) -> Result<(), TryRuntimeError> {
 		if level.is_zero() {
-			return Ok(())
+			return Ok(());
 		}
 		// note: while a bit wacky, since they have the same key, even collecting to vec should
 		// result in the same set of keys, in the same order.
@@ -3439,7 +3478,7 @@ impl<T: Config> Pallet<T> {
 		);
 
 		if level <= 1 {
-			return Ok(())
+			return Ok(());
 		}
 
 		for (pool_id, _pool) in BondedPools::<T>::iter() {
@@ -3451,14 +3490,14 @@ impl<T: Config> Pallet<T> {
 			let total_balance = T::PoolAdapter::total_balance(&pool_account);
 
 			assert!(
-				total_balance >= bonded_balance + sum_unbonding_balance,
-				"faulty pool: {:?} / {:?}, total_balance {:?} >= bonded_balance {:?} + sum_unbonding_balance {:?}",
-				pool_id,
-				_pool,
-				total_balance,
-				bonded_balance,
-				sum_unbonding_balance
-			);
+                total_balance >= bonded_balance + sum_unbonding_balance,
+                "faulty pool: {:?} / {:?}, total_balance {:?} >= bonded_balance {:?} + sum_unbonding_balance {:?}",
+                pool_id,
+                _pool,
+                total_balance,
+                bonded_balance,
+                sum_unbonding_balance
+            );
 		}
 
 		// Warn if any pool has incorrect ED frozen. We don't want to fail hard as this could be a
@@ -3481,21 +3520,21 @@ impl<T: Config> Pallet<T> {
 	pub fn check_ed_imbalance() -> Result<(), DispatchError> {
 		let mut failed: u32 = 0;
 		BondedPools::<T>::iter_keys().for_each(|id| {
-			let reward_acc = Self::create_reward_account(id);
-			let frozen_balance =
-				T::Currency::balance_frozen(&FreezeReason::PoolMinBalance.into(), &reward_acc);
-
-			let expected_frozen_balance = T::Currency::minimum_balance();
-			if frozen_balance != expected_frozen_balance {
-				failed += 1;
-				log::warn!(
+            let reward_acc = Self::create_reward_account(id);
+            let frozen_balance =
+                T::Currency::balance_frozen(&FreezeReason::PoolMinBalance.into(), &reward_acc);
+
+            let expected_frozen_balance = T::Currency::minimum_balance();
+            if frozen_balance != expected_frozen_balance {
+                failed += 1;
+                log::warn!(
 					"pool {:?} has incorrect ED frozen that can result from change in ED. Expected  = {:?},  Actual = {:?}",
 					id,
 					expected_frozen_balance,
 					frozen_balance,
 				);
-			}
-		});
+            }
+        });
 
 		ensure!(failed == 0, "Some pools do not have correct ED frozen");
 		Ok(())
@@ -3528,7 +3567,7 @@ impl<T: Config> Pallet<T> {
 				let (current_reward_counter, _) = reward_pool
 					.current_reward_counter(pool_member.pool_id, bonded_pool.points, commission)
 					.ok()?;
-				return pool_member.pending_rewards(current_reward_counter).ok()
+				return pool_member.pending_rewards(current_reward_counter).ok();
 			}
 		}
 
@@ -3574,7 +3613,9 @@ impl<T: Config> sp_staking::OnStakingUpdate<T::AccountId, BalanceOf<T>> for Pall
 		slashed_unlocking: &BTreeMap<EraIndex, BalanceOf<T>>,
 		total_slashed: BalanceOf<T>,
 	) {
-		let Some(pool_id) = ReversePoolIdLookup::<T>::get(pool_account) else { return };
+		let Some(pool_id) = ReversePoolIdLookup::<T>::get(pool_account) else {
+			return;
+		};
 		// As the slashed account belongs to a `BondedPool` the `TotalValueLocked` decreases and
 		// an event is emitted.
 		TotalValueLocked::<T>::mutate(|tvl| {
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index ea59fd3522851..18c01c47dd1b4 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -175,7 +175,7 @@ pub trait PoolAdapter {
 	/// Balance that is free and can be released to delegator.
 	fn releasable_balance(who: &Self::AccountId) -> Self::Balance;
 
-	/// Similar to [Inspect::total_balance].
+	/// Total balance of the account held for staking.
 	fn total_balance(who: &Self::AccountId) -> Self::Balance;
 
 	/// Initiate delegation to the pool account.
@@ -201,7 +201,11 @@ pub trait PoolAdapter {
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult;
-	fn apply_slash(
+
+	/// Apply a slash to the `delegator`.
+	///
+	/// This is called when the corresponding `delegate` has pending slash to be applied.
+	fn delegator_slash(
 		delegate: &Self::AccountId,
 		delegator: &Self::AccountId,
 		value: Self::Balance,

From 2049a7c5c0ee67d0713d54a1e78793c185877eb5 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 24 Feb 2024 19:43:56 +0100
Subject: [PATCH 143/202] fmt

---
 substrate/frame/delegated-staking/src/impls.rs |  7 +------
 substrate/frame/delegated-staking/src/lib.rs   |  9 ++-------
 substrate/frame/delegated-staking/src/tests.rs |  3 ++-
 substrate/frame/nomination-pools/src/lib.rs    | 18 +++++++++++++-----
 4 files changed, 18 insertions(+), 19 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 9f6c5d646a87a..176e2659b7205 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -322,11 +322,6 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 		value: Self::Balance,
 		maybe_reporter: Option<Self::AccountId>,
 	) -> DispatchResult {
-		Pallet::<T>::do_slash(
-			delegate.clone(),
-			delegator.clone(),
-			value,
-			maybe_reporter,
-		)
+		Pallet::<T>::do_slash(delegate.clone(), delegator.clone(), value, maybe_reporter)
 	}
 }
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 735630784f597..201fd6ea920d4 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -624,8 +624,7 @@ impl<T: Config> Pallet<T> {
 		maybe_reporter: Option<T::AccountId>,
 	) -> DispatchResult {
 		let mut delegate = Delegate::<T>::from(&delegate_acc)?;
-		let mut delegation =
-			<Delegators<T>>::get(&delegator).ok_or(Error::<T>::NotDelegator)?;
+		let mut delegation = <Delegators<T>>::get(&delegator).ok_or(Error::<T>::NotDelegator)?;
 
 		ensure!(delegation.delegate == delegate_acc, Error::<T>::NotDelegate);
 		ensure!(delegation.amount >= amount, Error::<T>::NotEnoughFunds);
@@ -658,11 +657,7 @@ impl<T: Config> Pallet<T> {
 
 		T::OnSlash::on_unbalanced(credit);
 
-		Self::deposit_event(Event::<T>::Slashed {
-			delegate: delegate_acc,
-			delegator,
-			amount,
-		});
+		Self::deposit_event(Event::<T>::Slashed { delegate: delegate_acc, delegator, amount });
 
 		Ok(())
 	}
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index bd5234cbd8103..5a73af747cb11 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -1011,7 +1011,8 @@ mod pool_integration {
 			assert_eq!(Balances::free_balance(301) - pre_301, 50);
 
 			// delegators cannot unbond without applying pending slash on their accounts.
-			// slash_amount = total balance held - (balance from active pool + balance from unbonding pool)
+			// slash_amount = total balance held - (balance from active pool + balance from
+			// unbonding pool)
 
 			// when unbonding, should apply slash. Make sure numbers are good.
 		});
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index 7bffb910f5348..6b76355ca6b5c 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -1939,8 +1939,8 @@ pub mod pallet {
 		BondExtraRestricted,
 		/// No imbalance in the ED deposit for the pool.
 		NothingToAdjust,
-        /// No slash pending that can be applied to the member.
-        NothingToSlash,
+		/// No slash pending that can be applied to the member.
+		NothingToSlash,
 	}
 
 	#[derive(Encode, Decode, PartialEq, TypeInfo, PalletError, RuntimeDebug)]
@@ -3274,7 +3274,10 @@ impl<T: Config> Pallet<T> {
 		Ok(())
 	}
 
-	fn do_apply_slash(member_account: T::AccountId, reporter: Option<T::AccountId>) -> DispatchResult {
+	fn do_apply_slash(
+		member_account: T::AccountId,
+		reporter: Option<T::AccountId>,
+	) -> DispatchResult {
 		// calculate points to be slashed.
 		let member =
 			PoolMembers::<T>::get(&member_account).ok_or(Error::<T>::PoolMemberNotFound)?;
@@ -3287,10 +3290,15 @@ impl<T: Config> Pallet<T> {
 			"delegated balance should always be greater or equal to current balance"
 		);
 
-        // if nothing to slash, return error.
+		// if nothing to slash, return error.
 		ensure!(delegated_balance > current_balance, Error::<T>::NothingToSlash);
 
-		T::PoolAdapter::delegator_slash(&bonded_pool, &member_account, delegated_balance.defensive_saturating_sub(current_balance), reporter)
+		T::PoolAdapter::delegator_slash(
+			&bonded_pool,
+			&member_account,
+			delegated_balance.defensive_saturating_sub(current_balance),
+			reporter,
+		)
 	}
 
 	/// Apply freeze on reward account to restrict it from going below ED.

From 1d31384fcf93062f77907a688a3981a76edc7f1b Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 24 Feb 2024 20:09:56 +0100
Subject: [PATCH 144/202] slash works

---
 .../frame/delegated-staking/src/impls.rs      |   6 +
 substrate/frame/delegated-staking/src/lib.rs  |   4 +-
 .../frame/nomination-pools/src/adapter.rs     |   8 +-
 substrate/frame/nomination-pools/src/lib.rs   |  18 ++-
 .../primitives/staking/src/delegation.rs      | 107 +-----------------
 5 files changed, 32 insertions(+), 111 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 176e2659b7205..c49e3ff90ea4b 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -316,6 +316,12 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 		Pallet::<T>::release(RawOrigin::Signed(pool_account.clone()).into(), who.clone(), amount, 0)
 	}
 
+	fn has_pending_slash(delegate: &Self::AccountId) -> bool {
+		Delegate::<T>::from(delegate)
+			.map(|d| !d.ledger.pending_slash.is_zero())
+			.unwrap_or(false)
+	}
+
 	fn delegator_slash(
 		delegate: &Self::AccountId,
 		delegator: &Self::AccountId,
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 201fd6ea920d4..04ee1f3525d77 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -83,8 +83,7 @@ use sp_runtime::{
 	ArithmeticError, DispatchResult, Perbill, RuntimeDebug, Saturating, TryRuntimeError,
 };
 use sp_staking::{
-	delegation::{DelegationInterface, StakingDelegationSupport},
-	EraIndex, Stake, StakerStatus, StakingInterface,
+	delegation::StakingDelegationSupport, EraIndex, Stake, StakerStatus, StakingInterface,
 };
 use sp_std::{convert::TryInto, prelude::*};
 
@@ -638,6 +637,7 @@ impl<T: Config> Pallet<T> {
 
 		// remove the slashed amount
 		delegate.ledger.pending_slash.saturating_reduce(actual_slash);
+		delegate.ledger.total_delegated.saturating_reduce(actual_slash);
 		delegate.save();
 
 		delegation
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index 19ee78ddd6371..0fbb5826f145f 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -69,6 +69,11 @@ impl<T: Config> PoolAdapter for NoDelegation<T> {
 		Ok(())
 	}
 
+	fn has_pending_slash(delegate: &Self::AccountId) -> bool {
+		// for direct staking, slashing is eager, and we don't need to do anything here.
+		false
+	}
+
 	fn delegator_slash(
 		_delegate: &Self::AccountId,
 		_delegator: &Self::AccountId,
@@ -76,6 +81,7 @@ impl<T: Config> PoolAdapter for NoDelegation<T> {
 		_maybe_reporter: Option<Self::AccountId>,
 	) -> sp_runtime::DispatchResult {
 		// for direct staking, slashing is eager, and we don't need to do anything here.
-		Ok(())
+		defensive!("Delegator slash is not supported for direct staking");
+		Err(Error::<T>::NothingToSlash.into())
 	}
 }
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index 6b76355ca6b5c..da160498210b0 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -1286,6 +1286,10 @@ impl<T: Config> BondedPool<T> {
 			});
 		};
 	}
+
+	fn has_pending_slash(&self) -> bool {
+		T::PoolAdapter::has_pending_slash(&self.bonded_account())
+	}
 }
 
 /// A reward pool.
@@ -2244,6 +2248,11 @@ pub mod pallet {
 			let mut sub_pools =
 				SubPoolsStorage::<T>::get(member.pool_id).ok_or(Error::<T>::SubPoolsNotFound)?;
 
+			if bonded_pool.has_pending_slash(){
+				// apply slash if any before withdraw.
+				let _ = Self::do_apply_slash(&member_account, None);
+			}
+
 			bonded_pool.ok_to_withdraw_unbonded_with(&caller, &member_account)?;
 
 			// NOTE: must do this after we have done the `ok_to_withdraw_unbonded_other_with` check.
@@ -2792,7 +2801,7 @@ pub mod pallet {
 		) -> DispatchResult {
 			let who = ensure_signed(origin)?;
 			let member_account = T::Lookup::lookup(member_account)?;
-			Self::do_apply_slash(member_account, Some(who))
+			Self::do_apply_slash(&member_account, Some(who))
 		}
 	}
 
@@ -3275,13 +3284,14 @@ impl<T: Config> Pallet<T> {
 	}
 
 	fn do_apply_slash(
-		member_account: T::AccountId,
+		member_account: &T::AccountId,
 		reporter: Option<T::AccountId>,
 	) -> DispatchResult {
 		// calculate points to be slashed.
 		let member =
 			PoolMembers::<T>::get(&member_account).ok_or(Error::<T>::PoolMemberNotFound)?;
-		let bonded_pool = Self::create_bonded_account(member.pool_id);
+		let bonded_account = Self::create_bonded_account(member.pool_id);
+		ensure!(T::PoolAdapter::has_pending_slash(&bonded_account), Error::<T>::NothingToSlash);
 
 		let delegated_balance = T::PoolAdapter::total_balance(&member_account);
 		let current_balance = member.total_balance();
@@ -3294,7 +3304,7 @@ impl<T: Config> Pallet<T> {
 		ensure!(delegated_balance > current_balance, Error::<T>::NothingToSlash);
 
 		T::PoolAdapter::delegator_slash(
-			&bonded_pool,
+			&bonded_account,
 			&member_account,
 			delegated_balance.defensive_saturating_sub(current_balance),
 			reporter,
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 18c01c47dd1b4..eff5a72c1889d 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -20,110 +20,6 @@ use scale_info::TypeInfo;
 use sp_runtime::{DispatchResult, Saturating};
 use sp_std::ops::Sub;
 
-/// Allows an account to accept stake delegations and manage its operations.
-// FIXME(ank4n): Remove this and add a new trait (in delegation pallet) for NP adapter.
-pub trait DelegationInterface {
-	/// Balance type used by the staking system.
-	type Balance: Sub<Output = Self::Balance>
-		+ Ord
-		+ PartialEq
-		+ Default
-		+ Copy
-		+ MaxEncodedLen
-		+ FullCodec
-		+ TypeInfo
-		+ Saturating;
-
-	/// AccountId type used by the staking system.
-	type AccountId: Clone + sp_std::fmt::Debug;
-
-	/// Total delegated balance to this account.
-	fn delegated_balance(who: &Self::AccountId) -> Self::Balance;
-
-	/// Total delegated balance to this account that is not yet bonded to staking.
-	fn unbonded_balance(who: &Self::AccountId) -> Self::Balance;
-
-	/// Set intention to accept delegations.
-	fn accept_delegations(
-		delegate: &Self::AccountId,
-		reward_destination: &Self::AccountId,
-	) -> DispatchResult;
-
-	/// Migrate a nominator account into a `delegate`.
-	///
-	/// # Arguments
-	///
-	/// * `new_delegate`: This is the current nominator account. Funds will be moved from this
-	///   account to `proxy_delegator` and delegated back to `new_delegate`.
-	/// * `proxy_delegator`: All existing staked funds will be moved to this account. Future
-	///   migration of funds from `proxy_delegator` to `delegator` is possible via calling
-	///   [`Self::migrate_delegator`].
-	/// * `payee`: `Delegate` needs to set where they want their rewards to be paid out. This can be
-	///   anything other than the `delegate` account itself.
-	///
-	/// This is similar to [`Self::accept_delegations`] but allows a current nominator to migrate to
-	/// a `delegate`.
-	fn migrate_accept_delegations(
-		new_delegate: &Self::AccountId,
-		proxy_delegator: &Self::AccountId,
-		payee: &Self::AccountId,
-	) -> DispatchResult;
-
-	/// Stop accepting new delegations to this account.
-	fn block_delegations(delegate: &Self::AccountId) -> DispatchResult;
-
-	/// Unblock delegations to this account.
-	fn unblock_delegations(delegate: &Self::AccountId) -> DispatchResult;
-
-	/// Remove oneself as a `delegate`.
-	///
-	/// This will only succeed if all delegations to this `delegate` are withdrawn.
-	fn kill_delegate(delegate: &Self::AccountId) -> DispatchResult;
-
-	/// Bond all fund that is delegated but not staked.
-	/// FIXME(ank4n): Should not be allowed as withdrawn funds would get restaked.
-	fn bond_all(delegate: &Self::AccountId) -> DispatchResult;
-
-	/// Request withdrawal of unbonded stake of `delegate` belonging to the provided `delegator`.
-	///
-	/// Important: It is upto `delegate` to enforce which `delegator` can withdraw `value`. The
-	/// withdrawn value is released in `delegator`'s account.
-	fn delegate_withdraw(
-		delegate: &Self::AccountId,
-		delegator: &Self::AccountId,
-		value: Self::Balance,
-		num_slashing_spans: u32,
-	) -> DispatchResult;
-
-	/// Applies a pending slash on `delegate` by passing a delegator account who should be slashed
-	/// and the value to be slashed. Optionally also takes a reporter account who will be rewarded
-	/// from part of the slash imbalance.
-	fn apply_slash(
-		delegate: &Self::AccountId,
-		delegator: &Self::AccountId,
-		value: Self::Balance,
-		reporter: Option<Self::AccountId>,
-	) -> DispatchResult;
-
-	/// Move a delegated amount from `proxy_delegator` to `new_delegator`.
-	///
-	/// `Delegate` must have used [`Self::migrate_accept_delegations`] to setup a `proxy_delegator`.
-	/// This is useful for migrating old pool accounts using direct staking to lazily move
-	/// delegators to the new delegated pool account.
-	fn migrate_delegator(
-		delegate: &Self::AccountId,
-		new_delegator: &Self::AccountId,
-		value: Self::Balance,
-	) -> DispatchResult;
-
-	/// Delegate some funds to a `delegate` account.
-	fn delegate(
-		delegator: &Self::AccountId,
-		delegate: &Self::AccountId,
-		value: Self::Balance,
-	) -> DispatchResult;
-}
-
 /// Something that provides delegation support to core staking.
 pub trait StakingDelegationSupport {
 	/// Balance type used by the staking system.
@@ -202,6 +98,9 @@ pub trait PoolAdapter {
 		amount: Self::Balance,
 	) -> DispatchResult;
 
+	/// Returns true if the `delegate` has pending slash to be applied.
+	fn has_pending_slash(delegate: &Self::AccountId) -> bool;
+
 	/// Apply a slash to the `delegator`.
 	///
 	/// This is called when the corresponding `delegate` has pending slash to be applied.

From 7c276abc615ece012e82e94da54f71cabe2ebd91 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 24 Feb 2024 20:10:16 +0100
Subject: [PATCH 145/202] fmt

---
 substrate/frame/nomination-pools/src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index da160498210b0..5c084fb30eb94 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -2248,7 +2248,7 @@ pub mod pallet {
 			let mut sub_pools =
 				SubPoolsStorage::<T>::get(member.pool_id).ok_or(Error::<T>::SubPoolsNotFound)?;
 
-			if bonded_pool.has_pending_slash(){
+			if bonded_pool.has_pending_slash() {
 				// apply slash if any before withdraw.
 				let _ = Self::do_apply_slash(&member_account, None);
 			}

From 086d2f68370a02595b172fcfc75415a8498c9ef9 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 24 Feb 2024 21:15:12 +0100
Subject: [PATCH 146/202] finish test for slashing

---
 substrate/frame/delegated-staking/src/lib.rs  |  3 +-
 substrate/frame/delegated-staking/src/mock.rs |  2 +
 .../frame/delegated-staking/src/tests.rs      | 65 ++++++++++++-------
 3 files changed, 45 insertions(+), 25 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 04ee1f3525d77..fd44eeb7625e4 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -636,6 +636,7 @@ impl<T: Config> Pallet<T> {
 		let actual_slash = credit.peek();
 
 		// remove the slashed amount
+		// FIXME(ank4n) add a ledger method to reduce pending slash.
 		delegate.ledger.pending_slash.saturating_reduce(actual_slash);
 		delegate.ledger.total_delegated.saturating_reduce(actual_slash);
 		delegate.save();
@@ -691,8 +692,6 @@ impl<T: Config> Pallet<T> {
 				"delegate should be bonded and not validator"
 			);
 
-			println!("stakeable_balance: {:?}", ledger.stakeable_balance());
-			println!("stake: {:?}", T::CoreStaking::stake(&delegate).unwrap());
 			ensure!(
 				ledger.stakeable_balance() >=
 					T::CoreStaking::total_stake(&delegate)
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 8c5113a5e6b03..f31035b3c7259 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -266,6 +266,8 @@ impl ExtBuilder {
 		let mut ext = self.build();
 		ext.execute_with(test);
 		ext.execute_with(|| {
+			// make sure pool state is correct.
+			Pools::do_try_state(255).unwrap();
 			DelegatedStaking::do_try_state().unwrap();
 		});
 	}
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 5a73af747cb11..c83b2c3f750b9 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -959,10 +959,10 @@ mod pool_integration {
 			assert_eq!(
 				pool_events_since_last_call(),
 				vec![
-					// 301 did not get slashed as all as it unbonded in an era before slash.
-					// 302 got slashed 50% of 100 = 50.
+					// 300 did not get slashed as all as it unbonded in an era before slash.
+					// 301 got slashed 50% of 100 = 50.
 					PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 6, balance: 50 },
-					// 303 got slashed 50% of 100 = 50.
+					// 302 got slashed 50% of 100 = 50.
 					PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 7, balance: 50 },
 					// Rest of the pool slashed 50% of 800 = 400.
 					PoolsEvent::PoolSlashed { pool_id: 1, balance: 400 },
@@ -990,31 +990,50 @@ mod pool_integration {
 			assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(300).into(), 300, 1));
 			assert_eq!(
 				events_since_last_call(),
-				vec![Event::Withdrawn { delegate: pool_acc, delegator: 300, amount: 100 },]
+				vec![Event::Withdrawn { delegate: pool_acc, delegator: 300, amount: 100 }]
 			);
 			assert_eq!(get_pool_delegate(pool_id).ledger.pending_slash, 500);
 
-			let pre_301 = Balances::free_balance(301);
-			// 301 is slashed and should only be able to withdraw 50.
-			assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(301).into(), 301, 1));
-			assert_eq!(
-				events_since_last_call(),
-				vec![
-					// half amount is slashed first.
-					Event::Slashed { delegate: pool_acc, delegator: 301, amount: 50 },
-					// rest of it is withdrawn.
-					Event::Withdrawn { delegate: pool_acc, delegator: 301, amount: 50 },
-				]
-			);
-			assert_eq!(get_pool_delegate(pool_id).ledger.pending_slash, 450);
-			assert_eq!(held_balance(&301), 0);
-			assert_eq!(Balances::free_balance(301) - pre_301, 50);
+			// withdraw the other two delegators (301 and 302) who were unbonding.
+			for i in 301..=302 {
+				let pre_balance = Balances::free_balance(i);
+				let pre_pending_slash = get_pool_delegate(pool_id).ledger.pending_slash;
+				assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(i).into(), i, 0));
+				assert_eq!(
+					events_since_last_call(),
+					vec![
+						Event::Slashed { delegate: pool_acc, delegator: i, amount: 50 },
+						Event::Withdrawn { delegate: pool_acc, delegator: i, amount: 50 },
+					]
+				);
+				assert_eq!(get_pool_delegate(pool_id).ledger.pending_slash, pre_pending_slash - 50);
+				assert_eq!(held_balance(&i), 0);
+				assert_eq!(Balances::free_balance(i) - pre_balance, 50);
+			}
+
+			// let's update all the slash
+			let slash_reporter = 99;
+			// give our reporter some balance.
+			fund(&slash_reporter, 100);
 
-			// delegators cannot unbond without applying pending slash on their accounts.
-			// slash_amount = total balance held - (balance from active pool + balance from
-			// unbonding pool)
+			for i in 303..306 {
+				let pre_pending_slash = get_pool_delegate(pool_id).ledger.pending_slash;
+				assert_ok!(Pools::apply_slash(RawOrigin::Signed(slash_reporter).into(), i));
 
-			// when unbonding, should apply slash. Make sure numbers are good.
+				// each member is slashed 50% of 100 = 50.
+				assert_eq!(get_pool_delegate(pool_id).ledger.pending_slash, pre_pending_slash - 50);
+				// left with 50.
+				assert_eq!(held_balance(&i), 50);
+			}
+			// reporter is paid SlashRewardFraction of the slash, i.e. 10% of 50 = 5
+			assert_eq!(Balances::free_balance(slash_reporter), 100 + 5 * 3);
+			// slash creator
+			assert_ok!(Pools::apply_slash(RawOrigin::Signed(slash_reporter).into(), creator));
+			// all slash should be applied now.
+			assert_eq!(get_pool_delegate(pool_id).ledger.pending_slash, 0);
+			// for creator, 50% of stake should be slashed (250), 10% of which should go to reporter
+			// (25).
+			assert_eq!(Balances::free_balance(slash_reporter), 115 + 25);
 		});
 	}
 

From afc08216baa6408500476a1f74010b39c739384b Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sat, 24 Feb 2024 21:23:23 +0100
Subject: [PATCH 147/202] few more fixmes

---
 substrate/frame/delegated-staking/src/tests.rs | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index c83b2c3f750b9..0e34dc2f30cae 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -199,7 +199,11 @@ fn delegate_restrictions() {
 
 #[test]
 fn apply_pending_slash() {
-	ExtBuilder::default().build_and_execute(|| ());
+	ExtBuilder::default().build_and_execute(|| {
+		(
+        // fixme(ank4n): add tests for apply_pending_slash
+        )
+	});
 }
 
 /// Integration tests with pallet-staking.
@@ -488,8 +492,7 @@ mod staking_integration {
 		ExtBuilder::default().build_and_execute(|| {
 			setup_delegation_stake(200, 201, (210..250).collect(), 100, 0);
 			start_era(1);
-
-			// delegate is slashed
+            // fixme(ank4n): add tests for slashing
 		});
 	}
 

From fb1eba4441634d2e391c7930727b9413da3a63ce Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 25 Feb 2024 00:05:14 +0100
Subject: [PATCH 148/202] add crate docs

---
 substrate/frame/delegated-staking/src/lib.rs | 145 +++++++++++++++----
 1 file changed, 120 insertions(+), 25 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index fd44eeb7625e4..870fd0274602c 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -15,35 +15,129 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#![cfg_attr(not(feature = "std"), no_std)]
-#![deny(rustdoc::broken_intra_doc_links)]
-// FIXME(ank4n): fix docs
-//! An implementation of a delegation system for staking that can be utilised using
-//! [`DelegationInterface`]. In future, if exposed via extrinsic, these primitives could also be
-//! used by off-chain entities, or by foreign multi-locations (via xcm).
+//! # Delegated Staking Pallet
+//!
+//! An abstraction over staking pallet to support delegation of funds to a `delegate` account which
+//! can use all the delegated funds to it in the staking pallet as if its own fund.
+//!
+//! NOTE: The pallet exposes extrinsics which are not yet meant to be exposed in the runtime but
+//! only to be used by other pallets in the same runtime.
+//!
+//! ## Goals
+//!
+//! The direct nominators on Staking pallet does not scale well. NominationPool was created to
+//! address this by pooling delegator funds into one account and then staking it. This though had
+//! a very important limitation that the funds were moved from delegator account to pool account
+//! and hence the delegator lost control over their funds for using it for other purposes such as
+//! governance. This pallet aims to solve this by extending the staking pallet to support a new
+//! primitive function: delegation of funds to an account for the intent of staking.
+//!
+//! #### Reward and Slashing
+//! This pallet does not enforce any specific strategy for how rewards or slashes are applied. It
+//! is upto the `delegate` account to decide how to apply the rewards and slashes.
+//!
+//! This importantly allows clients of this pallet to build their own strategies for reward/slashes.
+//! For example, a `delegate` account can choose to first slash the reward pot before slashing the
+//! delegators. Or part of the reward can go to a insurance fund that can be used to cover any
+//! potential future slashes. The goal is to eventually allow foreign MultiLocations
+//! (smart contracts or pallets on another chain) to build their own pooled staking solutions
+//! similar to `NominationPool`.
+//!
+//! ## Key Terminologies
+//! - *Delegate*: An account who accepts delegations from other accounts (called `Delegators`).
+//! - *Delegator*: An account who delegates their funds to a `delegate`.
+//! - *DelegationLedger*: A data structure that stores important information about the `delegate`
+//! 	such as their total delegated stake.
+//! - *Delegation*: A data structure that stores the amount of funds delegated to a `delegate` by a
+//! 	`delegator`.
+//!
+//! ## Interface
+//!
+//! ### Dispatchable Calls
+//! The pallet exposes the following [`Call`]s:
+//! - `register_as_delegate`: Register an account to be a `Delegate`. Once an account is registered
+//! 	as a `Delegate`, for staking operations, only its delegated funds are used. This means it
+//! 	cannot use its own free balance to stake.
+//! - `migrate_to_delegate`: This allows a `Nominator` account to become a `Delegate` account.
+//! 	Explained in more detail in the `Migration` section.
+//! - `release`: Release funds to `delegator` from `unclaimed_withdrawals` register of the
+//!   `delegate`.
+//! - `migrate_delegation`: Migrate delegated funds from one account to another. This is useful for
+//!   example, delegators to a pool account which has migrated to be `delegate` to migrate their
+//!   funds from pool account back to their own account and delegated to pool as a `delegator`. Once
+//!   the funds are migrated, the `delegator` can use the funds for other purposes which allows
+//!   usage of held funds in an account, such as governance.
+//! - `delegate_funds`: Delegate funds to a `Delegate` account and update the bond to staking.
+//!
+//! ### (Staking Interface)[StakingInterface]
+//! This pallet reimplements the staking interface as a wrapper implementation over
+//! [Config::CoreStaking] to provide delegation based staking. NominationPool can use this pallet as
+//! its Staking provider to support delegation based staking from pool accounts.
+//!
+//! ### (Staking Delegation Support)[StakingDelegationSupport]
+//! The pallet implements the staking delegation support trait which staking pallet can use to
+//! provide compatibility with this pallet.
 //!
-//! Delegate: Someone who accepts delegations. An account can set their intention to accept
-//! delegations by calling [`DelegationInterface::accept_delegations`]. This account cannot have
-//! another role in the staking system and once set as `delegate`, can only stake with their
-//! delegated balance, i.e. cannot use their own free balance to stake. They can also block new
-//! delegations by calling [`DelegationInterface::block_delegations`] or remove themselves from
-//! being a `delegate` by calling [`DelegationInterface::kill_delegate`] once all delegations to it
-//! are removed.
+//! ### (Pool Adapter)[delegation::PoolAdapter]
+//! The pallet also implements the pool adapter trait which allows NominationPool to use this pallet
+//! to support delegation based staking from pool accounts. This strategy also allows the pool to
+//! switch implementations while having minimal changes to its own logic.
 //!
-//! Delegate is also responsible for managing reward distribution and slashes of delegators.
+//! ## Lazy Slashing
+//! One of the reasons why direct nominators on staking pallet cannot scale well is because all
+//! nominators are slashed at the same time. This is expensive and needs to be bounded operation.
 //!
-//! Delegator: Someone who delegates their funds to a `delegate`. A delegator can delegate their
-//! funds to one and only one `delegate`. They also can not be a nominator or validator.
+//! This pallet implements a lazy slashing mechanism. Any slashes to a `delegate` are posted in its
+//! [`DelegationLedger`] as a pending slash. Since the actual amount is held in the multiple
+//! `delegator` accounts, this pallet has no way to know how to apply slash. It is `delegate`'s
+//! responsibility to apply slashes for each delegator, one at a time. Staking pallet ensures the
+//! pending slash never exceeds staked amount and would freeze further withdraws until pending
+//! slashes are applied.
 //!
-//! Reward payouts destination: Rewards cannot be paid out to `delegate` account since these funds
-//! are not directly exposed. This implies, rewards cannot be auto-compounded and needs to be staked
-//! again after distributing it to delegators.
+//! `NominationPool` can apply slash for all its members by calling [PoolAdapter::apply_slash].
 //!
-//! Any slashes to a `delegate` are posted in its [`DelegationLedger`] as a pending slash. Since the
-//! actual amount is held in the multiple `delegator` accounts, this pallet has no way to know how
-//! to apply slash. It is `delegate`'s responsibility to apply slashes for each delegator, one at a
-//! time. Staking pallet ensures the pending slash never exceeds staked amount and would freeze
-//! further withdraws until pending slashes are applied.
+//! ## Migration from Nominator to Delegate
+//! More details here. https://hackmd.io/1jhFRj2MTzeEmAkJgbsBtA?both
+//!
+//! ## Reward Destination Restrictions
+//! This pallets set an important restriction of rewards account to be separate from `delegate`
+//! account. This is because, `delegate` balance is not what is directly exposed but the funds that
+//! are delegated to it. For `delegate` accounts, we have also no way to auto-compound rewards. The
+//! rewards need to be paid out to delegators and then delegated again to the `delegate` account.
+//!
+//! ## Nomination Pool vs Delegation Staking
+//! This pallet is not a replacement for Nomination Pool but adds a new primitive over staking
+//! pallet that can be used by Nomination Pool to support delegation based staking. It can be
+//! thought of as something in middle of Nomination Pool and Staking Pallet. Technically, these
+//! changes could be made in one of those pallets as well but that would have meant significant
+//! refactoring and high chances of introducing a regression. With this approach, we can keep the
+//! existing pallets with minimal changes and introduce a new pallet that can be optionally used by
+//! Nomination Pool. This is completely configurable and a runtime can choose whether to use
+//! this pallet or not.
+//!
+//! With that said, following is the main difference between
+//! #### Nomination Pool without delegation support
+//!  1) transfer fund from delegator to pool account, and
+//!  2) stake from pool account as a direct nominator.
+//!
+//! #### Nomination Pool with delegation support
+//!  1) delegate fund from delegator to pool account, and
+//!  2) stake from pool account as a `Delegate` account on the staking pallet.
+//!
+//! The difference being, in the second approach, the delegated funds will be locked in-place in
+//! user's account enabling them to participate in use cases that allows use of `held` funds such
+//! as participation in governance voting.
+//!
+//! Nomination pool still does all the heavy lifting around pool administration, reward
+//! distribution, lazy slashing and as such, is not meant to be replaced with this pallet.
+//!
+//! ## Limitations
+//! TODO(ank4n): Add limitations.
+//!
+
+#![cfg_attr(not(feature = "std"), no_std)]
+#![deny(rustdoc::broken_intra_doc_links)]
+
 #[cfg(test)]
 mod mock;
 
@@ -83,7 +177,8 @@ use sp_runtime::{
 	ArithmeticError, DispatchResult, Perbill, RuntimeDebug, Saturating, TryRuntimeError,
 };
 use sp_staking::{
-	delegation::StakingDelegationSupport, EraIndex, Stake, StakerStatus, StakingInterface,
+	delegation, delegation::StakingDelegationSupport, EraIndex, Stake, StakerStatus,
+	StakingInterface,
 };
 use sp_std::{convert::TryInto, prelude::*};
 

From a714f72988cc18066160a6f80303d3688eb009e8 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 25 Feb 2024 00:16:39 +0100
Subject: [PATCH 149/202] fix docs

---
 substrate/frame/delegated-staking/src/impls.rs |  6 +++---
 substrate/frame/delegated-staking/src/lib.rs   | 18 +++++++++---------
 substrate/frame/delegated-staking/src/tests.rs |  2 +-
 substrate/primitives/staking/src/delegation.rs |  2 --
 4 files changed, 13 insertions(+), 15 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index c49e3ff90ea4b..fa4160ca4b387 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -125,7 +125,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 
 	/// Withdraw unbonding funds until current era.
 	///
-	/// Funds are moved to unclaimed_withdrawals register of the [`DelegationLedger`].
+	/// Funds are moved to unclaimed_withdrawals register of the `DelegationLedger`.
 	fn withdraw_unbonded(
 		pool_acc: Self::AccountId,
 		num_slashing_spans: u32,
@@ -260,8 +260,8 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 
 	/// Returns balance of account that is held.
 	///
-	/// - For [Delegate] accounts, this is their total delegation amount.
-	/// - For [Delegators], this is their delegation amount.
+	/// - For `delegate` accounts, this is their total delegation amount.
+	/// - For `delegator` accounts, this is their delegation amount.
 	fn total_balance(who: &Self::AccountId) -> Self::Balance {
 		if Self::is_delegator(who) {
 			return Delegation::<T>::get(who).map(|d| d.amount).unwrap_or(Zero::zero());
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 870fd0274602c..a3b2bd8a3a946 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -53,7 +53,7 @@
 //!
 //! ## Interface
 //!
-//! ### Dispatchable Calls
+//! #### Dispatchable Calls
 //! The pallet exposes the following [`Call`]s:
 //! - `register_as_delegate`: Register an account to be a `Delegate`. Once an account is registered
 //! 	as a `Delegate`, for staking operations, only its delegated funds are used. This means it
@@ -69,16 +69,16 @@
 //!   usage of held funds in an account, such as governance.
 //! - `delegate_funds`: Delegate funds to a `Delegate` account and update the bond to staking.
 //!
-//! ### (Staking Interface)[StakingInterface]
+//! #### [Staking Interface](StakingInterface)
 //! This pallet reimplements the staking interface as a wrapper implementation over
 //! [Config::CoreStaking] to provide delegation based staking. NominationPool can use this pallet as
 //! its Staking provider to support delegation based staking from pool accounts.
 //!
-//! ### (Staking Delegation Support)[StakingDelegationSupport]
+//! #### [Staking Delegation Support](StakingDelegationSupport)
 //! The pallet implements the staking delegation support trait which staking pallet can use to
 //! provide compatibility with this pallet.
 //!
-//! ### (Pool Adapter)[delegation::PoolAdapter]
+//! #### [Pool Adapter](delegation::PoolAdapter)
 //! The pallet also implements the pool adapter trait which allows NominationPool to use this pallet
 //! to support delegation based staking from pool accounts. This strategy also allows the pool to
 //! switch implementations while having minimal changes to its own logic.
@@ -88,16 +88,17 @@
 //! nominators are slashed at the same time. This is expensive and needs to be bounded operation.
 //!
 //! This pallet implements a lazy slashing mechanism. Any slashes to a `delegate` are posted in its
-//! [`DelegationLedger`] as a pending slash. Since the actual amount is held in the multiple
+//! `DelegationLedger` as a pending slash. Since the actual amount is held in the multiple
 //! `delegator` accounts, this pallet has no way to know how to apply slash. It is `delegate`'s
 //! responsibility to apply slashes for each delegator, one at a time. Staking pallet ensures the
 //! pending slash never exceeds staked amount and would freeze further withdraws until pending
 //! slashes are applied.
 //!
-//! `NominationPool` can apply slash for all its members by calling [PoolAdapter::apply_slash].
+//! `NominationPool` can apply slash for all its members by calling
+//! [delegation::PoolAdapter::delegator_slash].
 //!
 //! ## Migration from Nominator to Delegate
-//! More details here. https://hackmd.io/1jhFRj2MTzeEmAkJgbsBtA?both
+//! More details [here](https://hackmd.io/@ak0n/np-delegated-staking-migration).
 //!
 //! ## Reward Destination Restrictions
 //! This pallets set an important restriction of rewards account to be separate from `delegate`
@@ -133,7 +134,6 @@
 //!
 //! ## Limitations
 //! TODO(ank4n): Add limitations.
-//!
 
 #![cfg_attr(not(feature = "std"), no_std)]
 #![deny(rustdoc::broken_intra_doc_links)]
@@ -388,7 +388,7 @@ pub mod pallet {
 			Self::do_migrate_delegation(&proxy_delegator, &delegator, amount)
 		}
 
-		/// Delegate funds to a `Delegate` account and bonds it to [T::CoreStaking].
+		/// Delegate funds to a `Delegate` account and bonds it to [Config::CoreStaking].
 		///
 		/// If delegation already exists, it increases the delegation by `amount`.
 		#[pallet::call_index(4)]
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 0e34dc2f30cae..9e3bd86ed6b07 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -492,7 +492,7 @@ mod staking_integration {
 		ExtBuilder::default().build_and_execute(|| {
 			setup_delegation_stake(200, 201, (210..250).collect(), 100, 0);
 			start_era(1);
-            // fixme(ank4n): add tests for slashing
+			// fixme(ank4n): add tests for slashing
 		});
 	}
 
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index eff5a72c1889d..d686fd8634bb4 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -90,8 +90,6 @@ pub trait PoolAdapter {
 	) -> DispatchResult;
 
 	/// Revoke delegation to pool account.
-	///
-	/// Similar to [Mutate::transfer] for Direct Stake but in reverse direction to [Self::delegate].
 	fn release_delegation(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,

From f337a9d754e8a6521921d6eec4121445bcd5f227 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 25 Feb 2024 09:19:00 +0100
Subject: [PATCH 150/202] limitations

---
 substrate/frame/delegated-staking/src/lib.rs | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index a3b2bd8a3a946..e7944e107cc10 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -133,7 +133,10 @@
 //! distribution, lazy slashing and as such, is not meant to be replaced with this pallet.
 //!
 //! ## Limitations
-//! TODO(ank4n): Add limitations.
+//! - Rewards are not auto-compounded.
+//! - Slashes are lazy and hence there could be a period of time when an account can use funds for
+//! 	operations such as voting in governance even though they should be slashed.
+//!
 
 #![cfg_attr(not(feature = "std"), no_std)]
 #![deny(rustdoc::broken_intra_doc_links)]

From bccb01e46ebae7073e74e4a16ddb12eecdc011a0 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 25 Feb 2024 10:31:52 +0100
Subject: [PATCH 151/202] small edit

---
 substrate/frame/delegated-staking/src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index e7944e107cc10..4c0043db8642a 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -133,7 +133,7 @@
 //! distribution, lazy slashing and as such, is not meant to be replaced with this pallet.
 //!
 //! ## Limitations
-//! - Rewards are not auto-compounded.
+//! - Rewards can not be auto-compounded.
 //! - Slashes are lazy and hence there could be a period of time when an account can use funds for
 //! 	operations such as voting in governance even though they should be slashed.
 //!

From 72ee3e4bc297931271f657230896eb4e7ddd7d58 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 25 Feb 2024 13:09:11 +0100
Subject: [PATCH 152/202] minor doc fixes

---
 substrate/frame/delegated-staking/src/lib.rs  | 66 ++++++++++---------
 .../frame/delegated-staking/src/tests.rs      | 10 +--
 2 files changed, 41 insertions(+), 35 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 4c0043db8642a..d095bec220568 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -136,14 +136,12 @@
 //! - Rewards can not be auto-compounded.
 //! - Slashes are lazy and hence there could be a period of time when an account can use funds for
 //! 	operations such as voting in governance even though they should be slashed.
-//!
 
 #![cfg_attr(not(feature = "std"), no_std)]
 #![deny(rustdoc::broken_intra_doc_links)]
 
 #[cfg(test)]
 mod mock;
-
 #[cfg(test)]
 mod tests;
 
@@ -153,7 +151,6 @@ mod types;
 
 use types::*;
 
-// implementation of public traits.
 mod impls;
 
 #[cfg(feature = "runtime-benchmarks")]
@@ -206,12 +203,14 @@ pub mod pallet {
 		#[pallet::constant]
 		type PalletId: Get<frame_support::PalletId>;
 
+		/// Currency type.
 		type Currency: FunHoldMutate<Self::AccountId, Reason = Self::RuntimeHoldReason>
 			+ FunMutate<Self::AccountId>
 			+ FunHoldBalanced<Self::AccountId>;
 
 		/// Handler for the unbalanced reduction when slashing a delegator.
 		type OnSlash: OnUnbalanced<Credit<Self::AccountId, Self::Currency>>;
+
 		/// Overarching hold reason.
 		type RuntimeHoldReason: From<HoldReason>;
 
@@ -230,9 +229,8 @@ pub mod pallet {
 		/// Delegation conditions are not met.
 		///
 		/// Possible issues are
-		/// 1) Account does not accept or has blocked delegation.
-		/// 2) Cannot delegate to self,
-		/// 3) Cannot delegate to multiple delegates,
+		/// 1) Cannot delegate to self,
+		/// 2) Cannot delegate to multiple delegates,
 		InvalidDelegation,
 		/// The account does not have enough funds to perform the operation.
 		NotEnoughFunds,
@@ -244,9 +242,9 @@ pub mod pallet {
 		BadState,
 		/// Unapplied pending slash restricts operation on `delegate`.
 		UnappliedSlash,
-		/// Failed to withdraw amount from Core Staking Ledger.
+		/// Failed to withdraw amount from Core Staking.
 		WithdrawFailed,
-		/// This operation is not supported with Delegation Staking.
+		/// Operation not supported by this pallet.
 		NotSupported,
 		/// Account does not accept delegations.
 		NotAcceptingDelegations,
@@ -260,32 +258,26 @@ pub mod pallet {
 		Delegating,
 	}
 
-	// #[pallet::genesis_config]
-	// #[derive(frame_support::DefaultNoBound)]
-	// pub struct GenesisConfig<T: Config> {}
-	//
-	// #[pallet::genesis_build]
-	// impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
-	// 	fn build(&self) {}
-	// }
-
 	#[pallet::event]
 	#[pallet::generate_deposit(pub (super) fn deposit_event)]
 	pub enum Event<T: Config> {
+		/// Funds delegated by a delegator.
 		Delegated { delegate: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
-		Withdrawn { delegate: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
+		/// Funds released to a delegator.
+		Released { delegate: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
+		/// Funds slashed from a delegator.
 		Slashed { delegate: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
 	}
 
-	/// Map of Delegators to their delegation, i.e. (delegate, delegation_amount).
+	/// Map of Delegators to their `Delegation`.
 	///
-	/// Note: We are not using a double map with delegator and `delegate` account as keys since we
-	/// want to restrict delegators to delegate only to one account.
+	/// Implementation note: We are not using a double map with `delegator` and `delegate` account
+	/// as keys since we want to restrict delegators to delegate only to one account at a time.
 	#[pallet::storage]
 	pub(crate) type Delegators<T: Config> =
 		CountedStorageMap<_, Twox64Concat, T::AccountId, Delegation<T>, OptionQuery>;
 
-	/// Map of `Delegate` to their Ledger.
+	/// Map of `Delegate` to their `DelegationLedger`.
 	#[pallet::storage]
 	pub(crate) type Delegates<T: Config> =
 		CountedStorageMap<_, Twox64Concat, T::AccountId, DelegationLedger<T>, OptionQuery>;
@@ -322,7 +314,17 @@ pub mod pallet {
 
 		/// Migrate from a `Nominator` account to `Delegate` account.
 		///
-		/// Internally transfers minimum balance to a proxy delegator account created for it.
+		/// The origin needs to
+		/// - be a `Nominator` with `CoreStaking`,
+		/// - not already a `Delegate`,
+		/// - have enough funds to transfer existential deposit to a delegator account created for
+		///   the migration.
+		///
+		/// This operation will create a new delegator account for the origin called
+		/// `proxy_delegator` and transfer the staked amount to it. The `proxy_delegator` delegates
+		/// the funds to the origin making origin a `Delegate` account. The actual `delegator`
+		/// accounts of the origin can later migrate their funds using [Call::migrate_delegation] to
+		/// claim back their share of delegated funds from `proxy_delegator` to self.
 		#[pallet::call_index(1)]
 		#[pallet::weight(Weight::default())]
 		pub fn migrate_to_delegate(
@@ -330,9 +332,10 @@ pub mod pallet {
 			reward_account: T::AccountId,
 		) -> DispatchResult {
 			let who = ensure_signed(origin)?;
-			// Ensure is not already a delegate.
+			// ensure who is not already a delegate.
 			ensure!(!Self::is_delegate(&who), Error::<T>::NotAllowed);
 
+			// and they should already be a nominator in `CoreStaking`.
 			ensure!(Self::is_direct_nominator(&who), Error::<T>::NotAllowed);
 
 			// Reward account cannot be same as `delegate` account.
@@ -343,9 +346,10 @@ pub mod pallet {
 
 		/// Release delegated amount to delegator.
 		///
-		/// Tries to withdraw unbonded fund if needed from staking and release amount to delegator.
+		/// This can be called by existing `delegate` accounts.
 		///
-		/// Only `delegate` account can call this.
+		/// Tries to withdraw unbonded fund from `CoreStaking` if needed and release amount to
+		/// `delegator`.
 		#[pallet::call_index(2)]
 		#[pallet::weight(Weight::default())]
 		pub fn release(
@@ -360,9 +364,9 @@ pub mod pallet {
 
 		/// Migrate delegated fund.
 		///
-		/// This moves delegator funds from `pxoxy_delegator` account to `delegator` account.
+		/// This can be called by migrating `delegate` accounts.
 		///
-		/// Only `delegate` account can call this.
+		/// This moves delegator funds from `pxoxy_delegator` account to `delegator` account.
 		#[pallet::call_index(3)]
 		#[pallet::weight(Weight::default())]
 		pub fn migrate_delegation(
@@ -383,7 +387,7 @@ pub mod pallet {
 			// ensure delegate is sane.
 			ensure!(Self::is_delegate(&delegate), Error::<T>::NotDelegate);
 
-			// and has some delegated balance to migrate.
+			// and has enough delegated balance to migrate.
 			let proxy_delegator = Self::sub_account(AccountType::ProxyDelegator, delegate);
 			let balance_remaining = Self::held_balance_of(&proxy_delegator);
 			ensure!(balance_remaining >= amount, Error::<T>::NotEnoughFunds);
@@ -420,7 +424,9 @@ pub mod pallet {
 				T::Currency::reducible_balance(&who, Preservation::Preserve, Fortitude::Polite);
 			ensure!(delegator_balance >= amount, Error::<T>::NotEnoughFunds);
 
+			// add to delegation
 			Self::do_delegate(&who, &delegate, amount)?;
+			// bond the amount to `CoreStaking`.
 			Self::do_bond(&delegate, amount)
 		}
 
@@ -622,7 +628,7 @@ impl<T: Config> Pallet<T> {
 
 		defensive_assert!(released == amount, "hold should have been released fully");
 
-		Self::deposit_event(Event::<T>::Withdrawn {
+		Self::deposit_event(Event::<T>::Released {
 			delegate: who.clone(),
 			delegator: delegator.clone(),
 			amount,
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 9e3bd86ed6b07..f536584c8e946 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -769,7 +769,7 @@ mod pool_integration {
 			assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(301).into(), 301, 0));
 			assert_eq!(
 				events_since_last_call(),
-				vec![Event::Withdrawn { delegate: pool_acc, delegator: 301, amount: 50 }]
+				vec![Event::Released { delegate: pool_acc, delegator: 301, amount: 50 }]
 			);
 			assert_eq!(
 				pool_events_since_last_call(),
@@ -786,8 +786,8 @@ mod pool_integration {
 			assert_eq!(
 				events_since_last_call(),
 				vec![
-					Event::Withdrawn { delegate: pool_acc, delegator: 302, amount: 100 },
-					Event::Withdrawn { delegate: pool_acc, delegator: 303, amount: 200 },
+					Event::Released { delegate: pool_acc, delegator: 302, amount: 100 },
+					Event::Released { delegate: pool_acc, delegator: 303, amount: 200 },
 				]
 			);
 			assert_eq!(
@@ -993,7 +993,7 @@ mod pool_integration {
 			assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(300).into(), 300, 1));
 			assert_eq!(
 				events_since_last_call(),
-				vec![Event::Withdrawn { delegate: pool_acc, delegator: 300, amount: 100 }]
+				vec![Event::Released { delegate: pool_acc, delegator: 300, amount: 100 }]
 			);
 			assert_eq!(get_pool_delegate(pool_id).ledger.pending_slash, 500);
 
@@ -1006,7 +1006,7 @@ mod pool_integration {
 					events_since_last_call(),
 					vec![
 						Event::Slashed { delegate: pool_acc, delegator: i, amount: 50 },
-						Event::Withdrawn { delegate: pool_acc, delegator: i, amount: 50 },
+						Event::Released { delegate: pool_acc, delegator: i, amount: 50 },
 					]
 				);
 				assert_eq!(get_pool_delegate(pool_id).ledger.pending_slash, pre_pending_slash - 50);

From 278225ebfd0e56878d31511a32847cb6788c3033 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 25 Feb 2024 13:16:25 +0100
Subject: [PATCH 153/202] rename block delegation

---
 substrate/frame/delegated-staking/src/lib.rs   | 10 ++++++----
 substrate/frame/delegated-staking/src/tests.rs |  6 +++---
 2 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index d095bec220568..cb0b5ea7acb9d 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -430,16 +430,18 @@ pub mod pallet {
 			Self::do_bond(&delegate, amount)
 		}
 
-		/// Stop accepting new delegation.
+		/// Toggle delegate status to start or stop accepting new delegations.
 		///
-		/// To unblock, pass false.
+		/// This can only be used by existing delegates. If not a delegate yet, use
+		/// [Call::register_as_delegate] first.
 		#[pallet::call_index(5)]
 		#[pallet::weight(Weight::default())]
-		pub fn block_delegations(origin: OriginFor<T>, block: bool) -> DispatchResult {
+		pub fn toggle_delegate_status(origin: OriginFor<T>) -> DispatchResult {
 			let who = ensure_signed(origin)?;
 
 			let delegate = Delegate::<T>::from(&who)?;
-			delegate.update_status(block).save();
+            let should_block = !delegate.ledger.blocked;
+			delegate.update_status(should_block).save();
 
 			Ok(())
 		}
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index f536584c8e946..b253fad01871b 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -462,7 +462,7 @@ mod staking_integration {
 	}
 
 	#[test]
-	fn block_delegations() {
+	fn toggle_delegate_status() {
 		ExtBuilder::default().build_and_execute(|| {
 			assert_ok!(DelegatedStaking::register_as_delegate(RawOrigin::Signed(200).into(), 201));
 
@@ -471,7 +471,7 @@ mod staking_integration {
 			assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(300).into(), 200, 100));
 
 			// delegate blocks delegation
-			assert_ok!(DelegatedStaking::block_delegations(RawOrigin::Signed(200).into(), true));
+			assert_ok!(DelegatedStaking::toggle_delegate_status(RawOrigin::Signed(200).into()));
 
 			// cannot delegate to it anymore
 			assert_noop!(
@@ -480,7 +480,7 @@ mod staking_integration {
 			);
 
 			// delegate can unblock delegation
-			assert_ok!(DelegatedStaking::block_delegations(RawOrigin::Signed(200).into(), false));
+			assert_ok!(DelegatedStaking::toggle_delegate_status(RawOrigin::Signed(200).into()));
 
 			// delegation works again
 			assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(300).into(), 200, 100));

From b32dceda913a6a03d3ae1ccb93f375c788e724f5 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 25 Feb 2024 13:23:35 +0100
Subject: [PATCH 154/202] add slash call

---
 substrate/frame/delegated-staking/src/lib.rs | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index cb0b5ea7acb9d..bdecb3834c11b 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -445,6 +445,18 @@ pub mod pallet {
 
 			Ok(())
 		}
+
+		/// Apply slash to a delegator account.
+		///
+		/// `Delegate` accounts with pending slash in their ledger can call this to apply slash to
+		/// one of its `delegator` account. Each slash to a delegator account needs to be posted
+		/// separately until all pending slash is cleared.
+		#[pallet::call_index(6)]
+		#[pallet::weight(Weight::default())]
+		pub fn apply_slash(origin: OriginFor<T>, delegator: T::AccountId, amount: BalanceOf<T>) -> DispatchResult {
+			let who = ensure_signed(origin)?;
+			Self::do_slash(who, delegator, amount, None)
+		}
 	}
 
 	#[pallet::hooks]

From 03efe85c07122c6e007b965bf3f1e299297a1959 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 25 Feb 2024 13:23:49 +0100
Subject: [PATCH 155/202] fmt

---
 substrate/frame/delegated-staking/src/lib.rs | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index bdecb3834c11b..4879c4699bbdf 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -440,7 +440,7 @@ pub mod pallet {
 			let who = ensure_signed(origin)?;
 
 			let delegate = Delegate::<T>::from(&who)?;
-            let should_block = !delegate.ledger.blocked;
+			let should_block = !delegate.ledger.blocked;
 			delegate.update_status(should_block).save();
 
 			Ok(())
@@ -453,7 +453,11 @@ pub mod pallet {
 		/// separately until all pending slash is cleared.
 		#[pallet::call_index(6)]
 		#[pallet::weight(Weight::default())]
-		pub fn apply_slash(origin: OriginFor<T>, delegator: T::AccountId, amount: BalanceOf<T>) -> DispatchResult {
+		pub fn apply_slash(
+			origin: OriginFor<T>,
+			delegator: T::AccountId,
+			amount: BalanceOf<T>,
+		) -> DispatchResult {
 			let who = ensure_signed(origin)?;
 			Self::do_slash(who, delegator, amount, None)
 		}

From 9807c51befb68ddab932f6150c8b0f9795a06b6b Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 25 Feb 2024 13:40:42 +0100
Subject: [PATCH 156/202] minor refactors

---
 substrate/frame/delegated-staking/src/lib.rs   | 15 +++++++++------
 substrate/frame/delegated-staking/src/types.rs | 18 +++++++++++++++---
 2 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 4879c4699bbdf..df60893d53e02 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -475,6 +475,7 @@ pub mod pallet {
 }
 
 impl<T: Config> Pallet<T> {
+	/// Derive a (keyless) pot account from the given delegate account and account type.
 	pub(crate) fn sub_account(
 		account_type: AccountType,
 		delegate_account: T::AccountId,
@@ -486,20 +487,23 @@ impl<T: Config> Pallet<T> {
 	pub(crate) fn held_balance_of(who: &T::AccountId) -> BalanceOf<T> {
 		T::Currency::balance_on_hold(&HoldReason::Delegating.into(), who)
 	}
+
+	/// Returns true if who is registered as a `Delegate`.
 	fn is_delegate(who: &T::AccountId) -> bool {
 		<Delegates<T>>::contains_key(who)
 	}
 
+	/// Returns true if who is delegating to a `Delegate` account.
 	fn is_delegator(who: &T::AccountId) -> bool {
 		<Delegators<T>>::contains_key(who)
 	}
 
-	/// Returns true if who is not already staking.
+	/// Returns true if who is not already staking on [`Config::CoreStaking`].
 	fn not_direct_staker(who: &T::AccountId) -> bool {
 		T::CoreStaking::status(&who).is_err()
 	}
 
-	/// Returns true if who is not already staking.
+	/// Returns true if who is a [`StakerStatus::Nominator`] on [`Config::CoreStaking`].
 	fn is_direct_nominator(who: &T::AccountId) -> bool {
 		T::CoreStaking::status(who)
 			.map(|status| matches!(status, StakerStatus::Nominator(_)))
@@ -619,7 +623,7 @@ impl<T: Config> Pallet<T> {
 		ensure!(delegate.ledger.unclaimed_withdrawals >= amount, Error::<T>::NotEnoughFunds);
 
 		// book keep into ledger
-		delegate.try_withdraw(amount)?;
+		delegate.remove_unclaimed_withdraw(amount)?;
 
 		// kill delegate if not delegated and nothing to claim anymore.
 		delegate.save_or_kill()?;
@@ -678,7 +682,7 @@ impl<T: Config> Pallet<T> {
 		let new_withdrawn =
 			pre_total.checked_sub(&post_total).defensive_ok_or(Error::<T>::BadState)?;
 
-		delegate.try_add_unclaimed_withdraw(new_withdrawn)?;
+		delegate.add_unclaimed_withdraw(new_withdrawn)?;
 
 		delegate.clone().save();
 
@@ -759,8 +763,7 @@ impl<T: Config> Pallet<T> {
 
 		// remove the slashed amount
 		// FIXME(ank4n) add a ledger method to reduce pending slash.
-		delegate.ledger.pending_slash.saturating_reduce(actual_slash);
-		delegate.ledger.total_delegated.saturating_reduce(actual_slash);
+		delegate.remove_slash(actual_slash);
 		delegate.save();
 
 		delegation
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index 6d68f4af62f22..e1b818aa9c82b 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -19,6 +19,7 @@
 //! Basic types used in delegated staking.
 
 use super::*;
+use frame_support::traits::DefensiveSaturating;
 
 /// The type of pot account being created.
 #[derive(Encode, Decode)]
@@ -93,7 +94,8 @@ pub struct DelegationLedger<T: Config> {
 	/// Sum of all delegated funds to this `delegate`.
 	#[codec(compact)]
 	pub total_delegated: BalanceOf<T>,
-	/// Funds that are withdrawn from core staking but not released to delegator/s.
+	/// Funds that are withdrawn from core staking but not released to delegator/s. It is a subset
+	/// of `total_delegated` and can never be greater than it.
 	// FIXME(ank4n): Check/test about rebond: where delegator rebond what is unlocking.
 	#[codec(compact)]
 	pub unclaimed_withdrawals: BalanceOf<T>,
@@ -158,7 +160,10 @@ impl<T: Config> Delegate<T> {
 		Ok(Delegate { key: delegate.clone(), ledger })
 	}
 
-	pub(crate) fn try_withdraw(&mut self, amount: BalanceOf<T>) -> Result<(), DispatchError> {
+	pub(crate) fn remove_unclaimed_withdraw(
+		&mut self,
+		amount: BalanceOf<T>,
+	) -> Result<(), DispatchError> {
 		self.ledger.total_delegated = self
 			.ledger
 			.total_delegated
@@ -173,7 +178,7 @@ impl<T: Config> Delegate<T> {
 		Ok(())
 	}
 
-	pub(crate) fn try_add_unclaimed_withdraw(
+	pub(crate) fn add_unclaimed_withdraw(
 		&mut self,
 		amount: BalanceOf<T>,
 	) -> Result<(), DispatchError> {
@@ -214,6 +219,10 @@ impl<T: Config> Delegate<T> {
 		net_balance.saturating_sub(bonded_stake)
 	}
 
+	pub(crate) fn remove_slash(&mut self, amount: BalanceOf<T>) {
+		self.ledger.pending_slash.defensive_saturating_reduce(amount);
+		self.ledger.total_delegated.defensive_saturating_reduce(amount);
+	}
 	pub(crate) fn ledger(&self) -> Option<DelegationLedger<T>> {
 		DelegationLedger::<T>::get(&self.key)
 	}
@@ -239,6 +248,9 @@ impl<T: Config> Delegate<T> {
 		self.ledger.save(&key)
 	}
 
+	/// Save self and remove if no delegation left.
+	///
+	/// Can return error if the delegate is in an unexpected state.
 	pub(crate) fn save_or_kill(self) -> Result<(), DispatchError> {
 		let key = self.key;
 		// see if delegate can be killed

From dbde2868bd0fc33fab135a930c1e5174ff9b17ac Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 25 Feb 2024 15:06:28 +0100
Subject: [PATCH 157/202] minor refactors

---
 .../frame/delegated-staking/src/impls.rs      |  2 +-
 substrate/frame/delegated-staking/src/lib.rs  | 15 ++++----
 substrate/frame/delegated-staking/src/mock.rs |  2 +-
 .../frame/delegated-staking/src/tests.rs      | 16 ++++-----
 .../frame/delegated-staking/src/types.rs      | 36 ++++++++++++-------
 .../frame/nomination-pools/src/adapter.rs     |  2 +-
 6 files changed, 41 insertions(+), 32 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index fa4160ca4b387..57bb4d6012901 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -254,7 +254,7 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 	/// Equivalent to [FunInspect::balance] for non delegate accounts.
 	fn releasable_balance(who: &Self::AccountId) -> Self::Balance {
 		Delegate::<T>::from(who)
-			.map(|delegate| delegate.unbonded())
+			.map(|delegate| delegate.total_unbonded())
 			.unwrap_or(Zero::zero())
 	}
 
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index df60893d53e02..f35c29f432b4a 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -168,16 +168,15 @@ use frame_support::{
 		tokens::{fungible::Credit, Fortitude, Precision, Preservation},
 		Defensive, DefensiveOption, Imbalance, OnUnbalanced,
 	},
-	transactional,
 	weights::Weight,
 };
 
 use sp_runtime::{
 	traits::{AccountIdConversion, CheckedAdd, CheckedSub, Zero},
-	ArithmeticError, DispatchResult, Perbill, RuntimeDebug, Saturating, TryRuntimeError,
+	ArithmeticError, DispatchResult, Perbill, RuntimeDebug, Saturating,
 };
 use sp_staking::{
-	delegation, delegation::StakingDelegationSupport, EraIndex, Stake, StakerStatus,
+	delegation::StakingDelegationSupport, EraIndex, Stake, StakerStatus,
 	StakingInterface,
 };
 use sp_std::{convert::TryInto, prelude::*};
@@ -695,7 +694,7 @@ impl<T: Config> Pallet<T> {
 		destination_delegator: &T::AccountId,
 		amount: BalanceOf<T>,
 	) -> DispatchResult {
-		let mut source_delegation =
+		let source_delegation =
 			Delegators::<T>::get(&source_delegator).defensive_ok_or(Error::<T>::BadState)?;
 
 		// some checks that must have already been checked before.
@@ -749,7 +748,7 @@ impl<T: Config> Pallet<T> {
 		maybe_reporter: Option<T::AccountId>,
 	) -> DispatchResult {
 		let mut delegate = Delegate::<T>::from(&delegate_acc)?;
-		let mut delegation = <Delegators<T>>::get(&delegator).ok_or(Error::<T>::NotDelegator)?;
+		let delegation = <Delegators<T>>::get(&delegator).ok_or(Error::<T>::NotDelegator)?;
 
 		ensure!(delegation.delegate == delegate_acc, Error::<T>::NotDelegate);
 		ensure!(delegation.amount >= amount, Error::<T>::NotEnoughFunds);
@@ -794,7 +793,7 @@ use sp_std::collections::btree_map::BTreeMap;
 
 #[cfg(any(test, feature = "try-runtime"))]
 impl<T: Config> Pallet<T> {
-	pub(crate) fn do_try_state() -> Result<(), TryRuntimeError> {
+	pub(crate) fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> {
 		// build map to avoid reading storage multiple times.
 		let delegation_map = Delegators::<T>::iter().collect::<BTreeMap<_, _>>();
 		let ledger_map = Delegates::<T>::iter().collect::<BTreeMap<_, _>>();
@@ -807,7 +806,7 @@ impl<T: Config> Pallet<T> {
 
 	fn check_delegates(
 		ledgers: BTreeMap<T::AccountId, DelegationLedger<T>>,
-	) -> Result<(), TryRuntimeError> {
+	) -> Result<(), sp_runtime::TryRuntimeError> {
 		for (delegate, ledger) in ledgers {
 			ensure!(
 				matches!(
@@ -831,7 +830,7 @@ impl<T: Config> Pallet<T> {
 	fn check_delegators(
 		delegations: BTreeMap<T::AccountId, Delegation<T>>,
 		ledger: BTreeMap<T::AccountId, DelegationLedger<T>>,
-	) -> Result<(), TryRuntimeError> {
+	) -> Result<(), sp_runtime::TryRuntimeError> {
 		let mut delegation_aggregation = BTreeMap::<T::AccountId, BalanceOf<T>>::new();
 		for (delegator, delegation) in delegations.iter() {
 			ensure!(
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index f31035b3c7259..439dc23df6e47 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -17,7 +17,7 @@
 
 use crate::{self as delegated_staking, types::Delegate, HoldReason};
 use frame_support::{
-	assert_noop, assert_ok, derive_impl,
+	assert_ok, derive_impl,
 	pallet_prelude::*,
 	parameter_types,
 	traits::{fungible::InspectHold, ConstU64, Currency},
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index b253fad01871b..8de4d3f419feb 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -246,7 +246,6 @@ mod staking_integration {
 				let delegate_obj = get_delegate(&delegate);
 				assert_eq!(delegate_obj.ledger.stakeable_balance(), delegated_balance);
 				assert_eq!(delegate_obj.available_to_bond(), 0);
-				assert_eq!(delegate_obj.available_to_bond(), 0);
 				assert_eq!(delegate_obj.bonded_stake(), delegated_balance);
 			}
 
@@ -607,7 +606,7 @@ mod pool_integration {
 			// verify state
 			assert_eq!(delegate.ledger.effective_balance(), delegate_amount);
 			assert_eq!(delegate.available_to_bond(), 0);
-			assert_eq!(delegate.unbonded(), 0);
+			assert_eq!(delegate.total_unbonded(), 0);
 		});
 	}
 
@@ -640,7 +639,7 @@ mod pool_integration {
 			assert_eq!(pool_delegate.ledger.effective_balance(), staked_amount);
 			assert_eq!(pool_delegate.bonded_stake(), staked_amount);
 			assert_eq!(pool_delegate.available_to_bond(), 0);
-			assert_eq!(pool_delegate.unbonded(), 0);
+			assert_eq!(pool_delegate.total_unbonded(), 0);
 
 			// let a bunch of delegators join this pool
 			for i in 301..350 {
@@ -650,10 +649,11 @@ mod pool_integration {
 				assert_eq!(held_balance(&i), 100 + i);
 			}
 
-			assert_eq!(pool_delegate.refresh().unwrap().ledger.effective_balance(), staked_amount);
+			let pool_delegate = pool_delegate.refresh().unwrap();
+			assert_eq!(pool_delegate.ledger.effective_balance(), staked_amount);
 			assert_eq!(pool_delegate.bonded_stake(), staked_amount);
 			assert_eq!(pool_delegate.available_to_bond(), 0);
-			assert_eq!(pool_delegate.unbonded(), 0);
+			assert_eq!(pool_delegate.total_unbonded(), 0);
 		});
 	}
 
@@ -827,17 +827,17 @@ mod pool_integration {
 			start_era(5);
 			// withdraw pool should withdraw 1000 tokens
 			assert_ok!(Pools::pool_withdraw_unbonded(RawOrigin::Signed(100).into(), pool_id, 0));
-			assert_eq!(get_pool_delegate(pool_id).unbonded(), 1000);
+			assert_eq!(get_pool_delegate(pool_id).total_unbonded(), 1000);
 
 			start_era(6);
 			// should withdraw 500 more
 			assert_ok!(Pools::pool_withdraw_unbonded(RawOrigin::Signed(100).into(), pool_id, 0));
-			assert_eq!(get_pool_delegate(pool_id).unbonded(), 1000 + 500);
+			assert_eq!(get_pool_delegate(pool_id).total_unbonded(), 1000 + 500);
 
 			start_era(7);
 			// Nothing to withdraw, still at 1500.
 			assert_ok!(Pools::pool_withdraw_unbonded(RawOrigin::Signed(100).into(), pool_id, 0));
-			assert_eq!(get_pool_delegate(pool_id).unbonded(), 1500);
+			assert_eq!(get_pool_delegate(pool_id).total_unbonded(), 1500);
 		});
 	}
 
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index e1b818aa9c82b..847c3a7cf78ab 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -30,6 +30,7 @@ pub(crate) enum AccountType {
 	ProxyDelegator,
 }
 
+/// Information about delegation of a `delegator`.
 #[derive(Default, Encode, Clone, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
 #[scale_info(skip_type_params(T))]
 pub struct Delegation<T: Config> {
@@ -64,6 +65,7 @@ impl<T: Config> Delegation<T> {
 	}
 
 	/// Checked increase of delegation amount. Consumes self and returns a new copy.
+	#[allow(unused)]
 	pub(crate) fn increase_delegation(self, amount: BalanceOf<T>) -> Option<Self> {
 		let updated_delegation = self.amount.checked_add(&amount)?;
 		Some(Delegation::from(&self.delegate, updated_delegation))
@@ -148,6 +150,7 @@ impl<T: Config> DelegationLedger<T> {
 	}
 }
 
+/// Wrapper around `DelegationLedger` to provide additional functionality.
 #[derive(Clone)]
 pub struct Delegate<T: Config> {
 	pub key: T::AccountId,
@@ -160,6 +163,10 @@ impl<T: Config> Delegate<T> {
 		Ok(Delegate { key: delegate.clone(), ledger })
 	}
 
+	/// Remove funds that are withdrawn from [Config::CoreStaking] but not claimed by a delegator.
+	///
+	/// Checked decrease of delegation amount from `total_delegated` and `unclaimed_withdrawals`
+	/// registers. Mutates self.
 	pub(crate) fn remove_unclaimed_withdraw(
 		&mut self,
 		amount: BalanceOf<T>,
@@ -178,6 +185,7 @@ impl<T: Config> Delegate<T> {
 		Ok(())
 	}
 
+	/// Add funds that are withdrawn from [Config::CoreStaking] to be claimed by delegators later.
 	pub(crate) fn add_unclaimed_withdraw(
 		&mut self,
 		amount: BalanceOf<T>,
@@ -190,42 +198,44 @@ impl<T: Config> Delegate<T> {
 
 		Ok(())
 	}
-	// re-reads the delegate from database and returns a new instance.
+
+	/// Reloads self from storage.
+	#[allow(unused)]
 	pub(crate) fn refresh(&self) -> Result<Delegate<T>, DispatchError> {
 		Self::from(&self.key)
 	}
 
+	/// Amount that is delegated but not bonded yet.
+	///
+	/// This importantly does not include `unclaimed_withdrawals` as those should not be bonded
+	/// again unless explicitly requested.
 	pub(crate) fn available_to_bond(&self) -> BalanceOf<T> {
 		let bonded_stake = self.bonded_stake();
-
-		let stakeable =
-			self.ledger().map(|ledger| ledger.stakeable_balance()).unwrap_or(Zero::zero());
+		let stakeable = self.ledger.stakeable_balance();
 
 		defensive_assert!(stakeable >= bonded_stake, "cannot expose more than delegate balance");
 
 		stakeable.saturating_sub(bonded_stake)
 	}
 
-	/// Similar to [`Self::available_to_bond`] but includes `DelegationLedger.unclaimed_withdrawals`
-	/// as well.
-	pub(crate) fn unbonded(&self) -> BalanceOf<T> {
+	/// Balance of `Delegate` that is not bonded.
+	///
+	/// Includes `unclaimed_withdrawals` of `Delegate`.
+	pub(crate) fn total_unbonded(&self) -> BalanceOf<T> {
 		let bonded_stake = self.bonded_stake();
 
-		let net_balance =
-			self.ledger().map(|ledger| ledger.effective_balance()).unwrap_or(Zero::zero());
+		let net_balance = self.ledger.effective_balance();
 
 		defensive_assert!(net_balance >= bonded_stake, "cannot expose more than delegate balance");
 
 		net_balance.saturating_sub(bonded_stake)
 	}
 
+    /// Remove slashes that are applied.
 	pub(crate) fn remove_slash(&mut self, amount: BalanceOf<T>) {
 		self.ledger.pending_slash.defensive_saturating_reduce(amount);
 		self.ledger.total_delegated.defensive_saturating_reduce(amount);
 	}
-	pub(crate) fn ledger(&self) -> Option<DelegationLedger<T>> {
-		DelegationLedger::<T>::get(&self.key)
-	}
 
 	pub(crate) fn bonded_stake(&self) -> BalanceOf<T> {
 		T::CoreStaking::total_stake(&self.key).unwrap_or(Zero::zero())
@@ -250,7 +260,7 @@ impl<T: Config> Delegate<T> {
 
 	/// Save self and remove if no delegation left.
 	///
-	/// Can return error if the delegate is in an unexpected state.
+	/// Returns error if the delegate is in an unexpected state.
 	pub(crate) fn save_or_kill(self) -> Result<(), DispatchError> {
 		let key = self.key;
 		// see if delegate can be killed
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index 0fbb5826f145f..b6c5f12d27739 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -69,7 +69,7 @@ impl<T: Config> PoolAdapter for NoDelegation<T> {
 		Ok(())
 	}
 
-	fn has_pending_slash(delegate: &Self::AccountId) -> bool {
+	fn has_pending_slash(_delegate: &Self::AccountId) -> bool {
 		// for direct staking, slashing is eager, and we don't need to do anything here.
 		false
 	}

From 0ccd901867ba4bf474ceab2ed68fc476431104d0 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 25 Feb 2024 15:06:47 +0100
Subject: [PATCH 158/202] fmt

---
 substrate/frame/delegated-staking/src/lib.rs   | 3 +--
 substrate/frame/delegated-staking/src/types.rs | 2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index f35c29f432b4a..476000bf16bb8 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -176,8 +176,7 @@ use sp_runtime::{
 	ArithmeticError, DispatchResult, Perbill, RuntimeDebug, Saturating,
 };
 use sp_staking::{
-	delegation::StakingDelegationSupport, EraIndex, Stake, StakerStatus,
-	StakingInterface,
+	delegation::StakingDelegationSupport, EraIndex, Stake, StakerStatus, StakingInterface,
 };
 use sp_std::{convert::TryInto, prelude::*};
 
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index 847c3a7cf78ab..8f8b523ff144f 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -231,7 +231,7 @@ impl<T: Config> Delegate<T> {
 		net_balance.saturating_sub(bonded_stake)
 	}
 
-    /// Remove slashes that are applied.
+	/// Remove slashes that are applied.
 	pub(crate) fn remove_slash(&mut self, amount: BalanceOf<T>) {
 		self.ledger.pending_slash.defensive_saturating_reduce(amount);
 		self.ledger.total_delegated.defensive_saturating_reduce(amount);

From 814d2a51daca823bb0f04cebec0d23b9b3f1e3e7 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 25 Feb 2024 15:10:06 +0100
Subject: [PATCH 159/202] refactor types

---
 substrate/frame/delegated-staking/src/lib.rs   |  7 ++-----
 substrate/frame/delegated-staking/src/types.rs | 17 ++++++++++++-----
 2 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 476000bf16bb8..13dc19a4592f7 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -620,11 +620,8 @@ impl<T: Config> Pallet<T> {
 		// if we still do not have enough funds to release, abort.
 		ensure!(delegate.ledger.unclaimed_withdrawals >= amount, Error::<T>::NotEnoughFunds);
 
-		// book keep into ledger
-		delegate.remove_unclaimed_withdraw(amount)?;
-
-		// kill delegate if not delegated and nothing to claim anymore.
-		delegate.save_or_kill()?;
+		// claim withdraw from delegate.
+		delegate.remove_unclaimed_withdraw(amount)?.save_or_kill()?;
 
 		// book keep delegation
 		delegation.amount = delegation
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index 8f8b523ff144f..d232258f96824 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -168,21 +168,28 @@ impl<T: Config> Delegate<T> {
 	/// Checked decrease of delegation amount from `total_delegated` and `unclaimed_withdrawals`
 	/// registers. Mutates self.
 	pub(crate) fn remove_unclaimed_withdraw(
-		&mut self,
+		self,
 		amount: BalanceOf<T>,
-	) -> Result<(), DispatchError> {
-		self.ledger.total_delegated = self
+	) -> Result<Self, DispatchError> {
+		let new_total_delegated = self
 			.ledger
 			.total_delegated
 			.checked_sub(&amount)
 			.defensive_ok_or(ArithmeticError::Overflow)?;
-		self.ledger.unclaimed_withdrawals = self
+		let new_unclaimed_withdrawals = self
 			.ledger
 			.unclaimed_withdrawals
 			.checked_sub(&amount)
 			.defensive_ok_or(ArithmeticError::Overflow)?;
 
-		Ok(())
+		Ok(Delegate {
+			ledger: DelegationLedger {
+				total_delegated: new_total_delegated,
+				unclaimed_withdrawals: new_unclaimed_withdrawals,
+				..self.ledger
+			},
+			..self
+		})
 	}
 
 	/// Add funds that are withdrawn from [Config::CoreStaking] to be claimed by delegators later.

From 4e681979dc8793725a6db1d26efb4f4816b3a32f Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 25 Feb 2024 15:17:17 +0100
Subject: [PATCH 160/202] minor refactor

---
 substrate/frame/delegated-staking/src/lib.rs  | 12 ++++-----
 .../frame/delegated-staking/src/types.rs      | 27 +++++++++++++------
 2 files changed, 24 insertions(+), 15 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 13dc19a4592f7..26fe02e9a7569 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -658,7 +658,7 @@ impl<T: Config> Pallet<T> {
 		delegate_acc: &T::AccountId,
 		num_slashing_spans: u32,
 	) -> Result<Delegate<T>, DispatchError> {
-		let mut delegate = Delegate::<T>::from(delegate_acc)?;
+		let delegate = Delegate::<T>::from(delegate_acc)?;
 		let pre_total = T::CoreStaking::stake(delegate_acc).defensive()?.total;
 
 		let stash_killed: bool =
@@ -677,7 +677,7 @@ impl<T: Config> Pallet<T> {
 		let new_withdrawn =
 			pre_total.checked_sub(&post_total).defensive_ok_or(Error::<T>::BadState)?;
 
-		delegate.add_unclaimed_withdraw(new_withdrawn)?;
+		let delegate = delegate.add_unclaimed_withdraw(new_withdrawn)?;
 
 		delegate.clone().save();
 
@@ -743,7 +743,7 @@ impl<T: Config> Pallet<T> {
 		amount: BalanceOf<T>,
 		maybe_reporter: Option<T::AccountId>,
 	) -> DispatchResult {
-		let mut delegate = Delegate::<T>::from(&delegate_acc)?;
+		let delegate = Delegate::<T>::from(&delegate_acc)?;
 		let delegation = <Delegators<T>>::get(&delegator).ok_or(Error::<T>::NotDelegator)?;
 
 		ensure!(delegation.delegate == delegate_acc, Error::<T>::NotDelegate);
@@ -756,10 +756,8 @@ impl<T: Config> Pallet<T> {
 
 		let actual_slash = credit.peek();
 
-		// remove the slashed amount
-		// FIXME(ank4n) add a ledger method to reduce pending slash.
-		delegate.remove_slash(actual_slash);
-		delegate.save();
+		// remove the applied slashed amount from delegate.
+		delegate.remove_slash(actual_slash).save();
 
 		delegation
 			.decrease_delegation(actual_slash)
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index d232258f96824..30c700df3820d 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -166,7 +166,7 @@ impl<T: Config> Delegate<T> {
 	/// Remove funds that are withdrawn from [Config::CoreStaking] but not claimed by a delegator.
 	///
 	/// Checked decrease of delegation amount from `total_delegated` and `unclaimed_withdrawals`
-	/// registers. Mutates self.
+	/// registers. Consumes self and returns a new instance of self if success.
 	pub(crate) fn remove_unclaimed_withdraw(
 		self,
 		amount: BalanceOf<T>,
@@ -194,16 +194,22 @@ impl<T: Config> Delegate<T> {
 
 	/// Add funds that are withdrawn from [Config::CoreStaking] to be claimed by delegators later.
 	pub(crate) fn add_unclaimed_withdraw(
-		&mut self,
+		self,
 		amount: BalanceOf<T>,
-	) -> Result<(), DispatchError> {
-		self.ledger.unclaimed_withdrawals = self
+	) -> Result<Self, DispatchError> {
+		let new_unclaimed_withdrawals = self
 			.ledger
 			.unclaimed_withdrawals
 			.checked_add(&amount)
 			.defensive_ok_or(ArithmeticError::Overflow)?;
 
-		Ok(())
+		Ok(Delegate {
+			ledger: DelegationLedger {
+				unclaimed_withdrawals: new_unclaimed_withdrawals,
+				..self.ledger
+			},
+			..self
+		})
 	}
 
 	/// Reloads self from storage.
@@ -239,9 +245,14 @@ impl<T: Config> Delegate<T> {
 	}
 
 	/// Remove slashes that are applied.
-	pub(crate) fn remove_slash(&mut self, amount: BalanceOf<T>) {
-		self.ledger.pending_slash.defensive_saturating_reduce(amount);
-		self.ledger.total_delegated.defensive_saturating_reduce(amount);
+	pub(crate) fn remove_slash(self, amount: BalanceOf<T>) -> Self {
+		let pending_slash = self.ledger.pending_slash.defensive_saturating_sub(amount);
+		let total_delegated = self.ledger.total_delegated.defensive_saturating_sub(amount);
+
+		Delegate {
+			ledger: DelegationLedger { pending_slash, total_delegated, ..self.ledger },
+			..self
+		}
 	}
 
 	pub(crate) fn bonded_stake(&self) -> BalanceOf<T> {

From 8d00bdf18be97d1d63ca1adde7594c6e7f500714 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 25 Feb 2024 15:25:56 +0100
Subject: [PATCH 161/202] improve np diff

---
 substrate/frame/nomination-pools/src/lib.rs | 22 ++++++++++-----------
 1 file changed, 10 insertions(+), 12 deletions(-)

diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index 5c084fb30eb94..911323b3804a1 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -748,7 +748,7 @@ impl<T: Config> Commission<T> {
 			//
 			// Throttled if the attempted increase in commission is greater than `max_increase`.
 			if (*to).saturating_sub(commission_as_percent) > t.max_increase {
-				return true;
+				return true
 			}
 
 			// Test for `min_delay` throttling.
@@ -771,7 +771,7 @@ impl<T: Config> Commission<T> {
 						blocks_surpassed < t.min_delay
 					}
 				},
-			);
+			)
 		}
 		false
 	}
@@ -829,7 +829,7 @@ impl<T: Config> Commission<T> {
 		);
 		if let Some(old) = self.max.as_mut() {
 			if new_max > *old {
-				return Err(Error::<T>::MaxCommissionRestricted.into());
+				return Err(Error::<T>::MaxCommissionRestricted.into())
 			}
 			*old = new_max;
 		} else {
@@ -1215,7 +1215,7 @@ impl<T: Config> BondedPool<T> {
 			},
 			(false, true) => {
 				// the depositor can simply not be unbonded permissionlessly, period.
-				return Err(Error::<T>::DoesNotHavePermission.into());
+				return Err(Error::<T>::DoesNotHavePermission.into())
 			},
 		};
 
@@ -2991,7 +2991,7 @@ impl<T: Config> Pallet<T> {
 		let balance = T::U256ToBalance::convert;
 		if current_balance.is_zero() || current_points.is_zero() || points.is_zero() {
 			// There is nothing to unbond
-			return Zero::zero();
+			return Zero::zero()
 		}
 
 		// Equivalent of (current_balance / current_points) * points
@@ -3028,7 +3028,7 @@ impl<T: Config> Pallet<T> {
 		// will be zero.
 		let pending_rewards = member.pending_rewards(current_reward_counter)?;
 		if pending_rewards.is_zero() {
-			return Ok(pending_rewards);
+			return Ok(pending_rewards)
 		}
 
 		// IFF the reward is non-zero alter the member and reward pool info.
@@ -3256,7 +3256,7 @@ impl<T: Config> Pallet<T> {
 		let min_balance = T::Currency::minimum_balance();
 
 		if pre_frozen_balance == min_balance {
-			return Err(Error::<T>::NothingToAdjust.into());
+			return Err(Error::<T>::NothingToAdjust.into())
 		}
 
 		// Update frozen amount with current ED.
@@ -3363,7 +3363,7 @@ impl<T: Config> Pallet<T> {
 	#[cfg(any(feature = "try-runtime", feature = "fuzzing", test, debug_assertions))]
 	pub fn do_try_state(level: u8) -> Result<(), TryRuntimeError> {
 		if level.is_zero() {
-			return Ok(());
+			return Ok(())
 		}
 		// note: while a bit wacky, since they have the same key, even collecting to vec should
 		// result in the same set of keys, in the same order.
@@ -3496,7 +3496,7 @@ impl<T: Config> Pallet<T> {
 		);
 
 		if level <= 1 {
-			return Ok(());
+			return Ok(())
 		}
 
 		for (pool_id, _pool) in BondedPools::<T>::iter() {
@@ -3631,9 +3631,7 @@ impl<T: Config> sp_staking::OnStakingUpdate<T::AccountId, BalanceOf<T>> for Pall
 		slashed_unlocking: &BTreeMap<EraIndex, BalanceOf<T>>,
 		total_slashed: BalanceOf<T>,
 	) {
-		let Some(pool_id) = ReversePoolIdLookup::<T>::get(pool_account) else {
-			return;
-		};
+		let Some(pool_id) = ReversePoolIdLookup::<T>::get(pool_account) else { return };
 		// As the slashed account belongs to a `BondedPool` the `TotalValueLocked` decreases and
 		// an event is emitted.
 		TotalValueLocked::<T>::mutate(|tvl| {

From e3602670415ec40bcecea2085b5d3ad29b689318 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 25 Feb 2024 15:26:55 +0100
Subject: [PATCH 162/202] missed semicolon

---
 substrate/frame/nomination-pools/src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index 911323b3804a1..ab09fbba15b69 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -742,7 +742,7 @@ impl<T: Config> Commission<T> {
 
 			// do not throttle if `to` is the same or a decrease in commission.
 			if *to <= commission_as_percent {
-				return false;
+				return false
 			}
 			// Test for `max_increase` throttling.
 			//

From 05e7ba6b83435cba57e1a9102bd0c79841545940 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 25 Feb 2024 15:44:17 +0100
Subject: [PATCH 163/202] clean diff

---
 substrate/frame/staking/src/pallet/impls.rs |  1 +
 substrate/frame/staking/src/pallet/mod.rs   |  1 -
 substrate/frame/staking/src/slashing.rs     | 13 +++++++------
 substrate/primitives/staking/src/lib.rs     |  9 +++++++++
 4 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 08ab7c81afb13..3b2a7b512e2ee 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1879,6 +1879,7 @@ impl<T: Config> StakingDelegationSupport for NoDelegation<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 	fn stakeable_balance(_who: &Self::AccountId) -> Self::Balance {
+		defensive!("stakeable balance should not have been called for NoDelegation");
 		BalanceOf::<T>::zero()
 	}
 	fn is_delegate(_who: &Self::AccountId) -> bool {
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index 80cde75abc211..27fdb320b5ba8 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -863,7 +863,6 @@ pub mod pallet {
 		ControllerDeprecated,
 		/// Provided reward destination is not allowed.
 		RewardDestinationRestricted,
-		// FIXME(ank4n): look at the error again
 		/// Not enough funds available to withdraw
 		NotEnoughFunds,
 	}
diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs
index bed0b9f621d92..00cdf64f5d4a2 100644
--- a/substrate/frame/staking/src/slashing.rs
+++ b/substrate/frame/staking/src/slashing.rs
@@ -125,7 +125,7 @@ impl SlashingSpans {
 	pub(crate) fn end_span(&mut self, now: EraIndex) -> bool {
 		let next_start = now.defensive_saturating_add(1);
 		if next_start <= self.last_start {
-			return false;
+			return false
 		}
 
 		let last_length = next_start.defensive_saturating_sub(self.last_start);
@@ -242,7 +242,7 @@ pub(crate) fn compute_slash<T: Config>(
 		// kick out the validator even if they won't be slashed,
 		// as long as the misbehavior is from their most recent slashing span.
 		kick_out_if_recent::<T>(params);
-		return None;
+		return None
 	}
 
 	let prior_slash_p = ValidatorSlashInEra::<T>::get(&params.slash_era, params.stash)
@@ -264,7 +264,7 @@ pub(crate) fn compute_slash<T: Config>(
 		// pays out some reward even if the latest report is not max-in-era.
 		// we opt to avoid the nominator lookups and edits and leave more rewards
 		// for more drastic misbehavior.
-		return None;
+		return None
 	}
 
 	// apply slash to validator.
@@ -542,7 +542,7 @@ impl<'a, T: 'a + Config> Drop for InspectingSpans<'a, T> {
 	fn drop(&mut self) {
 		// only update on disk if we slashed this account.
 		if !self.dirty {
-			return;
+			return
 		}
 
 		if let Some((start, end)) = self.spans.prune(self.window_start) {
@@ -613,8 +613,9 @@ pub fn do_slash<T: Config>(
 
 	if value.is_zero() {
 		// nothing to do
-		return;
+		return
 	}
+
 	if lazy_slash {
 		// If delegated staking, report slash and move on.
 		T::DelegationSupport::report_slash(stash, value);
@@ -675,7 +676,7 @@ fn pay_reporters<T: Config>(
 		// nobody to pay out to or nothing to pay;
 		// just treat the whole value as slashed.
 		T::Slash::on_unbalanced(slashed_imbalance);
-		return;
+		return
 	}
 
 	// take rewards out of the slashed imbalance.
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 46825775fd625..99f78234a218a 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -98,6 +98,9 @@ pub struct Stake<Balance> {
 #[impl_trait_for_tuples::impl_for_tuples(10)]
 pub trait OnStakingUpdate<AccountId, Balance> {
 	/// Fired when the stake amount of someone updates.
+	///
+	/// This is effectively any changes to the bond amount, such as bonding more funds, and
+	/// unbonding.
 	fn on_stake_update(_who: &AccountId, _prev_stake: Option<Stake<Balance>>) {}
 
 	/// Fired when someone sets their intention to nominate.
@@ -113,6 +116,9 @@ pub trait OnStakingUpdate<AccountId, Balance> {
 	fn on_nominator_update(_who: &AccountId, _prev_nominations: Vec<AccountId>) {}
 
 	/// Fired when someone removes their intention to nominate, either due to chill or validating.
+	///
+	/// The set of nominations at the time of removal is provided as it can no longer be fetched in
+	/// any way.
 	fn on_nominator_remove(_who: &AccountId, _nominations: Vec<AccountId>) {}
 
 	/// Fired when someone sets their intention to validate.
@@ -151,6 +157,9 @@ pub trait OnStakingUpdate<AccountId, Balance> {
 }
 
 /// A generic representation of a staking implementation.
+///
+/// This interface uses the terminology of NPoS, but it is aims to be generic enough to cover other
+/// implementations as well.
 pub trait StakingInterface {
 	/// Balance type used by the staking system.
 	type Balance: Sub<Output = Self::Balance>

From 95e3ca0fa5b2814a68c481424399b8984937888d Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Sun, 25 Feb 2024 20:56:12 +0100
Subject: [PATCH 164/202] doc fix

---
 substrate/frame/delegated-staking/src/lib.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 26fe02e9a7569..d58696d14b1a2 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -78,7 +78,7 @@
 //! The pallet implements the staking delegation support trait which staking pallet can use to
 //! provide compatibility with this pallet.
 //!
-//! #### [Pool Adapter](delegation::PoolAdapter)
+//! #### [Pool Adapter](sp_staking::delegation::PoolAdapter)
 //! The pallet also implements the pool adapter trait which allows NominationPool to use this pallet
 //! to support delegation based staking from pool accounts. This strategy also allows the pool to
 //! switch implementations while having minimal changes to its own logic.
@@ -95,7 +95,7 @@
 //! slashes are applied.
 //!
 //! `NominationPool` can apply slash for all its members by calling
-//! [delegation::PoolAdapter::delegator_slash].
+//! [PoolAdapter::delegator_slash](sp_staking::delegation::PoolAdapter::delegator_slash).
 //!
 //! ## Migration from Nominator to Delegate
 //! More details [here](https://hackmd.io/@ak0n/np-delegated-staking-migration).

From 89dd29be3315d762196f8bb9526784c9131bb27f Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Mon, 26 Feb 2024 15:10:45 +0100
Subject: [PATCH 165/202] rename to transferable

---
 substrate/frame/delegated-staking/src/impls.rs  | 2 +-
 substrate/frame/nomination-pools/src/adapter.rs | 4 +++-
 substrate/frame/nomination-pools/src/lib.rs     | 2 +-
 substrate/primitives/staking/src/delegation.rs  | 2 +-
 4 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 57bb4d6012901..2009c2e6596a7 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -252,7 +252,7 @@ impl<T: Config> PoolAdapter for Pallet<T> {
 	/// Return balance of the `Delegate` (pool account) that is not bonded.
 	///
 	/// Equivalent to [FunInspect::balance] for non delegate accounts.
-	fn releasable_balance(who: &Self::AccountId) -> Self::Balance {
+	fn transferable_balance(who: &Self::AccountId) -> Self::Balance {
 		Delegate::<T>::from(who)
 			.map(|delegate| delegate.total_unbonded())
 			.unwrap_or(Zero::zero())
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index b6c5f12d27739..0c41f1ce0fb2d 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -23,11 +23,13 @@ use crate::*;
 /// tokens in delegator's accounts.
 pub struct NoDelegation<T: Config>(PhantomData<T>);
 
+
+/// TODO(ankan) Call it FundManager/CurrencyAdapter/DelegationManager
 impl<T: Config> PoolAdapter for NoDelegation<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
-	fn releasable_balance(who: &Self::AccountId) -> Self::Balance {
+	fn transferable_balance(who: &Self::AccountId) -> Self::Balance {
 		// Note on why we can't use `Currency::reducible_balance`: Since pooled account has a
 		// provider (staking pallet), the account can not be set expendable by
 		// `pallet-nomination-pool`. This means reducible balance always returns balance preserving
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index ab09fbba15b69..e929666f06c53 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -1056,7 +1056,7 @@ impl<T: Config> BondedPool<T> {
 
 	/// The pools balance that is transferable provided it is expendable by staking pallet.
 	fn transferable_balance(&self) -> BalanceOf<T> {
-		T::PoolAdapter::releasable_balance(&self.bonded_account())
+		T::PoolAdapter::transferable_balance(&self.bonded_account())
 	}
 
 	fn is_root(&self, who: &T::AccountId) -> bool {
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index d686fd8634bb4..40e06ab5157ef 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -69,7 +69,7 @@ pub trait PoolAdapter {
 	type AccountId: Clone + sp_std::fmt::Debug;
 
 	/// Balance that is free and can be released to delegator.
-	fn releasable_balance(who: &Self::AccountId) -> Self::Balance;
+	fn transferable_balance(who: &Self::AccountId) -> Self::Balance;
 
 	/// Total balance of the account held for staking.
 	fn total_balance(who: &Self::AccountId) -> Self::Balance;

From 8a41c860f6862efa1c31004b03122f09e235cc1b Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Tue, 27 Feb 2024 00:09:46 +0100
Subject: [PATCH 166/202] stake adapter

---
 .../frame/nomination-pools/src/adapter.rs     | 33 ++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index 0c41f1ce0fb2d..adcda12771988 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -23,7 +23,6 @@ use crate::*;
 /// tokens in delegator's accounts.
 pub struct NoDelegation<T: Config>(PhantomData<T>);
 
-
 /// TODO(ankan) Call it FundManager/CurrencyAdapter/DelegationManager
 impl<T: Config> PoolAdapter for NoDelegation<T> {
 	type Balance = BalanceOf<T>;
@@ -87,3 +86,35 @@ impl<T: Config> PoolAdapter for NoDelegation<T> {
 		Err(Error::<T>::NothingToSlash.into())
 	}
 }
+
+/// Stake Strategy trait that can support different ways of staking such as `Transfer and Stake` or
+/// `Delegate and Stake`.
+pub trait StakeStrategy {
+	type Balance: frame_support::traits::tokens::Balance;
+	type AccountId: Clone + sp_std::fmt::Debug;
+
+	/// Delegate to pool account.
+	///
+	/// This is only used for first time delegation. For adding more delegation, use
+	/// [`Self::delegate_extra`].
+	fn delegate(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		reward_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
+
+	/// Add more delegation to the pool account.
+	fn delegate_extra(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
+
+	/// Withdraw delegation from pool account to self.
+	fn withdraw_delegation(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
+}

From 318eababb931a849b9530070960084fd2f0b8e23 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Tue, 27 Feb 2024 00:35:59 +0100
Subject: [PATCH 167/202] add delegation related functions to staking interface

---
 .../frame/delegated-staking/src/tests.rs      |  1 +
 substrate/frame/nomination-pools/src/mock.rs  | 38 +++++++++++++++++++
 substrate/primitives/staking/src/lib.rs       | 26 +++++++++++++
 3 files changed, 65 insertions(+)

diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 8de4d3f419feb..e58bec8bcf5bd 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -574,6 +574,7 @@ mod staking_integration {
 	}
 }
 
+// FIMXE(ank4n): Move these integration test to nomination pools.
 mod pool_integration {
 	use super::*;
 	use pallet_nomination_pools::{BondExtra, BondedPools, PoolState};
diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs
index 85b8c3b644055..5feb9e42bbe02 100644
--- a/substrate/frame/nomination-pools/src/mock.rs
+++ b/substrate/frame/nomination-pools/src/mock.rs
@@ -228,6 +228,44 @@ impl sp_staking::StakingInterface for StakingMock {
 	fn release_all(_who: &Self::AccountId) {
 		unimplemented!("method currently not used in testing")
 	}
+
+	fn is_delegatee(who: &Self::AccountId) -> bool {
+		unimplemented!("method currently not used in testing")
+	}
+
+	/// Effective balance of the delegatee account.
+	fn delegatee_balance(who: &Self::AccountId) -> Self::Balance {
+		unimplemented!("method currently not used in testing")
+	}
+
+	/// Delegate funds to `Delegatee`.
+	fn delegate(who: &Self::AccountId, delegatee: &Self::AccountId, reward_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+		unimplemented!("method currently not used in testing")
+	}
+
+	/// Add more delegation to the pool account.
+	fn delegate_extra(
+		who: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
+		unimplemented!("method currently not used in testing")
+	}
+
+	/// Withdraw delegation from pool account to self.
+	fn withdraw_delegation(who: &Self::AccountId, delegatee: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+		unimplemented!("method currently not used in testing")
+	}
+
+	/// Does the delegatee have any pending slash.
+	fn has_pending_slash(delegatee: &Self::AccountId) -> bool {
+		unimplemented!("method currently not used in testing")
+	}
+
+	fn delegator_slash(delegatee: &Self::AccountId, delegator: &Self::AccountId, value: Self::Balance, maybe_reporter: Option<Self::AccountId>) -> sp_runtime::DispatchResult {
+		unimplemented!("method currently not used in testing")
+	}
+
 }
 
 #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 99f78234a218a..ef7ad329a4ca8 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -170,6 +170,7 @@ pub trait StakingInterface {
 		+ MaxEncodedLen
 		+ FullCodec
 		+ TypeInfo
+		+ Zero
 		+ Saturating;
 
 	/// AccountId type used by the staking system.
@@ -308,6 +309,31 @@ pub trait StakingInterface {
 
 	#[cfg(feature = "runtime-benchmarks")]
 	fn set_current_era(era: EraIndex);
+
+	/// Returns true if who is a `delegatee` account.
+	fn is_delegatee(who: &Self::AccountId) -> bool;
+
+	/// Effective balance of the delegatee account.
+	fn delegatee_balance(who: &Self::AccountId) -> Self::Balance;
+
+	/// Delegate funds to `Delegatee`.
+	fn delegate(who: &Self::AccountId, delegatee: &Self::AccountId, reward_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult;
+
+	/// Add more delegation to the pool account.
+	fn delegate_extra(
+		who: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
+
+	/// Withdraw delegation from pool account to self.
+	fn withdraw_delegation(who: &Self::AccountId, delegatee: &Self::AccountId, amount: Self::Balance) -> DispatchResult;
+
+	/// Does the delegatee have any pending slash.
+	fn has_pending_slash(delegatee: &Self::AccountId) -> bool;
+
+	fn delegator_slash(delegatee: &Self::AccountId, delegator: &Self::AccountId, value: Self::Balance, maybe_reporter: Option<Self::AccountId>) -> sp_runtime::DispatchResult;
+
 }
 
 /// The amount of exposure for an era that an individual nominator has (susceptible to slashing).

From aaa3cbc10589f9f97bf07bddeead19e2fdc9d1d6 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Tue, 27 Feb 2024 00:50:11 +0100
Subject: [PATCH 168/202] staking interface impl updated

---
 .../frame/delegated-staking/src/impls.rs      | 55 +++++++++++++++++++
 substrate/frame/staking/src/pallet/impls.rs   | 39 +++++++++++++
 substrate/primitives/staking/src/lib.rs       |  2 +
 3 files changed, 96 insertions(+)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 2009c2e6596a7..a349ca6c32de9 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -194,6 +194,61 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	fn set_current_era(era: EraIndex) {
 		T::CoreStaking::set_current_era(era)
 	}
+
+	fn is_delegatee(who: &Self::AccountId) -> bool {
+		Self::is_delegate(who)
+	}
+
+	/// Effective balance of the delegatee account.
+	fn delegatee_balance(who: &Self::AccountId) -> Self::Balance {
+		Delegate::<T>::from(who)
+			.map(|delegate| delegate.ledger.effective_balance())
+			.unwrap_or_default()
+	}
+
+	/// Delegate funds to `Delegatee`.
+	fn delegate(who: &Self::AccountId, delegatee: &Self::AccountId, reward_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+		Pallet::<T>::register_as_delegate(
+			RawOrigin::Signed(delegatee.clone()).into(),
+			reward_account.clone(),
+		)?;
+
+		// Delegate the funds from who to the pool account.
+		Pallet::<T>::delegate_funds(
+			RawOrigin::Signed(who.clone()).into(),
+			delegatee.clone(),
+			amount,
+		)
+	}
+
+	/// Add more delegation to the pool account.
+	fn delegate_extra(
+		who: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
+		Pallet::<T>::delegate_funds(
+			RawOrigin::Signed(who.clone()).into(),
+			delegatee.clone(),
+			amount,
+		)
+	}
+
+	/// Withdraw delegation from pool account to self.
+	fn withdraw_delegation(who: &Self::AccountId, delegatee: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+		Pallet::<T>::release(RawOrigin::Signed(delegatee.clone()).into(), who.clone(), amount, 0)
+	}
+
+	/// Does the delegatee have any pending slash.
+	fn has_pending_slash(delegatee: &Self::AccountId) -> bool {
+		Delegate::<T>::from(delegatee)
+			.map(|d| !d.ledger.pending_slash.is_zero())
+			.unwrap_or(false)
+	}
+
+	fn delegator_slash(delegatee: &Self::AccountId, delegator: &Self::AccountId, value: Self::Balance, maybe_reporter: Option<Self::AccountId>) -> sp_runtime::DispatchResult {
+		Pallet::<T>::do_slash(delegatee.clone(), delegator.clone(), value, maybe_reporter)
+	}
 }
 
 impl<T: Config> StakingDelegationSupport for Pallet<T> {
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 3b2a7b512e2ee..99f605bb9812c 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1870,6 +1870,45 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	fn release_all(who: &Self::AccountId) {
 		T::Currency::remove_lock(crate::STAKING_ID, who)
 	}
+
+	fn is_delegatee(who: &Self::AccountId) -> bool {
+		defensive!("is_delegatee is not supported");
+		false
+	}
+
+	fn delegatee_balance(who: &Self::AccountId) -> Self::Balance {
+		defensive!("delegatee_balance is not supported");
+		BalanceOf::<T>::zero()
+	}
+
+	/// Delegate funds to `Delegatee`.
+	fn delegate(who: &Self::AccountId, delegatee: &Self::AccountId, reward_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+		Err(DispatchError::Other("delegate is not supported"))
+	}
+
+	/// Add more delegation to the pool account.
+	fn delegate_extra(
+		who: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
+		Err(DispatchError::Other("delegate is not supported"))
+	}
+
+	/// Withdraw delegation from pool account to self.
+	fn withdraw_delegation(who: &Self::AccountId, delegatee: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+		Err(DispatchError::Other("delegate is not supported"))
+	}
+
+	/// Does the delegatee have any pending slash.
+	fn has_pending_slash(delegatee: &Self::AccountId) -> bool {
+		// slashing is greedy, so no pending slash.
+		false
+	}
+
+	fn delegator_slash(delegatee: &Self::AccountId, delegator: &Self::AccountId, value: Self::Balance, maybe_reporter: Option<Self::AccountId>) -> sp_runtime::DispatchResult {
+		Err(DispatchError::Other("delegate is not supported"))
+	}
 }
 
 /// Standard implementation of `StakingDelegationSupport` that supports only direct staking and no
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index ef7ad329a4ca8..6279756d566c1 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -310,6 +310,8 @@ pub trait StakingInterface {
 	#[cfg(feature = "runtime-benchmarks")]
 	fn set_current_era(era: EraIndex);
 
+	// FIXME(ank4n): Break down this trait maybe? It is too bloated currently.
+
 	/// Returns true if who is a `delegatee` account.
 	fn is_delegatee(who: &Self::AccountId) -> bool;
 

From d80797945e6d2a3ba8fcb806f7347c93caa6bece Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Tue, 27 Feb 2024 01:16:53 +0100
Subject: [PATCH 169/202] compiles but potentially buggy

---
 .../frame/delegated-staking/src/impls.rs      |  89 +-------------
 .../frame/nomination-pools/src/adapter.rs     | 113 ++++++++++++------
 substrate/frame/nomination-pools/src/lib.rs   |  25 ++--
 substrate/frame/nomination-pools/src/mock.rs  |   4 +-
 .../primitives/staking/src/delegation.rs      |  57 +--------
 5 files changed, 95 insertions(+), 193 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index a349ca6c32de9..893a2013ea1d9 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -298,91 +298,4 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 			},
 		});
 	}
-}
-
-impl<T: Config> PoolAdapter for Pallet<T> {
-	type Balance = BalanceOf<T>;
-	type AccountId = T::AccountId;
-
-	/// Return balance of the `Delegate` (pool account) that is not bonded.
-	///
-	/// Equivalent to [FunInspect::balance] for non delegate accounts.
-	fn transferable_balance(who: &Self::AccountId) -> Self::Balance {
-		Delegate::<T>::from(who)
-			.map(|delegate| delegate.total_unbonded())
-			.unwrap_or(Zero::zero())
-	}
-
-	/// Returns balance of account that is held.
-	///
-	/// - For `delegate` accounts, this is their total delegation amount.
-	/// - For `delegator` accounts, this is their delegation amount.
-	fn total_balance(who: &Self::AccountId) -> Self::Balance {
-		if Self::is_delegator(who) {
-			return Delegation::<T>::get(who).map(|d| d.amount).unwrap_or(Zero::zero());
-		}
-
-		Delegate::<T>::from(who)
-			.map(|delegate| delegate.ledger.effective_balance())
-			.unwrap_or(Zero::zero())
-	}
-
-	/// Add initial delegation to the pool account.
-	///
-	/// Equivalent to [FunMutate::transfer] for Direct Staking.
-	fn delegate(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		reward_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult {
-		// This is the first delegation so we needs to register the pool account as a `delegate`.
-		Pallet::<T>::register_as_delegate(
-			RawOrigin::Signed(pool_account.clone()).into(),
-			reward_account.clone(),
-		)?;
-
-		// Delegate the funds from who to the pool account.
-		Pallet::<T>::delegate_funds(
-			RawOrigin::Signed(who.clone()).into(),
-			pool_account.clone(),
-			amount,
-		)
-	}
-
-	fn delegate_extra(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult {
-		Pallet::<T>::delegate_funds(
-			RawOrigin::Signed(who.clone()).into(),
-			pool_account.clone(),
-			amount,
-		)
-	}
-
-	fn release_delegation(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult {
-		// fixme(ank4n): This should not require slashing spans.
-		Pallet::<T>::release(RawOrigin::Signed(pool_account.clone()).into(), who.clone(), amount, 0)
-	}
-
-	fn has_pending_slash(delegate: &Self::AccountId) -> bool {
-		Delegate::<T>::from(delegate)
-			.map(|d| !d.ledger.pending_slash.is_zero())
-			.unwrap_or(false)
-	}
-
-	fn delegator_slash(
-		delegate: &Self::AccountId,
-		delegator: &Self::AccountId,
-		value: Self::Balance,
-		maybe_reporter: Option<Self::AccountId>,
-	) -> DispatchResult {
-		Pallet::<T>::do_slash(delegate.clone(), delegator.clone(), value, maybe_reporter)
-	}
-}
+}
\ No newline at end of file
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index adcda12771988..7e7f9d26af818 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -17,14 +17,49 @@
 
 use crate::*;
 
+/// Pool adapter trait that can support multiple modes of staking: i.e. Delegated or Direct.
+pub trait StakeAdapter {
+	type Balance: frame_support::traits::tokens::Balance;
+	type AccountId: Clone + sp_std::fmt::Debug;
+
+	/// Balance that is free and can be released to delegator.
+	fn transferable_balance(who: &Self::AccountId) -> Self::Balance;
+
+	/// Total balance of the account held for staking.
+	fn total_balance(who: &Self::AccountId) -> Self::Balance;
+
+	/// Initiate delegation to the pool account.
+	fn bond(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		reward_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
+
+	/// Add more delegation to the pool account.
+	fn bond_extra(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
+
+	/// Revoke delegation to pool account.
+	fn withdraw(
+		who: &Self::AccountId,
+		pool_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
+}
+
+
 /// Basic pool adapter that only supports Direct Staking.
 ///
 /// When delegating, tokens are moved between the delegator and pool account as opposed to holding
 /// tokens in delegator's accounts.
-pub struct NoDelegation<T: Config>(PhantomData<T>);
+pub struct TransferStake<T: Config>(PhantomData<T>);
 
 /// TODO(ankan) Call it FundManager/CurrencyAdapter/DelegationManager
-impl<T: Config> PoolAdapter for NoDelegation<T> {
+impl<T: Config> StakeAdapter for TransferStake<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
@@ -41,7 +76,7 @@ impl<T: Config> PoolAdapter for NoDelegation<T> {
 		T::Currency::total_balance(who)
 	}
 
-	fn delegate(
+	fn bond(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		reward_account: &Self::AccountId,
@@ -51,7 +86,7 @@ impl<T: Config> PoolAdapter for NoDelegation<T> {
 		T::Staking::bond(pool_account, amount, reward_account)
 	}
 
-	fn delegate_extra(
+	fn bond_extra(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
@@ -60,7 +95,7 @@ impl<T: Config> PoolAdapter for NoDelegation<T> {
 		T::Staking::bond_extra(pool_account, amount)
 	}
 
-	fn release_delegation(
+	fn withdraw(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
@@ -69,52 +104,60 @@ impl<T: Config> PoolAdapter for NoDelegation<T> {
 
 		Ok(())
 	}
+}
 
-	fn has_pending_slash(_delegate: &Self::AccountId) -> bool {
-		// for direct staking, slashing is eager, and we don't need to do anything here.
-		false
-	}
+pub struct DelegationStake<T: Config>(PhantomData<T>);
+impl<T: Config> StakeAdapter for DelegationStake<T> {
+	type Balance = BalanceOf<T>;
+	type AccountId = T::AccountId;
 
-	fn delegator_slash(
-		_delegate: &Self::AccountId,
-		_delegator: &Self::AccountId,
-		_value: Self::Balance,
-		_maybe_reporter: Option<Self::AccountId>,
-	) -> sp_runtime::DispatchResult {
-		// for direct staking, slashing is eager, and we don't need to do anything here.
-		defensive!("Delegator slash is not supported for direct staking");
-		Err(Error::<T>::NothingToSlash.into())
+	/// Return balance of the `Delegate` (pool account) that is not bonded.
+	///
+	/// Equivalent to [FunInspect::balance] for non delegate accounts.
+	fn transferable_balance(who: &Self::AccountId) -> Self::Balance {
+		T::Staking::delegatee_balance(who).saturating_sub(T::Staking::active_stake(who).unwrap_or_default())
 	}
-}
 
-/// Stake Strategy trait that can support different ways of staking such as `Transfer and Stake` or
-/// `Delegate and Stake`.
-pub trait StakeStrategy {
-	type Balance: frame_support::traits::tokens::Balance;
-	type AccountId: Clone + sp_std::fmt::Debug;
+	/// Returns balance of account that is held.
+	///
+	/// - For `delegate` accounts, this is their total delegation amount.
+	/// - For `delegator` accounts, this is their delegation amount.
+	fn total_balance(who: &Self::AccountId) -> Self::Balance {
+		if T::Staking::is_delegatee(who) {
+			return T::Staking::delegatee_balance(who)
+		}
+
+		// for delegators we return their held balance as well.
+		T::Currency::total_balance(who)
+	}
 
-	/// Delegate to pool account.
+	/// Add initial delegation to the pool account.
 	///
-	/// This is only used for first time delegation. For adding more delegation, use
-	/// [`Self::delegate_extra`].
-	fn delegate(
+	/// Equivalent to [FunMutate::transfer] for Direct Staking.
+	fn bond(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		reward_account: &Self::AccountId,
 		amount: Self::Balance,
-	) -> DispatchResult;
+	) -> DispatchResult {
+		// This is the first delegation so we needs to register the pool account as a `delegate`.
+		T::Staking::delegate(who, pool_account, reward_account, amount)
+	}
 
-	/// Add more delegation to the pool account.
-	fn delegate_extra(
+	fn bond_extra(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
-	) -> DispatchResult;
+	) -> DispatchResult {
+		T::Staking::delegate_extra(who, pool_account, amount)
+	}
 
-	/// Withdraw delegation from pool account to self.
-	fn withdraw_delegation(
+	fn withdraw(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
-	) -> DispatchResult;
+	) -> DispatchResult {
+		// fixme(ank4n): This should not require slashing spans.
+		T::Staking::withdraw_delegation(who, pool_account, amount)
+	}
 }
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index e929666f06c53..3ea2fd47ff90e 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -373,8 +373,9 @@ use sp_runtime::{
 	},
 	FixedPointNumber, Perbill,
 };
-use sp_staking::{delegation::PoolAdapter, EraIndex, StakingInterface};
+use sp_staking::{EraIndex, StakingInterface};
 use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, ops::Div, vec::Vec};
+use adapter::StakeAdapter;
 
 #[cfg(any(feature = "try-runtime", feature = "fuzzing", test, debug_assertions))]
 use sp_runtime::TryRuntimeError;
@@ -1056,7 +1057,7 @@ impl<T: Config> BondedPool<T> {
 
 	/// The pools balance that is transferable provided it is expendable by staking pallet.
 	fn transferable_balance(&self) -> BalanceOf<T> {
-		T::PoolAdapter::transferable_balance(&self.bonded_account())
+		T::StakeAdapter::transferable_balance(&self.bonded_account())
 	}
 
 	fn is_root(&self, who: &T::AccountId) -> bool {
@@ -1262,11 +1263,11 @@ impl<T: Config> BondedPool<T> {
 
 		match ty {
 			BondType::Create =>
-				T::PoolAdapter::delegate(who, &bonded_account, &reward_account, amount)?,
+				T::StakeAdapter::bond(who, &bonded_account, &reward_account, amount)?,
 			// The pool should always be created in such a way its in a state to bond extra, but if
 			// the active balance is slashed below the minimum bonded or the account cannot be
 			// found, we exit early.
-			BondType::Later => T::PoolAdapter::delegate_extra(who, &bonded_account, amount)?,
+			BondType::Later => T::StakeAdapter::bond_extra(who, &bonded_account, amount)?,
 		}
 		TotalValueLocked::<T>::mutate(|tvl| {
 			tvl.saturating_accrue(amount);
@@ -1288,7 +1289,7 @@ impl<T: Config> BondedPool<T> {
 	}
 
 	fn has_pending_slash(&self) -> bool {
-		T::PoolAdapter::has_pending_slash(&self.bonded_account())
+		T::Staking::has_pending_slash(&self.bonded_account())
 	}
 }
 
@@ -1652,7 +1653,7 @@ pub mod pallet {
 		type MaxMetadataLen: Get<u32>;
 
 		/// An adapter to support delegated to direct staking.
-		type PoolAdapter: PoolAdapter<AccountId = Self::AccountId, Balance = BalanceOf<Self>>;
+		type StakeAdapter: adapter::StakeAdapter<AccountId = Self::AccountId, Balance = BalanceOf<Self>>;
 	}
 
 	/// The sum of funds across all pools.
@@ -2297,7 +2298,7 @@ pub mod pallet {
 				// order to ensure members can leave the pool and it can be destroyed.
 				.min(bonded_pool.transferable_balance());
 
-			T::PoolAdapter::release_delegation(
+			T::StakeAdapter::withdraw(
 				&member_account,
 				&bonded_pool.bonded_account(),
 				balance_to_unbond,
@@ -2895,7 +2896,7 @@ impl<T: Config> Pallet<T> {
 			"could not transfer all amount to depositor while dissolving pool"
 		);
 		defensive_assert!(
-			T::PoolAdapter::total_balance(&bonded_pool.bonded_account()) == Zero::zero(),
+			T::StakeAdapter::total_balance(&bonded_pool.bonded_account()) == Zero::zero(),
 			"dissolving pool should not have any balance"
 		);
 		// NOTE: Defensively force set balance to zero.
@@ -3291,9 +3292,9 @@ impl<T: Config> Pallet<T> {
 		let member =
 			PoolMembers::<T>::get(&member_account).ok_or(Error::<T>::PoolMemberNotFound)?;
 		let bonded_account = Self::create_bonded_account(member.pool_id);
-		ensure!(T::PoolAdapter::has_pending_slash(&bonded_account), Error::<T>::NothingToSlash);
+		ensure!(T::Staking::has_pending_slash(&bonded_account), Error::<T>::NothingToSlash);
 
-		let delegated_balance = T::PoolAdapter::total_balance(&member_account);
+		let delegated_balance = T::StakeAdapter::total_balance(&member_account);
 		let current_balance = member.total_balance();
 		defensive_assert!(
 			delegated_balance >= current_balance,
@@ -3303,7 +3304,7 @@ impl<T: Config> Pallet<T> {
 		// if nothing to slash, return error.
 		ensure!(delegated_balance > current_balance, Error::<T>::NothingToSlash);
 
-		T::PoolAdapter::delegator_slash(
+		T::Staking::delegator_slash(
 			&bonded_account,
 			&member_account,
 			delegated_balance.defensive_saturating_sub(current_balance),
@@ -3505,7 +3506,7 @@ impl<T: Config> Pallet<T> {
 
 			let sum_unbonding_balance = subs.sum_unbonding_balance();
 			let bonded_balance = T::Staking::active_stake(&pool_account).unwrap_or_default();
-			let total_balance = T::PoolAdapter::total_balance(&pool_account);
+			let total_balance = T::StakeAdapter::total_balance(&pool_account);
 
 			assert!(
                 total_balance >= bonded_balance + sum_unbonding_balance,
diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs
index 5feb9e42bbe02..b3bcc6f41c755 100644
--- a/substrate/frame/nomination-pools/src/mock.rs
+++ b/substrate/frame/nomination-pools/src/mock.rs
@@ -259,7 +259,7 @@ impl sp_staking::StakingInterface for StakingMock {
 
 	/// Does the delegatee have any pending slash.
 	fn has_pending_slash(delegatee: &Self::AccountId) -> bool {
-		unimplemented!("method currently not used in testing")
+		false
 	}
 
 	fn delegator_slash(delegatee: &Self::AccountId, delegator: &Self::AccountId, value: Self::Balance, maybe_reporter: Option<Self::AccountId>) -> sp_runtime::DispatchResult {
@@ -349,7 +349,7 @@ impl pools::Config for Runtime {
 	type MaxMetadataLen = MaxMetadataLen;
 	type MaxUnbonding = MaxUnbonding;
 	type MaxPointsToBalance = frame_support::traits::ConstU8<10>;
-	type PoolAdapter = adapter::NoDelegation<Self>;
+	type StakeAdapter = adapter::TransferStake<Self>;
 }
 
 type Block = frame_system::mocking::MockBlock<Runtime>;
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 40e06ab5157ef..0f18f32f3ccca 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -53,59 +53,4 @@ pub trait StakingDelegationSupport {
 
 	/// Reports an ongoing slash to the `delegate` account that would be applied lazily.
 	fn report_slash(who: &Self::AccountId, slash: Self::Balance);
-}
-
-/// Pool adapter trait that can support multiple modes of staking: i.e. Delegated or Direct.
-pub trait PoolAdapter {
-	type Balance: Sub<Output = Self::Balance>
-		+ Ord
-		+ PartialEq
-		+ Default
-		+ Copy
-		+ MaxEncodedLen
-		+ FullCodec
-		+ TypeInfo
-		+ Saturating;
-	type AccountId: Clone + sp_std::fmt::Debug;
-
-	/// Balance that is free and can be released to delegator.
-	fn transferable_balance(who: &Self::AccountId) -> Self::Balance;
-
-	/// Total balance of the account held for staking.
-	fn total_balance(who: &Self::AccountId) -> Self::Balance;
-
-	/// Initiate delegation to the pool account.
-	fn delegate(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		reward_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult;
-
-	/// Add more delegation to the pool account.
-	fn delegate_extra(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult;
-
-	/// Revoke delegation to pool account.
-	fn release_delegation(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult;
-
-	/// Returns true if the `delegate` has pending slash to be applied.
-	fn has_pending_slash(delegate: &Self::AccountId) -> bool;
-
-	/// Apply a slash to the `delegator`.
-	///
-	/// This is called when the corresponding `delegate` has pending slash to be applied.
-	fn delegator_slash(
-		delegate: &Self::AccountId,
-		delegator: &Self::AccountId,
-		value: Self::Balance,
-		maybe_reporter: Option<Self::AccountId>,
-	) -> DispatchResult;
-}
+}
\ No newline at end of file

From 2668e783dacb14fbf983de28407081eb443bbff4 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Tue, 27 Feb 2024 01:25:25 +0100
Subject: [PATCH 170/202] one test failing

---
 substrate/frame/delegated-staking/src/impls.rs            | 1 -
 substrate/frame/delegated-staking/src/mock.rs             | 2 +-
 substrate/frame/nomination-pools/src/adapter.rs           | 6 +++---
 substrate/frame/nomination-pools/src/lib.rs               | 2 +-
 substrate/frame/nomination-pools/test-staking/src/mock.rs | 2 +-
 5 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 893a2013ea1d9..bc8d41034cae7 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -19,7 +19,6 @@
 //! Implementations of public traits, namely [StakingInterface], and [StakingDelegationSupport].
 
 use super::*;
-use sp_staking::delegation::PoolAdapter;
 
 /// StakingInterface implementation with delegation support.
 ///
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 439dc23df6e47..4d0388a7f6bc2 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -181,7 +181,7 @@ impl pallet_nomination_pools::Config for Runtime {
 	type MaxMetadataLen = ConstU32<256>;
 	type MaxUnbonding = MaxUnbonding;
 	type MaxPointsToBalance = frame_support::traits::ConstU8<10>;
-	type PoolAdapter = DelegatedStaking;
+	type StakeAdapter = pallet_nomination_pools::adapter::DelegationStake<Self>;
 }
 
 frame_support::construct_runtime!(
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index 7e7f9d26af818..9af228a04611a 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -44,7 +44,7 @@ pub trait StakeAdapter {
 	) -> DispatchResult;
 
 	/// Revoke delegation to pool account.
-	fn withdraw(
+	fn claim_withdraw(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
@@ -95,7 +95,7 @@ impl<T: Config> StakeAdapter for TransferStake<T> {
 		T::Staking::bond_extra(pool_account, amount)
 	}
 
-	fn withdraw(
+	fn claim_withdraw(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
@@ -152,7 +152,7 @@ impl<T: Config> StakeAdapter for DelegationStake<T> {
 		T::Staking::delegate_extra(who, pool_account, amount)
 	}
 
-	fn withdraw(
+	fn claim_withdraw(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index 3ea2fd47ff90e..702bcc94c2c11 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -2298,7 +2298,7 @@ pub mod pallet {
 				// order to ensure members can leave the pool and it can be destroyed.
 				.min(bonded_pool.transferable_balance());
 
-			T::StakeAdapter::withdraw(
+			T::StakeAdapter::claim_withdraw(
 				&member_account,
 				&bonded_pool.bonded_account(),
 				balance_to_unbond,
diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs
index 60b782d5b9ac2..c8446a6e077a0 100644
--- a/substrate/frame/nomination-pools/test-staking/src/mock.rs
+++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs
@@ -187,7 +187,7 @@ impl pallet_nomination_pools::Config for Runtime {
 	type MaxUnbonding = ConstU32<8>;
 	type MaxPointsToBalance = ConstU8<10>;
 	type PalletId = PoolsPalletId;
-	type PoolAdapter = pallet_nomination_pools::adapter::NoDelegation<Self>;
+	type StakeAdapter = pallet_nomination_pools::adapter::TransferStake<Self>;
 }
 
 type Block = frame_system::mocking::MockBlock<Runtime>;

From c8fc6a1ba1b7e7cf7d5e659ea889a4b03d7cd7aa Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Tue, 27 Feb 2024 02:03:26 +0100
Subject: [PATCH 171/202] all test passes

---
 substrate/frame/delegated-staking/src/impls.rs  | 4 ++++
 substrate/frame/delegated-staking/src/lib.rs    | 8 ++------
 substrate/frame/delegated-staking/src/types.rs  | 2 +-
 substrate/frame/nomination-pools/src/adapter.rs | 7 +------
 substrate/frame/nomination-pools/src/lib.rs     | 2 +-
 substrate/frame/nomination-pools/src/mock.rs    | 4 ++++
 substrate/frame/staking/src/pallet/impls.rs     | 5 +++++
 substrate/primitives/staking/src/lib.rs         | 2 ++
 8 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index bc8d41034cae7..62f67f390531c 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -248,6 +248,10 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	fn delegator_slash(delegatee: &Self::AccountId, delegator: &Self::AccountId, value: Self::Balance, maybe_reporter: Option<Self::AccountId>) -> sp_runtime::DispatchResult {
 		Pallet::<T>::do_slash(delegatee.clone(), delegator.clone(), value, maybe_reporter)
 	}
+
+	fn delegated_balance(delegator: &Self::AccountId) -> Self::Balance {
+		Delegation::<T>::get(delegator).map(|d| d.amount).unwrap_or_default()
+	}
 }
 
 impl<T: Config> StakingDelegationSupport for Pallet<T> {
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index d58696d14b1a2..41ef8a3a0b2cd 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -582,7 +582,6 @@ impl<T: Config> Pallet<T> {
 			};
 
 		Delegation::<T>::from(delegate, new_delegation_amount).save(delegator);
-
 		ledger.total_delegated =
 			ledger.total_delegated.checked_add(&amount).ok_or(ArithmeticError::Overflow)?;
 		ledger.save(delegate);
@@ -630,11 +629,8 @@ impl<T: Config> Pallet<T> {
 			.defensive_ok_or(ArithmeticError::Overflow)?;
 
 		// remove delegator if nothing delegated anymore
-		if delegation.amount == BalanceOf::<T>::zero() {
-			<Delegators<T>>::remove(delegator);
-		} else {
-			delegation.save(delegator);
-		}
+		delegation.save(delegator);
+
 
 		let released = T::Currency::release(
 			&HoldReason::Delegating.into(),
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index 30c700df3820d..add4ae21847ed 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -75,7 +75,7 @@ impl<T: Config> Delegation<T> {
 		// Clean up if no delegation left.
 		if self.amount == Zero::zero() {
 			<Delegators<T>>::remove(key);
-			return;
+			return
 		}
 
 		<Delegators<T>>::insert(key, self)
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index 9af228a04611a..f4f5e18a2c9b7 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -123,12 +123,7 @@ impl<T: Config> StakeAdapter for DelegationStake<T> {
 	/// - For `delegate` accounts, this is their total delegation amount.
 	/// - For `delegator` accounts, this is their delegation amount.
 	fn total_balance(who: &Self::AccountId) -> Self::Balance {
-		if T::Staking::is_delegatee(who) {
-			return T::Staking::delegatee_balance(who)
-		}
-
-		// for delegators we return their held balance as well.
-		T::Currency::total_balance(who)
+		T::Staking::delegatee_balance(who)
 	}
 
 	/// Add initial delegation to the pool account.
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index 702bcc94c2c11..500ca0564314b 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -3294,7 +3294,7 @@ impl<T: Config> Pallet<T> {
 		let bonded_account = Self::create_bonded_account(member.pool_id);
 		ensure!(T::Staking::has_pending_slash(&bonded_account), Error::<T>::NothingToSlash);
 
-		let delegated_balance = T::StakeAdapter::total_balance(&member_account);
+		let delegated_balance = T::Staking::delegated_balance(&member_account);
 		let current_balance = member.total_balance();
 		defensive_assert!(
 			delegated_balance >= current_balance,
diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs
index b3bcc6f41c755..cc5eec42cfff9 100644
--- a/substrate/frame/nomination-pools/src/mock.rs
+++ b/substrate/frame/nomination-pools/src/mock.rs
@@ -266,6 +266,10 @@ impl sp_staking::StakingInterface for StakingMock {
 		unimplemented!("method currently not used in testing")
 	}
 
+	fn delegated_balance(delegator: &Self::AccountId) -> Self::Balance {
+		unimplemented!("method currently not used in testing")
+	}
+
 }
 
 #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 99f605bb9812c..cb26c3c8009c4 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1909,6 +1909,11 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	fn delegator_slash(delegatee: &Self::AccountId, delegator: &Self::AccountId, value: Self::Balance, maybe_reporter: Option<Self::AccountId>) -> sp_runtime::DispatchResult {
 		Err(DispatchError::Other("delegate is not supported"))
 	}
+
+	fn delegated_balance(delegator: &Self::AccountId) -> Self::Balance {
+		defensive!("delegated_balance is not supported");
+		BalanceOf::<T>::zero()
+	}
 }
 
 /// Standard implementation of `StakingDelegationSupport` that supports only direct staking and no
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 6279756d566c1..1515cd0138add 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -336,6 +336,8 @@ pub trait StakingInterface {
 
 	fn delegator_slash(delegatee: &Self::AccountId, delegator: &Self::AccountId, value: Self::Balance, maybe_reporter: Option<Self::AccountId>) -> sp_runtime::DispatchResult;
 
+	fn delegated_balance(delegator: &Self::AccountId) -> Self::Balance;
+
 }
 
 /// The amount of exposure for an era that an individual nominator has (susceptible to slashing).

From d41fa5343ffc5bb36438569e93e63ce6f00c615d Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Tue, 27 Feb 2024 02:18:28 +0100
Subject: [PATCH 172/202] rename trait method

---
 .../frame/nomination-pools/src/adapter.rs     | 32 ++++++++++---------
 substrate/frame/nomination-pools/src/lib.rs   |  4 ++-
 2 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index f4f5e18a2c9b7..41e0581d84895 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -22,8 +22,8 @@ pub trait StakeAdapter {
 	type Balance: frame_support::traits::tokens::Balance;
 	type AccountId: Clone + sp_std::fmt::Debug;
 
-	/// Balance that is free and can be released to delegator.
-	fn transferable_balance(who: &Self::AccountId) -> Self::Balance;
+	/// Balance of the account.
+	fn balance(who: &Self::AccountId) -> Self::Balance;
 
 	/// Total balance of the account held for staking.
 	fn total_balance(who: &Self::AccountId) -> Self::Balance;
@@ -51,7 +51,6 @@ pub trait StakeAdapter {
 	) -> DispatchResult;
 }
 
-
 /// Basic pool adapter that only supports Direct Staking.
 ///
 /// When delegating, tokens are moved between the delegator and pool account as opposed to holding
@@ -63,13 +62,13 @@ impl<T: Config> StakeAdapter for TransferStake<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
-	fn transferable_balance(who: &Self::AccountId) -> Self::Balance {
+	fn balance(who: &Self::AccountId) -> Self::Balance {
 		// Note on why we can't use `Currency::reducible_balance`: Since pooled account has a
 		// provider (staking pallet), the account can not be set expendable by
 		// `pallet-nomination-pool`. This means reducible balance always returns balance preserving
 		// ED in the account. What we want though is transferable balance given the account can be
 		// dusted.
-		T::Currency::balance(who).saturating_sub(T::Staking::active_stake(who).unwrap_or_default())
+		T::Currency::balance(who)
 	}
 
 	fn total_balance(who: &Self::AccountId) -> Self::Balance {
@@ -107,23 +106,26 @@ impl<T: Config> StakeAdapter for TransferStake<T> {
 }
 
 pub struct DelegationStake<T: Config>(PhantomData<T>);
+
 impl<T: Config> StakeAdapter for DelegationStake<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
-	/// Return balance of the `Delegate` (pool account) that is not bonded.
-	///
-	/// Equivalent to [FunInspect::balance] for non delegate accounts.
-	fn transferable_balance(who: &Self::AccountId) -> Self::Balance {
-		T::Staking::delegatee_balance(who).saturating_sub(T::Staking::active_stake(who).unwrap_or_default())
+	fn balance(who: &Self::AccountId) -> Self::Balance {
+		if T::Staking::is_delegatee(who) {
+			return T::Staking::delegatee_balance(who)
+		}
+
+		T::Currency::balance(who)
 	}
 
-	/// Returns balance of account that is held.
-	///
-	/// - For `delegate` accounts, this is their total delegation amount.
-	/// - For `delegator` accounts, this is their delegation amount.
+	/// Return total balance of the account.
 	fn total_balance(who: &Self::AccountId) -> Self::Balance {
-		T::Staking::delegatee_balance(who)
+		if T::Staking::is_delegatee(who) {
+			return T::Staking::delegatee_balance(who);
+		}
+
+		T::Currency::total_balance(who)
 	}
 
 	/// Add initial delegation to the pool account.
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index 500ca0564314b..10e6fc69a04c5 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -1057,7 +1057,9 @@ impl<T: Config> BondedPool<T> {
 
 	/// The pools balance that is transferable provided it is expendable by staking pallet.
 	fn transferable_balance(&self) -> BalanceOf<T> {
-		T::StakeAdapter::transferable_balance(&self.bonded_account())
+		let account = self.bonded_account();
+		T::StakeAdapter::balance(&account)
+			.saturating_sub(T::Staking::active_stake(&account).unwrap_or_default())
 	}
 
 	fn is_root(&self, who: &T::AccountId) -> bool {

From c408581a624044beb296c71d83ad704e8e70677d Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Tue, 27 Feb 2024 02:33:08 +0100
Subject: [PATCH 173/202] minor refactors

---
 .../frame/delegated-staking/src/impls.rs      |  3 +-
 substrate/frame/delegated-staking/src/lib.rs  |  2 +-
 .../frame/nomination-pools/src/adapter.rs     | 35 ++++++++++---------
 substrate/frame/nomination-pools/src/mock.rs  |  2 +-
 substrate/frame/staking/src/ledger.rs         |  2 +-
 substrate/frame/staking/src/pallet/impls.rs   |  2 +-
 substrate/primitives/staking/src/lib.rs       |  4 +--
 7 files changed, 27 insertions(+), 23 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 62f67f390531c..141a8651503f3 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -171,7 +171,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		T::CoreStaking::slash_reward_fraction()
 	}
 
-	fn release_all(_who: &Self::AccountId) {
+	fn unsafe_release_all(_who: &Self::AccountId) {
 		defensive_assert!(false, "not supported for delegated impl of staking interface");
 	}
 
@@ -235,6 +235,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 
 	/// Withdraw delegation from pool account to self.
 	fn withdraw_delegation(who: &Self::AccountId, delegatee: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+		// fixme(ank4n): This should not require slashing spans.
 		Pallet::<T>::release(RawOrigin::Signed(delegatee.clone()).into(), who.clone(), amount, 0)
 	}
 
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 41ef8a3a0b2cd..95242fe60f9d3 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -535,7 +535,7 @@ impl<T: Config> Pallet<T> {
 		let stake = T::CoreStaking::stake(who)?;
 
 		// release funds from core staking.
-		T::CoreStaking::release_all(who);
+		T::CoreStaking::unsafe_release_all(who);
 
 		// transferring just released staked amount. This should never fail but if it does, it
 		// indicates bad state and we abort.
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index 41e0581d84895..0bf042fd47e79 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -17,7 +17,11 @@
 
 use crate::*;
 
-/// Pool adapter trait that can support multiple modes of staking: i.e. Delegated or Direct.
+/// An adapter trait that can support multiple staking strategies: e.g. `Transfer and stake` or
+/// `delegation and stake`.
+///
+/// This trait is very specific to nomination pool and meant to make switching between different
+/// staking implementations easier.
 pub trait StakeAdapter {
 	type Balance: frame_support::traits::tokens::Balance;
 	type AccountId: Clone + sp_std::fmt::Debug;
@@ -25,10 +29,10 @@ pub trait StakeAdapter {
 	/// Balance of the account.
 	fn balance(who: &Self::AccountId) -> Self::Balance;
 
-	/// Total balance of the account held for staking.
+	/// Total balance of the account.
 	fn total_balance(who: &Self::AccountId) -> Self::Balance;
 
-	/// Initiate delegation to the pool account.
+	/// Bond delegator via the pool account.
 	fn bond(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
@@ -36,14 +40,14 @@ pub trait StakeAdapter {
 		amount: Self::Balance,
 	) -> DispatchResult;
 
-	/// Add more delegation to the pool account.
+	/// Add more bond via the pool account.
 	fn bond_extra(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult;
 
-	/// Revoke delegation to pool account.
+	/// Claim withdrawn amount in the pool account.
 	fn claim_withdraw(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
@@ -51,13 +55,11 @@ pub trait StakeAdapter {
 	) -> DispatchResult;
 }
 
-/// Basic pool adapter that only supports Direct Staking.
+/// An adapter implementation that supports transfer based staking
 ///
-/// When delegating, tokens are moved between the delegator and pool account as opposed to holding
-/// tokens in delegator's accounts.
+/// The funds are transferred to the pool account and then staked via the pool account.
 pub struct TransferStake<T: Config>(PhantomData<T>);
 
-/// TODO(ankan) Call it FundManager/CurrencyAdapter/DelegationManager
 impl<T: Config> StakeAdapter for TransferStake<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
@@ -105,6 +107,10 @@ impl<T: Config> StakeAdapter for TransferStake<T> {
 	}
 }
 
+/// An adapter implementation that supports delegation based staking
+///
+/// The funds are delegated from pool account to a delegatee and then staked. The advantage of this
+/// approach is that the funds are held in the delegator account and not in the pool account.
 pub struct DelegationStake<T: Config>(PhantomData<T>);
 
 impl<T: Config> StakeAdapter for DelegationStake<T> {
@@ -112,14 +118,15 @@ impl<T: Config> StakeAdapter for DelegationStake<T> {
 	type AccountId = T::AccountId;
 
 	fn balance(who: &Self::AccountId) -> Self::Balance {
+		// Pool account is a delegatee, and its balance is the sum of all member delegations towards
+		// it.
 		if T::Staking::is_delegatee(who) {
-			return T::Staking::delegatee_balance(who)
+			return T::Staking::delegatee_balance(who);
 		}
 
 		T::Currency::balance(who)
 	}
 
-	/// Return total balance of the account.
 	fn total_balance(who: &Self::AccountId) -> Self::Balance {
 		if T::Staking::is_delegatee(who) {
 			return T::Staking::delegatee_balance(who);
@@ -128,16 +135,13 @@ impl<T: Config> StakeAdapter for DelegationStake<T> {
 		T::Currency::total_balance(who)
 	}
 
-	/// Add initial delegation to the pool account.
-	///
-	/// Equivalent to [FunMutate::transfer] for Direct Staking.
 	fn bond(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		reward_account: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult {
-		// This is the first delegation so we needs to register the pool account as a `delegate`.
+		// For delegation staking, we just delegate the funds to pool account.
 		T::Staking::delegate(who, pool_account, reward_account, amount)
 	}
 
@@ -154,7 +158,6 @@ impl<T: Config> StakeAdapter for DelegationStake<T> {
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult {
-		// fixme(ank4n): This should not require slashing spans.
 		T::Staking::withdraw_delegation(who, pool_account, amount)
 	}
 }
diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs
index cc5eec42cfff9..be4c644beea39 100644
--- a/substrate/frame/nomination-pools/src/mock.rs
+++ b/substrate/frame/nomination-pools/src/mock.rs
@@ -225,7 +225,7 @@ impl sp_staking::StakingInterface for StakingMock {
 		unimplemented!("method currently not used in testing")
 	}
 
-	fn release_all(_who: &Self::AccountId) {
+	fn unsafe_release_all(_who: &Self::AccountId) {
 		unimplemented!("method currently not used in testing")
 	}
 
diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs
index eed459500a641..afab32366f9d2 100644
--- a/substrate/frame/staking/src/ledger.rs
+++ b/substrate/frame/staking/src/ledger.rs
@@ -207,7 +207,7 @@ impl<T: Config> StakingLedger<T> {
 		let controller = <Bonded<T>>::get(stash).ok_or(Error::<T>::NotStash)?;
 
 		<Ledger<T>>::get(&controller).ok_or(Error::<T>::NotController).map(|ledger| {
-			Pallet::<T>::release_all(&ledger.stash);
+			Pallet::<T>::unsafe_release_all(&ledger.stash);
 			Ledger::<T>::remove(controller);
 
 			<Bonded<T>>::remove(&stash);
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index cb26c3c8009c4..33387817b95c0 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1867,7 +1867,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		SlashRewardFraction::<T>::get()
 	}
 
-	fn release_all(who: &Self::AccountId) {
+	fn unsafe_release_all(who: &Self::AccountId) {
 		T::Currency::remove_lock(crate::STAKING_ID, who)
 	}
 
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 1515cd0138add..0e1384442106f 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -294,8 +294,8 @@ pub trait StakingInterface {
 
 	/// Release all funds bonded for stake.
 	///
-	/// Unsafe, only used for migration of `delegate` accounts.
-	fn release_all(who: &Self::AccountId);
+	/// Unsafe, only used for migration of `delegatee` accounts.
+	fn unsafe_release_all(who: &Self::AccountId);
 
 	#[cfg(feature = "runtime-benchmarks")]
 	fn max_exposure_page_size() -> Page;

From d95a6febebcca3e369d632cff15d6bb204724a08 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Tue, 27 Feb 2024 03:15:48 +0100
Subject: [PATCH 174/202] rename delegate to delegatee

---
 .../frame/delegated-staking/src/impls.rs      |  50 +--
 substrate/frame/delegated-staking/src/lib.rs  | 213 +++++++------
 substrate/frame/delegated-staking/src/mock.rs |  22 +-
 .../frame/delegated-staking/src/tests.rs      | 290 +++++++++---------
 .../frame/delegated-staking/src/types.rs      |  54 ++--
 substrate/frame/staking/src/pallet/impls.rs   |  16 +-
 substrate/frame/staking/src/slashing.rs       |   2 +-
 .../primitives/staking/src/delegation.rs      |   4 +-
 8 files changed, 323 insertions(+), 328 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 141a8651503f3..585378e9c74e8 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -23,7 +23,7 @@ use super::*;
 /// StakingInterface implementation with delegation support.
 ///
 /// Only supports Nominators via Delegated Bonds. It is possible for a nominator to migrate and
-/// become a `Delegate`.
+/// become a `delegatee`.
 impl<T: Config> StakingInterface for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
@@ -53,12 +53,12 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	fn stake(who: &Self::AccountId) -> Result<Stake<Self::Balance>, DispatchError> {
-		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
+		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
 		return T::CoreStaking::stake(who);
 	}
 
 	fn total_stake(who: &Self::AccountId) -> Result<Self::Balance, DispatchError> {
-		if Self::is_delegate(who) {
+		if Self::is_delegatee(who) {
 			return T::CoreStaking::total_stake(who);
 		}
 
@@ -79,7 +79,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	fn fully_unbond(who: &Self::AccountId) -> DispatchResult {
-		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
+		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
 		return T::CoreStaking::fully_unbond(who);
 	}
 
@@ -89,35 +89,35 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		payee: &Self::AccountId,
 	) -> DispatchResult {
 		// ensure who is not already staked
-		ensure!(T::CoreStaking::status(who).is_err(), Error::<T>::NotDelegate);
-		let delegate = Delegate::<T>::from(who)?;
+		ensure!(T::CoreStaking::status(who).is_err(), Error::<T>::NotDelegatee);
+		let delegatee = Delegatee::<T>::from(who)?;
 
-		ensure!(delegate.available_to_bond() >= value, Error::<T>::NotEnoughFunds);
-		ensure!(delegate.ledger.payee == *payee, Error::<T>::InvalidRewardDestination);
+		ensure!(delegatee.available_to_bond() >= value, Error::<T>::NotEnoughFunds);
+		ensure!(delegatee.ledger.payee == *payee, Error::<T>::InvalidRewardDestination);
 
 		T::CoreStaking::bond(who, value, payee)
 	}
 
 	fn nominate(who: &Self::AccountId, validators: Vec<Self::AccountId>) -> DispatchResult {
-		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
+		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
 		return T::CoreStaking::nominate(who, validators);
 	}
 
 	fn chill(who: &Self::AccountId) -> DispatchResult {
-		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
+		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
 		return T::CoreStaking::chill(who);
 	}
 
 	fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult {
-		let delegation_register = <Delegates<T>>::get(who).ok_or(Error::<T>::NotDelegate)?;
+		let delegation_register = <Delegates<T>>::get(who).ok_or(Error::<T>::NotDelegatee)?;
 		ensure!(delegation_register.stakeable_balance() >= extra, Error::<T>::NotEnoughFunds);
 
 		T::CoreStaking::bond_extra(who, extra)
 	}
 
 	fn unbond(stash: &Self::AccountId, value: Self::Balance) -> DispatchResult {
-		let delegate = Delegate::<T>::from(stash)?;
-		ensure!(delegate.bonded_stake() >= value, Error::<T>::NotEnoughFunds);
+		let delegatee = Delegatee::<T>::from(stash)?;
+		ensure!(delegatee.bonded_stake() >= value, Error::<T>::NotEnoughFunds);
 
 		T::CoreStaking::unbond(stash, value)
 	}
@@ -130,7 +130,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		num_slashing_spans: u32,
 	) -> Result<bool, DispatchError> {
 		Pallet::<T>::withdraw_unbonded(&pool_acc, num_slashing_spans)
-			.map(|delegate| delegate.ledger.total_delegated.is_zero())
+			.map(|delegatee| delegatee.ledger.total_delegated.is_zero())
 	}
 
 	fn desired_validator_count() -> u32 {
@@ -154,7 +154,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	fn status(who: &Self::AccountId) -> Result<StakerStatus<Self::AccountId>, DispatchError> {
-		ensure!(Self::is_delegate(who), Error::<T>::NotSupported);
+		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
 		T::CoreStaking::status(who)
 	}
 
@@ -195,24 +195,24 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	fn is_delegatee(who: &Self::AccountId) -> bool {
-		Self::is_delegate(who)
+		Self::is_delegatee(who)
 	}
 
 	/// Effective balance of the delegatee account.
 	fn delegatee_balance(who: &Self::AccountId) -> Self::Balance {
-		Delegate::<T>::from(who)
-			.map(|delegate| delegate.ledger.effective_balance())
+		Delegatee::<T>::from(who)
+			.map(|delegatee| delegatee.ledger.effective_balance())
 			.unwrap_or_default()
 	}
 
 	/// Delegate funds to `Delegatee`.
 	fn delegate(who: &Self::AccountId, delegatee: &Self::AccountId, reward_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
-		Pallet::<T>::register_as_delegate(
+		Pallet::<T>::register_as_delegatee(
 			RawOrigin::Signed(delegatee.clone()).into(),
 			reward_account.clone(),
 		)?;
 
-		// Delegate the funds from who to the pool account.
+		// Delegate the funds from who to the delegatee account.
 		Pallet::<T>::delegate_funds(
 			RawOrigin::Signed(who.clone()).into(),
 			delegatee.clone(),
@@ -241,7 +241,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 
 	/// Does the delegatee have any pending slash.
 	fn has_pending_slash(delegatee: &Self::AccountId) -> bool {
-		Delegate::<T>::from(delegatee)
+		Delegatee::<T>::from(delegatee)
 			.map(|d| !d.ledger.pending_slash.is_zero())
 			.unwrap_or(false)
 	}
@@ -262,8 +262,8 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 	/// this balance is total delegator that can be staked, and importantly not extra balance that
 	/// is delegated but not bonded yet.
 	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
-		Delegate::<T>::from(who)
-			.map(|delegate| delegate.ledger.stakeable_balance())
+		Delegatee::<T>::from(who)
+			.map(|delegatee| delegatee.ledger.stakeable_balance())
 			.unwrap_or_default()
 	}
 
@@ -290,8 +290,8 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 		register.payee != reward_acc
 	}
 
-	fn is_delegate(who: &Self::AccountId) -> bool {
-		Self::is_delegate(who)
+	fn is_delegatee(who: &Self::AccountId) -> bool {
+		Self::is_delegatee(who)
 	}
 
 	fn report_slash(who: &Self::AccountId, slash: Self::Balance) {
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 95242fe60f9d3..8890b2f261d01 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -17,7 +17,7 @@
 
 //! # Delegated Staking Pallet
 //!
-//! An abstraction over staking pallet to support delegation of funds to a `delegate` account which
+//! An abstraction over staking pallet to support delegation of funds to a `delegatee` account which
 //! can use all the delegated funds to it in the staking pallet as if its own fund.
 //!
 //! NOTE: The pallet exposes extrinsics which are not yet meant to be exposed in the runtime but
@@ -34,40 +34,40 @@
 //!
 //! #### Reward and Slashing
 //! This pallet does not enforce any specific strategy for how rewards or slashes are applied. It
-//! is upto the `delegate` account to decide how to apply the rewards and slashes.
+//! is upto the `delegatee` account to decide how to apply the rewards and slashes.
 //!
 //! This importantly allows clients of this pallet to build their own strategies for reward/slashes.
-//! For example, a `delegate` account can choose to first slash the reward pot before slashing the
+//! For example, a `delegatee` account can choose to first slash the reward pot before slashing the
 //! delegators. Or part of the reward can go to a insurance fund that can be used to cover any
 //! potential future slashes. The goal is to eventually allow foreign MultiLocations
 //! (smart contracts or pallets on another chain) to build their own pooled staking solutions
 //! similar to `NominationPool`.
 //!
 //! ## Key Terminologies
-//! - *Delegate*: An account who accepts delegations from other accounts (called `Delegators`).
-//! - *Delegator*: An account who delegates their funds to a `delegate`.
-//! - *DelegationLedger*: A data structure that stores important information about the `delegate`
+//! - *delegatee*: An account who accepts delegations from other accounts (called `Delegators`).
+//! - *Delegator*: An account who delegates their funds to a `delegatee`.
+//! - *DelegationLedger*: A data structure that stores important information about the `delegatee`
 //! 	such as their total delegated stake.
-//! - *Delegation*: A data structure that stores the amount of funds delegated to a `delegate` by a
+//! - *Delegation*: A data structure that stores the amount of funds delegated to a `delegatee` by a
 //! 	`delegator`.
 //!
 //! ## Interface
 //!
 //! #### Dispatchable Calls
 //! The pallet exposes the following [`Call`]s:
-//! - `register_as_delegate`: Register an account to be a `Delegate`. Once an account is registered
-//! 	as a `Delegate`, for staking operations, only its delegated funds are used. This means it
+//! - `register_as_delegatee`: Register an account to be a `delegatee`. Once an account is registered
+//! 	as a `delegatee`, for staking operations, only its delegated funds are used. This means it
 //! 	cannot use its own free balance to stake.
-//! - `migrate_to_delegate`: This allows a `Nominator` account to become a `Delegate` account.
+//! - `migrate_to_delegate`: This allows a `Nominator` account to become a `delegatee` account.
 //! 	Explained in more detail in the `Migration` section.
 //! - `release`: Release funds to `delegator` from `unclaimed_withdrawals` register of the
-//!   `delegate`.
+//!   `delegatee`.
 //! - `migrate_delegation`: Migrate delegated funds from one account to another. This is useful for
-//!   example, delegators to a pool account which has migrated to be `delegate` to migrate their
+//!   example, delegators to a pool account which has migrated to be `delegatee` to migrate their
 //!   funds from pool account back to their own account and delegated to pool as a `delegator`. Once
 //!   the funds are migrated, the `delegator` can use the funds for other purposes which allows
 //!   usage of held funds in an account, such as governance.
-//! - `delegate_funds`: Delegate funds to a `Delegate` account and update the bond to staking.
+//! - `delegate_funds`: Delegate funds to a `delegatee` account and update the bond to staking.
 //!
 //! #### [Staking Interface](StakingInterface)
 //! This pallet reimplements the staking interface as a wrapper implementation over
@@ -78,33 +78,28 @@
 //! The pallet implements the staking delegation support trait which staking pallet can use to
 //! provide compatibility with this pallet.
 //!
-//! #### [Pool Adapter](sp_staking::delegation::PoolAdapter)
-//! The pallet also implements the pool adapter trait which allows NominationPool to use this pallet
-//! to support delegation based staking from pool accounts. This strategy also allows the pool to
-//! switch implementations while having minimal changes to its own logic.
-//!
 //! ## Lazy Slashing
 //! One of the reasons why direct nominators on staking pallet cannot scale well is because all
 //! nominators are slashed at the same time. This is expensive and needs to be bounded operation.
 //!
-//! This pallet implements a lazy slashing mechanism. Any slashes to a `delegate` are posted in its
+//! This pallet implements a lazy slashing mechanism. Any slashes to a `delegatee` are posted in its
 //! `DelegationLedger` as a pending slash. Since the actual amount is held in the multiple
-//! `delegator` accounts, this pallet has no way to know how to apply slash. It is `delegate`'s
+//! `delegator` accounts, this pallet has no way to know how to apply slash. It is `delegatee`'s
 //! responsibility to apply slashes for each delegator, one at a time. Staking pallet ensures the
 //! pending slash never exceeds staked amount and would freeze further withdraws until pending
 //! slashes are applied.
 //!
 //! `NominationPool` can apply slash for all its members by calling
-//! [PoolAdapter::delegator_slash](sp_staking::delegation::PoolAdapter::delegator_slash).
+//! [StakingInterface::delegator_slash](sp_staking::StakingInterface::delegator_slash).
 //!
 //! ## Migration from Nominator to Delegate
 //! More details [here](https://hackmd.io/@ak0n/np-delegated-staking-migration).
 //!
 //! ## Reward Destination Restrictions
-//! This pallets set an important restriction of rewards account to be separate from `delegate`
-//! account. This is because, `delegate` balance is not what is directly exposed but the funds that
-//! are delegated to it. For `delegate` accounts, we have also no way to auto-compound rewards. The
-//! rewards need to be paid out to delegators and then delegated again to the `delegate` account.
+//! This pallets set an important restriction of rewards account to be separate from `delegatee`
+//! account. This is because, `delegatee` balance is not what is directly exposed but the funds that
+//! are delegated to it. For `delegatee` accounts, we have also no way to auto-compound rewards. The
+//! rewards need to be paid out to delegators and then delegated again to the `delegatee` account.
 //!
 //! ## Nomination Pool vs Delegation Staking
 //! This pallet is not a replacement for Nomination Pool but adds a new primitive over staking
@@ -220,9 +215,9 @@ pub mod pallet {
 	pub enum Error<T> {
 		/// The account cannot perform this operation.
 		NotAllowed,
-		/// An existing staker cannot become a `delegate`.
+		/// An existing staker cannot become a `delegatee`.
 		AlreadyStaker,
-		/// Reward Destination cannot be `delegate` account.
+		/// Reward Destination cannot be `delegatee` account.
 		InvalidRewardDestination,
 		/// Delegation conditions are not met.
 		///
@@ -232,13 +227,13 @@ pub mod pallet {
 		InvalidDelegation,
 		/// The account does not have enough funds to perform the operation.
 		NotEnoughFunds,
-		/// Not an existing `delegate` account.
-		NotDelegate,
+		/// Not an existing `delegatee` account.
+		NotDelegatee,
 		/// Not a Delegator account.
 		NotDelegator,
 		/// Some corruption in internal state.
 		BadState,
-		/// Unapplied pending slash restricts operation on `delegate`.
+		/// Unapplied pending slash restricts operation on `delegatee`.
 		UnappliedSlash,
 		/// Failed to withdraw amount from Core Staking.
 		WithdrawFailed,
@@ -260,16 +255,16 @@ pub mod pallet {
 	#[pallet::generate_deposit(pub (super) fn deposit_event)]
 	pub enum Event<T: Config> {
 		/// Funds delegated by a delegator.
-		Delegated { delegate: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
+		Delegated { delegatee: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
 		/// Funds released to a delegator.
-		Released { delegate: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
+		Released { delegatee: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
 		/// Funds slashed from a delegator.
-		Slashed { delegate: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
+		Slashed { delegatee: T::AccountId, delegator: T::AccountId, amount: BalanceOf<T> },
 	}
 
 	/// Map of Delegators to their `Delegation`.
 	///
-	/// Implementation note: We are not using a double map with `delegator` and `delegate` account
+	/// Implementation note: We are not using a double map with `delegator` and `delegatee` account
 	/// as keys since we want to restrict delegators to delegate only to one account at a time.
 	#[pallet::storage]
 	pub(crate) type Delegators<T: Config> =
@@ -288,22 +283,22 @@ pub mod pallet {
 		/// behalf.
 		#[pallet::call_index(0)]
 		#[pallet::weight(Weight::default())]
-		pub fn register_as_delegate(
+		pub fn register_as_delegatee(
 			origin: OriginFor<T>,
 			reward_account: T::AccountId,
 		) -> DispatchResult {
 			let who = ensure_signed(origin)?;
 
-			// Existing `delegate` cannot register again.
-			ensure!(!Self::is_delegate(&who), Error::<T>::NotAllowed);
+			// Existing `delegatee` cannot register again.
+			ensure!(!Self::is_delegatee(&who), Error::<T>::NotAllowed);
 
-			// A delegator cannot become a `delegate`.
+			// A delegator cannot become a `delegatee`.
 			ensure!(!Self::is_delegator(&who), Error::<T>::NotAllowed);
 
 			// They cannot be already a direct staker in the staking pallet.
 			ensure!(Self::not_direct_staker(&who), Error::<T>::AlreadyStaker);
 
-			// Reward account cannot be same as `delegate` account.
+			// Reward account cannot be same as `delegatee` account.
 			ensure!(reward_account != who, Error::<T>::InvalidRewardDestination);
 
 			Self::do_register_delegator(&who, &reward_account);
@@ -325,26 +320,26 @@ pub mod pallet {
 		/// claim back their share of delegated funds from `proxy_delegator` to self.
 		#[pallet::call_index(1)]
 		#[pallet::weight(Weight::default())]
-		pub fn migrate_to_delegate(
+		pub fn migrate_to_delegatee(
 			origin: OriginFor<T>,
 			reward_account: T::AccountId,
 		) -> DispatchResult {
 			let who = ensure_signed(origin)?;
-			// ensure who is not already a delegate.
-			ensure!(!Self::is_delegate(&who), Error::<T>::NotAllowed);
+			// ensure who is not already a delegatee.
+			ensure!(!Self::is_delegatee(&who), Error::<T>::NotAllowed);
 
 			// and they should already be a nominator in `CoreStaking`.
 			ensure!(Self::is_direct_nominator(&who), Error::<T>::NotAllowed);
 
-			// Reward account cannot be same as `delegate` account.
+			// Reward account cannot be same as `delegatee` account.
 			ensure!(reward_account != who, Error::<T>::InvalidRewardDestination);
 
-			Self::do_migrate_to_delegate(&who, &reward_account)
+			Self::do_migrate_to_delegatee(&who, &reward_account)
 		}
 
 		/// Release delegated amount to delegator.
 		///
-		/// This can be called by existing `delegate` accounts.
+		/// This can be called by existing `delegatee` accounts.
 		///
 		/// Tries to withdraw unbonded fund from `CoreStaking` if needed and release amount to
 		/// `delegator`.
@@ -362,7 +357,7 @@ pub mod pallet {
 
 		/// Migrate delegated fund.
 		///
-		/// This can be called by migrating `delegate` accounts.
+		/// This can be called by migrating `delegatee` accounts.
 		///
 		/// This moves delegator funds from `pxoxy_delegator` account to `delegator` account.
 		#[pallet::call_index(3)]
@@ -372,21 +367,21 @@ pub mod pallet {
 			delegator: T::AccountId,
 			amount: BalanceOf<T>,
 		) -> DispatchResult {
-			let delegate = ensure_signed(origin)?;
+			let delegatee = ensure_signed(origin)?;
 
 			// Ensure they have minimum delegation.
 			ensure!(amount >= T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
 
 			// Ensure delegator is sane.
-			ensure!(!Self::is_delegate(&delegator), Error::<T>::NotAllowed);
+			ensure!(!Self::is_delegatee(&delegator), Error::<T>::NotAllowed);
 			ensure!(!Self::is_delegator(&delegator), Error::<T>::NotAllowed);
 			ensure!(Self::not_direct_staker(&delegator), Error::<T>::AlreadyStaker);
 
 			// ensure delegate is sane.
-			ensure!(Self::is_delegate(&delegate), Error::<T>::NotDelegate);
+			ensure!(Self::is_delegatee(&delegatee), Error::<T>::NotDelegatee);
 
 			// and has enough delegated balance to migrate.
-			let proxy_delegator = Self::sub_account(AccountType::ProxyDelegator, delegate);
+			let proxy_delegator = Self::sub_account(AccountType::ProxyDelegator, delegatee);
 			let balance_remaining = Self::held_balance_of(&proxy_delegator);
 			ensure!(balance_remaining >= amount, Error::<T>::NotEnoughFunds);
 
@@ -400,7 +395,7 @@ pub mod pallet {
 		#[pallet::weight(Weight::default())]
 		pub fn delegate_funds(
 			origin: OriginFor<T>,
-			delegate: T::AccountId,
+			delegatee: T::AccountId,
 			amount: BalanceOf<T>,
 		) -> DispatchResult {
 			let who = ensure_signed(origin)?;
@@ -409,12 +404,12 @@ pub mod pallet {
 			ensure!(amount > T::Currency::minimum_balance(), Error::<T>::NotEnoughFunds);
 
 			// ensure delegator is sane.
-			ensure!(Delegation::<T>::can_delegate(&who, &delegate), Error::<T>::InvalidDelegation);
+			ensure!(Delegation::<T>::can_delegate(&who, &delegatee), Error::<T>::InvalidDelegation);
 			ensure!(Self::not_direct_staker(&who), Error::<T>::AlreadyStaker);
 
 			// ensure delegate is sane.
 			ensure!(
-				DelegationLedger::<T>::can_accept_delegation(&delegate),
+				DelegationLedger::<T>::can_accept_delegation(&delegatee),
 				Error::<T>::NotAcceptingDelegations
 			);
 
@@ -423,23 +418,23 @@ pub mod pallet {
 			ensure!(delegator_balance >= amount, Error::<T>::NotEnoughFunds);
 
 			// add to delegation
-			Self::do_delegate(&who, &delegate, amount)?;
+			Self::do_delegate(&who, &delegatee, amount)?;
 			// bond the amount to `CoreStaking`.
-			Self::do_bond(&delegate, amount)
+			Self::do_bond(&delegatee, amount)
 		}
 
 		/// Toggle delegate status to start or stop accepting new delegations.
 		///
 		/// This can only be used by existing delegates. If not a delegate yet, use
-		/// [Call::register_as_delegate] first.
+		/// [Call::register_as_delegatee] first.
 		#[pallet::call_index(5)]
 		#[pallet::weight(Weight::default())]
-		pub fn toggle_delegate_status(origin: OriginFor<T>) -> DispatchResult {
+		pub fn toggle_delegatee_status(origin: OriginFor<T>) -> DispatchResult {
 			let who = ensure_signed(origin)?;
 
-			let delegate = Delegate::<T>::from(&who)?;
-			let should_block = !delegate.ledger.blocked;
-			delegate.update_status(should_block).save();
+			let delegatee = Delegatee::<T>::from(&who)?;
+			let should_block = !delegatee.ledger.blocked;
+			delegatee.update_status(should_block).save();
 
 			Ok(())
 		}
@@ -476,9 +471,9 @@ impl<T: Config> Pallet<T> {
 	/// Derive a (keyless) pot account from the given delegate account and account type.
 	pub(crate) fn sub_account(
 		account_type: AccountType,
-		delegate_account: T::AccountId,
+		delegatee_account: T::AccountId,
 	) -> T::AccountId {
-		T::PalletId::get().into_sub_account_truncating((account_type, delegate_account.clone()))
+		T::PalletId::get().into_sub_account_truncating((account_type, delegatee_account.clone()))
 	}
 
 	/// Balance of a delegator that is delegated.
@@ -487,7 +482,7 @@ impl<T: Config> Pallet<T> {
 	}
 
 	/// Returns true if who is registered as a `Delegate`.
-	fn is_delegate(who: &T::AccountId) -> bool {
+	fn is_delegatee(who: &T::AccountId) -> bool {
 		<Delegates<T>>::contains_key(who)
 	}
 
@@ -517,7 +512,7 @@ impl<T: Config> Pallet<T> {
 		frame_system::Pallet::<T>::inc_providers(who);
 	}
 
-	fn do_migrate_to_delegate(who: &T::AccountId, reward_account: &T::AccountId) -> DispatchResult {
+	fn do_migrate_to_delegatee(who: &T::AccountId, reward_account: &T::AccountId) -> DispatchResult {
 		// We create a proxy delegator that will keep all the delegation funds until funds are
 		// transferred to actual delegator.
 		let proxy_delegator = Self::sub_account(AccountType::ProxyDelegator, who.clone());
@@ -549,30 +544,30 @@ impl<T: Config> Pallet<T> {
 		Self::do_delegate(&proxy_delegator, who, stake.total)
 	}
 
-	fn do_bond(delegate_acc: &T::AccountId, amount: BalanceOf<T>) -> DispatchResult {
-		let delegate = Delegate::<T>::from(delegate_acc)?;
+	fn do_bond(delegatee_acc: &T::AccountId, amount: BalanceOf<T>) -> DispatchResult {
+		let delegatee = Delegatee::<T>::from(delegatee_acc)?;
 
-		let available_to_bond = delegate.available_to_bond();
+		let available_to_bond = delegatee.available_to_bond();
 		defensive_assert!(amount == available_to_bond, "not expected value to bond");
 
-		if delegate.is_bonded() {
-			T::CoreStaking::bond_extra(&delegate.key, amount)
+		if delegatee.is_bonded() {
+			T::CoreStaking::bond_extra(&delegatee.key, amount)
 		} else {
-			T::CoreStaking::bond(&delegate.key, amount, &delegate.reward_account())
+			T::CoreStaking::bond(&delegatee.key, amount, &delegatee.reward_account())
 		}
 	}
 
 	fn do_delegate(
 		delegator: &T::AccountId,
-		delegate: &T::AccountId,
+		delegatee: &T::AccountId,
 		amount: BalanceOf<T>,
 	) -> DispatchResult {
-		let mut ledger = DelegationLedger::<T>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
+		let mut ledger = DelegationLedger::<T>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
 		debug_assert!(!ledger.blocked);
 
 		let new_delegation_amount =
 			if let Some(existing_delegation) = Delegation::<T>::get(delegator) {
-				ensure!(&existing_delegation.delegate == delegate, Error::<T>::InvalidDelegation);
+				ensure!(&existing_delegation.delegatee == delegatee, Error::<T>::InvalidDelegation);
 				existing_delegation
 					.amount
 					.checked_add(&amount)
@@ -581,15 +576,15 @@ impl<T: Config> Pallet<T> {
 				amount
 			};
 
-		Delegation::<T>::from(delegate, new_delegation_amount).save(delegator);
+		Delegation::<T>::from(delegatee, new_delegation_amount).save(delegator);
 		ledger.total_delegated =
 			ledger.total_delegated.checked_add(&amount).ok_or(ArithmeticError::Overflow)?;
-		ledger.save(delegate);
+		ledger.save(delegatee);
 
 		T::Currency::hold(&HoldReason::Delegating.into(), delegator, amount)?;
 
 		Self::deposit_event(Event::<T>::Delegated {
-			delegate: delegate.clone(),
+			delegatee: delegatee.clone(),
 			delegator: delegator.clone(),
 			amount,
 		});
@@ -603,24 +598,24 @@ impl<T: Config> Pallet<T> {
 		amount: BalanceOf<T>,
 		num_slashing_spans: u32,
 	) -> DispatchResult {
-		let mut delegate = Delegate::<T>::from(who)?;
+		let mut delegatee = Delegatee::<T>::from(who)?;
 		let mut delegation = Delegation::<T>::get(delegator).ok_or(Error::<T>::NotDelegator)?;
 
 		// make sure delegation to be released is sound.
-		ensure!(&delegation.delegate == who, Error::<T>::NotDelegate);
+		ensure!(&delegation.delegatee == who, Error::<T>::NotDelegatee);
 		ensure!(delegation.amount >= amount, Error::<T>::NotEnoughFunds);
 
 		// if we do not already have enough funds to be claimed, try withdraw some more.
-		if delegate.ledger.unclaimed_withdrawals < amount {
+		if delegatee.ledger.unclaimed_withdrawals < amount {
 			// get the updated delegate
-			delegate = Self::withdraw_unbonded(who, num_slashing_spans)?;
+			delegatee = Self::withdraw_unbonded(who, num_slashing_spans)?;
 		}
 
 		// if we still do not have enough funds to release, abort.
-		ensure!(delegate.ledger.unclaimed_withdrawals >= amount, Error::<T>::NotEnoughFunds);
+		ensure!(delegatee.ledger.unclaimed_withdrawals >= amount, Error::<T>::NotEnoughFunds);
 
-		// claim withdraw from delegate.
-		delegate.remove_unclaimed_withdraw(amount)?.save_or_kill()?;
+		// claim withdraw from delegatee.
+		delegatee.remove_unclaimed_withdraw(amount)?.save_or_kill()?;
 
 		// book keep delegation
 		delegation.amount = delegation
@@ -642,7 +637,7 @@ impl<T: Config> Pallet<T> {
 		defensive_assert!(released == amount, "hold should have been released fully");
 
 		Self::deposit_event(Event::<T>::Released {
-			delegate: who.clone(),
+			delegatee: who.clone(),
 			delegator: delegator.clone(),
 			amount,
 		});
@@ -651,17 +646,17 @@ impl<T: Config> Pallet<T> {
 	}
 
 	fn withdraw_unbonded(
-		delegate_acc: &T::AccountId,
+		delegatee_acc: &T::AccountId,
 		num_slashing_spans: u32,
-	) -> Result<Delegate<T>, DispatchError> {
-		let delegate = Delegate::<T>::from(delegate_acc)?;
-		let pre_total = T::CoreStaking::stake(delegate_acc).defensive()?.total;
+	) -> Result<Delegatee<T>, DispatchError> {
+		let delegatee = Delegatee::<T>::from(delegatee_acc)?;
+		let pre_total = T::CoreStaking::stake(delegatee_acc).defensive()?.total;
 
 		let stash_killed: bool =
-			T::CoreStaking::withdraw_unbonded(delegate_acc.clone(), num_slashing_spans)
+			T::CoreStaking::withdraw_unbonded(delegatee_acc.clone(), num_slashing_spans)
 				.map_err(|_| Error::<T>::WithdrawFailed)?;
 
-		let maybe_post_total = T::CoreStaking::stake(delegate_acc);
+		let maybe_post_total = T::CoreStaking::stake(delegatee_acc);
 		// One of them should be true
 		defensive_assert!(
 			!(stash_killed && maybe_post_total.is_ok()),
@@ -673,11 +668,11 @@ impl<T: Config> Pallet<T> {
 		let new_withdrawn =
 			pre_total.checked_sub(&post_total).defensive_ok_or(Error::<T>::BadState)?;
 
-		let delegate = delegate.add_unclaimed_withdraw(new_withdrawn)?;
+		let delegatee = delegatee.add_unclaimed_withdraw(new_withdrawn)?;
 
-		delegate.clone().save();
+		delegatee.clone().save();
 
-		Ok(delegate)
+		Ok(delegatee)
 	}
 
 	/// Migrates delegation of `amount` from `source` account to `destination` account.
@@ -692,11 +687,11 @@ impl<T: Config> Pallet<T> {
 		// some checks that must have already been checked before.
 		ensure!(source_delegation.amount >= amount, Error::<T>::NotEnoughFunds);
 		debug_assert!(
-			!Self::is_delegator(destination_delegator) && !Self::is_delegate(destination_delegator)
+			!Self::is_delegator(destination_delegator) && !Self::is_delegatee(destination_delegator)
 		);
 
 		// update delegations
-		Delegation::<T>::from(&source_delegation.delegate, amount).save(destination_delegator);
+		Delegation::<T>::from(&source_delegation.delegatee, amount).save(destination_delegator);
 
 		source_delegation
 			.decrease_delegation(amount)
@@ -734,15 +729,15 @@ impl<T: Config> Pallet<T> {
 	}
 
 	pub fn do_slash(
-		delegate_acc: T::AccountId,
+		delegatee_acc: T::AccountId,
 		delegator: T::AccountId,
 		amount: BalanceOf<T>,
 		maybe_reporter: Option<T::AccountId>,
 	) -> DispatchResult {
-		let delegate = Delegate::<T>::from(&delegate_acc)?;
+		let delegatee = Delegatee::<T>::from(&delegatee_acc)?;
 		let delegation = <Delegators<T>>::get(&delegator).ok_or(Error::<T>::NotDelegator)?;
 
-		ensure!(delegation.delegate == delegate_acc, Error::<T>::NotDelegate);
+		ensure!(delegation.delegatee == delegatee_acc, Error::<T>::NotDelegatee);
 		ensure!(delegation.amount >= amount, Error::<T>::NotEnoughFunds);
 
 		let (mut credit, missing) =
@@ -752,8 +747,8 @@ impl<T: Config> Pallet<T> {
 
 		let actual_slash = credit.peek();
 
-		// remove the applied slashed amount from delegate.
-		delegate.remove_slash(actual_slash).save();
+		// remove the applied slashed amount from delegatee.
+		delegatee.remove_slash(actual_slash).save();
 
 		delegation
 			.decrease_delegation(actual_slash)
@@ -772,7 +767,7 @@ impl<T: Config> Pallet<T> {
 
 		T::OnSlash::on_unbalanced(credit);
 
-		Self::deposit_event(Event::<T>::Slashed { delegate: delegate_acc, delegator, amount });
+		Self::deposit_event(Event::<T>::Slashed { delegatee: delegatee_acc, delegator, amount });
 
 		Ok(())
 	}
@@ -797,10 +792,10 @@ impl<T: Config> Pallet<T> {
 	fn check_delegates(
 		ledgers: BTreeMap<T::AccountId, DelegationLedger<T>>,
 	) -> Result<(), sp_runtime::TryRuntimeError> {
-		for (delegate, ledger) in ledgers {
+		for (delegatee, ledger) in ledgers {
 			ensure!(
 				matches!(
-					T::CoreStaking::status(&delegate).expect("delegate should be bonded"),
+					T::CoreStaking::status(&delegatee).expect("delegate should be bonded"),
 					StakerStatus::Nominator(_) | StakerStatus::Idle
 				),
 				"delegate should be bonded and not validator"
@@ -808,7 +803,7 @@ impl<T: Config> Pallet<T> {
 
 			ensure!(
 				ledger.stakeable_balance() >=
-					T::CoreStaking::total_stake(&delegate)
+					T::CoreStaking::total_stake(&delegatee)
 						.expect("delegate should exist as a nominator"),
 				"Cannot stake more than balance"
 			);
@@ -827,18 +822,18 @@ impl<T: Config> Pallet<T> {
 				T::CoreStaking::status(delegator).is_err(),
 				"delegator should not be directly staked"
 			);
-			ensure!(!Self::is_delegate(delegator), "delegator cannot be delegate");
+			ensure!(!Self::is_delegatee(delegator), "delegator cannot be delegate");
 
 			delegation_aggregation
-				.entry(delegation.delegate.clone())
+				.entry(delegation.delegatee.clone())
 				.and_modify(|e| *e += delegation.amount)
 				.or_insert(delegation.amount);
 		}
 
-		for (delegate, total_delegated) in delegation_aggregation {
-			ensure!(!Self::is_delegator(&delegate), "delegate cannot be delegator");
+		for (delegatee, total_delegated) in delegation_aggregation {
+			ensure!(!Self::is_delegator(&delegatee), "delegate cannot be delegator");
 
-			let ledger = ledger.get(&delegate).expect("ledger should exist");
+			let ledger = ledger.get(&delegatee).expect("ledger should exist");
 			ensure!(
 				ledger.total_delegated == total_delegated,
 				"ledger total delegated should match delegations"
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 4d0388a7f6bc2..56c8cee65d407 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -15,7 +15,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use crate::{self as delegated_staking, types::Delegate, HoldReason};
+use crate::{self as delegated_staking, types::Delegatee, HoldReason};
 use frame_support::{
 	assert_ok, derive_impl,
 	pallet_prelude::*,
@@ -283,15 +283,15 @@ pub(crate) fn fund(who: &AccountId, amount: Balance) {
 /// `delegate_amount` is incremented by the amount `increment` starting with `base_delegate_amount`
 /// from lower index to higher index of delegators.
 pub(crate) fn setup_delegation_stake(
-	delegate: AccountId,
+	delegatee: AccountId,
 	reward_acc: AccountId,
 	delegators: Vec<AccountId>,
 	base_delegate_amount: Balance,
 	increment: Balance,
 ) -> Balance {
-	fund(&delegate, 100);
-	assert_ok!(DelegatedStaking::register_as_delegate(
-		RawOrigin::Signed(delegate).into(),
+	fund(&delegatee, 100);
+	assert_ok!(DelegatedStaking::register_as_delegatee(
+		RawOrigin::Signed(delegatee).into(),
 		reward_acc
 	));
 	let mut delegated_amount: Balance = 0;
@@ -302,14 +302,14 @@ pub(crate) fn setup_delegation_stake(
 		fund(delegator, amount_to_delegate + ExistentialDeposit::get());
 		assert_ok!(DelegatedStaking::delegate_funds(
 			RawOrigin::Signed(delegator.clone()).into(),
-			delegate,
+			delegatee,
 			amount_to_delegate
 		));
 	}
 
 	// sanity checks
-	assert_eq!(DelegatedStaking::stakeable_balance(&delegate), delegated_amount);
-	assert_eq!(Delegate::<T>::from(&delegate).unwrap().available_to_bond(), 0);
+	assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), delegated_amount);
+	assert_eq!(Delegatee::<T>::from(&delegatee).unwrap().available_to_bond(), 0);
 
 	delegated_amount
 }
@@ -320,11 +320,11 @@ pub(crate) fn start_era(era: sp_staking::EraIndex) {
 
 pub(crate) fn eq_stake(who: AccountId, total: Balance, active: Balance) -> bool {
 	Staking::stake(&who).unwrap() == Stake { total, active } &&
-		get_delegate(&who).ledger.stakeable_balance() == total
+		get_delegatee(&who).ledger.stakeable_balance() == total
 }
 
-pub(crate) fn get_delegate(delegate: &AccountId) -> Delegate<T> {
-	Delegate::<T>::from(delegate).expect("delegate should exist")
+pub(crate) fn get_delegatee(delegatee: &AccountId) -> Delegatee<T> {
+	Delegatee::<T>::from(delegatee).expect("delegate should exist")
 }
 
 pub(crate) fn held_balance(who: &AccountId) -> Balance {
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index e58bec8bcf5bd..6835424dde727 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -25,16 +25,16 @@ use pallet_staking::Error as StakingError;
 use sp_staking::delegation::StakingDelegationSupport;
 
 #[test]
-fn create_a_delegate_with_first_delegator() {
+fn create_a_delegatee_with_first_delegator() {
 	ExtBuilder::default().build_and_execute(|| {
-		let delegate: AccountId = 200;
+		let delegatee: AccountId = 200;
 		let reward_account: AccountId = 201;
 		let delegator: AccountId = 202;
 
 		// set intention to accept delegation.
-		fund(&delegate, 1000);
-		assert_ok!(DelegatedStaking::register_as_delegate(
-			RawOrigin::Signed(delegate).into(),
+		fund(&delegatee, 1000);
+		assert_ok!(DelegatedStaking::register_as_delegatee(
+			RawOrigin::Signed(delegatee).into(),
 			reward_account
 		));
 
@@ -42,45 +42,45 @@ fn create_a_delegate_with_first_delegator() {
 		fund(&delegator, 1000);
 		assert_ok!(DelegatedStaking::delegate_funds(
 			RawOrigin::Signed(delegator).into(),
-			delegate,
+			delegatee,
 			100
 		));
 
 		// verify
-		assert!(DelegatedStaking::is_delegate(&delegate));
-		assert_eq!(DelegatedStaking::stakeable_balance(&delegate), 100);
+		assert!(DelegatedStaking::is_delegatee(&delegatee));
+		assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100);
 		assert_eq!(Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator), 100);
 	});
 }
 
 #[test]
-fn cannot_become_delegate() {
+fn cannot_become_delegatee() {
 	ExtBuilder::default().build_and_execute(|| {
-		// cannot set reward account same as delegate account
+		// cannot set reward account same as delegatee account
 		assert_noop!(
-			DelegatedStaking::register_as_delegate(RawOrigin::Signed(100).into(), 100),
+			DelegatedStaking::register_as_delegatee(RawOrigin::Signed(100).into(), 100),
 			Error::<T>::InvalidRewardDestination
 		);
 
-		// an existing validator cannot become delegate
+		// an existing validator cannot become delegatee
 		assert_noop!(
-			DelegatedStaking::register_as_delegate(
+			DelegatedStaking::register_as_delegatee(
 				RawOrigin::Signed(mock::GENESIS_VALIDATOR).into(),
 				100
 			),
 			Error::<T>::AlreadyStaker
 		);
 
-		// an existing nominator cannot become delegate
+		// an existing nominator cannot become delegatee
 		assert_noop!(
-			DelegatedStaking::register_as_delegate(
+			DelegatedStaking::register_as_delegatee(
 				RawOrigin::Signed(mock::GENESIS_NOMINATOR_ONE).into(),
 				100
 			),
 			Error::<T>::AlreadyStaker
 		);
 		assert_noop!(
-			DelegatedStaking::register_as_delegate(
+			DelegatedStaking::register_as_delegatee(
 				RawOrigin::Signed(mock::GENESIS_NOMINATOR_TWO).into(),
 				100
 			),
@@ -92,17 +92,17 @@ fn cannot_become_delegate() {
 #[test]
 fn create_multiple_delegators() {
 	ExtBuilder::default().build_and_execute(|| {
-		let delegate: AccountId = 200;
+		let delegatee: AccountId = 200;
 		let reward_account: AccountId = 201;
 
-		// stakeable balance is 0 for non delegate
-		fund(&delegate, 1000);
-		assert!(!DelegatedStaking::is_delegate(&delegate));
-		assert_eq!(DelegatedStaking::stakeable_balance(&delegate), 0);
+		// stakeable balance is 0 for non delegatee
+		fund(&delegatee, 1000);
+		assert!(!DelegatedStaking::is_delegatee(&delegatee));
+		assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 0);
 
 		// set intention to accept delegation.
-		assert_ok!(DelegatedStaking::register_as_delegate(
-			RawOrigin::Signed(delegate).into(),
+		assert_ok!(DelegatedStaking::register_as_delegatee(
+			RawOrigin::Signed(delegatee).into(),
 			reward_account
 		));
 
@@ -111,65 +111,65 @@ fn create_multiple_delegators() {
 			fund(&i, 100 + ExistentialDeposit::get());
 			assert_ok!(DelegatedStaking::delegate_funds(
 				RawOrigin::Signed(i).into(),
-				delegate,
+				delegatee,
 				100
 			));
-			// Balance of 100 held on delegator account for delegating to the delegate.
+			// Balance of 100 held on delegator account for delegating to the delegatee.
 			assert_eq!(Balances::balance_on_hold(&HoldReason::Delegating.into(), &i), 100);
 		}
 
 		// verify
-		assert!(DelegatedStaking::is_delegate(&delegate));
-		assert_eq!(DelegatedStaking::stakeable_balance(&delegate), 100 * 100);
+		assert!(DelegatedStaking::is_delegatee(&delegatee));
+		assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100 * 100);
 	});
 }
 
 #[test]
-fn delegate_restrictions() {
+fn delegatee_restrictions() {
 	// Similar to creating a nomination pool
 	ExtBuilder::default().build_and_execute(|| {
-		let delegate_one = 200;
+		let delegatee_one = 200;
 		let delegator_one = 210;
-		fund(&delegate_one, 100);
-		assert_ok!(DelegatedStaking::register_as_delegate(
-			RawOrigin::Signed(delegate_one).into(),
-			delegate_one + 1
+		fund(&delegatee_one, 100);
+		assert_ok!(DelegatedStaking::register_as_delegatee(
+			RawOrigin::Signed(delegatee_one).into(),
+			delegatee_one + 1
 		));
 		fund(&delegator_one, 200);
 		assert_ok!(DelegatedStaking::delegate_funds(
 			RawOrigin::Signed(delegator_one).into(),
-			delegate_one,
+			delegatee_one,
 			100
 		));
 
-		let delegate_two = 300;
+		let delegatee_two = 300;
 		let delegator_two = 310;
-		fund(&delegate_two, 100);
-		assert_ok!(DelegatedStaking::register_as_delegate(
-			RawOrigin::Signed(delegate_two).into(),
-			delegate_two + 1
+		fund(&delegatee_two, 100);
+		assert_ok!(DelegatedStaking::register_as_delegatee(
+			RawOrigin::Signed(delegatee_two).into(),
+			delegatee_two + 1
 		));
 		fund(&delegator_two, 200);
 		assert_ok!(DelegatedStaking::delegate_funds(
 			RawOrigin::Signed(delegator_two).into(),
-			delegate_two,
+			delegatee_two,
 			100
 		));
 
-		// delegate one tries to delegate to delegate 2
+		// delegatee one tries to delegate to delegatee 2
 		assert_noop!(
 			DelegatedStaking::delegate_funds(
-				RawOrigin::Signed(delegate_one).into(),
-				delegate_two,
+				RawOrigin::Signed(delegatee_one).into(),
+				delegatee_two,
 				10
 			),
 			Error::<T>::InvalidDelegation
 		);
 
-		// delegate one tries to delegate to a delegator
+		// delegatee one tries to delegate to a delegator
 		assert_noop!(
 			DelegatedStaking::delegate_funds(
-				RawOrigin::Signed(delegate_one).into(),
+				RawOrigin::Signed(delegatee_one).into(),
 				delegator_one,
 				10
 			),
@@ -177,19 +177,19 @@ fn delegate_restrictions() {
 		);
 		assert_noop!(
 			DelegatedStaking::delegate_funds(
-				RawOrigin::Signed(delegate_one).into(),
+				RawOrigin::Signed(delegatee_one).into(),
 				delegator_two,
 				10
 			),
 			Error::<T>::InvalidDelegation
 		);
 
-		// delegator one tries to delegate to delegate 2 as well (it already delegates to delegate
+		// delegator one tries to delegate to delegatee 2 as well (it already delegates to delegatee
 		// 1)
 		assert_noop!(
 			DelegatedStaking::delegate_funds(
 				RawOrigin::Signed(delegator_one).into(),
-				delegate_two,
+				delegatee_two,
 				10
 			),
 			Error::<T>::InvalidDelegation
@@ -215,17 +215,17 @@ mod staking_integration {
 	#[test]
 	fn bond() {
 		ExtBuilder::default().build_and_execute(|| {
-			let delegate: AccountId = 99;
+			let delegatee: AccountId = 99;
 			let reward_acc: AccountId = 100;
-			assert_eq!(Staking::status(&delegate), Err(StakingError::<T>::NotStash.into()));
+			assert_eq!(Staking::status(&delegatee), Err(StakingError::<T>::NotStash.into()));
 
-			// set intention to become a delegate
-			fund(&delegate, 100);
-			assert_ok!(DelegatedStaking::register_as_delegate(
-				RawOrigin::Signed(delegate).into(),
+			// set intention to become a delegatee
+			fund(&delegatee, 100);
+			assert_ok!(DelegatedStaking::register_as_delegatee(
+				RawOrigin::Signed(delegatee).into(),
 				reward_acc
 			));
-			assert_eq!(DelegatedStaking::stakeable_balance(&delegate), 0);
+			assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 0);
 
 			let mut delegated_balance: Balance = 0;
 
@@ -234,7 +234,7 @@ mod staking_integration {
 				fund(&delegator, 200);
 				assert_ok!(DelegatedStaking::delegate_funds(
 					RawOrigin::Signed(delegator).into(),
-					delegate,
+					delegatee,
 					100
 				));
 				delegated_balance += 100;
@@ -243,14 +243,14 @@ mod staking_integration {
 					100
 				);
 
-				let delegate_obj = get_delegate(&delegate);
-				assert_eq!(delegate_obj.ledger.stakeable_balance(), delegated_balance);
-				assert_eq!(delegate_obj.available_to_bond(), 0);
-				assert_eq!(delegate_obj.bonded_stake(), delegated_balance);
+				let delegatee_obj = get_delegatee(&delegatee);
+				assert_eq!(delegatee_obj.ledger.stakeable_balance(), delegated_balance);
+				assert_eq!(delegatee_obj.available_to_bond(), 0);
+				assert_eq!(delegatee_obj.bonded_stake(), delegated_balance);
 			}
 
 			assert_eq!(
-				Staking::stake(&delegate).unwrap(),
+				Staking::stake(&delegatee).unwrap(),
 				Stake { total: 50 * 100, active: 50 * 100 }
 			)
 		});
@@ -261,89 +261,89 @@ mod staking_integration {
 		ExtBuilder::default().build_and_execute(|| {
 			// initial era
 			start_era(1);
-			let delegate: AccountId = 200;
+			let delegatee: AccountId = 200;
 			let reward_acc: AccountId = 201;
 			let delegators: Vec<AccountId> = (301..=350).collect();
 			let total_staked =
-				setup_delegation_stake(delegate, reward_acc, delegators.clone(), 10, 10);
+				setup_delegation_stake(delegatee, reward_acc, delegators.clone(), 10, 10);
 
 			// lets go to a new era
 			start_era(2);
 
-			assert!(eq_stake(delegate, total_staked, total_staked));
+			assert!(eq_stake(delegatee, total_staked, total_staked));
 			// Withdrawing without unbonding would fail.
 			assert_noop!(
-				DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 301, 50, 0),
+				DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 301, 50, 0),
 				Error::<T>::NotEnoughFunds
 			);
-			// assert_noop!(DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 200, 50,
+			// assert_noop!(DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 200, 50,
 			// 0), Error::<T>::NotAllowed); active and total stake remains same
-			assert!(eq_stake(delegate, total_staked, total_staked));
+			assert!(eq_stake(delegatee, total_staked, total_staked));
 
 			// 305 wants to unbond 50 in era 2, withdrawable in era 5.
-			assert_ok!(DelegatedStaking::unbond(&delegate, 50));
+			assert_ok!(DelegatedStaking::unbond(&delegatee, 50));
 			// 310 wants to unbond 100 in era 3, withdrawable in era 6.
 			start_era(3);
-			assert_ok!(DelegatedStaking::unbond(&delegate, 100));
+			assert_ok!(DelegatedStaking::unbond(&delegatee, 100));
 			// 320 wants to unbond 200 in era 4, withdrawable in era 7.
 			start_era(4);
-			assert_ok!(DelegatedStaking::unbond(&delegate, 200));
+			assert_ok!(DelegatedStaking::unbond(&delegatee, 200));
 
 			// active stake is now reduced..
 			let expected_active = total_staked - (50 + 100 + 200);
-			assert!(eq_stake(delegate, total_staked, expected_active));
+			assert!(eq_stake(delegatee, total_staked, expected_active));
 
 			// nothing to withdraw at era 4
 			assert_noop!(
-				DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 305, 50, 0),
+				DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 305, 50, 0),
 				Error::<T>::NotEnoughFunds
 			);
 
-			assert!(eq_stake(delegate, total_staked, expected_active));
-			assert_eq!(get_delegate(&delegate).available_to_bond(), 0);
+			assert!(eq_stake(delegatee, total_staked, expected_active));
+			assert_eq!(get_delegatee(&delegatee).available_to_bond(), 0);
 			// full amount is still delegated
-			assert_eq!(get_delegate(&delegate).ledger.effective_balance(), total_staked);
+			assert_eq!(get_delegatee(&delegatee).ledger.effective_balance(), total_staked);
 
 			start_era(5);
 			// at era 5, 50 tokens are withdrawable, cannot withdraw more.
 			assert_noop!(
-				DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 305, 51, 0),
+				DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 305, 51, 0),
 				Error::<T>::NotEnoughFunds
 			);
 			// less is possible
-			assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 305, 30, 0));
-			assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 305, 20, 0));
+			assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 305, 30, 0));
+			assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 305, 20, 0));
 
 			// Lets go to future era where everything is unbonded. Withdrawable amount: 100 + 200
 			start_era(7);
 			// 305 has no more amount delegated so it cannot withdraw.
 			assert_noop!(
-				DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 305, 5, 0),
+				DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 305, 5, 0),
 				Error::<T>::NotDelegator
 			);
 			// 309 is an active delegator but has total delegation of 90, so it cannot withdraw more
 			// than that.
 			assert_noop!(
-				DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 309, 91, 0),
+				DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 309, 91, 0),
 				Error::<T>::NotEnoughFunds
 			);
 			// 310 cannot withdraw more than delegated funds.
 			assert_noop!(
-				DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 310, 101, 0),
+				DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 310, 101, 0),
 				Error::<T>::NotEnoughFunds
 			);
 			// but can withdraw all its delegation amount.
-			assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 310, 100, 0));
+			assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 310, 100, 0));
 			// 320 can withdraw all its delegation amount.
-			assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 320, 200, 0));
+			assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 320, 200, 0));
 
 			// cannot withdraw anything more..
 			assert_noop!(
-				DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 301, 1, 0),
+				DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 301, 1, 0),
 				Error::<T>::NotEnoughFunds
 			);
 			assert_noop!(
-				DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 350, 1, 0),
+				DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 350, 1, 0),
 				Error::<T>::NotEnoughFunds
 			);
 		});
@@ -352,12 +352,12 @@ mod staking_integration {
 	#[test]
 	fn withdraw_happens_with_unbonded_balance_first() {
 		ExtBuilder::default().build_and_execute(|| {
-			let delegate = 200;
-			setup_delegation_stake(delegate, 201, (300..350).collect(), 100, 0);
+			let delegatee = 200;
+			setup_delegation_stake(delegatee, 201, (300..350).collect(), 100, 0);
 
 			// verify withdraw not possible yet
 			assert_noop!(
-				DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 300, 100, 0),
+				DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 300, 100, 0),
 				Error::<T>::NotEnoughFunds
 			);
 
@@ -371,11 +371,11 @@ mod staking_integration {
 			// 100));
 			//
 			// // verify unbonded balance
-			// assert_eq!(get_delegate(&delegate).available_to_bond(), 100);
+			// assert_eq!(get_delegatee(&delegatee).available_to_bond(), 100);
 			//
 			// // withdraw works now without unbonding
-			// assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegate).into(), 300, 100,
-			// 0)); assert_eq!(get_delegate(&delegate).available_to_bond(), 0);
+			// assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 300, 100,
+			// 0)); assert_eq!(get_delegatee(&delegatee).available_to_bond(), 0);
 		});
 	}
 
@@ -386,14 +386,14 @@ mod staking_integration {
 			fund(&200, 1000);
 			let balance_200 = Balances::free_balance(200);
 
-			// `delegate` account cannot be reward destination
+			// `delegatee` account cannot be reward destination
 			assert_noop!(
-				DelegatedStaking::register_as_delegate(RawOrigin::Signed(200).into(), 200),
+				DelegatedStaking::register_as_delegatee(RawOrigin::Signed(200).into(), 200),
 				Error::<T>::InvalidRewardDestination
 			);
 
 			// different reward account works
-			assert_ok!(DelegatedStaking::register_as_delegate(RawOrigin::Signed(200).into(), 201));
+			assert_ok!(DelegatedStaking::register_as_delegatee(RawOrigin::Signed(200).into(), 201));
 			// add some delegations to it
 			fund(&300, 1000);
 			assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(300).into(), 200, 100));
@@ -419,8 +419,8 @@ mod staking_integration {
 
 			// amount is staked correctly
 			assert!(eq_stake(200, 100, 100));
-			assert_eq!(get_delegate(&200).available_to_bond(), 0);
-			assert_eq!(get_delegate(&200).ledger.effective_balance(), 100);
+			assert_eq!(get_delegatee(&200).available_to_bond(), 0);
+			assert_eq!(get_delegatee(&200).ledger.effective_balance(), 100);
 
 			// free balance of delegate is untouched
 			assert_eq!(Balances::free_balance(200), balance_200);
@@ -428,30 +428,30 @@ mod staking_integration {
 	}
 
 	#[test]
-	fn delegate_restrictions() {
+	fn delegatee_restrictions() {
 		ExtBuilder::default().build_and_execute(|| {
 			setup_delegation_stake(200, 201, (202..203).collect(), 100, 0);
 
 			// Registering again is noop
 			assert_noop!(
-				DelegatedStaking::register_as_delegate(RawOrigin::Signed(200).into(), 201),
+				DelegatedStaking::register_as_delegatee(RawOrigin::Signed(200).into(), 201),
 				Error::<T>::NotAllowed
 			);
 			// a delegator cannot become delegate
 			assert_noop!(
-				DelegatedStaking::register_as_delegate(RawOrigin::Signed(202).into(), 203),
+				DelegatedStaking::register_as_delegatee(RawOrigin::Signed(202).into(), 203),
 				Error::<T>::NotAllowed
 			);
 			// existing staker cannot become a delegate
 			assert_noop!(
-				DelegatedStaking::register_as_delegate(
+				DelegatedStaking::register_as_delegatee(
 					RawOrigin::Signed(GENESIS_NOMINATOR_ONE).into(),
 					201
 				),
 				Error::<T>::AlreadyStaker
 			);
 			assert_noop!(
-				DelegatedStaking::register_as_delegate(
+				DelegatedStaking::register_as_delegatee(
 					RawOrigin::Signed(GENESIS_VALIDATOR).into(),
 					201
 				),
@@ -461,16 +461,16 @@ mod staking_integration {
 	}
 
 	#[test]
-	fn toggle_delegate_status() {
+	fn toggle_delegatee_status() {
 		ExtBuilder::default().build_and_execute(|| {
-			assert_ok!(DelegatedStaking::register_as_delegate(RawOrigin::Signed(200).into(), 201));
+			assert_ok!(DelegatedStaking::register_as_delegatee(RawOrigin::Signed(200).into(), 201));
 
 			// delegation works
 			fund(&300, 1000);
 			assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(300).into(), 200, 100));
 
 			// delegate blocks delegation
-			assert_ok!(DelegatedStaking::toggle_delegate_status(RawOrigin::Signed(200).into()));
+			assert_ok!(DelegatedStaking::toggle_delegatee_status(RawOrigin::Signed(200).into()));
 
 			// cannot delegate to it anymore
 			assert_noop!(
@@ -479,7 +479,7 @@ mod staking_integration {
 			);
 
 			// delegate can unblock delegation
-			assert_ok!(DelegatedStaking::toggle_delegate_status(RawOrigin::Signed(200).into()));
+			assert_ok!(DelegatedStaking::toggle_delegatee_status(RawOrigin::Signed(200).into()));
 
 			// delegation works again
 			assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(300).into(), 200, 100));
@@ -520,7 +520,7 @@ mod staking_integration {
 			// with at least ED.
 			let proxy_delegator = DelegatedStaking::sub_account(AccountType::ProxyDelegator, 200);
 
-			assert_ok!(DelegatedStaking::migrate_to_delegate(RawOrigin::Signed(200).into(), 201));
+			assert_ok!(DelegatedStaking::migrate_to_delegatee(RawOrigin::Signed(200).into(), 201));
 
 			// verify all went well
 			let mut expected_proxy_delegated_amount = staked_amount;
@@ -534,8 +534,8 @@ mod staking_integration {
 				5000 - staked_amount - ExistentialDeposit::get()
 			);
 			assert_eq!(DelegatedStaking::stake(&200).unwrap(), init_stake);
-			assert_eq!(get_delegate(&200).ledger.effective_balance(), 4000);
-			assert_eq!(get_delegate(&200).available_to_bond(), 0);
+			assert_eq!(get_delegatee(&200).ledger.effective_balance(), 4000);
+			assert_eq!(get_delegatee(&200).available_to_bond(), 0);
 
 			// now lets migrate the delegators
 			let delegator_share = staked_amount / 4;
@@ -561,8 +561,8 @@ mod staking_integration {
 
 				// delegate stake is unchanged.
 				assert_eq!(DelegatedStaking::stake(&200).unwrap(), init_stake);
-				assert_eq!(get_delegate(&200).ledger.effective_balance(), 4000);
-				assert_eq!(get_delegate(&200).available_to_bond(), 0);
+				assert_eq!(get_delegatee(&200).ledger.effective_balance(), 4000);
+				assert_eq!(get_delegatee(&200).available_to_bond(), 0);
 			}
 
 			// cannot use migrate delegator anymore
@@ -602,12 +602,12 @@ mod pool_integration {
 			assert_eq!(held_balance(&creator), delegate_amount);
 
 			let pool_account = Pools::create_bonded_account(1);
-			let delegate = get_delegate(&pool_account);
+			let delegatee = get_delegatee(&pool_account);
 
 			// verify state
-			assert_eq!(delegate.ledger.effective_balance(), delegate_amount);
-			assert_eq!(delegate.available_to_bond(), 0);
-			assert_eq!(delegate.total_unbonded(), 0);
+			assert_eq!(delegatee.ledger.effective_balance(), delegate_amount);
+			assert_eq!(delegatee.available_to_bond(), 0);
+			assert_eq!(delegatee.total_unbonded(), 0);
 		});
 	}
 
@@ -635,12 +635,12 @@ mod pool_integration {
 			// delegator is not actively exposed to core staking.
 			assert_eq!(Staking::status(&delegator), Err(StakingError::<T>::NotStash.into()));
 
-			let pool_delegate = get_delegate(&Pools::create_bonded_account(1));
+			let pool_delegatee = get_delegatee(&Pools::create_bonded_account(1));
 			// verify state
-			assert_eq!(pool_delegate.ledger.effective_balance(), staked_amount);
-			assert_eq!(pool_delegate.bonded_stake(), staked_amount);
-			assert_eq!(pool_delegate.available_to_bond(), 0);
-			assert_eq!(pool_delegate.total_unbonded(), 0);
+			assert_eq!(pool_delegatee.ledger.effective_balance(), staked_amount);
+			assert_eq!(pool_delegatee.bonded_stake(), staked_amount);
+			assert_eq!(pool_delegatee.available_to_bond(), 0);
+			assert_eq!(pool_delegatee.total_unbonded(), 0);
 
 			// let a bunch of delegators join this pool
 			for i in 301..350 {
@@ -650,11 +650,11 @@ mod pool_integration {
 				assert_eq!(held_balance(&i), 100 + i);
 			}
 
-			let pool_delegate = pool_delegate.refresh().unwrap();
-			assert_eq!(pool_delegate.ledger.effective_balance(), staked_amount);
-			assert_eq!(pool_delegate.bonded_stake(), staked_amount);
-			assert_eq!(pool_delegate.available_to_bond(), 0);
-			assert_eq!(pool_delegate.total_unbonded(), 0);
+			let pool_delegatee = pool_delegatee.refresh().unwrap();
+			assert_eq!(pool_delegatee.ledger.effective_balance(), staked_amount);
+			assert_eq!(pool_delegatee.bonded_stake(), staked_amount);
+			assert_eq!(pool_delegatee.available_to_bond(), 0);
+			assert_eq!(pool_delegatee.total_unbonded(), 0);
 		});
 	}
 
@@ -664,7 +664,7 @@ mod pool_integration {
 			let pool_id = create_pool(100, 200);
 			add_delegators_to_pool(pool_id, (300..310).collect(), 100);
 			let mut staked_amount = 200 + 100 * 10;
-			assert_eq!(get_pool_delegate(pool_id).bonded_stake(), staked_amount);
+			assert_eq!(get_pool_delegatee(pool_id).bonded_stake(), staked_amount);
 
 			// bond extra to pool
 			for i in 300..310 {
@@ -673,7 +673,7 @@ mod pool_integration {
 					BondExtra::FreeBalance(50)
 				));
 				staked_amount += 50;
-				assert_eq!(get_pool_delegate(pool_id).bonded_stake(), staked_amount);
+				assert_eq!(get_pool_delegatee(pool_id).bonded_stake(), staked_amount);
 			}
 		});
 	}
@@ -770,7 +770,7 @@ mod pool_integration {
 			assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(301).into(), 301, 0));
 			assert_eq!(
 				events_since_last_call(),
-				vec![Event::Released { delegate: pool_acc, delegator: 301, amount: 50 }]
+				vec![Event::Released { delegatee: pool_acc, delegator: 301, amount: 50 }]
 			);
 			assert_eq!(
 				pool_events_since_last_call(),
@@ -787,8 +787,8 @@ mod pool_integration {
 			assert_eq!(
 				events_since_last_call(),
 				vec![
-					Event::Released { delegate: pool_acc, delegator: 302, amount: 100 },
-					Event::Released { delegate: pool_acc, delegator: 303, amount: 200 },
+					Event::Released { delegatee: pool_acc, delegator: 302, amount: 100 },
+					Event::Released { delegatee: pool_acc, delegator: 303, amount: 200 },
 				]
 			);
 			assert_eq!(
@@ -828,17 +828,17 @@ mod pool_integration {
 			start_era(5);
 			// withdraw pool should withdraw 1000 tokens
 			assert_ok!(Pools::pool_withdraw_unbonded(RawOrigin::Signed(100).into(), pool_id, 0));
-			assert_eq!(get_pool_delegate(pool_id).total_unbonded(), 1000);
+			assert_eq!(get_pool_delegatee(pool_id).total_unbonded(), 1000);
 
 			start_era(6);
 			// should withdraw 500 more
 			assert_ok!(Pools::pool_withdraw_unbonded(RawOrigin::Signed(100).into(), pool_id, 0));
-			assert_eq!(get_pool_delegate(pool_id).total_unbonded(), 1000 + 500);
+			assert_eq!(get_pool_delegatee(pool_id).total_unbonded(), 1000 + 500);
 
 			start_era(7);
 			// Nothing to withdraw, still at 1500.
 			assert_ok!(Pools::pool_withdraw_unbonded(RawOrigin::Signed(100).into(), pool_id, 0));
-			assert_eq!(get_pool_delegate(pool_id).total_unbonded(), 1500);
+			assert_eq!(get_pool_delegatee(pool_id).total_unbonded(), 1500);
 		});
 	}
 
@@ -979,12 +979,12 @@ mod pool_integration {
 				assert_eq!(held_balance(&i), delegator_stake);
 			}
 			assert_eq!(
-				get_pool_delegate(pool_id).ledger.effective_balance(),
+				get_pool_delegatee(pool_id).ledger.effective_balance(),
 				Staking::total_stake(&pool_acc).unwrap()
 			);
 
 			// pending slash is book kept.
-			assert_eq!(get_pool_delegate(pool_id).ledger.pending_slash, 500);
+			assert_eq!(get_pool_delegatee(pool_id).ledger.pending_slash, 500);
 
 			// go in some distant future era.
 			start_era(10);
@@ -994,23 +994,23 @@ mod pool_integration {
 			assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(300).into(), 300, 1));
 			assert_eq!(
 				events_since_last_call(),
-				vec![Event::Released { delegate: pool_acc, delegator: 300, amount: 100 }]
+				vec![Event::Released { delegatee: pool_acc, delegator: 300, amount: 100 }]
 			);
-			assert_eq!(get_pool_delegate(pool_id).ledger.pending_slash, 500);
+			assert_eq!(get_pool_delegatee(pool_id).ledger.pending_slash, 500);
 
 			// withdraw the other two delegators (301 and 302) who were unbonding.
 			for i in 301..=302 {
 				let pre_balance = Balances::free_balance(i);
-				let pre_pending_slash = get_pool_delegate(pool_id).ledger.pending_slash;
+				let pre_pending_slash = get_pool_delegatee(pool_id).ledger.pending_slash;
 				assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(i).into(), i, 0));
 				assert_eq!(
 					events_since_last_call(),
 					vec![
-						Event::Slashed { delegate: pool_acc, delegator: i, amount: 50 },
-						Event::Released { delegate: pool_acc, delegator: i, amount: 50 },
+						Event::Slashed { delegatee: pool_acc, delegator: i, amount: 50 },
+						Event::Released { delegatee: pool_acc, delegator: i, amount: 50 },
 					]
 				);
-				assert_eq!(get_pool_delegate(pool_id).ledger.pending_slash, pre_pending_slash - 50);
+				assert_eq!(get_pool_delegatee(pool_id).ledger.pending_slash, pre_pending_slash - 50);
 				assert_eq!(held_balance(&i), 0);
 				assert_eq!(Balances::free_balance(i) - pre_balance, 50);
 			}
@@ -1021,11 +1021,11 @@ mod pool_integration {
 			fund(&slash_reporter, 100);
 
 			for i in 303..306 {
-				let pre_pending_slash = get_pool_delegate(pool_id).ledger.pending_slash;
+				let pre_pending_slash = get_pool_delegatee(pool_id).ledger.pending_slash;
 				assert_ok!(Pools::apply_slash(RawOrigin::Signed(slash_reporter).into(), i));
 
 				// each member is slashed 50% of 100 = 50.
-				assert_eq!(get_pool_delegate(pool_id).ledger.pending_slash, pre_pending_slash - 50);
+				assert_eq!(get_pool_delegatee(pool_id).ledger.pending_slash, pre_pending_slash - 50);
 				// left with 50.
 				assert_eq!(held_balance(&i), 50);
 			}
@@ -1034,7 +1034,7 @@ mod pool_integration {
 			// slash creator
 			assert_ok!(Pools::apply_slash(RawOrigin::Signed(slash_reporter).into(), creator));
 			// all slash should be applied now.
-			assert_eq!(get_pool_delegate(pool_id).ledger.pending_slash, 0);
+			assert_eq!(get_pool_delegatee(pool_id).ledger.pending_slash, 0);
 			// for creator, 50% of stake should be slashed (250), 10% of which should go to reporter
 			// (25).
 			assert_eq!(Balances::free_balance(slash_reporter), 115 + 25);
@@ -1061,7 +1061,7 @@ mod pool_integration {
 		}
 	}
 
-	fn get_pool_delegate(pool_id: u32) -> Delegate<T> {
-		get_delegate(&Pools::create_bonded_account(pool_id))
+	fn get_pool_delegatee(pool_id: u32) -> Delegatee<T> {
+		get_delegatee(&Pools::create_bonded_account(pool_id))
 	}
 }
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index add4ae21847ed..698a30b6b2588 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -24,9 +24,9 @@ use frame_support::traits::DefensiveSaturating;
 /// The type of pot account being created.
 #[derive(Encode, Decode)]
 pub(crate) enum AccountType {
-	/// A proxy delegator account created for a nominator who migrated to a `delegate` account.
+	/// A proxy delegator account created for a nominator who migrated to a `delegatee` account.
 	///
-	/// Funds for unmigrated `delegator` accounts of the `delegate` are kept here.
+	/// Funds for unmigrated `delegator` accounts of the `delegatee` are kept here.
 	ProxyDelegator,
 }
 
@@ -35,7 +35,7 @@ pub(crate) enum AccountType {
 #[scale_info(skip_type_params(T))]
 pub struct Delegation<T: Config> {
 	/// The target of delegation.
-	pub delegate: T::AccountId,
+	pub delegatee: T::AccountId,
 	/// The amount delegated.
 	pub amount: BalanceOf<T>,
 }
@@ -45,15 +45,15 @@ impl<T: Config> Delegation<T> {
 		<Delegators<T>>::get(delegator)
 	}
 
-	pub(crate) fn from(delegate: &T::AccountId, amount: BalanceOf<T>) -> Self {
-		Delegation { delegate: delegate.clone(), amount }
+	pub(crate) fn from(delegatee: &T::AccountId, amount: BalanceOf<T>) -> Self {
+		Delegation { delegatee: delegatee.clone(), amount }
 	}
 
-	pub(crate) fn can_delegate(delegator: &T::AccountId, delegate: &T::AccountId) -> bool {
+	pub(crate) fn can_delegate(delegator: &T::AccountId, delegatee: &T::AccountId) -> bool {
 		Delegation::<T>::get(delegator)
-			.map(|delegation| delegation.delegate == delegate.clone())
+			.map(|delegation| delegation.delegatee == delegatee.clone())
 			.unwrap_or(
-				// all good if its a new delegator expect it should not am existing delegate.
+				// all good if its a new delegator except it should not be an existing delegatee.
 				!<Delegates<T>>::contains_key(delegator),
 			)
 	}
@@ -61,14 +61,14 @@ impl<T: Config> Delegation<T> {
 	/// Checked decrease of delegation amount. Consumes self and returns a new copy.
 	pub(crate) fn decrease_delegation(self, amount: BalanceOf<T>) -> Option<Self> {
 		let updated_delegation = self.amount.checked_sub(&amount)?;
-		Some(Delegation::from(&self.delegate, updated_delegation))
+		Some(Delegation::from(&self.delegatee, updated_delegation))
 	}
 
 	/// Checked increase of delegation amount. Consumes self and returns a new copy.
 	#[allow(unused)]
 	pub(crate) fn increase_delegation(self, amount: BalanceOf<T>) -> Option<Self> {
 		let updated_delegation = self.amount.checked_add(&amount)?;
-		Some(Delegation::from(&self.delegate, updated_delegation))
+		Some(Delegation::from(&self.delegatee, updated_delegation))
 	}
 
 	pub(crate) fn save(self, key: &T::AccountId) {
@@ -84,8 +84,8 @@ impl<T: Config> Delegation<T> {
 
 /// Ledger of all delegations to a `Delegate`.
 ///
-/// This keeps track of the active balance of the `delegate` that is made up from the funds that are
-/// currently delegated to this `delegate`. It also tracks the pending slashes yet to be applied
+/// This keeps track of the active balance of the `delegatee` that is made up from the funds that are
+/// currently delegated to this `delegatee`. It also tracks the pending slashes yet to be applied
 /// among other things.
 // FIXME(ank4n): Break up into two storage items - bookkeeping stuff and settings stuff.
 #[derive(Default, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
@@ -93,7 +93,7 @@ impl<T: Config> Delegation<T> {
 pub struct DelegationLedger<T: Config> {
 	/// Where the reward should be paid out.
 	pub payee: T::AccountId,
-	/// Sum of all delegated funds to this `delegate`.
+	/// Sum of all delegated funds to this `delegatee`.
 	#[codec(compact)]
 	pub total_delegated: BalanceOf<T>,
 	/// Funds that are withdrawn from core staking but not released to delegator/s. It is a subset
@@ -104,7 +104,7 @@ pub struct DelegationLedger<T: Config> {
 	/// Slashes that are not yet applied.
 	#[codec(compact)]
 	pub pending_slash: BalanceOf<T>,
-	/// Whether this `delegate` is blocked from receiving new delegations.
+	/// Whether this `delegatee` is blocked from receiving new delegations.
 	pub blocked: bool,
 }
 
@@ -123,8 +123,8 @@ impl<T: Config> DelegationLedger<T> {
 		<Delegates<T>>::get(key)
 	}
 
-	pub(crate) fn can_accept_delegation(delegate: &T::AccountId) -> bool {
-		DelegationLedger::<T>::get(delegate)
+	pub(crate) fn can_accept_delegation(delegatee: &T::AccountId) -> bool {
+		DelegationLedger::<T>::get(delegatee)
 			.map(|ledger| !ledger.blocked)
 			.unwrap_or(false)
 	}
@@ -133,7 +133,7 @@ impl<T: Config> DelegationLedger<T> {
 		<Delegates<T>>::insert(key, self)
 	}
 
-	/// Effective total balance of the `delegate`.
+	/// Effective total balance of the `delegatee`.
 	pub(crate) fn effective_balance(&self) -> BalanceOf<T> {
 		defensive_assert!(
 			self.total_delegated >= self.pending_slash,
@@ -152,15 +152,15 @@ impl<T: Config> DelegationLedger<T> {
 
 /// Wrapper around `DelegationLedger` to provide additional functionality.
 #[derive(Clone)]
-pub struct Delegate<T: Config> {
+pub struct Delegatee<T: Config> {
 	pub key: T::AccountId,
 	pub ledger: DelegationLedger<T>,
 }
 
-impl<T: Config> Delegate<T> {
-	pub(crate) fn from(delegate: &T::AccountId) -> Result<Delegate<T>, DispatchError> {
-		let ledger = DelegationLedger::<T>::get(delegate).ok_or(Error::<T>::NotDelegate)?;
-		Ok(Delegate { key: delegate.clone(), ledger })
+impl<T: Config> Delegatee<T> {
+	pub(crate) fn from(delegatee: &T::AccountId) -> Result<Delegatee<T>, DispatchError> {
+		let ledger = DelegationLedger::<T>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
+		Ok(Delegatee { key: delegatee.clone(), ledger })
 	}
 
 	/// Remove funds that are withdrawn from [Config::CoreStaking] but not claimed by a delegator.
@@ -182,7 +182,7 @@ impl<T: Config> Delegate<T> {
 			.checked_sub(&amount)
 			.defensive_ok_or(ArithmeticError::Overflow)?;
 
-		Ok(Delegate {
+		Ok(Delegatee {
 			ledger: DelegationLedger {
 				total_delegated: new_total_delegated,
 				unclaimed_withdrawals: new_unclaimed_withdrawals,
@@ -203,7 +203,7 @@ impl<T: Config> Delegate<T> {
 			.checked_add(&amount)
 			.defensive_ok_or(ArithmeticError::Overflow)?;
 
-		Ok(Delegate {
+		Ok(Delegatee {
 			ledger: DelegationLedger {
 				unclaimed_withdrawals: new_unclaimed_withdrawals,
 				..self.ledger
@@ -214,7 +214,7 @@ impl<T: Config> Delegate<T> {
 
 	/// Reloads self from storage.
 	#[allow(unused)]
-	pub(crate) fn refresh(&self) -> Result<Delegate<T>, DispatchError> {
+	pub(crate) fn refresh(&self) -> Result<Delegatee<T>, DispatchError> {
 		Self::from(&self.key)
 	}
 
@@ -249,7 +249,7 @@ impl<T: Config> Delegate<T> {
 		let pending_slash = self.ledger.pending_slash.defensive_saturating_sub(amount);
 		let total_delegated = self.ledger.total_delegated.defensive_saturating_sub(amount);
 
-		Delegate {
+		Delegatee {
 			ledger: DelegationLedger { pending_slash, total_delegated, ..self.ledger },
 			..self
 		}
@@ -268,7 +268,7 @@ impl<T: Config> Delegate<T> {
 	}
 
 	pub(crate) fn update_status(self, block: bool) -> Self {
-		Delegate { ledger: DelegationLedger { blocked: block, ..self.ledger }, ..self }
+		Delegatee { ledger: DelegationLedger { blocked: block, ..self.ledger }, ..self }
 	}
 
 	pub(crate) fn save(self) {
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 33387817b95c0..28dcec8d11f22 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1107,7 +1107,7 @@ impl<T: Config> Pallet<T> {
 	}
 
 	pub(crate) fn stakeable_balance(who: &T::AccountId) -> BalanceOf<T> {
-		if T::DelegationSupport::is_delegate(who) {
+		if T::DelegationSupport::is_delegatee(who) {
 			return T::DelegationSupport::stakeable_balance(who);
 		}
 
@@ -1118,7 +1118,7 @@ impl<T: Config> Pallet<T> {
 		who: &T::AccountId,
 		reward_destination: Option<T::AccountId>,
 	) -> bool {
-		if T::DelegationSupport::is_delegate(who) {
+		if T::DelegationSupport::is_delegatee(who) {
 			return T::DelegationSupport::restrict_reward_destination(who, reward_destination);
 		}
 
@@ -1129,8 +1129,8 @@ impl<T: Config> Pallet<T> {
 		who: &T::AccountId,
 		amount: BalanceOf<T>,
 	) -> sp_runtime::DispatchResult {
-		// only apply lock if it is not a delegate. Delegate accounts are already locked/held.
-		if !T::DelegationSupport::is_delegate(who) {
+		// only apply lock if it is not a delegatee. delegatee accounts are already locked/held.
+		if !T::DelegationSupport::is_delegatee(who) {
 			T::Currency::set_lock(crate::STAKING_ID, who, amount, WithdrawReasons::all());
 		}
 
@@ -1892,12 +1892,12 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		delegatee: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult {
-		Err(DispatchError::Other("delegate is not supported"))
+		Err(DispatchError::Other("delegate_extra is not supported"))
 	}
 
 	/// Withdraw delegation from pool account to self.
 	fn withdraw_delegation(who: &Self::AccountId, delegatee: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
-		Err(DispatchError::Other("delegate is not supported"))
+		Err(DispatchError::Other("withdraw_delegation is not supported"))
 	}
 
 	/// Does the delegatee have any pending slash.
@@ -1907,7 +1907,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	fn delegator_slash(delegatee: &Self::AccountId, delegator: &Self::AccountId, value: Self::Balance, maybe_reporter: Option<Self::AccountId>) -> sp_runtime::DispatchResult {
-		Err(DispatchError::Other("delegate is not supported"))
+		Err(DispatchError::Other("delegator_slash is not supported"))
 	}
 
 	fn delegated_balance(delegator: &Self::AccountId) -> Self::Balance {
@@ -1926,7 +1926,7 @@ impl<T: Config> StakingDelegationSupport for NoDelegation<T> {
 		defensive!("stakeable balance should not have been called for NoDelegation");
 		BalanceOf::<T>::zero()
 	}
-	fn is_delegate(_who: &Self::AccountId) -> bool {
+	fn is_delegatee(_who: &Self::AccountId) -> bool {
 		false
 	}
 	fn report_slash(_who: &Self::AccountId, _slash: Self::Balance) {
diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs
index 00cdf64f5d4a2..dcc9b9fe440b7 100644
--- a/substrate/frame/staking/src/slashing.rs
+++ b/substrate/frame/staking/src/slashing.rs
@@ -608,7 +608,7 @@ pub fn do_slash<T: Config>(
 			Err(_) => return, // nothing to do.
 		};
 
-	let lazy_slash = T::DelegationSupport::is_delegate(stash);
+	let lazy_slash = T::DelegationSupport::is_delegatee(stash);
 	let value = ledger.slash(value, T::Currency::minimum_balance(), slash_era);
 
 	if value.is_zero() {
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 0f18f32f3ccca..e7bfb55a27e49 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -49,8 +49,8 @@ pub trait StakingDelegationSupport {
 	}
 
 	/// Returns true if `who` accepts delegations for stake.
-	fn is_delegate(who: &Self::AccountId) -> bool;
+	fn is_delegatee(who: &Self::AccountId) -> bool;
 
-	/// Reports an ongoing slash to the `delegate` account that would be applied lazily.
+	/// Reports an ongoing slash to the `delegatee` account that would be applied lazily.
 	fn report_slash(who: &Self::AccountId, slash: Self::Balance);
 }
\ No newline at end of file

From b68bb9d848689eb2977562f7da2345208fbcb124 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Tue, 27 Feb 2024 03:19:03 +0100
Subject: [PATCH 175/202] fmt

---
 .../frame/delegated-staking/src/impls.rs      | 22 +++++++++++++++----
 substrate/frame/delegated-staking/src/lib.rs  | 17 ++++++++------
 .../frame/delegated-staking/src/tests.rs      | 10 +++++++--
 .../frame/delegated-staking/src/types.rs      |  6 ++---
 substrate/frame/nomination-pools/src/lib.rs   |  7 ++++--
 substrate/frame/nomination-pools/src/mock.rs  | 21 ++++++++++++++----
 substrate/frame/staking/src/pallet/impls.rs   | 20 ++++++++++++++---
 .../primitives/staking/src/delegation.rs      |  2 +-
 substrate/primitives/staking/src/lib.rs       | 21 ++++++++++++++----
 9 files changed, 96 insertions(+), 30 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 585378e9c74e8..e2d4fe99f1c77 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -206,7 +206,12 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	/// Delegate funds to `Delegatee`.
-	fn delegate(who: &Self::AccountId, delegatee: &Self::AccountId, reward_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+	fn delegate(
+		who: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		reward_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
 		Pallet::<T>::register_as_delegatee(
 			RawOrigin::Signed(delegatee.clone()).into(),
 			reward_account.clone(),
@@ -234,7 +239,11 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	/// Withdraw delegation from pool account to self.
-	fn withdraw_delegation(who: &Self::AccountId, delegatee: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+	fn withdraw_delegation(
+		who: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
 		// fixme(ank4n): This should not require slashing spans.
 		Pallet::<T>::release(RawOrigin::Signed(delegatee.clone()).into(), who.clone(), amount, 0)
 	}
@@ -246,7 +255,12 @@ impl<T: Config> StakingInterface for Pallet<T> {
 			.unwrap_or(false)
 	}
 
-	fn delegator_slash(delegatee: &Self::AccountId, delegator: &Self::AccountId, value: Self::Balance, maybe_reporter: Option<Self::AccountId>) -> sp_runtime::DispatchResult {
+	fn delegator_slash(
+		delegatee: &Self::AccountId,
+		delegator: &Self::AccountId,
+		value: Self::Balance,
+		maybe_reporter: Option<Self::AccountId>,
+	) -> sp_runtime::DispatchResult {
 		Pallet::<T>::do_slash(delegatee.clone(), delegator.clone(), value, maybe_reporter)
 	}
 
@@ -302,4 +316,4 @@ impl<T: Config> StakingDelegationSupport for Pallet<T> {
 			},
 		});
 	}
-}
\ No newline at end of file
+}
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 8890b2f261d01..e86792d35e54a 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -55,11 +55,11 @@
 //!
 //! #### Dispatchable Calls
 //! The pallet exposes the following [`Call`]s:
-//! - `register_as_delegatee`: Register an account to be a `delegatee`. Once an account is registered
-//! 	as a `delegatee`, for staking operations, only its delegated funds are used. This means it
-//! 	cannot use its own free balance to stake.
+//! - `register_as_delegatee`: Register an account to be a `delegatee`. Once an account is
+//!   registered as a `delegatee`, for staking operations, only its delegated funds are used. This
+//!   means it cannot use its own free balance to stake.
 //! - `migrate_to_delegate`: This allows a `Nominator` account to become a `delegatee` account.
-//! 	Explained in more detail in the `Migration` section.
+//!   Explained in more detail in the `Migration` section.
 //! - `release`: Release funds to `delegator` from `unclaimed_withdrawals` register of the
 //!   `delegatee`.
 //! - `migrate_delegation`: Migrate delegated funds from one account to another. This is useful for
@@ -512,7 +512,10 @@ impl<T: Config> Pallet<T> {
 		frame_system::Pallet::<T>::inc_providers(who);
 	}
 
-	fn do_migrate_to_delegatee(who: &T::AccountId, reward_account: &T::AccountId) -> DispatchResult {
+	fn do_migrate_to_delegatee(
+		who: &T::AccountId,
+		reward_account: &T::AccountId,
+	) -> DispatchResult {
 		// We create a proxy delegator that will keep all the delegation funds until funds are
 		// transferred to actual delegator.
 		let proxy_delegator = Self::sub_account(AccountType::ProxyDelegator, who.clone());
@@ -626,7 +629,6 @@ impl<T: Config> Pallet<T> {
 		// remove delegator if nothing delegated anymore
 		delegation.save(delegator);
 
-
 		let released = T::Currency::release(
 			&HoldReason::Delegating.into(),
 			&delegator,
@@ -687,7 +689,8 @@ impl<T: Config> Pallet<T> {
 		// some checks that must have already been checked before.
 		ensure!(source_delegation.amount >= amount, Error::<T>::NotEnoughFunds);
 		debug_assert!(
-			!Self::is_delegator(destination_delegator) && !Self::is_delegatee(destination_delegator)
+			!Self::is_delegator(destination_delegator) &&
+				!Self::is_delegatee(destination_delegator)
 		);
 
 		// update delegations
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 6835424dde727..0f30918caf18e 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -1010,7 +1010,10 @@ mod pool_integration {
 						Event::Released { delegatee: pool_acc, delegator: i, amount: 50 },
 					]
 				);
-				assert_eq!(get_pool_delegatee(pool_id).ledger.pending_slash, pre_pending_slash - 50);
+				assert_eq!(
+					get_pool_delegatee(pool_id).ledger.pending_slash,
+					pre_pending_slash - 50
+				);
 				assert_eq!(held_balance(&i), 0);
 				assert_eq!(Balances::free_balance(i) - pre_balance, 50);
 			}
@@ -1025,7 +1028,10 @@ mod pool_integration {
 				assert_ok!(Pools::apply_slash(RawOrigin::Signed(slash_reporter).into(), i));
 
 				// each member is slashed 50% of 100 = 50.
-				assert_eq!(get_pool_delegatee(pool_id).ledger.pending_slash, pre_pending_slash - 50);
+				assert_eq!(
+					get_pool_delegatee(pool_id).ledger.pending_slash,
+					pre_pending_slash - 50
+				);
 				// left with 50.
 				assert_eq!(held_balance(&i), 50);
 			}
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index 698a30b6b2588..e31d84b6943b5 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -84,9 +84,9 @@ impl<T: Config> Delegation<T> {
 
 /// Ledger of all delegations to a `Delegate`.
 ///
-/// This keeps track of the active balance of the `delegatee` that is made up from the funds that are
-/// currently delegated to this `delegatee`. It also tracks the pending slashes yet to be applied
-/// among other things.
+/// This keeps track of the active balance of the `delegatee` that is made up from the funds that
+/// are currently delegated to this `delegatee`. It also tracks the pending slashes yet to be
+/// applied among other things.
 // FIXME(ank4n): Break up into two storage items - bookkeeping stuff and settings stuff.
 #[derive(Default, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
 #[scale_info(skip_type_params(T))]
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index 10e6fc69a04c5..327b4aa6260bc 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -351,6 +351,7 @@
 
 #![cfg_attr(not(feature = "std"), no_std)]
 
+use adapter::StakeAdapter;
 use codec::Codec;
 use frame_support::{
 	defensive, defensive_assert, ensure,
@@ -375,7 +376,6 @@ use sp_runtime::{
 };
 use sp_staking::{EraIndex, StakingInterface};
 use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, ops::Div, vec::Vec};
-use adapter::StakeAdapter;
 
 #[cfg(any(feature = "try-runtime", feature = "fuzzing", test, debug_assertions))]
 use sp_runtime::TryRuntimeError;
@@ -1655,7 +1655,10 @@ pub mod pallet {
 		type MaxMetadataLen: Get<u32>;
 
 		/// An adapter to support delegated to direct staking.
-		type StakeAdapter: adapter::StakeAdapter<AccountId = Self::AccountId, Balance = BalanceOf<Self>>;
+		type StakeAdapter: adapter::StakeAdapter<
+			AccountId = Self::AccountId,
+			Balance = BalanceOf<Self>,
+		>;
 	}
 
 	/// The sum of funds across all pools.
diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs
index be4c644beea39..7fec33043fbd3 100644
--- a/substrate/frame/nomination-pools/src/mock.rs
+++ b/substrate/frame/nomination-pools/src/mock.rs
@@ -239,7 +239,12 @@ impl sp_staking::StakingInterface for StakingMock {
 	}
 
 	/// Delegate funds to `Delegatee`.
-	fn delegate(who: &Self::AccountId, delegatee: &Self::AccountId, reward_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+	fn delegate(
+		who: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		reward_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
 		unimplemented!("method currently not used in testing")
 	}
 
@@ -253,7 +258,11 @@ impl sp_staking::StakingInterface for StakingMock {
 	}
 
 	/// Withdraw delegation from pool account to self.
-	fn withdraw_delegation(who: &Self::AccountId, delegatee: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+	fn withdraw_delegation(
+		who: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
 		unimplemented!("method currently not used in testing")
 	}
 
@@ -262,14 +271,18 @@ impl sp_staking::StakingInterface for StakingMock {
 		false
 	}
 
-	fn delegator_slash(delegatee: &Self::AccountId, delegator: &Self::AccountId, value: Self::Balance, maybe_reporter: Option<Self::AccountId>) -> sp_runtime::DispatchResult {
+	fn delegator_slash(
+		delegatee: &Self::AccountId,
+		delegator: &Self::AccountId,
+		value: Self::Balance,
+		maybe_reporter: Option<Self::AccountId>,
+	) -> sp_runtime::DispatchResult {
 		unimplemented!("method currently not used in testing")
 	}
 
 	fn delegated_balance(delegator: &Self::AccountId) -> Self::Balance {
 		unimplemented!("method currently not used in testing")
 	}
-
 }
 
 #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 28dcec8d11f22..8fb22fc13f574 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1882,7 +1882,12 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	/// Delegate funds to `Delegatee`.
-	fn delegate(who: &Self::AccountId, delegatee: &Self::AccountId, reward_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+	fn delegate(
+		who: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		reward_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
 		Err(DispatchError::Other("delegate is not supported"))
 	}
 
@@ -1896,7 +1901,11 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	/// Withdraw delegation from pool account to self.
-	fn withdraw_delegation(who: &Self::AccountId, delegatee: &Self::AccountId, amount: Self::Balance) -> DispatchResult {
+	fn withdraw_delegation(
+		who: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult {
 		Err(DispatchError::Other("withdraw_delegation is not supported"))
 	}
 
@@ -1906,7 +1915,12 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		false
 	}
 
-	fn delegator_slash(delegatee: &Self::AccountId, delegator: &Self::AccountId, value: Self::Balance, maybe_reporter: Option<Self::AccountId>) -> sp_runtime::DispatchResult {
+	fn delegator_slash(
+		delegatee: &Self::AccountId,
+		delegator: &Self::AccountId,
+		value: Self::Balance,
+		maybe_reporter: Option<Self::AccountId>,
+	) -> sp_runtime::DispatchResult {
 		Err(DispatchError::Other("delegator_slash is not supported"))
 	}
 
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index e7bfb55a27e49..d7b8fc1e12461 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -53,4 +53,4 @@ pub trait StakingDelegationSupport {
 
 	/// Reports an ongoing slash to the `delegatee` account that would be applied lazily.
 	fn report_slash(who: &Self::AccountId, slash: Self::Balance);
-}
\ No newline at end of file
+}
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 0e1384442106f..0ed417155f054 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -319,7 +319,12 @@ pub trait StakingInterface {
 	fn delegatee_balance(who: &Self::AccountId) -> Self::Balance;
 
 	/// Delegate funds to `Delegatee`.
-	fn delegate(who: &Self::AccountId, delegatee: &Self::AccountId, reward_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult;
+	fn delegate(
+		who: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		reward_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
 
 	/// Add more delegation to the pool account.
 	fn delegate_extra(
@@ -329,15 +334,23 @@ pub trait StakingInterface {
 	) -> DispatchResult;
 
 	/// Withdraw delegation from pool account to self.
-	fn withdraw_delegation(who: &Self::AccountId, delegatee: &Self::AccountId, amount: Self::Balance) -> DispatchResult;
+	fn withdraw_delegation(
+		who: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
 
 	/// Does the delegatee have any pending slash.
 	fn has_pending_slash(delegatee: &Self::AccountId) -> bool;
 
-	fn delegator_slash(delegatee: &Self::AccountId, delegator: &Self::AccountId, value: Self::Balance, maybe_reporter: Option<Self::AccountId>) -> sp_runtime::DispatchResult;
+	fn delegator_slash(
+		delegatee: &Self::AccountId,
+		delegator: &Self::AccountId,
+		value: Self::Balance,
+		maybe_reporter: Option<Self::AccountId>,
+	) -> sp_runtime::DispatchResult;
 
 	fn delegated_balance(delegator: &Self::AccountId) -> Self::Balance;
-
 }
 
 /// The amount of exposure for an era that an individual nominator has (susceptible to slashing).

From a34094995f4abb81f83ea54a4ee95cefe2570370 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Tue, 27 Feb 2024 03:24:58 +0100
Subject: [PATCH 176/202] name changes

---
 .../frame/nomination-pools/src/adapter.rs     | 22 +++++++++----------
 substrate/frame/nomination-pools/src/lib.rs   |  6 ++---
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index 0bf042fd47e79..5b098e20ad1cd 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -33,22 +33,22 @@ pub trait StakeAdapter {
 	fn total_balance(who: &Self::AccountId) -> Self::Balance;
 
 	/// Bond delegator via the pool account.
-	fn bond(
+	fn delegator_bond(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		reward_account: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult;
 
-	/// Add more bond via the pool account.
-	fn bond_extra(
+	/// Add more bond for delegator via the pool account.
+	fn delegator_bond_extra(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult;
 
-	/// Claim withdrawn amount in the pool account.
-	fn claim_withdraw(
+	/// Withdrawn amount from pool to delegator.
+	fn delegator_withdraw(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
@@ -77,7 +77,7 @@ impl<T: Config> StakeAdapter for TransferStake<T> {
 		T::Currency::total_balance(who)
 	}
 
-	fn bond(
+	fn delegator_bond(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		reward_account: &Self::AccountId,
@@ -87,7 +87,7 @@ impl<T: Config> StakeAdapter for TransferStake<T> {
 		T::Staking::bond(pool_account, amount, reward_account)
 	}
 
-	fn bond_extra(
+	fn delegator_bond_extra(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
@@ -96,7 +96,7 @@ impl<T: Config> StakeAdapter for TransferStake<T> {
 		T::Staking::bond_extra(pool_account, amount)
 	}
 
-	fn claim_withdraw(
+	fn delegator_withdraw(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
@@ -135,7 +135,7 @@ impl<T: Config> StakeAdapter for DelegationStake<T> {
 		T::Currency::total_balance(who)
 	}
 
-	fn bond(
+	fn delegator_bond(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		reward_account: &Self::AccountId,
@@ -145,7 +145,7 @@ impl<T: Config> StakeAdapter for DelegationStake<T> {
 		T::Staking::delegate(who, pool_account, reward_account, amount)
 	}
 
-	fn bond_extra(
+	fn delegator_bond_extra(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
@@ -153,7 +153,7 @@ impl<T: Config> StakeAdapter for DelegationStake<T> {
 		T::Staking::delegate_extra(who, pool_account, amount)
 	}
 
-	fn claim_withdraw(
+	fn delegator_withdraw(
 		who: &Self::AccountId,
 		pool_account: &Self::AccountId,
 		amount: Self::Balance,
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index 327b4aa6260bc..f76a1fb9ed3ae 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -1265,11 +1265,11 @@ impl<T: Config> BondedPool<T> {
 
 		match ty {
 			BondType::Create =>
-				T::StakeAdapter::bond(who, &bonded_account, &reward_account, amount)?,
+				T::StakeAdapter::delegator_bond(who, &bonded_account, &reward_account, amount)?,
 			// The pool should always be created in such a way its in a state to bond extra, but if
 			// the active balance is slashed below the minimum bonded or the account cannot be
 			// found, we exit early.
-			BondType::Later => T::StakeAdapter::bond_extra(who, &bonded_account, amount)?,
+			BondType::Later => T::StakeAdapter::delegator_bond_extra(who, &bonded_account, amount)?,
 		}
 		TotalValueLocked::<T>::mutate(|tvl| {
 			tvl.saturating_accrue(amount);
@@ -2303,7 +2303,7 @@ pub mod pallet {
 				// order to ensure members can leave the pool and it can be destroyed.
 				.min(bonded_pool.transferable_balance());
 
-			T::StakeAdapter::claim_withdraw(
+			T::StakeAdapter::delegator_withdraw(
 				&member_account,
 				&bonded_pool.bonded_account(),
 				balance_to_unbond,

From de8f87542aa417a8d5369392ffdd2cf696b0f3d0 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Tue, 27 Feb 2024 16:29:21 +0100
Subject: [PATCH 177/202] doc update

---
 .../frame/delegated-staking/src/impls.rs      |  4 +--
 substrate/frame/delegated-staking/src/lib.rs  |  4 +--
 substrate/frame/delegated-staking/src/mock.rs |  4 +--
 .../frame/delegated-staking/src/tests.rs      |  2 +-
 .../frame/nomination-pools/src/adapter.rs     | 19 +++++++-------
 .../nomination-pools/test-staking/src/mock.rs |  2 +-
 substrate/frame/staking/src/mock.rs           |  2 +-
 substrate/frame/staking/src/pallet/impls.rs   | 26 +++++++++----------
 substrate/frame/staking/src/pallet/mod.rs     |  8 +++---
 substrate/frame/staking/src/slashing.rs       |  6 ++---
 .../primitives/staking/src/delegation.rs      | 20 +++++++++-----
 11 files changed, 53 insertions(+), 44 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index e2d4fe99f1c77..028ac34465d57 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -16,7 +16,7 @@
 // You should have received a copy of the GNU General Public License
 // along with this program. If not, see <https://www.gnu.org/licenses/>.
 
-//! Implementations of public traits, namely [StakingInterface], and [StakingDelegationSupport].
+//! Implementations of public traits, namely [StakingInterface], and [DelegateeSupport].
 
 use super::*;
 
@@ -269,7 +269,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 }
 
-impl<T: Config> StakingDelegationSupport for Pallet<T> {
+impl<T: Config> DelegateeSupport for Pallet<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index e86792d35e54a..bb2dac70eb4e6 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -74,7 +74,7 @@
 //! [Config::CoreStaking] to provide delegation based staking. NominationPool can use this pallet as
 //! its Staking provider to support delegation based staking from pool accounts.
 //!
-//! #### [Staking Delegation Support](StakingDelegationSupport)
+//! #### [Staking Delegation Support](DelegateeSupport)
 //! The pallet implements the staking delegation support trait which staking pallet can use to
 //! provide compatibility with this pallet.
 //!
@@ -171,7 +171,7 @@ use sp_runtime::{
 	ArithmeticError, DispatchResult, Perbill, RuntimeDebug, Saturating,
 };
 use sp_staking::{
-	delegation::StakingDelegationSupport, EraIndex, Stake, StakerStatus, StakingInterface,
+	delegation::DelegateeSupport, EraIndex, Stake, StakerStatus, StakingInterface,
 };
 use sp_std::{convert::TryInto, prelude::*};
 
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 56c8cee65d407..756b43316e172 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -34,7 +34,7 @@ use frame_support::dispatch::RawOrigin;
 use pallet_staking::CurrentEra;
 use sp_core::U256;
 use sp_runtime::traits::Convert;
-use sp_staking::{delegation::StakingDelegationSupport, Stake, StakingInterface};
+use sp_staking::{delegation::DelegateeSupport, Stake, StakingInterface};
 
 pub type T = Runtime;
 type Block = frame_system::mocking::MockBlock<Runtime>;
@@ -109,7 +109,7 @@ impl onchain::Config for OnChainSeqPhragmen {
 impl pallet_staking::Config for Runtime {
 	type Currency = Balances;
 	type CurrencyBalance = Balance;
-	type DelegationSupport = DelegatedStaking;
+	type DelegateeSupport = DelegatedStaking;
 	type UnixTime = pallet_timestamp::Pallet<Self>;
 	type CurrencyToVote = ();
 	type RewardRemainder = ();
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 0f30918caf18e..0dfdfd5746505 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -22,7 +22,7 @@ use crate::mock::*;
 use frame_support::{assert_noop, assert_ok, traits::fungible::InspectHold};
 use pallet_nomination_pools::{Error as PoolsError, Event as PoolsEvent};
 use pallet_staking::Error as StakingError;
-use sp_staking::delegation::StakingDelegationSupport;
+use sp_staking::delegation::DelegateeSupport;
 
 #[test]
 fn create_a_delegatee_with_first_delegator() {
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index 5b098e20ad1cd..6f42514493b2b 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -17,11 +17,10 @@
 
 use crate::*;
 
-/// An adapter trait that can support multiple staking strategies: e.g. `Transfer and stake` or
-/// `delegation and stake`.
+/// An adapter trait that can support multiple staking strategies.
 ///
-/// This trait is very specific to nomination pool and meant to make switching between different
-/// staking implementations easier.
+/// Depending on which staking strategy we want to use, the staking logic can be slightly
+/// different. Refer the two possible strategies currently: [`TransferStake`] and [`DelegationStake`].
 pub trait StakeAdapter {
 	type Balance: frame_support::traits::tokens::Balance;
 	type AccountId: Clone + sp_std::fmt::Debug;
@@ -55,9 +54,10 @@ pub trait StakeAdapter {
 	) -> DispatchResult;
 }
 
-/// An adapter implementation that supports transfer based staking
+/// An adapter implementation that supports transfer based staking.
 ///
-/// The funds are transferred to the pool account and then staked via the pool account.
+/// In order to stake, this adapter transfers the funds from the delegator account to the pool
+/// account and stakes directly on [Config::Staking].
 pub struct TransferStake<T: Config>(PhantomData<T>);
 
 impl<T: Config> StakeAdapter for TransferStake<T> {
@@ -107,10 +107,11 @@ impl<T: Config> StakeAdapter for TransferStake<T> {
 	}
 }
 
-/// An adapter implementation that supports delegation based staking
+/// An adapter implementation that supports delegation based staking.
 ///
-/// The funds are delegated from pool account to a delegatee and then staked. The advantage of this
-/// approach is that the funds are held in the delegator account and not in the pool account.
+/// In this approach, first the funds are delegated from delegator to the pool account and later
+/// staked with [Config::Staking]. The advantage of this approach is that the funds are held in the
+/// use account itself and not in the pool account.
 pub struct DelegationStake<T: Config>(PhantomData<T>);
 
 impl<T: Config> StakeAdapter for DelegationStake<T> {
diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs
index c8446a6e077a0..54dfe198c6607 100644
--- a/substrate/frame/nomination-pools/test-staking/src/mock.rs
+++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs
@@ -111,7 +111,7 @@ parameter_types! {
 impl pallet_staking::Config for Runtime {
 	type Currency = Balances;
 	type CurrencyBalance = Balance;
-	type DelegationSupport = pallet_staking::NoDelegation<Self>;
+	type DelegateeSupport = pallet_staking::NoDelegation<Self>;
 	type UnixTime = pallet_timestamp::Pallet<Self>;
 	type CurrencyToVote = ();
 	type RewardRemainder = ();
diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs
index 725e5d753bdcf..44d171a1806c6 100644
--- a/substrate/frame/staking/src/mock.rs
+++ b/substrate/frame/staking/src/mock.rs
@@ -266,7 +266,7 @@ impl OnStakingUpdate<AccountId, Balance> for EventListenerMock {
 impl crate::pallet::pallet::Config for Test {
 	type Currency = Balances;
 	type CurrencyBalance = <Self as pallet_balances::Config>::Balance;
-	type DelegationSupport = pallet_staking::NoDelegation<Self>;
+	type DelegateeSupport = pallet_staking::NoDelegation<Self>;
 	type UnixTime = Timestamp;
 	type CurrencyToVote = ();
 	type RewardRemainder = RewardRemainderMock;
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 8fb22fc13f574..ecddb1b34e67b 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -39,12 +39,12 @@ use sp_runtime::{
 	Perbill, Percent,
 };
 use sp_staking::{
-	currency_to_vote::CurrencyToVote,
-	delegation::StakingDelegationSupport,
-	offence::{DisableStrategy, OffenceDetails, OnOffenceHandler},
-	EraIndex, OnStakingUpdate, Page, SessionIndex, Stake,
-	StakingAccount::{self, Controller, Stash},
-	StakingInterface,
+    currency_to_vote::CurrencyToVote,
+    delegation::DelegateeSupport,
+    offence::{DisableStrategy, OffenceDetails, OnOffenceHandler},
+    EraIndex, OnStakingUpdate, Page, SessionIndex, Stake,
+    StakingAccount::{self, Controller, Stash},
+    StakingInterface,
 };
 use sp_std::prelude::*;
 
@@ -1107,8 +1107,8 @@ impl<T: Config> Pallet<T> {
 	}
 
 	pub(crate) fn stakeable_balance(who: &T::AccountId) -> BalanceOf<T> {
-		if T::DelegationSupport::is_delegatee(who) {
-			return T::DelegationSupport::stakeable_balance(who);
+		if T::DelegateeSupport::is_delegatee(who) {
+			return T::DelegateeSupport::stakeable_balance(who);
 		}
 
 		T::Currency::free_balance(who)
@@ -1118,8 +1118,8 @@ impl<T: Config> Pallet<T> {
 		who: &T::AccountId,
 		reward_destination: Option<T::AccountId>,
 	) -> bool {
-		if T::DelegationSupport::is_delegatee(who) {
-			return T::DelegationSupport::restrict_reward_destination(who, reward_destination);
+		if T::DelegateeSupport::is_delegatee(who) {
+			return T::DelegateeSupport::restrict_reward_destination(who, reward_destination);
 		}
 
 		false
@@ -1130,7 +1130,7 @@ impl<T: Config> Pallet<T> {
 		amount: BalanceOf<T>,
 	) -> sp_runtime::DispatchResult {
 		// only apply lock if it is not a delegatee. delegatee accounts are already locked/held.
-		if !T::DelegationSupport::is_delegatee(who) {
+		if !T::DelegateeSupport::is_delegatee(who) {
 			T::Currency::set_lock(crate::STAKING_ID, who, amount, WithdrawReasons::all());
 		}
 
@@ -1930,10 +1930,10 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 }
 
-/// Standard implementation of `StakingDelegationSupport` that supports only direct staking and no
+/// Standard implementation of `DelegateeSupport` that supports only direct staking and no
 /// delegated staking.
 pub struct NoDelegation<T>(PhantomData<T>);
-impl<T: Config> StakingDelegationSupport for NoDelegation<T> {
+impl<T: Config> DelegateeSupport for NoDelegation<T> {
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 	fn stakeable_balance(_who: &Self::AccountId) -> Self::Balance {
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index 27fdb320b5ba8..861eda3016467 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -37,9 +37,9 @@ use sp_runtime::{
 };
 
 use sp_staking::{
-	delegation::StakingDelegationSupport,
-	EraIndex, Page, SessionIndex,
-	StakingAccount::{self, Controller, Stash},
+    delegation::DelegateeSupport,
+    EraIndex, Page, SessionIndex,
+    StakingAccount::{self, Controller, Stash},
 };
 use sp_std::prelude::*;
 
@@ -106,7 +106,7 @@ pub mod pallet {
 			+ MaxEncodedLen;
 
 		/// Something that provides delegation support to staking pallet.
-		type DelegationSupport: StakingDelegationSupport<
+		type DelegateeSupport: DelegateeSupport<
 			Balance = Self::CurrencyBalance,
 			AccountId = Self::AccountId,
 		>;
diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs
index dcc9b9fe440b7..364dc4215dfcd 100644
--- a/substrate/frame/staking/src/slashing.rs
+++ b/substrate/frame/staking/src/slashing.rs
@@ -64,7 +64,7 @@ use sp_runtime::{
 	traits::{Saturating, Zero},
 	DispatchResult, RuntimeDebug,
 };
-use sp_staking::{delegation::StakingDelegationSupport, offence::DisableStrategy, EraIndex};
+use sp_staking::{delegation::DelegateeSupport, offence::DisableStrategy, EraIndex};
 use sp_std::vec::Vec;
 
 /// The proportion of the slashing reward to be paid out on the first slashing detection.
@@ -608,7 +608,7 @@ pub fn do_slash<T: Config>(
 			Err(_) => return, // nothing to do.
 		};
 
-	let lazy_slash = T::DelegationSupport::is_delegatee(stash);
+	let lazy_slash = T::DelegateeSupport::is_delegatee(stash);
 	let value = ledger.slash(value, T::Currency::minimum_balance(), slash_era);
 
 	if value.is_zero() {
@@ -618,7 +618,7 @@ pub fn do_slash<T: Config>(
 
 	if lazy_slash {
 		// If delegated staking, report slash and move on.
-		T::DelegationSupport::report_slash(stash, value);
+		T::DelegateeSupport::report_slash(stash, value);
 	} else {
 		let (imbalance, missing) = T::Currency::slash(stash, value);
 		slashed_imbalance.subsume(imbalance);
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index d7b8fc1e12461..ede3f77cce8cb 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -20,8 +20,12 @@ use scale_info::TypeInfo;
 use sp_runtime::{DispatchResult, Saturating};
 use sp_std::ops::Sub;
 
-/// Something that provides delegation support to core staking.
-pub trait StakingDelegationSupport {
+/// A trait that can be used as a plugin to support delegation based accounts, called `Delegatee`.
+///
+/// For example, `pallet-staking` which implements `StakingInterface` but does not implement
+/// account delegations out of the box can be provided with a custom implementation of this trait to
+/// learn how to handle these special accounts.
+pub trait DelegateeSupport {
 	/// Balance type used by the staking system.
 	type Balance: Sub<Output = Self::Balance>
 		+ Ord
@@ -36,10 +40,11 @@ pub trait StakingDelegationSupport {
 	/// AccountId type used by the staking system.
 	type AccountId: Clone + sp_std::fmt::Debug;
 
-	/// Balance of who which is available for stake.
-	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance;
+	/// Balance of `delegatee` which is available for stake.
+	fn stakeable_balance(delegatee: &Self::AccountId) -> Self::Balance;
 
-	/// Returns true if provided reward destination is not allowed.
+	/// Returns true if `delegatee` is restricted to update which account they can receive their
+	/// staking rewards.
 	fn restrict_reward_destination(
 		_who: &Self::AccountId,
 		_reward_destination: Option<Self::AccountId>,
@@ -48,9 +53,12 @@ pub trait StakingDelegationSupport {
 		false
 	}
 
-	/// Returns true if `who` accepts delegations for stake.
+	/// Returns true if `who` is a `delegatee` and accepts delegations from other accounts.
 	fn is_delegatee(who: &Self::AccountId) -> bool;
 
 	/// Reports an ongoing slash to the `delegatee` account that would be applied lazily.
+	///
+	/// Slashing a delegatee account is not immediate since the balance is made up of multiple child
+	/// delegators. This function should bookkeep the slash to be applied later.
 	fn report_slash(who: &Self::AccountId, slash: Self::Balance);
 }

From fd27cd5044970153b294852afd7e2e0cfa630a4b Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Tue, 27 Feb 2024 16:55:42 +0100
Subject: [PATCH 178/202] rename to delegatee (missed ones)

---
 substrate/frame/delegated-staking/src/lib.rs | 52 ++++++++++----------
 1 file changed, 26 insertions(+), 26 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index bb2dac70eb4e6..f846292695b9a 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -74,9 +74,9 @@
 //! [Config::CoreStaking] to provide delegation based staking. NominationPool can use this pallet as
 //! its Staking provider to support delegation based staking from pool accounts.
 //!
-//! #### [Staking Delegation Support](DelegateeSupport)
-//! The pallet implements the staking delegation support trait which staking pallet can use to
-//! provide compatibility with this pallet.
+//! #### [Delegatee Support](DelegateeSupport)
+//! Implements `DelegateeSupport` trait which another pallet such as [Config::CoreStaking] can use
+//! to back-support `Delegatees` in their staking implementation.
 //!
 //! ## Lazy Slashing
 //! One of the reasons why direct nominators on staking pallet cannot scale well is because all
@@ -92,7 +92,7 @@
 //! `NominationPool` can apply slash for all its members by calling
 //! [StakingInterface::delegator_slash](sp_staking::StakingInterface::delegator_slash).
 //!
-//! ## Migration from Nominator to Delegate
+//! ## Migration from Nominator to Delegatee
 //! More details [here](https://hackmd.io/@ak0n/np-delegated-staking-migration).
 //!
 //! ## Reward Destination Restrictions
@@ -118,7 +118,7 @@
 //!
 //! #### Nomination Pool with delegation support
 //!  1) delegate fund from delegator to pool account, and
-//!  2) stake from pool account as a `Delegate` account on the staking pallet.
+//!  2) stake from pool account as a `Delegatee` account on the staking pallet.
 //!
 //! The difference being, in the second approach, the delegated funds will be locked in-place in
 //! user's account enabling them to participate in use cases that allows use of `held` funds such
@@ -270,16 +270,16 @@ pub mod pallet {
 	pub(crate) type Delegators<T: Config> =
 		CountedStorageMap<_, Twox64Concat, T::AccountId, Delegation<T>, OptionQuery>;
 
-	/// Map of `Delegate` to their `DelegationLedger`.
+	/// Map of `Delegatee` to their `DelegationLedger`.
 	#[pallet::storage]
 	pub(crate) type Delegates<T: Config> =
 		CountedStorageMap<_, Twox64Concat, T::AccountId, DelegationLedger<T>, OptionQuery>;
 
 	#[pallet::call]
 	impl<T: Config> Pallet<T> {
-		/// Register an account to be a `Delegate`.
+		/// Register an account to be a `Delegatee`.
 		///
-		/// `Delegate` accounts accepts delegations from other `delegator`s and stake funds on their
+		/// `Delegatee` accounts accepts delegations from other `delegator`s and stake funds on their
 		/// behalf.
 		#[pallet::call_index(0)]
 		#[pallet::weight(Weight::default())]
@@ -305,17 +305,17 @@ pub mod pallet {
 			Ok(())
 		}
 
-		/// Migrate from a `Nominator` account to `Delegate` account.
+		/// Migrate from a `Nominator` account to `Delegatee` account.
 		///
 		/// The origin needs to
 		/// - be a `Nominator` with `CoreStaking`,
-		/// - not already a `Delegate`,
+		/// - not already a `Delegatee`,
 		/// - have enough funds to transfer existential deposit to a delegator account created for
 		///   the migration.
 		///
 		/// This operation will create a new delegator account for the origin called
 		/// `proxy_delegator` and transfer the staked amount to it. The `proxy_delegator` delegates
-		/// the funds to the origin making origin a `Delegate` account. The actual `delegator`
+		/// the funds to the origin making origin a `Delegatee` account. The actual `delegator`
 		/// accounts of the origin can later migrate their funds using [Call::migrate_delegation] to
 		/// claim back their share of delegated funds from `proxy_delegator` to self.
 		#[pallet::call_index(1)]
@@ -377,7 +377,7 @@ pub mod pallet {
 			ensure!(!Self::is_delegator(&delegator), Error::<T>::NotAllowed);
 			ensure!(Self::not_direct_staker(&delegator), Error::<T>::AlreadyStaker);
 
-			// ensure delegate is sane.
+			// ensure delegatee is sane.
 			ensure!(Self::is_delegatee(&delegatee), Error::<T>::NotDelegatee);
 
 			// and has enough delegated balance to migrate.
@@ -388,7 +388,7 @@ pub mod pallet {
 			Self::do_migrate_delegation(&proxy_delegator, &delegator, amount)
 		}
 
-		/// Delegate funds to a `Delegate` account and bonds it to [Config::CoreStaking].
+		/// Delegate funds to a `Delegatee` account and bonds it to [Config::CoreStaking].
 		///
 		/// If delegation already exists, it increases the delegation by `amount`.
 		#[pallet::call_index(4)]
@@ -407,7 +407,7 @@ pub mod pallet {
 			ensure!(Delegation::<T>::can_delegate(&who, &delegatee), Error::<T>::InvalidDelegation);
 			ensure!(Self::not_direct_staker(&who), Error::<T>::AlreadyStaker);
 
-			// ensure delegate is sane.
+			// ensure delegatee is sane.
 			ensure!(
 				DelegationLedger::<T>::can_accept_delegation(&delegatee),
 				Error::<T>::NotAcceptingDelegations
@@ -423,9 +423,9 @@ pub mod pallet {
 			Self::do_bond(&delegatee, amount)
 		}
 
-		/// Toggle delegate status to start or stop accepting new delegations.
+		/// Toggle delegatee status to start or stop accepting new delegations.
 		///
-		/// This can only be used by existing delegates. If not a delegate yet, use
+		/// This can only be used by existing delegates. If not a delegatee yet, use
 		/// [Call::register_as_delegatee] first.
 		#[pallet::call_index(5)]
 		#[pallet::weight(Weight::default())]
@@ -441,7 +441,7 @@ pub mod pallet {
 
 		/// Apply slash to a delegator account.
 		///
-		/// `Delegate` accounts with pending slash in their ledger can call this to apply slash to
+		/// `Delegatee` accounts with pending slash in their ledger can call this to apply slash to
 		/// one of its `delegator` account. Each slash to a delegator account needs to be posted
 		/// separately until all pending slash is cleared.
 		#[pallet::call_index(6)]
@@ -468,7 +468,7 @@ pub mod pallet {
 }
 
 impl<T: Config> Pallet<T> {
-	/// Derive a (keyless) pot account from the given delegate account and account type.
+	/// Derive a (keyless) pot account from the given delegatee account and account type.
 	pub(crate) fn sub_account(
 		account_type: AccountType,
 		delegatee_account: T::AccountId,
@@ -481,12 +481,12 @@ impl<T: Config> Pallet<T> {
 		T::Currency::balance_on_hold(&HoldReason::Delegating.into(), who)
 	}
 
-	/// Returns true if who is registered as a `Delegate`.
+	/// Returns true if who is registered as a `Delegatee`.
 	fn is_delegatee(who: &T::AccountId) -> bool {
 		<Delegates<T>>::contains_key(who)
 	}
 
-	/// Returns true if who is delegating to a `Delegate` account.
+	/// Returns true if who is delegating to a `Delegatee` account.
 	fn is_delegator(who: &T::AccountId) -> bool {
 		<Delegators<T>>::contains_key(who)
 	}
@@ -610,7 +610,7 @@ impl<T: Config> Pallet<T> {
 
 		// if we do not already have enough funds to be claimed, try withdraw some more.
 		if delegatee.ledger.unclaimed_withdrawals < amount {
-			// get the updated delegate
+			// get the updated delegatee
 			delegatee = Self::withdraw_unbonded(who, num_slashing_spans)?;
 		}
 
@@ -798,16 +798,16 @@ impl<T: Config> Pallet<T> {
 		for (delegatee, ledger) in ledgers {
 			ensure!(
 				matches!(
-					T::CoreStaking::status(&delegatee).expect("delegate should be bonded"),
+					T::CoreStaking::status(&delegatee).expect("delegatee should be bonded"),
 					StakerStatus::Nominator(_) | StakerStatus::Idle
 				),
-				"delegate should be bonded and not validator"
+				"delegatee should be bonded and not validator"
 			);
 
 			ensure!(
 				ledger.stakeable_balance() >=
 					T::CoreStaking::total_stake(&delegatee)
-						.expect("delegate should exist as a nominator"),
+						.expect("delegatee should exist as a nominator"),
 				"Cannot stake more than balance"
 			);
 		}
@@ -825,7 +825,7 @@ impl<T: Config> Pallet<T> {
 				T::CoreStaking::status(delegator).is_err(),
 				"delegator should not be directly staked"
 			);
-			ensure!(!Self::is_delegatee(delegator), "delegator cannot be delegate");
+			ensure!(!Self::is_delegatee(delegator), "delegator cannot be delegatee");
 
 			delegation_aggregation
 				.entry(delegation.delegatee.clone())
@@ -834,7 +834,7 @@ impl<T: Config> Pallet<T> {
 		}
 
 		for (delegatee, total_delegated) in delegation_aggregation {
-			ensure!(!Self::is_delegator(&delegatee), "delegate cannot be delegator");
+			ensure!(!Self::is_delegator(&delegatee), "delegatee cannot be delegator");
 
 			let ledger = ledger.get(&delegatee).expect("ledger should exist");
 			ensure!(

From 1f120323c8d12ec9b5c8ff7ea0b1eb8342096027 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Tue, 27 Feb 2024 17:09:04 +0100
Subject: [PATCH 179/202] minor refactors

---
 .../frame/delegated-staking/src/impls.rs      |  6 ++--
 substrate/frame/delegated-staking/src/lib.rs  | 24 ++++++-------
 .../frame/delegated-staking/src/tests.rs      |  2 +-
 .../frame/delegated-staking/src/types.rs      | 22 ++++++------
 substrate/frame/staking/src/pallet/impls.rs   | 36 +++++++++----------
 .../primitives/staking/src/delegation.rs      |  2 +-
 6 files changed, 47 insertions(+), 45 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 028ac34465d57..356d59473842b 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -109,7 +109,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult {
-		let delegation_register = <Delegates<T>>::get(who).ok_or(Error::<T>::NotDelegatee)?;
+		let delegation_register = <Delegatees<T>>::get(who).ok_or(Error::<T>::NotDelegatee)?;
 		ensure!(delegation_register.stakeable_balance() >= extra, Error::<T>::NotEnoughFunds);
 
 		T::CoreStaking::bond_extra(who, extra)
@@ -285,7 +285,7 @@ impl<T: Config> DelegateeSupport for Pallet<T> {
 		who: &Self::AccountId,
 		reward_destination: Option<Self::AccountId>,
 	) -> bool {
-		let maybe_register = <Delegates<T>>::get(who);
+		let maybe_register = <Delegatees<T>>::get(who);
 
 		if maybe_register.is_none() {
 			// no restrictions for non delegates.
@@ -309,7 +309,7 @@ impl<T: Config> DelegateeSupport for Pallet<T> {
 	}
 
 	fn report_slash(who: &Self::AccountId, slash: Self::Balance) {
-		<Delegates<T>>::mutate(who, |maybe_register| match maybe_register {
+		<Delegatees<T>>::mutate(who, |maybe_register| match maybe_register {
 			Some(register) => register.pending_slash.saturating_accrue(slash),
 			None => {
 				defensive!("should not be called on non-delegate");
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index f846292695b9a..9af6593cf8af6 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -272,7 +272,7 @@ pub mod pallet {
 
 	/// Map of `Delegatee` to their `DelegationLedger`.
 	#[pallet::storage]
-	pub(crate) type Delegates<T: Config> =
+	pub(crate) type Delegatees<T: Config> =
 		CountedStorageMap<_, Twox64Concat, T::AccountId, DelegationLedger<T>, OptionQuery>;
 
 	#[pallet::call]
@@ -301,7 +301,7 @@ pub mod pallet {
 			// Reward account cannot be same as `delegatee` account.
 			ensure!(reward_account != who, Error::<T>::InvalidRewardDestination);
 
-			Self::do_register_delegator(&who, &reward_account);
+			Self::do_register_delegatee(&who, &reward_account);
 			Ok(())
 		}
 
@@ -483,7 +483,7 @@ impl<T: Config> Pallet<T> {
 
 	/// Returns true if who is registered as a `Delegatee`.
 	fn is_delegatee(who: &T::AccountId) -> bool {
-		<Delegates<T>>::contains_key(who)
+		<Delegatees<T>>::contains_key(who)
 	}
 
 	/// Returns true if who is delegating to a `Delegatee` account.
@@ -503,10 +503,10 @@ impl<T: Config> Pallet<T> {
 			.unwrap_or(false)
 	}
 
-	fn do_register_delegator(who: &T::AccountId, reward_account: &T::AccountId) {
+	fn do_register_delegatee(who: &T::AccountId, reward_account: &T::AccountId) {
 		DelegationLedger::<T>::new(reward_account).save(who);
 
-		// Pool account is a virtual account. Make this account exist.
+		// Delegatee is a virtual account. Make this account exist.
 		// TODO: Someday if we expose these calls in a runtime, we should take a deposit for
 		// being a delegator.
 		frame_system::Pallet::<T>::inc_providers(who);
@@ -540,7 +540,7 @@ impl<T: Config> Pallet<T> {
 		T::Currency::transfer(who, &proxy_delegator, stake.total, Preservation::Protect)
 			.map_err(|_| Error::<T>::BadState)?;
 
-		Self::do_register_delegator(who, reward_account);
+		Self::do_register_delegatee(who, reward_account);
 		// FIXME(ank4n) expose set payee in staking interface.
 		// T::CoreStaking::set_payee(who, reward_account)
 
@@ -579,7 +579,7 @@ impl<T: Config> Pallet<T> {
 				amount
 			};
 
-		Delegation::<T>::from(delegatee, new_delegation_amount).save(delegator);
+		Delegation::<T>::from(delegatee, new_delegation_amount).save_or_kill(delegator);
 		ledger.total_delegated =
 			ledger.total_delegated.checked_add(&amount).ok_or(ArithmeticError::Overflow)?;
 		ledger.save(delegatee);
@@ -627,7 +627,7 @@ impl<T: Config> Pallet<T> {
 			.defensive_ok_or(ArithmeticError::Overflow)?;
 
 		// remove delegator if nothing delegated anymore
-		delegation.save(delegator);
+		delegation.save_or_kill(delegator);
 
 		let released = T::Currency::release(
 			&HoldReason::Delegating.into(),
@@ -694,12 +694,12 @@ impl<T: Config> Pallet<T> {
 		);
 
 		// update delegations
-		Delegation::<T>::from(&source_delegation.delegatee, amount).save(destination_delegator);
+		Delegation::<T>::from(&source_delegation.delegatee, amount).save_or_kill(destination_delegator);
 
 		source_delegation
 			.decrease_delegation(amount)
 			.defensive_ok_or(Error::<T>::BadState)?
-			.save(source_delegator);
+			.save_or_kill(source_delegator);
 
 		// FIXME(ank4n): If all funds are migrated from source, it can be cleaned up and ED returned
 		// to delegate or alternatively whoever cleans it up. This could be a permission-less
@@ -756,7 +756,7 @@ impl<T: Config> Pallet<T> {
 		delegation
 			.decrease_delegation(actual_slash)
 			.ok_or(ArithmeticError::Overflow)?
-			.save(&delegator);
+			.save_or_kill(&delegator);
 
 		if let Some(reporter) = maybe_reporter {
 			let reward_payout: BalanceOf<T> =
@@ -784,7 +784,7 @@ impl<T: Config> Pallet<T> {
 	pub(crate) fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> {
 		// build map to avoid reading storage multiple times.
 		let delegation_map = Delegators::<T>::iter().collect::<BTreeMap<_, _>>();
-		let ledger_map = Delegates::<T>::iter().collect::<BTreeMap<_, _>>();
+		let ledger_map = Delegatees::<T>::iter().collect::<BTreeMap<_, _>>();
 
 		Self::check_delegates(ledger_map.clone())?;
 		Self::check_delegators(delegation_map, ledger_map)?;
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 0dfdfd5746505..9d29727d70d24 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -914,7 +914,7 @@ mod pool_integration {
 			);
 
 			// Make sure all data is cleaned up.
-			assert_eq!(Delegates::<T>::contains_key(Pools::create_bonded_account(pool_id)), false);
+			assert_eq!(Delegatees::<T>::contains_key(Pools::create_bonded_account(pool_id)), false);
 			assert_eq!(Delegators::<T>::contains_key(creator), false);
 			for i in 300..310 {
 				assert_eq!(Delegators::<T>::contains_key(i), false);
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index e31d84b6943b5..4edb4051bf3ad 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -54,7 +54,7 @@ impl<T: Config> Delegation<T> {
 			.map(|delegation| delegation.delegatee == delegatee.clone())
 			.unwrap_or(
 				// all good if its a new delegator except it should not be an existing delegatee.
-				!<Delegates<T>>::contains_key(delegator),
+				!<Delegatees<T>>::contains_key(delegator),
 			)
 	}
 
@@ -71,7 +71,7 @@ impl<T: Config> Delegation<T> {
 		Some(Delegation::from(&self.delegatee, updated_delegation))
 	}
 
-	pub(crate) fn save(self, key: &T::AccountId) {
+	pub(crate) fn save_or_kill(self, key: &T::AccountId) {
 		// Clean up if no delegation left.
 		if self.amount == Zero::zero() {
 			<Delegators<T>>::remove(key);
@@ -82,7 +82,7 @@ impl<T: Config> Delegation<T> {
 	}
 }
 
-/// Ledger of all delegations to a `Delegate`.
+/// Ledger of all delegations to a `Delegatee`.
 ///
 /// This keeps track of the active balance of the `delegatee` that is made up from the funds that
 /// are currently delegated to this `delegatee`. It also tracks the pending slashes yet to be
@@ -120,7 +120,7 @@ impl<T: Config> DelegationLedger<T> {
 	}
 
 	pub(crate) fn get(key: &T::AccountId) -> Option<Self> {
-		<Delegates<T>>::get(key)
+		<Delegatees<T>>::get(key)
 	}
 
 	pub(crate) fn can_accept_delegation(delegatee: &T::AccountId) -> bool {
@@ -130,7 +130,7 @@ impl<T: Config> DelegationLedger<T> {
 	}
 
 	pub(crate) fn save(self, key: &T::AccountId) {
-		<Delegates<T>>::insert(key, self)
+		<Delegatees<T>>::insert(key, self)
 	}
 
 	/// Effective total balance of the `delegatee`.
@@ -226,20 +226,22 @@ impl<T: Config> Delegatee<T> {
 		let bonded_stake = self.bonded_stake();
 		let stakeable = self.ledger.stakeable_balance();
 
-		defensive_assert!(stakeable >= bonded_stake, "cannot expose more than delegate balance");
+		defensive_assert!(stakeable >= bonded_stake, "cannot be bonded with more than delegatee balance");
 
 		stakeable.saturating_sub(bonded_stake)
 	}
 
-	/// Balance of `Delegate` that is not bonded.
+	/// Balance of `Delegatee` that is not bonded.
 	///
-	/// Includes `unclaimed_withdrawals` of `Delegate`.
+	/// This is similar to [Self::available_to_bond] except it also includes `unclaimed_withdrawals`
+	/// of `Delegatee`.
+	#[cfg(test)]
 	pub(crate) fn total_unbonded(&self) -> BalanceOf<T> {
 		let bonded_stake = self.bonded_stake();
 
 		let net_balance = self.ledger.effective_balance();
 
-		defensive_assert!(net_balance >= bonded_stake, "cannot expose more than delegate balance");
+		defensive_assert!(net_balance >= bonded_stake, "cannot be bonded with more than the delegatee balance");
 
 		net_balance.saturating_sub(bonded_stake)
 	}
@@ -288,7 +290,7 @@ impl<T: Config> Delegatee<T> {
 					self.ledger.pending_slash == Zero::zero(),
 				Error::<T>::BadState
 			);
-			<Delegates<T>>::remove(key);
+			<Delegatees<T>>::remove(key);
 		} else {
 			self.ledger.save(&key)
 		}
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index ecddb1b34e67b..bd3af7d103de9 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1871,60 +1871,60 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		T::Currency::remove_lock(crate::STAKING_ID, who)
 	}
 
-	fn is_delegatee(who: &Self::AccountId) -> bool {
+	fn is_delegatee(_who: &Self::AccountId) -> bool {
 		defensive!("is_delegatee is not supported");
 		false
 	}
 
-	fn delegatee_balance(who: &Self::AccountId) -> Self::Balance {
+	fn delegatee_balance(_who: &Self::AccountId) -> Self::Balance {
 		defensive!("delegatee_balance is not supported");
 		BalanceOf::<T>::zero()
 	}
 
 	/// Delegate funds to `Delegatee`.
 	fn delegate(
-		who: &Self::AccountId,
-		delegatee: &Self::AccountId,
-		reward_account: &Self::AccountId,
-		amount: Self::Balance,
+		_who: &Self::AccountId,
+		_delegatee: &Self::AccountId,
+		_reward_account: &Self::AccountId,
+		_amount: Self::Balance,
 	) -> DispatchResult {
 		Err(DispatchError::Other("delegate is not supported"))
 	}
 
 	/// Add more delegation to the pool account.
 	fn delegate_extra(
-		who: &Self::AccountId,
-		delegatee: &Self::AccountId,
-		amount: Self::Balance,
+		_who: &Self::AccountId,
+		_delegatee: &Self::AccountId,
+		_amount: Self::Balance,
 	) -> DispatchResult {
 		Err(DispatchError::Other("delegate_extra is not supported"))
 	}
 
 	/// Withdraw delegation from pool account to self.
 	fn withdraw_delegation(
-		who: &Self::AccountId,
-		delegatee: &Self::AccountId,
-		amount: Self::Balance,
+		_who: &Self::AccountId,
+		_delegatee: &Self::AccountId,
+		_amount: Self::Balance,
 	) -> DispatchResult {
 		Err(DispatchError::Other("withdraw_delegation is not supported"))
 	}
 
 	/// Does the delegatee have any pending slash.
-	fn has_pending_slash(delegatee: &Self::AccountId) -> bool {
+	fn has_pending_slash(_delegatee: &Self::AccountId) -> bool {
 		// slashing is greedy, so no pending slash.
 		false
 	}
 
 	fn delegator_slash(
-		delegatee: &Self::AccountId,
-		delegator: &Self::AccountId,
-		value: Self::Balance,
-		maybe_reporter: Option<Self::AccountId>,
+		_delegatee: &Self::AccountId,
+		_delegator: &Self::AccountId,
+		_value: Self::Balance,
+		_maybe_reporter: Option<Self::AccountId>,
 	) -> sp_runtime::DispatchResult {
 		Err(DispatchError::Other("delegator_slash is not supported"))
 	}
 
-	fn delegated_balance(delegator: &Self::AccountId) -> Self::Balance {
+	fn delegated_balance(_delegator: &Self::AccountId) -> Self::Balance {
 		defensive!("delegated_balance is not supported");
 		BalanceOf::<T>::zero()
 	}
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index ede3f77cce8cb..c8a9f366d701d 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -17,7 +17,7 @@
 
 use codec::{FullCodec, MaxEncodedLen};
 use scale_info::TypeInfo;
-use sp_runtime::{DispatchResult, Saturating};
+use sp_runtime::Saturating;
 use sp_std::ops::Sub;
 
 /// A trait that can be used as a plugin to support delegation based accounts, called `Delegatee`.

From 9c2bb9eb508574085c3c1ec3386bf820a000b504 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Tue, 27 Feb 2024 17:18:19 +0100
Subject: [PATCH 180/202] doc updates

---
 .../frame/delegated-staking/src/impls.rs      |  2 +-
 substrate/frame/delegated-staking/src/lib.rs  | 18 +++++++--------
 .../frame/delegated-staking/src/types.rs      | 22 +++++++++----------
 substrate/primitives/staking/src/lib.rs       | 15 ++++++++-----
 4 files changed, 31 insertions(+), 26 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 356d59473842b..438425e01b9b3 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -124,7 +124,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 
 	/// Withdraw unbonding funds until current era.
 	///
-	/// Funds are moved to unclaimed_withdrawals register of the `DelegationLedger`.
+	/// Funds are moved to unclaimed_withdrawals register of the `DelegateeLedger`.
 	fn withdraw_unbonded(
 		pool_acc: Self::AccountId,
 		num_slashing_spans: u32,
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 9af6593cf8af6..89360ad56d108 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -46,7 +46,7 @@
 //! ## Key Terminologies
 //! - *delegatee*: An account who accepts delegations from other accounts (called `Delegators`).
 //! - *Delegator*: An account who delegates their funds to a `delegatee`.
-//! - *DelegationLedger*: A data structure that stores important information about the `delegatee`
+//! - *DelegateeLedger*: A data structure that stores important information about the `delegatee`
 //! 	such as their total delegated stake.
 //! - *Delegation*: A data structure that stores the amount of funds delegated to a `delegatee` by a
 //! 	`delegator`.
@@ -83,7 +83,7 @@
 //! nominators are slashed at the same time. This is expensive and needs to be bounded operation.
 //!
 //! This pallet implements a lazy slashing mechanism. Any slashes to a `delegatee` are posted in its
-//! `DelegationLedger` as a pending slash. Since the actual amount is held in the multiple
+//! `DelegateeLedger` as a pending slash. Since the actual amount is held in the multiple
 //! `delegator` accounts, this pallet has no way to know how to apply slash. It is `delegatee`'s
 //! responsibility to apply slashes for each delegator, one at a time. Staking pallet ensures the
 //! pending slash never exceeds staked amount and would freeze further withdraws until pending
@@ -270,10 +270,10 @@ pub mod pallet {
 	pub(crate) type Delegators<T: Config> =
 		CountedStorageMap<_, Twox64Concat, T::AccountId, Delegation<T>, OptionQuery>;
 
-	/// Map of `Delegatee` to their `DelegationLedger`.
+	/// Map of `Delegatee` to their `DelegateeLedger`.
 	#[pallet::storage]
 	pub(crate) type Delegatees<T: Config> =
-		CountedStorageMap<_, Twox64Concat, T::AccountId, DelegationLedger<T>, OptionQuery>;
+		CountedStorageMap<_, Twox64Concat, T::AccountId, DelegateeLedger<T>, OptionQuery>;
 
 	#[pallet::call]
 	impl<T: Config> Pallet<T> {
@@ -409,7 +409,7 @@ pub mod pallet {
 
 			// ensure delegatee is sane.
 			ensure!(
-				DelegationLedger::<T>::can_accept_delegation(&delegatee),
+				DelegateeLedger::<T>::can_accept_delegation(&delegatee),
 				Error::<T>::NotAcceptingDelegations
 			);
 
@@ -504,7 +504,7 @@ impl<T: Config> Pallet<T> {
 	}
 
 	fn do_register_delegatee(who: &T::AccountId, reward_account: &T::AccountId) {
-		DelegationLedger::<T>::new(reward_account).save(who);
+		DelegateeLedger::<T>::new(reward_account).save(who);
 
 		// Delegatee is a virtual account. Make this account exist.
 		// TODO: Someday if we expose these calls in a runtime, we should take a deposit for
@@ -565,7 +565,7 @@ impl<T: Config> Pallet<T> {
 		delegatee: &T::AccountId,
 		amount: BalanceOf<T>,
 	) -> DispatchResult {
-		let mut ledger = DelegationLedger::<T>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
+		let mut ledger = DelegateeLedger::<T>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
 		debug_assert!(!ledger.blocked);
 
 		let new_delegation_amount =
@@ -793,7 +793,7 @@ impl<T: Config> Pallet<T> {
 	}
 
 	fn check_delegates(
-		ledgers: BTreeMap<T::AccountId, DelegationLedger<T>>,
+		ledgers: BTreeMap<T::AccountId, DelegateeLedger<T>>,
 	) -> Result<(), sp_runtime::TryRuntimeError> {
 		for (delegatee, ledger) in ledgers {
 			ensure!(
@@ -817,7 +817,7 @@ impl<T: Config> Pallet<T> {
 
 	fn check_delegators(
 		delegations: BTreeMap<T::AccountId, Delegation<T>>,
-		ledger: BTreeMap<T::AccountId, DelegationLedger<T>>,
+		ledger: BTreeMap<T::AccountId, DelegateeLedger<T>>,
 	) -> Result<(), sp_runtime::TryRuntimeError> {
 		let mut delegation_aggregation = BTreeMap::<T::AccountId, BalanceOf<T>>::new();
 		for (delegator, delegation) in delegations.iter() {
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index 4edb4051bf3ad..4356122f8b664 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -90,7 +90,7 @@ impl<T: Config> Delegation<T> {
 // FIXME(ank4n): Break up into two storage items - bookkeeping stuff and settings stuff.
 #[derive(Default, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
 #[scale_info(skip_type_params(T))]
-pub struct DelegationLedger<T: Config> {
+pub struct DelegateeLedger<T: Config> {
 	/// Where the reward should be paid out.
 	pub payee: T::AccountId,
 	/// Sum of all delegated funds to this `delegatee`.
@@ -108,9 +108,9 @@ pub struct DelegationLedger<T: Config> {
 	pub blocked: bool,
 }
 
-impl<T: Config> DelegationLedger<T> {
+impl<T: Config> DelegateeLedger<T> {
 	pub(crate) fn new(reward_destination: &T::AccountId) -> Self {
-		DelegationLedger {
+		DelegateeLedger {
 			payee: reward_destination.clone(),
 			total_delegated: Zero::zero(),
 			unclaimed_withdrawals: Zero::zero(),
@@ -124,7 +124,7 @@ impl<T: Config> DelegationLedger<T> {
 	}
 
 	pub(crate) fn can_accept_delegation(delegatee: &T::AccountId) -> bool {
-		DelegationLedger::<T>::get(delegatee)
+		DelegateeLedger::<T>::get(delegatee)
 			.map(|ledger| !ledger.blocked)
 			.unwrap_or(false)
 	}
@@ -150,16 +150,16 @@ impl<T: Config> DelegationLedger<T> {
 	}
 }
 
-/// Wrapper around `DelegationLedger` to provide additional functionality.
+/// Wrapper around `DelegateeLedger` to provide additional functionality.
 #[derive(Clone)]
 pub struct Delegatee<T: Config> {
 	pub key: T::AccountId,
-	pub ledger: DelegationLedger<T>,
+	pub ledger: DelegateeLedger<T>,
 }
 
 impl<T: Config> Delegatee<T> {
 	pub(crate) fn from(delegatee: &T::AccountId) -> Result<Delegatee<T>, DispatchError> {
-		let ledger = DelegationLedger::<T>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
+		let ledger = DelegateeLedger::<T>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
 		Ok(Delegatee { key: delegatee.clone(), ledger })
 	}
 
@@ -183,7 +183,7 @@ impl<T: Config> Delegatee<T> {
 			.defensive_ok_or(ArithmeticError::Overflow)?;
 
 		Ok(Delegatee {
-			ledger: DelegationLedger {
+			ledger: DelegateeLedger {
 				total_delegated: new_total_delegated,
 				unclaimed_withdrawals: new_unclaimed_withdrawals,
 				..self.ledger
@@ -204,7 +204,7 @@ impl<T: Config> Delegatee<T> {
 			.defensive_ok_or(ArithmeticError::Overflow)?;
 
 		Ok(Delegatee {
-			ledger: DelegationLedger {
+			ledger: DelegateeLedger {
 				unclaimed_withdrawals: new_unclaimed_withdrawals,
 				..self.ledger
 			},
@@ -252,7 +252,7 @@ impl<T: Config> Delegatee<T> {
 		let total_delegated = self.ledger.total_delegated.defensive_saturating_sub(amount);
 
 		Delegatee {
-			ledger: DelegationLedger { pending_slash, total_delegated, ..self.ledger },
+			ledger: DelegateeLedger { pending_slash, total_delegated, ..self.ledger },
 			..self
 		}
 	}
@@ -270,7 +270,7 @@ impl<T: Config> Delegatee<T> {
 	}
 
 	pub(crate) fn update_status(self, block: bool) -> Self {
-		Delegatee { ledger: DelegationLedger { blocked: block, ..self.ledger }, ..self }
+		Delegatee { ledger: DelegateeLedger { blocked: block, ..self.ledger }, ..self }
 	}
 
 	pub(crate) fn save(self) {
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 0ed417155f054..5131d0d9dc36d 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -320,29 +320,32 @@ pub trait StakingInterface {
 
 	/// Delegate funds to `Delegatee`.
 	fn delegate(
-		who: &Self::AccountId,
+		delegator: &Self::AccountId,
 		delegatee: &Self::AccountId,
 		reward_account: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult;
 
-	/// Add more delegation to the pool account.
+	/// Add more delegation to the `delegatee`.
 	fn delegate_extra(
-		who: &Self::AccountId,
+		delegator: &Self::AccountId,
 		delegatee: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult;
 
-	/// Withdraw delegation from pool account to self.
+	/// Withdraw or revoke delegation to `delegatee`.
 	fn withdraw_delegation(
 		who: &Self::AccountId,
 		delegatee: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult;
 
-	/// Does the delegatee have any pending slash.
+	/// Returns true if there are pending slashes posted to the `delegatee` account.
 	fn has_pending_slash(delegatee: &Self::AccountId) -> bool;
 
+	/// Apply a pending slash to a `delegatee` by slashing `value` from `delegator`.
+	///
+	/// If a reporter is provided, the reporter will receive a fraction of the slash as reward.
 	fn delegator_slash(
 		delegatee: &Self::AccountId,
 		delegator: &Self::AccountId,
@@ -350,6 +353,8 @@ pub trait StakingInterface {
 		maybe_reporter: Option<Self::AccountId>,
 	) -> sp_runtime::DispatchResult;
 
+
+	/// Returns the total amount of funds delegated by a `delegator`.
 	fn delegated_balance(delegator: &Self::AccountId) -> Self::Balance;
 }
 

From 244df2275e520cadf1095bd34872c3cdad3ffc71 Mon Sep 17 00:00:00 2001
From: Ankan <10196091+Ank4n@users.noreply.github.com>
Date: Wed, 28 Feb 2024 11:16:25 +0100
Subject: [PATCH 181/202] Stake Adapter refactor (#3502)

---
 .../frame/delegated-staking/src/impls.rs      |   3 +
 substrate/frame/delegated-staking/src/lib.rs  |  11 +-
 substrate/frame/delegated-staking/src/mock.rs |   3 +-
 .../frame/delegated-staking/src/types.rs      |  10 +-
 .../frame/nomination-pools/src/adapter.rs     | 301 +++++++++++++-----
 substrate/frame/nomination-pools/src/lib.rs   | 105 +++---
 .../frame/nomination-pools/src/migration.rs   |   5 +-
 substrate/frame/nomination-pools/src/mock.rs  |  58 +---
 .../nomination-pools/test-staking/src/mock.rs |   3 +-
 substrate/frame/staking/src/pallet/impls.rs   |  70 +---
 substrate/frame/staking/src/pallet/mod.rs     |   6 +-
 .../primitives/staking/src/delegation.rs      |  49 ++-
 substrate/primitives/staking/src/lib.rs       |  47 ---
 13 files changed, 335 insertions(+), 336 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 438425e01b9b3..67ff007b6d271 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -19,6 +19,7 @@
 //! Implementations of public traits, namely [StakingInterface], and [DelegateeSupport].
 
 use super::*;
+use sp_staking::delegation::DelegatedStakeInterface;
 
 /// StakingInterface implementation with delegation support.
 ///
@@ -193,7 +194,9 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	fn set_current_era(era: EraIndex) {
 		T::CoreStaking::set_current_era(era)
 	}
+}
 
+impl<T: Config> DelegatedStakeInterface for Pallet<T> {
 	fn is_delegatee(who: &Self::AccountId) -> bool {
 		Self::is_delegatee(who)
 	}
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 89360ad56d108..5b180f3e0b219 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -170,9 +170,7 @@ use sp_runtime::{
 	traits::{AccountIdConversion, CheckedAdd, CheckedSub, Zero},
 	ArithmeticError, DispatchResult, Perbill, RuntimeDebug, Saturating,
 };
-use sp_staking::{
-	delegation::DelegateeSupport, EraIndex, Stake, StakerStatus, StakingInterface,
-};
+use sp_staking::{delegation::DelegateeSupport, EraIndex, Stake, StakerStatus, StakingInterface};
 use sp_std::{convert::TryInto, prelude::*};
 
 pub type BalanceOf<T> =
@@ -279,8 +277,8 @@ pub mod pallet {
 	impl<T: Config> Pallet<T> {
 		/// Register an account to be a `Delegatee`.
 		///
-		/// `Delegatee` accounts accepts delegations from other `delegator`s and stake funds on their
-		/// behalf.
+		/// `Delegatee` accounts accepts delegations from other `delegator`s and stake funds on
+		/// their behalf.
 		#[pallet::call_index(0)]
 		#[pallet::weight(Weight::default())]
 		pub fn register_as_delegatee(
@@ -694,7 +692,8 @@ impl<T: Config> Pallet<T> {
 		);
 
 		// update delegations
-		Delegation::<T>::from(&source_delegation.delegatee, amount).save_or_kill(destination_delegator);
+		Delegation::<T>::from(&source_delegation.delegatee, amount)
+			.save_or_kill(destination_delegator);
 
 		source_delegation
 			.decrease_delegation(amount)
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 756b43316e172..892b69b624e44 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -175,13 +175,12 @@ impl pallet_nomination_pools::Config for Runtime {
 	type RewardCounter = sp_runtime::FixedU128;
 	type BalanceToU256 = BalanceToU256;
 	type U256ToBalance = U256ToBalance;
-	type Staking = DelegatedStaking;
 	type PostUnbondingPoolsWindow = ConstU32<2>;
 	type PalletId = PoolsPalletId;
 	type MaxMetadataLen = ConstU32<256>;
 	type MaxUnbonding = MaxUnbonding;
 	type MaxPointsToBalance = frame_support::traits::ConstU8<10>;
-	type StakeAdapter = pallet_nomination_pools::adapter::DelegationStake<Self>;
+	type StakeAdapter = pallet_nomination_pools::adapter::DelegateStake<Self, DelegatedStaking>;
 }
 
 frame_support::construct_runtime!(
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index 4356122f8b664..ec16c3da39877 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -226,7 +226,10 @@ impl<T: Config> Delegatee<T> {
 		let bonded_stake = self.bonded_stake();
 		let stakeable = self.ledger.stakeable_balance();
 
-		defensive_assert!(stakeable >= bonded_stake, "cannot be bonded with more than delegatee balance");
+		defensive_assert!(
+			stakeable >= bonded_stake,
+			"cannot be bonded with more than delegatee balance"
+		);
 
 		stakeable.saturating_sub(bonded_stake)
 	}
@@ -241,7 +244,10 @@ impl<T: Config> Delegatee<T> {
 
 		let net_balance = self.ledger.effective_balance();
 
-		defensive_assert!(net_balance >= bonded_stake, "cannot be bonded with more than the delegatee balance");
+		defensive_assert!(
+			net_balance >= bonded_stake,
+			"cannot be bonded with more than the delegatee balance"
+		);
 
 		net_balance.saturating_sub(bonded_stake)
 	}
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index 6f42514493b2b..6546ef5f38d76 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -16,149 +16,286 @@
 // limitations under the License.
 
 use crate::*;
+use sp_staking::delegation::DelegatedStakeInterface;
 
 /// An adapter trait that can support multiple staking strategies.
 ///
 /// Depending on which staking strategy we want to use, the staking logic can be slightly
-/// different. Refer the two possible strategies currently: [`TransferStake`] and [`DelegationStake`].
-pub trait StakeAdapter {
+/// different. Refer the two possible strategies currently: [`TransferStake`] and
+/// [`DelegateStake`].
+pub trait StakeStrategy {
 	type Balance: frame_support::traits::tokens::Balance;
 	type AccountId: Clone + sp_std::fmt::Debug;
 
-	/// Balance of the account.
-	fn balance(who: &Self::AccountId) -> Self::Balance;
+	fn bonding_duration() -> EraIndex;
+	fn current_era() -> EraIndex;
+	fn minimum_nominator_bond() -> Self::Balance;
 
-	/// Total balance of the account.
-	fn total_balance(who: &Self::AccountId) -> Self::Balance;
+	/// Transferable balance of the pool.
+	///
+	/// This is the amount that can be withdrawn from the pool.
+	///
+	/// Does not include reward account.
+	fn transferable_balance(id: PoolId) -> Self::Balance;
 
-	/// Bond delegator via the pool account.
-	fn delegator_bond(
+	/// Total balance of the pool including amount that is actively staked.
+	fn total_balance(id: PoolId) -> Self::Balance;
+	fn member_delegation_balance(member_account: &Self::AccountId) -> Self::Balance;
+
+	fn active_stake(pool: PoolId) -> Self::Balance;
+	fn total_stake(pool: PoolId) -> Self::Balance;
+
+	fn nominate(pool_id: PoolId, validators: Vec<Self::AccountId>) -> DispatchResult;
+
+	fn chill(pool_id: PoolId) -> DispatchResult;
+
+	fn bond(
 		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		reward_account: &Self::AccountId,
+		pool_id: PoolId,
 		amount: Self::Balance,
+		bond_type: BondType,
 	) -> DispatchResult;
 
-	/// Add more bond for delegator via the pool account.
-	fn delegator_bond_extra(
+	fn unbond(pool_id: PoolId, amount: Self::Balance) -> DispatchResult;
+
+	fn withdraw_unbonded(pool_id: PoolId, num_slashing_spans: u32) -> Result<bool, DispatchError>;
+
+	fn member_withdraw(
 		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
+		pool: PoolId,
 		amount: Self::Balance,
 	) -> DispatchResult;
 
-	/// Withdrawn amount from pool to delegator.
-	fn delegator_withdraw(
+	fn has_pending_slash(pool: PoolId) -> bool;
+
+	fn member_slash(
 		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
+		pool: PoolId,
 		amount: Self::Balance,
+		maybe_reporter: Option<Self::AccountId>,
 	) -> DispatchResult;
 }
 
-/// An adapter implementation that supports transfer based staking.
+/// A staking strategy implementation that supports transfer based staking.
 ///
 /// In order to stake, this adapter transfers the funds from the delegator account to the pool
-/// account and stakes directly on [Config::Staking].
-pub struct TransferStake<T: Config>(PhantomData<T>);
+/// account and stakes directly on `Staking`.
+pub struct TransferStake<T: Config, Staking: StakingInterface>(PhantomData<(T, Staking)>);
 
-impl<T: Config> StakeAdapter for TransferStake<T> {
+impl<T: Config, Staking: StakingInterface<Balance = BalanceOf<T>, AccountId = T::AccountId>>
+	StakeStrategy for TransferStake<T, Staking>
+{
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
-	fn balance(who: &Self::AccountId) -> Self::Balance {
-		// Note on why we can't use `Currency::reducible_balance`: Since pooled account has a
-		// provider (staking pallet), the account can not be set expendable by
-		// `pallet-nomination-pool`. This means reducible balance always returns balance preserving
-		// ED in the account. What we want though is transferable balance given the account can be
-		// dusted.
-		T::Currency::balance(who)
+	fn bonding_duration() -> EraIndex {
+		Staking::bonding_duration()
+	}
+	fn current_era() -> EraIndex {
+		Staking::current_era()
+	}
+	fn minimum_nominator_bond() -> Staking::Balance {
+		Staking::minimum_nominator_bond()
 	}
 
-	fn total_balance(who: &Self::AccountId) -> Self::Balance {
-		T::Currency::total_balance(who)
+	fn transferable_balance(pool: PoolId) -> BalanceOf<T> {
+		let pool_account = Pallet::<T>::create_bonded_account(pool);
+		T::Currency::balance(&pool_account).saturating_sub(Self::active_stake(pool))
 	}
 
-	fn delegator_bond(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		reward_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult {
-		T::Currency::transfer(who, &pool_account, amount, Preservation::Expendable)?;
-		T::Staking::bond(pool_account, amount, reward_account)
+	fn total_balance(pool: PoolId) -> BalanceOf<T> {
+		let pool_account = Pallet::<T>::create_bonded_account(pool);
+		T::Currency::total_balance(&pool_account)
 	}
 
-	fn delegator_bond_extra(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult {
-		T::Currency::transfer(who, pool_account, amount, Preservation::Preserve)?;
-		T::Staking::bond_extra(pool_account, amount)
+	fn member_delegation_balance(_member_account: &T::AccountId) -> Staking::Balance {
+		defensive!("delegation not supported");
+		Zero::zero()
 	}
 
-	fn delegator_withdraw(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		amount: Self::Balance,
+	fn active_stake(pool: PoolId) -> BalanceOf<T> {
+		let pool_account = Pallet::<T>::create_bonded_account(pool);
+		Staking::active_stake(&pool_account).unwrap_or_default()
+	}
+
+	fn total_stake(pool: PoolId) -> Staking::Balance {
+		let pool_account = Pallet::<T>::create_bonded_account(pool);
+		Staking::total_stake(&pool_account).unwrap_or_default()
+	}
+
+	fn nominate(pool_id: PoolId, validators: Vec<T::AccountId>) -> DispatchResult {
+		let pool_account = Pallet::<T>::create_bonded_account(pool_id);
+		Staking::nominate(&pool_account, validators)
+	}
+
+	fn chill(pool_id: PoolId) -> DispatchResult {
+		let pool_account = Pallet::<T>::create_bonded_account(pool_id);
+		Staking::chill(&pool_account)
+	}
+
+	fn bond(
+		who: &T::AccountId,
+		pool: PoolId,
+		amount: BalanceOf<T>,
+		bond_type: BondType,
 	) -> DispatchResult {
+		let pool_account = Pallet::<T>::create_bonded_account(pool);
+		let reward_account = Pallet::<T>::create_reward_account(pool);
+
+		match bond_type {
+			BondType::Create => {
+				// first bond
+				T::Currency::transfer(who, &pool_account, amount, Preservation::Expendable)?;
+				Staking::bond(&pool_account, amount, &reward_account)
+			},
+			BondType::Later => {
+				// additional bond
+				T::Currency::transfer(who, &pool_account, amount, Preservation::Preserve)?;
+				Staking::bond_extra(&pool_account, amount)
+			},
+		}
+	}
+
+	fn unbond(pool_id: PoolId, amount: Staking::Balance) -> DispatchResult {
+		let pool_account = Pallet::<T>::create_bonded_account(pool_id);
+		Staking::unbond(&pool_account, amount)
+	}
+
+	fn withdraw_unbonded(pool_id: PoolId, num_slashing_spans: u32) -> Result<bool, DispatchError> {
+		let pool_account = Pallet::<T>::create_bonded_account(pool_id);
+		Staking::withdraw_unbonded(pool_account, num_slashing_spans)
+	}
+
+	fn member_withdraw(who: &T::AccountId, pool: PoolId, amount: BalanceOf<T>) -> DispatchResult {
+		let pool_account = Pallet::<T>::create_bonded_account(pool);
 		T::Currency::transfer(&pool_account, &who, amount, Preservation::Expendable)?;
 
 		Ok(())
 	}
+
+	fn has_pending_slash(_pool: PoolId) -> bool {
+		// for transfer stake strategy, slashing is greedy
+		false
+	}
+
+	fn member_slash(
+		_who: &T::AccountId,
+		_pool: PoolId,
+		_amount: Staking::Balance,
+		_maybe_reporter: Option<T::AccountId>,
+	) -> DispatchResult {
+		Err(Error::<T>::Defensive(DefensiveError::DelegationUnsupported).into())
+	}
 }
 
-/// An adapter implementation that supports delegation based staking.
+/// A staking strategy implementation that supports delegation based staking.
 ///
 /// In this approach, first the funds are delegated from delegator to the pool account and later
-/// staked with [Config::Staking]. The advantage of this approach is that the funds are held in the
+/// staked with `Staking`. The advantage of this approach is that the funds are held in the
 /// use account itself and not in the pool account.
-pub struct DelegationStake<T: Config>(PhantomData<T>);
+pub struct DelegateStake<T: Config, Staking: DelegatedStakeInterface>(PhantomData<(T, Staking)>);
 
-impl<T: Config> StakeAdapter for DelegationStake<T> {
+impl<
+		T: Config,
+		Staking: DelegatedStakeInterface<Balance = BalanceOf<T>, AccountId = T::AccountId>,
+	> StakeStrategy for DelegateStake<T, Staking>
+{
 	type Balance = BalanceOf<T>;
 	type AccountId = T::AccountId;
 
-	fn balance(who: &Self::AccountId) -> Self::Balance {
-		// Pool account is a delegatee, and its balance is the sum of all member delegations towards
-		// it.
-		if T::Staking::is_delegatee(who) {
-			return T::Staking::delegatee_balance(who);
-		}
+	fn bonding_duration() -> EraIndex {
+		Staking::bonding_duration()
+	}
+	fn current_era() -> EraIndex {
+		Staking::current_era()
+	}
+	fn minimum_nominator_bond() -> Staking::Balance {
+		Staking::minimum_nominator_bond()
+	}
 
-		T::Currency::balance(who)
+	fn transferable_balance(pool: PoolId) -> BalanceOf<T> {
+		let pool_account = Pallet::<T>::create_bonded_account(pool);
+		Staking::delegatee_balance(&pool_account).saturating_sub(Self::active_stake(pool))
 	}
 
-	fn total_balance(who: &Self::AccountId) -> Self::Balance {
-		if T::Staking::is_delegatee(who) {
-			return T::Staking::delegatee_balance(who);
-		}
+	fn total_balance(pool: PoolId) -> BalanceOf<T> {
+		let pool_account = Pallet::<T>::create_bonded_account(pool);
+		Staking::delegatee_balance(&pool_account)
+	}
 
-		T::Currency::total_balance(who)
+	fn member_delegation_balance(member_account: &T::AccountId) -> Staking::Balance {
+		Staking::delegated_balance(member_account)
 	}
 
-	fn delegator_bond(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		reward_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult {
-		// For delegation staking, we just delegate the funds to pool account.
-		T::Staking::delegate(who, pool_account, reward_account, amount)
+	fn active_stake(pool: PoolId) -> BalanceOf<T> {
+		let pool_account = Pallet::<T>::create_bonded_account(pool);
+		Staking::active_stake(&pool_account).unwrap_or_default()
 	}
 
-	fn delegator_bond_extra(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		amount: Self::Balance,
+	fn total_stake(pool: PoolId) -> Staking::Balance {
+		let pool_account = Pallet::<T>::create_bonded_account(pool);
+		Staking::total_stake(&pool_account).unwrap_or_default()
+	}
+
+	fn nominate(pool_id: PoolId, validators: Vec<T::AccountId>) -> DispatchResult {
+		let pool_account = Pallet::<T>::create_bonded_account(pool_id);
+		Staking::nominate(&pool_account, validators)
+	}
+
+	fn chill(pool_id: PoolId) -> DispatchResult {
+		let pool_account = Pallet::<T>::create_bonded_account(pool_id);
+		Staking::chill(&pool_account)
+	}
+
+	fn bond(
+		who: &T::AccountId,
+		pool: PoolId,
+		amount: BalanceOf<T>,
+		bond_type: BondType,
 	) -> DispatchResult {
-		T::Staking::delegate_extra(who, pool_account, amount)
+		let pool_account = Pallet::<T>::create_bonded_account(pool);
+
+		match bond_type {
+			BondType::Create => {
+				// first delegation
+				let reward_account = Pallet::<T>::create_reward_account(pool);
+				Staking::delegate(who, &pool_account, &reward_account, amount)
+			},
+			BondType::Later => {
+				// additional delegation
+				Staking::delegate_extra(who, &pool_account, amount)
+			},
+		}
 	}
 
-	fn delegator_withdraw(
-		who: &Self::AccountId,
-		pool_account: &Self::AccountId,
-		amount: Self::Balance,
+	fn unbond(pool_id: PoolId, amount: Staking::Balance) -> DispatchResult {
+		let pool_account = Pallet::<T>::create_bonded_account(pool_id);
+		Staking::unbond(&pool_account, amount)
+	}
+
+	fn withdraw_unbonded(pool_id: PoolId, num_slashing_spans: u32) -> Result<bool, DispatchError> {
+		let pool_account = Pallet::<T>::create_bonded_account(pool_id);
+		Staking::withdraw_unbonded(pool_account, num_slashing_spans)
+	}
+
+	fn member_withdraw(who: &T::AccountId, pool: PoolId, amount: BalanceOf<T>) -> DispatchResult {
+		let pool_account = Pallet::<T>::create_bonded_account(pool);
+		Staking::withdraw_delegation(&who, &pool_account, amount)
+	}
+
+	fn has_pending_slash(pool: PoolId) -> bool {
+		// for transfer stake strategy, slashing is greedy
+		let pool_account = Pallet::<T>::create_bonded_account(pool);
+		Staking::has_pending_slash(&pool_account)
+	}
+
+	fn member_slash(
+		who: &T::AccountId,
+		pool: PoolId,
+		amount: Staking::Balance,
+		maybe_reporter: Option<T::AccountId>,
 	) -> DispatchResult {
-		T::Staking::withdraw_delegation(who, pool_account, amount)
+		let pool_account = Pallet::<T>::create_bonded_account(pool);
+		Staking::delegator_slash(&pool_account, who, amount, maybe_reporter)
 	}
 }
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index f76a1fb9ed3ae..83aefc7219e74 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -351,7 +351,7 @@
 
 #![cfg_attr(not(feature = "std"), no_std)]
 
-use adapter::StakeAdapter;
+use adapter::StakeStrategy;
 use codec::Codec;
 use frame_support::{
 	defensive, defensive_assert, ensure,
@@ -427,7 +427,7 @@ pub enum ConfigOp<T: Codec + Debug> {
 }
 
 /// The type of bonding that can happen to a pool.
-enum BondType {
+pub enum BondType {
 	/// Someone is bonding into the pool upon creation.
 	Create,
 	/// Someone is adding more funds later to this pool.
@@ -998,8 +998,7 @@ impl<T: Config> BondedPool<T> {
 	///
 	/// This is often used for bonding and issuing new funds into the pool.
 	fn balance_to_point(&self, new_funds: BalanceOf<T>) -> BalanceOf<T> {
-		let bonded_balance =
-			T::Staking::active_stake(&self.bonded_account()).unwrap_or(Zero::zero());
+		let bonded_balance = T::StakeAdapter::active_stake(self.id);
 		Pallet::<T>::balance_to_point(bonded_balance, self.points, new_funds)
 	}
 
@@ -1007,8 +1006,7 @@ impl<T: Config> BondedPool<T> {
 	///
 	/// This is often used for unbonding.
 	fn points_to_balance(&self, points: BalanceOf<T>) -> BalanceOf<T> {
-		let bonded_balance =
-			T::Staking::active_stake(&self.bonded_account()).unwrap_or(Zero::zero());
+		let bonded_balance = T::StakeAdapter::active_stake(self.id);
 		Pallet::<T>::point_to_balance(bonded_balance, self.points, points)
 	}
 
@@ -1055,13 +1053,6 @@ impl<T: Config> BondedPool<T> {
 		self
 	}
 
-	/// The pools balance that is transferable provided it is expendable by staking pallet.
-	fn transferable_balance(&self) -> BalanceOf<T> {
-		let account = self.bonded_account();
-		T::StakeAdapter::balance(&account)
-			.saturating_sub(T::Staking::active_stake(&account).unwrap_or_default())
-	}
-
 	fn is_root(&self, who: &T::AccountId) -> bool {
 		self.roles.root.as_ref().map_or(false, |root| root == who)
 	}
@@ -1125,8 +1116,7 @@ impl<T: Config> BondedPool<T> {
 	fn ok_to_be_open(&self) -> Result<(), DispatchError> {
 		ensure!(!self.is_destroying(), Error::<T>::CanNotChangeState);
 
-		let bonded_balance =
-			T::Staking::active_stake(&self.bonded_account()).unwrap_or(Zero::zero());
+		let bonded_balance = T::StakeAdapter::active_stake(self.id);
 		ensure!(!bonded_balance.is_zero(), Error::<T>::OverflowRisk);
 
 		let points_to_balance_ratio_floor = self
@@ -1255,22 +1245,14 @@ impl<T: Config> BondedPool<T> {
 		amount: BalanceOf<T>,
 		ty: BondType,
 	) -> Result<BalanceOf<T>, DispatchError> {
-		// Cache the value
-		let bonded_account = self.bonded_account();
-
 		// We must calculate the points issued *before* we bond who's funds, else points:balance
 		// ratio will be wrong.
 		let points_issued = self.issue(amount);
-		let reward_account = self.reward_account();
-
-		match ty {
-			BondType::Create =>
-				T::StakeAdapter::delegator_bond(who, &bonded_account, &reward_account, amount)?,
-			// The pool should always be created in such a way its in a state to bond extra, but if
-			// the active balance is slashed below the minimum bonded or the account cannot be
-			// found, we exit early.
-			BondType::Later => T::StakeAdapter::delegator_bond_extra(who, &bonded_account, amount)?,
-		}
+
+		// The pool should always be created in such a way it is in a state to bond extra, but if
+		// the active balance is slashed below the minimum bonded or the account cannot be
+		// found, we exit early.
+		T::StakeAdapter::bond(who, self.id, amount, ty)?;
 		TotalValueLocked::<T>::mutate(|tvl| {
 			tvl.saturating_accrue(amount);
 		});
@@ -1291,7 +1273,7 @@ impl<T: Config> BondedPool<T> {
 	}
 
 	fn has_pending_slash(&self) -> bool {
-		T::Staking::has_pending_slash(&self.bonded_account())
+		T::StakeAdapter::has_pending_slash(self.id)
 	}
 }
 
@@ -1564,8 +1546,8 @@ impl<T: Config> Get<u32> for TotalUnbondingPools<T> {
 	fn get() -> u32 {
 		// NOTE: this may be dangerous in the scenario bonding_duration gets decreased because
 		// we would no longer be able to decode `BoundedBTreeMap::<EraIndex, UnbondPool<T>,
-		// TotalUnbondingPools<T>>`, which uses `TotalUnbondingPools` as the bound
-		T::Staking::bonding_duration() + T::PostUnbondingPoolsWindow::get()
+		// TotalUnbondingPools<T>>`, werh uses `TotalUnbondingPools` as the bound
+		T::StakeAdapter::bonding_duration() + T::PostUnbondingPoolsWindow::get()
 	}
 }
 
@@ -1641,9 +1623,6 @@ pub mod pallet {
 		/// Infallible method for converting `U256` to `Currency::Balance`.
 		type U256ToBalance: Convert<U256, BalanceOf<Self>>;
 
-		/// The interface for nominating.
-		type Staking: StakingInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
-
 		/// The amount of eras a `SubPools::with_era` pool can exist before it gets merged into the
 		/// `SubPools::no_era` pool. In other words, this is the amount of eras a member will be
 		/// able to withdraw from an unbonding pool which is guaranteed to have the correct ratio of
@@ -1655,7 +1634,7 @@ pub mod pallet {
 		type MaxMetadataLen: Get<u32>;
 
 		/// An adapter to support delegated to direct staking.
-		type StakeAdapter: adapter::StakeAdapter<
+		type StakeAdapter: adapter::StakeStrategy<
 			AccountId = Self::AccountId,
 			Balance = BalanceOf<Self>,
 		>;
@@ -1966,6 +1945,8 @@ pub mod pallet {
 		/// The bonded account should only be killed by the staking system when the depositor is
 		/// withdrawing
 		BondedStashKilledPrematurely,
+		/// Using stake strategy that does not support delegation
+		DelegationUnsupported,
 	}
 
 	impl<T> From<DefensiveError> for Error<T> {
@@ -2142,12 +2123,12 @@ pub mod pallet {
 				&mut reward_pool,
 			)?;
 
-			let current_era = T::Staking::current_era();
-			let unbond_era = T::Staking::bonding_duration().saturating_add(current_era);
+			let current_era = T::StakeAdapter::current_era();
+			let unbond_era = T::StakeAdapter::bonding_duration().saturating_add(current_era);
 
 			// Unbond in the actual underlying nominator.
 			let unbonding_balance = bonded_pool.dissolve(unbonding_points);
-			T::Staking::unbond(&bonded_pool.bonded_account(), unbonding_balance)?;
+			T::StakeAdapter::unbond(bonded_pool.id, unbonding_balance)?;
 
 			// Note that we lazily create the unbonding pools here if they don't already exist
 			let mut sub_pools = SubPoolsStorage::<T>::get(member.pool_id)
@@ -2210,7 +2191,7 @@ pub mod pallet {
 			// For now we only allow a pool to withdraw unbonded if its not destroying. If the pool
 			// is destroying then `withdraw_unbonded` can be used.
 			ensure!(pool.state != PoolState::Destroying, Error::<T>::NotDestroying);
-			T::Staking::withdraw_unbonded(pool.bonded_account(), num_slashing_spans)?;
+			T::StakeAdapter::withdraw_unbonded(pool_id, num_slashing_spans)?;
 
 			Ok(())
 		}
@@ -2247,7 +2228,7 @@ pub mod pallet {
 			let member_account = T::Lookup::lookup(member_account)?;
 			let mut member =
 				PoolMembers::<T>::get(&member_account).ok_or(Error::<T>::PoolMemberNotFound)?;
-			let current_era = T::Staking::current_era();
+			let current_era = T::StakeAdapter::current_era();
 
 			let bonded_pool = BondedPool::<T>::get(member.pool_id)
 				.defensive_ok_or::<Error<T>>(DefensiveError::PoolNotFound.into())?;
@@ -2268,7 +2249,7 @@ pub mod pallet {
 			// Before calculating the `balance_to_unbond`, we call withdraw unbonded to ensure the
 			// `transferrable_balance` is correct.
 			let stash_killed =
-				T::Staking::withdraw_unbonded(bonded_pool.bonded_account(), num_slashing_spans)?;
+				T::StakeAdapter::withdraw_unbonded(bonded_pool.id, num_slashing_spans)?;
 
 			// defensive-only: the depositor puts enough funds into the stash so that it will only
 			// be destroyed when they are leaving.
@@ -2301,14 +2282,10 @@ pub mod pallet {
 				// don't exist. This check is also defensive in cases where the unbond pool does not
 				// update its balance (e.g. a bug in the slashing hook.) We gracefully proceed in
 				// order to ensure members can leave the pool and it can be destroyed.
-				.min(bonded_pool.transferable_balance());
+				.min(T::StakeAdapter::transferable_balance(bonded_pool.id));
 
-			T::StakeAdapter::delegator_withdraw(
-				&member_account,
-				&bonded_pool.bonded_account(),
-				balance_to_unbond,
-			)
-			.defensive()?;
+			T::StakeAdapter::member_withdraw(&member_account, bonded_pool.id, balance_to_unbond)
+				.defensive()?;
 
 			Self::deposit_event(Event::<T>::Withdrawn {
 				member: member_account.clone(),
@@ -2423,7 +2400,7 @@ pub mod pallet {
 			let who = ensure_signed(origin)?;
 			let bonded_pool = BondedPool::<T>::get(pool_id).ok_or(Error::<T>::PoolNotFound)?;
 			ensure!(bonded_pool.can_nominate(&who), Error::<T>::NotNominator);
-			T::Staking::nominate(&bonded_pool.bonded_account(), validators)
+			T::StakeAdapter::nominate(bonded_pool.id, validators)
 		}
 
 		/// Set a new state for the pool.
@@ -2596,7 +2573,7 @@ pub mod pallet {
 			let who = ensure_signed(origin)?;
 			let bonded_pool = BondedPool::<T>::get(pool_id).ok_or(Error::<T>::PoolNotFound)?;
 			ensure!(bonded_pool.can_nominate(&who), Error::<T>::NotNominator);
-			T::Staking::chill(&bonded_pool.bonded_account())
+			T::StakeAdapter::chill(bonded_pool.id)
 		}
 
 		/// `origin` bonds funds from `extra` for some pool member `member` into their respective
@@ -2824,7 +2801,7 @@ pub mod pallet {
 				"Minimum points to balance ratio must be greater than 0"
 			);
 			assert!(
-				T::Staking::bonding_duration() < TotalUnbondingPools::<T>::get(),
+				T::StakeAdapter::bonding_duration() < TotalUnbondingPools::<T>::get(),
 				"There must be more unbonding pools then the bonding duration /
 				so a slash can be applied to relevant unboding pools. (We assume /
 				the bonding duration > slash deffer duration.",
@@ -2842,7 +2819,7 @@ impl<T: Config> Pallet<T> {
 	/// It is essentially `max { MinNominatorBond, MinCreateBond, MinJoinBond }`, where the former
 	/// is coming from the staking pallet and the latter two are configured in this pallet.
 	pub fn depositor_min_bond() -> BalanceOf<T> {
-		T::Staking::minimum_nominator_bond()
+		T::StakeAdapter::minimum_nominator_bond()
 			.max(MinCreateBond::<T>::get())
 			.max(MinJoinBond::<T>::get())
 			.max(T::Currency::minimum_balance())
@@ -2878,7 +2855,7 @@ impl<T: Config> Pallet<T> {
 			"bonded account of dissolving pool should have no consumers"
 		);
 		defensive_assert!(
-			T::Staking::total_stake(&bonded_account).unwrap_or_default() == Zero::zero(),
+			T::StakeAdapter::total_stake(bonded_pool.id) == Zero::zero(),
 			"dissolving pool should not have any stake in the staking pallet"
 		);
 
@@ -2901,7 +2878,7 @@ impl<T: Config> Pallet<T> {
 			"could not transfer all amount to depositor while dissolving pool"
 		);
 		defensive_assert!(
-			T::StakeAdapter::total_balance(&bonded_pool.bonded_account()) == Zero::zero(),
+			T::StakeAdapter::total_balance(bonded_pool.id) == Zero::zero(),
 			"dissolving pool should not have any balance"
 		);
 		// NOTE: Defensively force set balance to zero.
@@ -3296,10 +3273,9 @@ impl<T: Config> Pallet<T> {
 		// calculate points to be slashed.
 		let member =
 			PoolMembers::<T>::get(&member_account).ok_or(Error::<T>::PoolMemberNotFound)?;
-		let bonded_account = Self::create_bonded_account(member.pool_id);
-		ensure!(T::Staking::has_pending_slash(&bonded_account), Error::<T>::NothingToSlash);
+		ensure!(T::StakeAdapter::has_pending_slash(member.pool_id), Error::<T>::NothingToSlash);
 
-		let delegated_balance = T::Staking::delegated_balance(&member_account);
+		let delegated_balance = T::StakeAdapter::member_delegation_balance(&member_account);
 		let current_balance = member.total_balance();
 		defensive_assert!(
 			delegated_balance >= current_balance,
@@ -3309,9 +3285,9 @@ impl<T: Config> Pallet<T> {
 		// if nothing to slash, return error.
 		ensure!(delegated_balance > current_balance, Error::<T>::NothingToSlash);
 
-		T::Staking::delegator_slash(
-			&bonded_account,
+		T::StakeAdapter::member_slash(
 			&member_account,
+			member.pool_id,
 			delegated_balance.defensive_saturating_sub(current_balance),
 			reporter,
 		)
@@ -3480,8 +3456,7 @@ impl<T: Config> Pallet<T> {
 				pool is being destroyed and the depositor is the last member",
 			);
 
-			expected_tvl +=
-				T::Staking::total_stake(&bonded_pool.bonded_account()).unwrap_or_default();
+			expected_tvl += T::StakeAdapter::total_stake(bonded_pool.id);
 
 			Ok(())
 		})?;
@@ -3506,12 +3481,11 @@ impl<T: Config> Pallet<T> {
 		}
 
 		for (pool_id, _pool) in BondedPools::<T>::iter() {
-			let pool_account = Pallet::<T>::create_bonded_account(pool_id);
 			let subs = SubPoolsStorage::<T>::get(pool_id).unwrap_or_default();
 
 			let sum_unbonding_balance = subs.sum_unbonding_balance();
-			let bonded_balance = T::Staking::active_stake(&pool_account).unwrap_or_default();
-			let total_balance = T::StakeAdapter::total_balance(&pool_account);
+			let bonded_balance = T::StakeAdapter::active_stake(pool_id);
+			let total_balance = T::StakeAdapter::total_balance(pool_id);
 
 			assert!(
                 total_balance >= bonded_balance + sum_unbonding_balance,
@@ -3614,8 +3588,7 @@ impl<T: Config> Pallet<T> {
 	/// If the pool ID does not exist, returns 0 ratio balance to points. Used by runtime API.
 	pub fn api_balance_to_points(pool_id: PoolId, new_funds: BalanceOf<T>) -> BalanceOf<T> {
 		if let Some(pool) = BondedPool::<T>::get(pool_id) {
-			let bonded_balance =
-				T::Staking::active_stake(&pool.bonded_account()).unwrap_or(Zero::zero());
+			let bonded_balance = T::StakeAdapter::active_stake(pool.id);
 			Pallet::<T>::balance_to_point(bonded_balance, pool.points, new_funds)
 		} else {
 			Zero::zero()
diff --git a/substrate/frame/nomination-pools/src/migration.rs b/substrate/frame/nomination-pools/src/migration.rs
index 6887fcfa7ecad..89fa91e2063d8 100644
--- a/substrate/frame/nomination-pools/src/migration.rs
+++ b/substrate/frame/nomination-pools/src/migration.rs
@@ -1023,10 +1023,7 @@ mod helpers {
 
 	pub(crate) fn calculate_tvl_by_total_stake<T: Config>() -> BalanceOf<T> {
 		BondedPools::<T>::iter()
-			.map(|(id, inner)| {
-				T::Staking::total_stake(&BondedPool { id, inner: inner.clone() }.bonded_account())
-					.unwrap_or_default()
-			})
+			.map(|(id, _inner)| T::StakeAdapter::total_stake(id))
 			.reduce(|acc, total_balance| acc + total_balance)
 			.unwrap_or_default()
 	}
diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs
index 7fec33043fbd3..23b356a62c31e 100644
--- a/substrate/frame/nomination-pools/src/mock.rs
+++ b/substrate/frame/nomination-pools/src/mock.rs
@@ -228,61 +228,6 @@ impl sp_staking::StakingInterface for StakingMock {
 	fn unsafe_release_all(_who: &Self::AccountId) {
 		unimplemented!("method currently not used in testing")
 	}
-
-	fn is_delegatee(who: &Self::AccountId) -> bool {
-		unimplemented!("method currently not used in testing")
-	}
-
-	/// Effective balance of the delegatee account.
-	fn delegatee_balance(who: &Self::AccountId) -> Self::Balance {
-		unimplemented!("method currently not used in testing")
-	}
-
-	/// Delegate funds to `Delegatee`.
-	fn delegate(
-		who: &Self::AccountId,
-		delegatee: &Self::AccountId,
-		reward_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult {
-		unimplemented!("method currently not used in testing")
-	}
-
-	/// Add more delegation to the pool account.
-	fn delegate_extra(
-		who: &Self::AccountId,
-		delegatee: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult {
-		unimplemented!("method currently not used in testing")
-	}
-
-	/// Withdraw delegation from pool account to self.
-	fn withdraw_delegation(
-		who: &Self::AccountId,
-		delegatee: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult {
-		unimplemented!("method currently not used in testing")
-	}
-
-	/// Does the delegatee have any pending slash.
-	fn has_pending_slash(delegatee: &Self::AccountId) -> bool {
-		false
-	}
-
-	fn delegator_slash(
-		delegatee: &Self::AccountId,
-		delegator: &Self::AccountId,
-		value: Self::Balance,
-		maybe_reporter: Option<Self::AccountId>,
-	) -> sp_runtime::DispatchResult {
-		unimplemented!("method currently not used in testing")
-	}
-
-	fn delegated_balance(delegator: &Self::AccountId) -> Self::Balance {
-		unimplemented!("method currently not used in testing")
-	}
 }
 
 #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
@@ -360,13 +305,12 @@ impl pools::Config for Runtime {
 	type RewardCounter = RewardCounter;
 	type BalanceToU256 = BalanceToU256;
 	type U256ToBalance = U256ToBalance;
-	type Staking = StakingMock;
 	type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow;
 	type PalletId = PoolsPalletId;
 	type MaxMetadataLen = MaxMetadataLen;
 	type MaxUnbonding = MaxUnbonding;
 	type MaxPointsToBalance = frame_support::traits::ConstU8<10>;
-	type StakeAdapter = adapter::TransferStake<Self>;
+	type StakeAdapter = adapter::TransferStake<Self, StakingMock>;
 }
 
 type Block = frame_system::mocking::MockBlock<Runtime>;
diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs
index 54dfe198c6607..189294ffe9a2d 100644
--- a/substrate/frame/nomination-pools/test-staking/src/mock.rs
+++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs
@@ -181,13 +181,12 @@ impl pallet_nomination_pools::Config for Runtime {
 	type RewardCounter = FixedU128;
 	type BalanceToU256 = BalanceToU256;
 	type U256ToBalance = U256ToBalance;
-	type Staking = Staking;
 	type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow;
 	type MaxMetadataLen = ConstU32<256>;
 	type MaxUnbonding = ConstU32<8>;
 	type MaxPointsToBalance = ConstU8<10>;
 	type PalletId = PoolsPalletId;
-	type StakeAdapter = pallet_nomination_pools::adapter::TransferStake<Self>;
+	type StakeAdapter = pallet_nomination_pools::adapter::TransferStake<Self, Staking>;
 }
 
 type Block = frame_system::mocking::MockBlock<Runtime>;
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index bd3af7d103de9..5302fdbebb2d0 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -39,12 +39,12 @@ use sp_runtime::{
 	Perbill, Percent,
 };
 use sp_staking::{
-    currency_to_vote::CurrencyToVote,
-    delegation::DelegateeSupport,
-    offence::{DisableStrategy, OffenceDetails, OnOffenceHandler},
-    EraIndex, OnStakingUpdate, Page, SessionIndex, Stake,
-    StakingAccount::{self, Controller, Stash},
-    StakingInterface,
+	currency_to_vote::CurrencyToVote,
+	delegation::DelegateeSupport,
+	offence::{DisableStrategy, OffenceDetails, OnOffenceHandler},
+	EraIndex, OnStakingUpdate, Page, SessionIndex, Stake,
+	StakingAccount::{self, Controller, Stash},
+	StakingInterface,
 };
 use sp_std::prelude::*;
 
@@ -1870,64 +1870,6 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	fn unsafe_release_all(who: &Self::AccountId) {
 		T::Currency::remove_lock(crate::STAKING_ID, who)
 	}
-
-	fn is_delegatee(_who: &Self::AccountId) -> bool {
-		defensive!("is_delegatee is not supported");
-		false
-	}
-
-	fn delegatee_balance(_who: &Self::AccountId) -> Self::Balance {
-		defensive!("delegatee_balance is not supported");
-		BalanceOf::<T>::zero()
-	}
-
-	/// Delegate funds to `Delegatee`.
-	fn delegate(
-		_who: &Self::AccountId,
-		_delegatee: &Self::AccountId,
-		_reward_account: &Self::AccountId,
-		_amount: Self::Balance,
-	) -> DispatchResult {
-		Err(DispatchError::Other("delegate is not supported"))
-	}
-
-	/// Add more delegation to the pool account.
-	fn delegate_extra(
-		_who: &Self::AccountId,
-		_delegatee: &Self::AccountId,
-		_amount: Self::Balance,
-	) -> DispatchResult {
-		Err(DispatchError::Other("delegate_extra is not supported"))
-	}
-
-	/// Withdraw delegation from pool account to self.
-	fn withdraw_delegation(
-		_who: &Self::AccountId,
-		_delegatee: &Self::AccountId,
-		_amount: Self::Balance,
-	) -> DispatchResult {
-		Err(DispatchError::Other("withdraw_delegation is not supported"))
-	}
-
-	/// Does the delegatee have any pending slash.
-	fn has_pending_slash(_delegatee: &Self::AccountId) -> bool {
-		// slashing is greedy, so no pending slash.
-		false
-	}
-
-	fn delegator_slash(
-		_delegatee: &Self::AccountId,
-		_delegator: &Self::AccountId,
-		_value: Self::Balance,
-		_maybe_reporter: Option<Self::AccountId>,
-	) -> sp_runtime::DispatchResult {
-		Err(DispatchError::Other("delegator_slash is not supported"))
-	}
-
-	fn delegated_balance(_delegator: &Self::AccountId) -> Self::Balance {
-		defensive!("delegated_balance is not supported");
-		BalanceOf::<T>::zero()
-	}
 }
 
 /// Standard implementation of `DelegateeSupport` that supports only direct staking and no
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index 861eda3016467..6fce9dd84c262 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -37,9 +37,9 @@ use sp_runtime::{
 };
 
 use sp_staking::{
-    delegation::DelegateeSupport,
-    EraIndex, Page, SessionIndex,
-    StakingAccount::{self, Controller, Stash},
+	delegation::DelegateeSupport,
+	EraIndex, Page, SessionIndex,
+	StakingAccount::{self, Controller, Stash},
 };
 use sp_std::prelude::*;
 
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index c8a9f366d701d..7490f97cecdbb 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -15,9 +15,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+use crate::StakingInterface;
 use codec::{FullCodec, MaxEncodedLen};
 use scale_info::TypeInfo;
-use sp_runtime::Saturating;
+use sp_runtime::{DispatchResult, Saturating};
 use sp_std::ops::Sub;
 
 /// A trait that can be used as a plugin to support delegation based accounts, called `Delegatee`.
@@ -62,3 +63,49 @@ pub trait DelegateeSupport {
 	/// delegators. This function should bookkeep the slash to be applied later.
 	fn report_slash(who: &Self::AccountId, slash: Self::Balance);
 }
+
+pub trait DelegatedStakeInterface: StakingInterface {
+	/// Returns true if who is a `delegatee` account.
+	fn is_delegatee(who: &Self::AccountId) -> bool;
+
+	/// Effective balance of the delegatee account.
+	fn delegatee_balance(who: &Self::AccountId) -> Self::Balance;
+
+	/// Delegate funds to `Delegatee`.
+	fn delegate(
+		delegator: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		reward_account: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
+
+	/// Add more delegation to the `delegatee`.
+	fn delegate_extra(
+		delegator: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
+
+	/// Withdraw or revoke delegation to `delegatee`.
+	fn withdraw_delegation(
+		who: &Self::AccountId,
+		delegatee: &Self::AccountId,
+		amount: Self::Balance,
+	) -> DispatchResult;
+
+	/// Returns true if there are pending slashes posted to the `delegatee` account.
+	fn has_pending_slash(delegatee: &Self::AccountId) -> bool;
+
+	/// Apply a pending slash to a `delegatee` by slashing `value` from `delegator`.
+	///
+	/// If a reporter is provided, the reporter will receive a fraction of the slash as reward.
+	fn delegator_slash(
+		delegatee: &Self::AccountId,
+		delegator: &Self::AccountId,
+		value: Self::Balance,
+		maybe_reporter: Option<Self::AccountId>,
+	) -> sp_runtime::DispatchResult;
+
+	/// Returns the total amount of funds delegated by a `delegator`.
+	fn delegated_balance(delegator: &Self::AccountId) -> Self::Balance;
+}
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 5131d0d9dc36d..d1ae0f65bf1f5 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -309,53 +309,6 @@ pub trait StakingInterface {
 
 	#[cfg(feature = "runtime-benchmarks")]
 	fn set_current_era(era: EraIndex);
-
-	// FIXME(ank4n): Break down this trait maybe? It is too bloated currently.
-
-	/// Returns true if who is a `delegatee` account.
-	fn is_delegatee(who: &Self::AccountId) -> bool;
-
-	/// Effective balance of the delegatee account.
-	fn delegatee_balance(who: &Self::AccountId) -> Self::Balance;
-
-	/// Delegate funds to `Delegatee`.
-	fn delegate(
-		delegator: &Self::AccountId,
-		delegatee: &Self::AccountId,
-		reward_account: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult;
-
-	/// Add more delegation to the `delegatee`.
-	fn delegate_extra(
-		delegator: &Self::AccountId,
-		delegatee: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult;
-
-	/// Withdraw or revoke delegation to `delegatee`.
-	fn withdraw_delegation(
-		who: &Self::AccountId,
-		delegatee: &Self::AccountId,
-		amount: Self::Balance,
-	) -> DispatchResult;
-
-	/// Returns true if there are pending slashes posted to the `delegatee` account.
-	fn has_pending_slash(delegatee: &Self::AccountId) -> bool;
-
-	/// Apply a pending slash to a `delegatee` by slashing `value` from `delegator`.
-	///
-	/// If a reporter is provided, the reporter will receive a fraction of the slash as reward.
-	fn delegator_slash(
-		delegatee: &Self::AccountId,
-		delegator: &Self::AccountId,
-		value: Self::Balance,
-		maybe_reporter: Option<Self::AccountId>,
-	) -> sp_runtime::DispatchResult;
-
-
-	/// Returns the total amount of funds delegated by a `delegator`.
-	fn delegated_balance(delegator: &Self::AccountId) -> Self::Balance;
 }
 
 /// The amount of exposure for an era that an individual nominator has (susceptible to slashing).

From df13e493880ac9f7b63e6f843b741775e50e71c2 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Wed, 28 Feb 2024 11:22:38 +0100
Subject: [PATCH 182/202] small doc update

---
 substrate/primitives/staking/src/delegation.rs | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 7490f97cecdbb..6144dcc53bc66 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -64,14 +64,16 @@ pub trait DelegateeSupport {
 	fn report_slash(who: &Self::AccountId, slash: Self::Balance);
 }
 
+/// Trait that extends on [`StakingInterface`] to provide additional capability to delegate funds to
+/// an account.
 pub trait DelegatedStakeInterface: StakingInterface {
 	/// Returns true if who is a `delegatee` account.
 	fn is_delegatee(who: &Self::AccountId) -> bool;
 
-	/// Effective balance of the delegatee account.
+	/// Effective balance of the `delegatee` account.
 	fn delegatee_balance(who: &Self::AccountId) -> Self::Balance;
 
-	/// Delegate funds to `Delegatee`.
+	/// Delegate funds to `delegatee`.
 	fn delegate(
 		delegator: &Self::AccountId,
 		delegatee: &Self::AccountId,

From 11bb08403e60438864e5af68cfb8d95bd2ee7172 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Wed, 28 Feb 2024 11:35:02 +0100
Subject: [PATCH 183/202] reorder methods

---
 substrate/frame/delegated-staking/src/impls.rs | 12 ++++--------
 substrate/primitives/staking/src/delegation.rs |  9 +++------
 2 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 67ff007b6d271..34d409eb16225 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -197,10 +197,6 @@ impl<T: Config> StakingInterface for Pallet<T> {
 }
 
 impl<T: Config> DelegatedStakeInterface for Pallet<T> {
-	fn is_delegatee(who: &Self::AccountId) -> bool {
-		Self::is_delegatee(who)
-	}
-
 	/// Effective balance of the delegatee account.
 	fn delegatee_balance(who: &Self::AccountId) -> Self::Balance {
 		Delegatee::<T>::from(who)
@@ -208,6 +204,10 @@ impl<T: Config> DelegatedStakeInterface for Pallet<T> {
 			.unwrap_or_default()
 	}
 
+	fn delegated_balance(delegator: &Self::AccountId) -> Self::Balance {
+		Delegation::<T>::get(delegator).map(|d| d.amount).unwrap_or_default()
+	}
+
 	/// Delegate funds to `Delegatee`.
 	fn delegate(
 		who: &Self::AccountId,
@@ -266,10 +266,6 @@ impl<T: Config> DelegatedStakeInterface for Pallet<T> {
 	) -> sp_runtime::DispatchResult {
 		Pallet::<T>::do_slash(delegatee.clone(), delegator.clone(), value, maybe_reporter)
 	}
-
-	fn delegated_balance(delegator: &Self::AccountId) -> Self::Balance {
-		Delegation::<T>::get(delegator).map(|d| d.amount).unwrap_or_default()
-	}
 }
 
 impl<T: Config> DelegateeSupport for Pallet<T> {
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 6144dcc53bc66..5bde51f5a0ea6 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -67,12 +67,12 @@ pub trait DelegateeSupport {
 /// Trait that extends on [`StakingInterface`] to provide additional capability to delegate funds to
 /// an account.
 pub trait DelegatedStakeInterface: StakingInterface {
-	/// Returns true if who is a `delegatee` account.
-	fn is_delegatee(who: &Self::AccountId) -> bool;
-
 	/// Effective balance of the `delegatee` account.
 	fn delegatee_balance(who: &Self::AccountId) -> Self::Balance;
 
+	/// Returns the total amount of funds delegated by a `delegator`.
+	fn delegated_balance(delegator: &Self::AccountId) -> Self::Balance;
+
 	/// Delegate funds to `delegatee`.
 	fn delegate(
 		delegator: &Self::AccountId,
@@ -107,7 +107,4 @@ pub trait DelegatedStakeInterface: StakingInterface {
 		value: Self::Balance,
 		maybe_reporter: Option<Self::AccountId>,
 	) -> sp_runtime::DispatchResult;
-
-	/// Returns the total amount of funds delegated by a `delegator`.
-	fn delegated_balance(delegator: &Self::AccountId) -> Self::Balance;
 }

From 78ea6aee79511c1875e49d45affb418bf0e90c02 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Wed, 28 Feb 2024 20:27:51 +0100
Subject: [PATCH 184/202] minor

---
 substrate/primitives/staking/src/delegation.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 5bde51f5a0ea6..84a50273e2913 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -68,7 +68,7 @@ pub trait DelegateeSupport {
 /// an account.
 pub trait DelegatedStakeInterface: StakingInterface {
 	/// Effective balance of the `delegatee` account.
-	fn delegatee_balance(who: &Self::AccountId) -> Self::Balance;
+	fn delegatee_balance(delegatee: &Self::AccountId) -> Self::Balance;
 
 	/// Returns the total amount of funds delegated by a `delegator`.
 	fn delegated_balance(delegator: &Self::AccountId) -> Self::Balance;
@@ -90,7 +90,7 @@ pub trait DelegatedStakeInterface: StakingInterface {
 
 	/// Withdraw or revoke delegation to `delegatee`.
 	fn withdraw_delegation(
-		who: &Self::AccountId,
+		delegator: &Self::AccountId,
 		delegatee: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult;

From ef3b3e79be94884cc6c39a70c00635888f678b49 Mon Sep 17 00:00:00 2001
From: Ankan <10196091+Ank4n@users.noreply.github.com>
Date: Thu, 29 Feb 2024 13:19:49 +0100
Subject: [PATCH 185/202] Update substrate/frame/delegated-staking/Cargo.toml
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Gonçalo Pestana <g6pestana@gmail.com>
---
 substrate/frame/delegated-staking/Cargo.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/substrate/frame/delegated-staking/Cargo.toml b/substrate/frame/delegated-staking/Cargo.toml
index 4b278af64cf3a..b4b9768256c61 100644
--- a/substrate/frame/delegated-staking/Cargo.toml
+++ b/substrate/frame/delegated-staking/Cargo.toml
@@ -6,7 +6,7 @@ edition.workspace = true
 license = "Apache-2.0"
 homepage = "https://substrate.io"
 repository.workspace = true
-description = "FRAME safe-mode pallet"
+description = "FRAME delegated staking pallet"
 
 [package.metadata.docs.rs]
 targets = ["x86_64-unknown-linux-gnu"]

From b4ef3972646740c1db6fdcf53e8cc8cfeffbf270 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 29 Feb 2024 13:46:38 +0100
Subject: [PATCH 186/202] fix pr feedbacks

---
 .../frame/delegated-staking/src/impls.rs      | 45 ++++++++++---------
 substrate/frame/delegated-staking/src/lib.rs  |  2 +-
 .../primitives/staking/src/delegation.rs      |  4 ++
 3 files changed, 28 insertions(+), 23 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 34d409eb16225..87be6e73eb5ae 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -35,12 +35,10 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	fn minimum_validator_bond() -> Self::Balance {
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
 		T::CoreStaking::minimum_validator_bond()
 	}
 
 	fn stash_by_ctrl(_controller: &Self::AccountId) -> Result<Self::AccountId, DispatchError> {
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
 		// ctrl are deprecated, just return err.
 		Err(Error::<T>::NotSupported.into())
 	}
@@ -90,7 +88,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		payee: &Self::AccountId,
 	) -> DispatchResult {
 		// ensure who is not already staked
-		ensure!(T::CoreStaking::status(who).is_err(), Error::<T>::NotDelegatee);
+		ensure!(T::CoreStaking::status(who).is_err(), Error::<T>::AlreadyStaker);
 		let delegatee = Delegatee::<T>::from(who)?;
 
 		ensure!(delegatee.available_to_bond() >= value, Error::<T>::NotEnoughFunds);
@@ -100,18 +98,18 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	fn nominate(who: &Self::AccountId, validators: Vec<Self::AccountId>) -> DispatchResult {
-		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
+		ensure!(Self::is_delegatee(who), Error::<T>::NotDelegatee);
 		return T::CoreStaking::nominate(who, validators);
 	}
 
 	fn chill(who: &Self::AccountId) -> DispatchResult {
-		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
+		ensure!(Self::is_delegatee(who), Error::<T>::NotDelegatee);
 		return T::CoreStaking::chill(who);
 	}
 
 	fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult {
-		let delegation_register = <Delegatees<T>>::get(who).ok_or(Error::<T>::NotDelegatee)?;
-		ensure!(delegation_register.stakeable_balance() >= extra, Error::<T>::NotEnoughFunds);
+		let ledger = <Delegatees<T>>::get(who).ok_or(Error::<T>::NotDelegatee)?;
+		ensure!(ledger.stakeable_balance() >= extra, Error::<T>::NotEnoughFunds);
 
 		T::CoreStaking::bond_extra(who, extra)
 	}
@@ -127,40 +125,35 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	///
 	/// Funds are moved to unclaimed_withdrawals register of the `DelegateeLedger`.
 	fn withdraw_unbonded(
-		pool_acc: Self::AccountId,
+		delegatee_acc: Self::AccountId,
 		num_slashing_spans: u32,
 	) -> Result<bool, DispatchError> {
-		Pallet::<T>::withdraw_unbonded(&pool_acc, num_slashing_spans)
+		Pallet::<T>::withdraw_unbonded(&delegatee_acc, num_slashing_spans)
 			.map(|delegatee| delegatee.ledger.total_delegated.is_zero())
 	}
 
 	fn desired_validator_count() -> u32 {
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
 		T::CoreStaking::desired_validator_count()
 	}
 
 	fn election_ongoing() -> bool {
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
 		T::CoreStaking::election_ongoing()
 	}
 
 	fn force_unstake(_who: Self::AccountId) -> DispatchResult {
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
 		Err(Error::<T>::NotSupported.into())
 	}
 
 	fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool {
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
 		T::CoreStaking::is_exposed_in_era(who, era)
 	}
 
 	fn status(who: &Self::AccountId) -> Result<StakerStatus<Self::AccountId>, DispatchError> {
-		ensure!(Self::is_delegatee(who), Error::<T>::NotSupported);
+		ensure!(Self::is_delegatee(who), Error::<T>::NotDelegatee);
 		T::CoreStaking::status(who)
 	}
 
 	fn is_validator(who: &Self::AccountId) -> bool {
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
 		T::CoreStaking::is_validator(who)
 	}
 
@@ -173,7 +166,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	}
 
 	fn unsafe_release_all(_who: &Self::AccountId) {
-		defensive_assert!(false, "not supported for delegated impl of staking interface");
+		defensive_assert!(false, "unsafe_release_all is not supported");
 	}
 
 	#[cfg(feature = "runtime-benchmarks")]
@@ -228,7 +221,7 @@ impl<T: Config> DelegatedStakeInterface for Pallet<T> {
 		)
 	}
 
-	/// Add more delegation to the pool account.
+	/// Add more delegation to the delegatee account.
 	fn delegate_extra(
 		who: &Self::AccountId,
 		delegatee: &Self::AccountId,
@@ -241,17 +234,25 @@ impl<T: Config> DelegatedStakeInterface for Pallet<T> {
 		)
 	}
 
-	/// Withdraw delegation from pool account to self.
+	/// Withdraw delegation of `delegator` to `delegatee`.
+	///
+	/// If there are funds in `delegatee` account that can be withdrawn, then those funds would be
+	/// unlocked/released in the delegator's account.
 	fn withdraw_delegation(
-		who: &Self::AccountId,
+		delegator: &Self::AccountId,
 		delegatee: &Self::AccountId,
 		amount: Self::Balance,
 	) -> DispatchResult {
-		// fixme(ank4n): This should not require slashing spans.
-		Pallet::<T>::release(RawOrigin::Signed(delegatee.clone()).into(), who.clone(), amount, 0)
+		// fixme(ank4n): Can this not require slashing spans?
+		Pallet::<T>::release(
+			RawOrigin::Signed(delegatee.clone()).into(),
+			delegator.clone(),
+			amount,
+			0,
+		)
 	}
 
-	/// Does the delegatee have any pending slash.
+	/// Returns true if the `delegatee` have any slash pending to be applied.
 	fn has_pending_slash(delegatee: &Self::AccountId) -> bool {
 		Delegatee::<T>::from(delegatee)
 			.map(|d| !d.ledger.pending_slash.is_zero())
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 5b180f3e0b219..0bfb57053d351 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -213,7 +213,7 @@ pub mod pallet {
 	pub enum Error<T> {
 		/// The account cannot perform this operation.
 		NotAllowed,
-		/// An existing staker cannot become a `delegatee`.
+		/// An existing staker cannot perform this action.
 		AlreadyStaker,
 		/// Reward Destination cannot be `delegatee` account.
 		InvalidRewardDestination,
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 84a50273e2913..c6e5a1029fc9a 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -46,6 +46,10 @@ pub trait DelegateeSupport {
 
 	/// Returns true if `delegatee` is restricted to update which account they can receive their
 	/// staking rewards.
+	///
+	/// For `delegatee` accounts we restrict the reward destination to be the same as the
+	/// `delegatee` account itself. This is since the actual `delegatee` balances is not considered
+	/// while staking. Instead, their balance is made up of multiple child delegators.
 	fn restrict_reward_destination(
 		_who: &Self::AccountId,
 		_reward_destination: Option<Self::AccountId>,

From 2877d0e9a05f9c0c48ceabb5425832db2c5b87c3 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 29 Feb 2024 13:51:39 +0100
Subject: [PATCH 187/202] rename delegator balance

---
 substrate/frame/delegated-staking/src/impls.rs  | 2 +-
 substrate/frame/delegated-staking/src/lib.rs    | 4 ++--
 substrate/frame/nomination-pools/src/adapter.rs | 2 +-
 substrate/frame/nomination-pools/src/lib.rs     | 2 +-
 substrate/primitives/staking/src/delegation.rs  | 2 +-
 5 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 87be6e73eb5ae..ef0edcf61563e 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -197,7 +197,7 @@ impl<T: Config> DelegatedStakeInterface for Pallet<T> {
 			.unwrap_or_default()
 	}
 
-	fn delegated_balance(delegator: &Self::AccountId) -> Self::Balance {
+	fn delegator_balance(delegator: &Self::AccountId) -> Self::Balance {
 		Delegation::<T>::get(delegator).map(|d| d.amount).unwrap_or_default()
 	}
 
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 0bfb57053d351..97acc10d55768 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -25,7 +25,7 @@
 //!
 //! ## Goals
 //!
-//! The direct nominators on Staking pallet does not scale well. NominationPool was created to
+//! Direct nomination on the Staking pallet does not scale well. Nominations pools were created to
 //! address this by pooling delegator funds into one account and then staking it. This though had
 //! a very important limitation that the funds were moved from delegator account to pool account
 //! and hence the delegator lost control over their funds for using it for other purposes such as
@@ -44,7 +44,7 @@
 //! similar to `NominationPool`.
 //!
 //! ## Key Terminologies
-//! - *delegatee*: An account who accepts delegations from other accounts (called `Delegators`).
+//! - *Delegatee*: An account who accepts delegations from other accounts.
 //! - *Delegator*: An account who delegates their funds to a `delegatee`.
 //! - *DelegateeLedger*: A data structure that stores important information about the `delegatee`
 //! 	such as their total delegated stake.
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index 6546ef5f38d76..c7bf6868e9532 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -224,7 +224,7 @@ impl<
 	}
 
 	fn member_delegation_balance(member_account: &T::AccountId) -> Staking::Balance {
-		Staking::delegated_balance(member_account)
+		Staking::delegator_balance(member_account)
 	}
 
 	fn active_stake(pool: PoolId) -> BalanceOf<T> {
diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs
index 83aefc7219e74..bf75d85097e5e 100644
--- a/substrate/frame/nomination-pools/src/lib.rs
+++ b/substrate/frame/nomination-pools/src/lib.rs
@@ -1633,7 +1633,7 @@ pub mod pallet {
 		/// The maximum length, in bytes, that a pools metadata maybe.
 		type MaxMetadataLen: Get<u32>;
 
-		/// An adapter to support delegated to direct staking.
+		/// Staking adapter to support different staking strategies.
 		type StakeAdapter: adapter::StakeStrategy<
 			AccountId = Self::AccountId,
 			Balance = BalanceOf<Self>,
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index c6e5a1029fc9a..8cf986dad1ffb 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -75,7 +75,7 @@ pub trait DelegatedStakeInterface: StakingInterface {
 	fn delegatee_balance(delegatee: &Self::AccountId) -> Self::Balance;
 
 	/// Returns the total amount of funds delegated by a `delegator`.
-	fn delegated_balance(delegator: &Self::AccountId) -> Self::Balance;
+	fn delegator_balance(delegator: &Self::AccountId) -> Self::Balance;
 
 	/// Delegate funds to `delegatee`.
 	fn delegate(

From 3de4c4aa710d47eb9b1d6beb828eae3deebd7d30 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 29 Feb 2024 14:38:57 +0100
Subject: [PATCH 188/202] add to docs

---
 substrate/frame/delegated-staking/src/lib.rs  | 21 ++++++++++++-------
 .../primitives/staking/src/delegation.rs      | 12 +++++++++++
 2 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 97acc10d55768..1d0c25e98a52d 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -20,8 +20,15 @@
 //! An abstraction over staking pallet to support delegation of funds to a `delegatee` account which
 //! can use all the delegated funds to it in the staking pallet as if its own fund.
 //!
-//! NOTE: The pallet exposes extrinsics which are not yet meant to be exposed in the runtime but
-//! only to be used by other pallets in the same runtime.
+//! NOTE: The pallet exposes some dispatchable calls already, but they might not be fully usable
+//! from outside the runtime. In the current version, the pallet is meant to be used by other
+//! pallets in the same runtime. Eventually though, expect those calls to be functionally complete
+//! and usable by off-chain programs as well as xcm based multi locations.
+//!
+//! Declaring dispatchable still has the benefit of being transactable for unit tests as well as
+//! aligned with general direction of moving towards a permissionless pallet. For example, we could
+//! clearly signal who is the expected signer of any interaction with this pallet and take into
+//! security considerations already.
 //!
 //! ## Goals
 //!
@@ -44,12 +51,12 @@
 //! similar to `NominationPool`.
 //!
 //! ## Key Terminologies
-//! - *Delegatee*: An account who accepts delegations from other accounts.
-//! - *Delegator*: An account who delegates their funds to a `delegatee`.
-//! - *DelegateeLedger*: A data structure that stores important information about the `delegatee`
+//! - **Delegatee**: An account who accepts delegations from other accounts.
+//! - **Delegator**: An account who delegates their funds to a `delegatee`.
+//! - **DelegateeLedger**: A data structure that stores important information about the `delegatee`
 //! 	such as their total delegated stake.
-//! - *Delegation*: A data structure that stores the amount of funds delegated to a `delegatee` by a
-//! 	`delegator`.
+//! - **Delegation**: A data structure that stores the amount of funds delegated to a `delegatee` by
+//! 	a `delegator`.
 //!
 //! ## Interface
 //!
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 8cf986dad1ffb..7d970d567d9e7 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -72,12 +72,16 @@ pub trait DelegateeSupport {
 /// an account.
 pub trait DelegatedStakeInterface: StakingInterface {
 	/// Effective balance of the `delegatee` account.
+	///
+	/// This takes into account any pending slashes to `Delegatee`.
 	fn delegatee_balance(delegatee: &Self::AccountId) -> Self::Balance;
 
 	/// Returns the total amount of funds delegated by a `delegator`.
 	fn delegator_balance(delegator: &Self::AccountId) -> Self::Balance;
 
 	/// Delegate funds to `delegatee`.
+	///
+	/// Only used for the initial delegation. Use [`Self::delegate_extra`] to add more delegation.
 	fn delegate(
 		delegator: &Self::AccountId,
 		delegatee: &Self::AccountId,
@@ -86,6 +90,8 @@ pub trait DelegatedStakeInterface: StakingInterface {
 	) -> DispatchResult;
 
 	/// Add more delegation to the `delegatee`.
+	///
+	/// If this is the first delegation, use [`Self::delegate`] instead.
 	fn delegate_extra(
 		delegator: &Self::AccountId,
 		delegatee: &Self::AccountId,
@@ -93,6 +99,9 @@ pub trait DelegatedStakeInterface: StakingInterface {
 	) -> DispatchResult;
 
 	/// Withdraw or revoke delegation to `delegatee`.
+	///
+	/// If there are `delegatee` funds upto `amount` available to withdraw, then those funds would be
+	/// released to the `delegator`
 	fn withdraw_delegation(
 		delegator: &Self::AccountId,
 		delegatee: &Self::AccountId,
@@ -100,6 +109,9 @@ pub trait DelegatedStakeInterface: StakingInterface {
 	) -> DispatchResult;
 
 	/// Returns true if there are pending slashes posted to the `delegatee` account.
+	///
+	/// Slashes to `delegatee` account are not immediate and are applied lazily. Since `delegatee`
+	/// has an unbounded number of delegators, immediate slashing is not possible.
 	fn has_pending_slash(delegatee: &Self::AccountId) -> bool;
 
 	/// Apply a pending slash to a `delegatee` by slashing `value` from `delegator`.

From 57e8992339ca8f270a1a295c092471b1c8bf826b Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 1 Mar 2024 03:38:13 +0100
Subject: [PATCH 189/202] rename error

---
 substrate/frame/delegated-staking/src/impls.rs |  2 +-
 substrate/frame/delegated-staking/src/lib.rs   | 18 +++++++++---------
 substrate/frame/delegated-staking/src/tests.rs | 10 +++++-----
 3 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index ef0edcf61563e..caf6b9aa4281e 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -88,7 +88,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		payee: &Self::AccountId,
 	) -> DispatchResult {
 		// ensure who is not already staked
-		ensure!(T::CoreStaking::status(who).is_err(), Error::<T>::AlreadyStaker);
+		ensure!(T::CoreStaking::status(who).is_err(), Error::<T>::AlreadyStaking);
 		let delegatee = Delegatee::<T>::from(who)?;
 
 		ensure!(delegatee.available_to_bond() >= value, Error::<T>::NotEnoughFunds);
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 1d0c25e98a52d..5da6ab1eb9370 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -28,13 +28,13 @@
 //! Declaring dispatchable still has the benefit of being transactable for unit tests as well as
 //! aligned with general direction of moving towards a permissionless pallet. For example, we could
 //! clearly signal who is the expected signer of any interaction with this pallet and take into
-//! security considerations already.
+//! account any security considerations associated with those interactions.
 //!
 //! ## Goals
 //!
 //! Direct nomination on the Staking pallet does not scale well. Nominations pools were created to
 //! address this by pooling delegator funds into one account and then staking it. This though had
-//! a very important limitation that the funds were moved from delegator account to pool account
+//! a very critical limitation that the funds were moved from delegator account to pool account
 //! and hence the delegator lost control over their funds for using it for other purposes such as
 //! governance. This pallet aims to solve this by extending the staking pallet to support a new
 //! primitive function: delegation of funds to an account for the intent of staking.
@@ -48,7 +48,7 @@
 //! delegators. Or part of the reward can go to a insurance fund that can be used to cover any
 //! potential future slashes. The goal is to eventually allow foreign MultiLocations
 //! (smart contracts or pallets on another chain) to build their own pooled staking solutions
-//! similar to `NominationPool`.
+//! similar to `NominationPools`.
 //!
 //! ## Key Terminologies
 //! - **Delegatee**: An account who accepts delegations from other accounts.
@@ -96,7 +96,7 @@
 //! pending slash never exceeds staked amount and would freeze further withdraws until pending
 //! slashes are applied.
 //!
-//! `NominationPool` can apply slash for all its members by calling
+//! The user of this pallet can apply slash using
 //! [StakingInterface::delegator_slash](sp_staking::StakingInterface::delegator_slash).
 //!
 //! ## Migration from Nominator to Delegatee
@@ -221,7 +221,7 @@ pub mod pallet {
 		/// The account cannot perform this operation.
 		NotAllowed,
 		/// An existing staker cannot perform this action.
-		AlreadyStaker,
+		AlreadyStaking,
 		/// Reward Destination cannot be `delegatee` account.
 		InvalidRewardDestination,
 		/// Delegation conditions are not met.
@@ -232,7 +232,7 @@ pub mod pallet {
 		InvalidDelegation,
 		/// The account does not have enough funds to perform the operation.
 		NotEnoughFunds,
-		/// Not an existing `delegatee` account.
+		/// Not an existing delegatee account.
 		NotDelegatee,
 		/// Not a Delegator account.
 		NotDelegator,
@@ -301,7 +301,7 @@ pub mod pallet {
 			ensure!(!Self::is_delegator(&who), Error::<T>::NotAllowed);
 
 			// They cannot be already a direct staker in the staking pallet.
-			ensure!(Self::not_direct_staker(&who), Error::<T>::AlreadyStaker);
+			ensure!(Self::not_direct_staker(&who), Error::<T>::AlreadyStaking);
 
 			// Reward account cannot be same as `delegatee` account.
 			ensure!(reward_account != who, Error::<T>::InvalidRewardDestination);
@@ -380,7 +380,7 @@ pub mod pallet {
 			// Ensure delegator is sane.
 			ensure!(!Self::is_delegatee(&delegator), Error::<T>::NotAllowed);
 			ensure!(!Self::is_delegator(&delegator), Error::<T>::NotAllowed);
-			ensure!(Self::not_direct_staker(&delegator), Error::<T>::AlreadyStaker);
+			ensure!(Self::not_direct_staker(&delegator), Error::<T>::AlreadyStaking);
 
 			// ensure delegatee is sane.
 			ensure!(Self::is_delegatee(&delegatee), Error::<T>::NotDelegatee);
@@ -410,7 +410,7 @@ pub mod pallet {
 
 			// ensure delegator is sane.
 			ensure!(Delegation::<T>::can_delegate(&who, &delegatee), Error::<T>::InvalidDelegation);
-			ensure!(Self::not_direct_staker(&who), Error::<T>::AlreadyStaker);
+			ensure!(Self::not_direct_staker(&who), Error::<T>::AlreadyStaking);
 
 			// ensure delegatee is sane.
 			ensure!(
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 9d29727d70d24..8b01536f558ad 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -68,7 +68,7 @@ fn cannot_become_delegatee() {
 				RawOrigin::Signed(mock::GENESIS_VALIDATOR).into(),
 				100
 			),
-			Error::<T>::AlreadyStaker
+			Error::<T>::AlreadyStaking
 		);
 
 		// an existing nominator cannot become delegatee
@@ -77,14 +77,14 @@ fn cannot_become_delegatee() {
 				RawOrigin::Signed(mock::GENESIS_NOMINATOR_ONE).into(),
 				100
 			),
-			Error::<T>::AlreadyStaker
+			Error::<T>::AlreadyStaking
 		);
 		assert_noop!(
 			DelegatedStaking::register_as_delegatee(
 				RawOrigin::Signed(mock::GENESIS_NOMINATOR_TWO).into(),
 				100
 			),
-			Error::<T>::AlreadyStaker
+			Error::<T>::AlreadyStaking
 		);
 	});
 }
@@ -448,14 +448,14 @@ mod staking_integration {
 					RawOrigin::Signed(GENESIS_NOMINATOR_ONE).into(),
 					201
 				),
-				Error::<T>::AlreadyStaker
+				Error::<T>::AlreadyStaking
 			);
 			assert_noop!(
 				DelegatedStaking::register_as_delegatee(
 					RawOrigin::Signed(GENESIS_VALIDATOR).into(),
 					201
 				),
-				Error::<T>::AlreadyStaker
+				Error::<T>::AlreadyStaking
 			);
 		});
 	}

From e95d800770504b146fda08e3911cb82c0a72bc34 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 1 Mar 2024 04:05:14 +0100
Subject: [PATCH 190/202] refactor types

---
 substrate/frame/delegated-staking/src/lib.rs  | 28 +-----
 .../frame/delegated-staking/src/tests.rs      | 26 ------
 .../frame/delegated-staking/src/types.rs      | 90 ++++++++++---------
 3 files changed, 53 insertions(+), 91 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 5da6ab1eb9370..06086390bf85f 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -75,6 +75,8 @@
 //!   the funds are migrated, the `delegator` can use the funds for other purposes which allows
 //!   usage of held funds in an account, such as governance.
 //! - `delegate_funds`: Delegate funds to a `delegatee` account and update the bond to staking.
+//! - `apply_slash`: If there is a pending slash in `delegatee` ledger, the passed delegator's
+//!   balance is slashed by the amount and the slash is removed from the delegatee ledger.
 //!
 //! #### [Staking Interface](StakingInterface)
 //! This pallet reimplements the staking interface as a wrapper implementation over
@@ -244,8 +246,6 @@ pub mod pallet {
 		WithdrawFailed,
 		/// Operation not supported by this pallet.
 		NotSupported,
-		/// Account does not accept delegations.
-		NotAcceptingDelegations,
 	}
 
 	/// A reason for placing a hold on funds.
@@ -413,10 +413,7 @@ pub mod pallet {
 			ensure!(Self::not_direct_staker(&who), Error::<T>::AlreadyStaking);
 
 			// ensure delegatee is sane.
-			ensure!(
-				DelegateeLedger::<T>::can_accept_delegation(&delegatee),
-				Error::<T>::NotAcceptingDelegations
-			);
+			ensure!(Self::is_delegatee(&delegatee), Error::<T>::NotDelegatee);
 
 			let delegator_balance =
 				T::Currency::reducible_balance(&who, Preservation::Preserve, Fortitude::Polite);
@@ -428,28 +425,12 @@ pub mod pallet {
 			Self::do_bond(&delegatee, amount)
 		}
 
-		/// Toggle delegatee status to start or stop accepting new delegations.
-		///
-		/// This can only be used by existing delegates. If not a delegatee yet, use
-		/// [Call::register_as_delegatee] first.
-		#[pallet::call_index(5)]
-		#[pallet::weight(Weight::default())]
-		pub fn toggle_delegatee_status(origin: OriginFor<T>) -> DispatchResult {
-			let who = ensure_signed(origin)?;
-
-			let delegatee = Delegatee::<T>::from(&who)?;
-			let should_block = !delegatee.ledger.blocked;
-			delegatee.update_status(should_block).save();
-
-			Ok(())
-		}
-
 		/// Apply slash to a delegator account.
 		///
 		/// `Delegatee` accounts with pending slash in their ledger can call this to apply slash to
 		/// one of its `delegator` account. Each slash to a delegator account needs to be posted
 		/// separately until all pending slash is cleared.
-		#[pallet::call_index(6)]
+		#[pallet::call_index(5)]
 		#[pallet::weight(Weight::default())]
 		pub fn apply_slash(
 			origin: OriginFor<T>,
@@ -571,7 +552,6 @@ impl<T: Config> Pallet<T> {
 		amount: BalanceOf<T>,
 	) -> DispatchResult {
 		let mut ledger = DelegateeLedger::<T>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
-		debug_assert!(!ledger.blocked);
 
 		let new_delegation_amount =
 			if let Some(existing_delegation) = Delegation::<T>::get(delegator) {
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 8b01536f558ad..a278fd8850ad9 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -460,32 +460,6 @@ mod staking_integration {
 		});
 	}
 
-	#[test]
-	fn toggle_delegatee_status() {
-		ExtBuilder::default().build_and_execute(|| {
-			assert_ok!(DelegatedStaking::register_as_delegatee(RawOrigin::Signed(200).into(), 201));
-
-			// delegation works
-			fund(&300, 1000);
-			assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(300).into(), 200, 100));
-
-			// delegate blocks delegation
-			assert_ok!(DelegatedStaking::toggle_delegatee_status(RawOrigin::Signed(200).into()));
-
-			// cannot delegate to it anymore
-			assert_noop!(
-				DelegatedStaking::delegate_funds(RawOrigin::Signed(300).into(), 200, 100),
-				Error::<T>::NotAcceptingDelegations
-			);
-
-			// delegate can unblock delegation
-			assert_ok!(DelegatedStaking::toggle_delegatee_status(RawOrigin::Signed(200).into()));
-
-			// delegation works again
-			assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(300).into(), 200, 100));
-		});
-	}
-
 	#[test]
 	fn slash_works() {
 		ExtBuilder::default().build_and_execute(|| {
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index ec16c3da39877..0dcdcc0659a40 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -41,14 +41,20 @@ pub struct Delegation<T: Config> {
 }
 
 impl<T: Config> Delegation<T> {
+	/// Get delegation of a `delegator`.
 	pub(crate) fn get(delegator: &T::AccountId) -> Option<Self> {
 		<Delegators<T>>::get(delegator)
 	}
 
+	/// Create and return a new delegation instance.
 	pub(crate) fn from(delegatee: &T::AccountId, amount: BalanceOf<T>) -> Self {
 		Delegation { delegatee: delegatee.clone(), amount }
 	}
 
+	/// Ensure the delegator is either a new delegator or they are adding more delegation to the
+	/// existing delegatee.
+	///
+	/// Delegators are prevented from delegating to multiple delegatees at the same time.
 	pub(crate) fn can_delegate(delegator: &T::AccountId, delegatee: &T::AccountId) -> bool {
 		Delegation::<T>::get(delegator)
 			.map(|delegation| delegation.delegatee == delegatee.clone())
@@ -71,6 +77,7 @@ impl<T: Config> Delegation<T> {
 		Some(Delegation::from(&self.delegatee, updated_delegation))
 	}
 
+	/// Save self to storage. If the delegation amount is zero, remove the delegation.
 	pub(crate) fn save_or_kill(self, key: &T::AccountId) {
 		// Clean up if no delegation left.
 		if self.amount == Zero::zero() {
@@ -87,7 +94,6 @@ impl<T: Config> Delegation<T> {
 /// This keeps track of the active balance of the `delegatee` that is made up from the funds that
 /// are currently delegated to this `delegatee`. It also tracks the pending slashes yet to be
 /// applied among other things.
-// FIXME(ank4n): Break up into two storage items - bookkeeping stuff and settings stuff.
 #[derive(Default, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
 #[scale_info(skip_type_params(T))]
 pub struct DelegateeLedger<T: Config> {
@@ -98,42 +104,41 @@ pub struct DelegateeLedger<T: Config> {
 	pub total_delegated: BalanceOf<T>,
 	/// Funds that are withdrawn from core staking but not released to delegator/s. It is a subset
 	/// of `total_delegated` and can never be greater than it.
+	///
+	/// We need this register to ensure that the `delegatee` does not bond funds from delegated
+	/// funds that are withdrawn and should be claimed by delegators.
 	// FIXME(ank4n): Check/test about rebond: where delegator rebond what is unlocking.
 	#[codec(compact)]
 	pub unclaimed_withdrawals: BalanceOf<T>,
-	/// Slashes that are not yet applied.
+	/// Slashes that are not yet applied. This affects the effective balance of the `delegatee`.
 	#[codec(compact)]
 	pub pending_slash: BalanceOf<T>,
-	/// Whether this `delegatee` is blocked from receiving new delegations.
-	pub blocked: bool,
 }
 
 impl<T: Config> DelegateeLedger<T> {
+	/// Create a new instance of `DelegateeLedger`.
 	pub(crate) fn new(reward_destination: &T::AccountId) -> Self {
 		DelegateeLedger {
 			payee: reward_destination.clone(),
 			total_delegated: Zero::zero(),
 			unclaimed_withdrawals: Zero::zero(),
 			pending_slash: Zero::zero(),
-			blocked: false,
 		}
 	}
 
+	/// Get `DelegateeLedger` from storage.
 	pub(crate) fn get(key: &T::AccountId) -> Option<Self> {
 		<Delegatees<T>>::get(key)
 	}
 
-	pub(crate) fn can_accept_delegation(delegatee: &T::AccountId) -> bool {
-		DelegateeLedger::<T>::get(delegatee)
-			.map(|ledger| !ledger.blocked)
-			.unwrap_or(false)
-	}
-
+	/// Save self to storage with the given key.
 	pub(crate) fn save(self, key: &T::AccountId) {
 		<Delegatees<T>>::insert(key, self)
 	}
 
 	/// Effective total balance of the `delegatee`.
+	///
+	/// This takes into account any slashes reported to `Delegatee` but unapplied.
 	pub(crate) fn effective_balance(&self) -> BalanceOf<T> {
 		defensive_assert!(
 			self.total_delegated >= self.pending_slash,
@@ -144,7 +149,7 @@ impl<T: Config> DelegateeLedger<T> {
 		self.total_delegated.saturating_sub(self.pending_slash)
 	}
 
-	/// Balance that can be bonded in [`T::CoreStaking`].
+	/// Delegatee balance that can be staked/bonded in [`T::CoreStaking`].
 	pub(crate) fn stakeable_balance(&self) -> BalanceOf<T> {
 		self.effective_balance().saturating_sub(self.unclaimed_withdrawals)
 	}
@@ -153,11 +158,14 @@ impl<T: Config> DelegateeLedger<T> {
 /// Wrapper around `DelegateeLedger` to provide additional functionality.
 #[derive(Clone)]
 pub struct Delegatee<T: Config> {
+	/// storage key
 	pub key: T::AccountId,
+	/// storage value
 	pub ledger: DelegateeLedger<T>,
 }
 
 impl<T: Config> Delegatee<T> {
+	/// Get `Delegatee` from storage if it exists or return an error.
 	pub(crate) fn from(delegatee: &T::AccountId) -> Result<Delegatee<T>, DispatchError> {
 		let ledger = DelegateeLedger::<T>::get(delegatee).ok_or(Error::<T>::NotDelegatee)?;
 		Ok(Delegatee { key: delegatee.clone(), ledger })
@@ -212,12 +220,6 @@ impl<T: Config> Delegatee<T> {
 		})
 	}
 
-	/// Reloads self from storage.
-	#[allow(unused)]
-	pub(crate) fn refresh(&self) -> Result<Delegatee<T>, DispatchError> {
-		Self::from(&self.key)
-	}
-
 	/// Amount that is delegated but not bonded yet.
 	///
 	/// This importantly does not include `unclaimed_withdrawals` as those should not be bonded
@@ -234,25 +236,7 @@ impl<T: Config> Delegatee<T> {
 		stakeable.saturating_sub(bonded_stake)
 	}
 
-	/// Balance of `Delegatee` that is not bonded.
-	///
-	/// This is similar to [Self::available_to_bond] except it also includes `unclaimed_withdrawals`
-	/// of `Delegatee`.
-	#[cfg(test)]
-	pub(crate) fn total_unbonded(&self) -> BalanceOf<T> {
-		let bonded_stake = self.bonded_stake();
-
-		let net_balance = self.ledger.effective_balance();
-
-		defensive_assert!(
-			net_balance >= bonded_stake,
-			"cannot be bonded with more than the delegatee balance"
-		);
-
-		net_balance.saturating_sub(bonded_stake)
-	}
-
-	/// Remove slashes that are applied.
+	/// Remove slashes from the `DelegateeLedger`.
 	pub(crate) fn remove_slash(self, amount: BalanceOf<T>) -> Self {
 		let pending_slash = self.ledger.pending_slash.defensive_saturating_sub(amount);
 		let total_delegated = self.ledger.total_delegated.defensive_saturating_sub(amount);
@@ -263,22 +247,22 @@ impl<T: Config> Delegatee<T> {
 		}
 	}
 
+	/// Get the total stake of delegatee bonded in [`Config::CoreStaking`].
 	pub(crate) fn bonded_stake(&self) -> BalanceOf<T> {
 		T::CoreStaking::total_stake(&self.key).unwrap_or(Zero::zero())
 	}
 
+	/// Returns true if the delegatee is bonded in [`Config::CoreStaking`].
 	pub(crate) fn is_bonded(&self) -> bool {
 		T::CoreStaking::stake(&self.key).is_ok()
 	}
 
+	/// Returns the reward account registered by the delegatee.
 	pub(crate) fn reward_account(&self) -> &T::AccountId {
 		&self.ledger.payee
 	}
 
-	pub(crate) fn update_status(self, block: bool) -> Self {
-		Delegatee { ledger: DelegateeLedger { blocked: block, ..self.ledger }, ..self }
-	}
-
+	/// Save self to storage.
 	pub(crate) fn save(self) {
 		let key = self.key;
 		self.ledger.save(&key)
@@ -303,4 +287,28 @@ impl<T: Config> Delegatee<T> {
 
 		Ok(())
 	}
+
+	/// Reloads self from storage.
+	#[cfg(test)]
+	pub(crate) fn refresh(&self) -> Result<Delegatee<T>, DispatchError> {
+		Self::from(&self.key)
+	}
+
+	/// Balance of `Delegatee` that is not bonded.
+	///
+	/// This is similar to [Self::available_to_bond] except it also includes `unclaimed_withdrawals`
+	/// of `Delegatee`.
+	#[cfg(test)]
+	pub(crate) fn total_unbonded(&self) -> BalanceOf<T> {
+		let bonded_stake = self.bonded_stake();
+
+		let net_balance = self.ledger.effective_balance();
+
+		defensive_assert!(
+			net_balance >= bonded_stake,
+			"cannot be bonded with more than the delegatee balance"
+		);
+
+		net_balance.saturating_sub(bonded_stake)
+	}
 }

From 25edbdee291a7346467954d737c64c74a9b3bdb8 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 1 Mar 2024 04:15:06 +0100
Subject: [PATCH 191/202] refactor

---
 substrate/frame/delegated-staking/src/lib.rs    |  4 ++--
 substrate/frame/nomination-pools/src/adapter.rs |  6 +++---
 substrate/primitives/staking/src/delegation.rs  | 12 +++++++-----
 3 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 06086390bf85f..60eabb005c995 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -84,8 +84,8 @@
 //! its Staking provider to support delegation based staking from pool accounts.
 //!
 //! #### [Delegatee Support](DelegateeSupport)
-//! Implements `DelegateeSupport` trait which another pallet such as [Config::CoreStaking] can use
-//! to back-support `Delegatees` in their staking implementation.
+//! Implements `DelegateeSupport` trait which an implementation of [StakingInterface] (such as
+//! pallet-staking) can use to back-support `delegatee` accounts.
 //!
 //! ## Lazy Slashing
 //! One of the reasons why direct nominators on staking pallet cannot scale well is because all
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index c7bf6868e9532..09c8fc488ad75 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -78,8 +78,8 @@ pub trait StakeStrategy {
 
 /// A staking strategy implementation that supports transfer based staking.
 ///
-/// In order to stake, this adapter transfers the funds from the delegator account to the pool
-/// account and stakes directly on `Staking`.
+/// In order to stake, this adapter transfers the funds from the member/delegator account to the
+/// pool account and stakes through the pool account on `Staking`.
 pub struct TransferStake<T: Config, Staking: StakingInterface>(PhantomData<(T, Staking)>);
 
 impl<T: Config, Staking: StakingInterface<Balance = BalanceOf<T>, AccountId = T::AccountId>>
@@ -192,7 +192,7 @@ impl<T: Config, Staking: StakingInterface<Balance = BalanceOf<T>, AccountId = T:
 ///
 /// In this approach, first the funds are delegated from delegator to the pool account and later
 /// staked with `Staking`. The advantage of this approach is that the funds are held in the
-/// use account itself and not in the pool account.
+/// user account itself and not in the pool account.
 pub struct DelegateStake<T: Config, Staking: DelegatedStakeInterface>(PhantomData<(T, Staking)>);
 
 impl<
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 7d970d567d9e7..6c893bfec70f0 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -21,11 +21,11 @@ use scale_info::TypeInfo;
 use sp_runtime::{DispatchResult, Saturating};
 use sp_std::ops::Sub;
 
-/// A trait that can be used as a plugin to support delegation based accounts, called `Delegatee`.
+/// Support plugin for `delegatee` accounts.
 ///
-/// For example, `pallet-staking` which implements `StakingInterface` but does not implement
-/// account delegations out of the box can be provided with a custom implementation of this trait to
-/// learn how to handle these special accounts.
+/// A `delegatee` account is an account that can receive delegations from other accounts. Their
+/// balance is made up of multiple child delegators. This trait allows a pallet such as
+/// `pallet-staking` to support these special accounts.
 pub trait DelegateeSupport {
 	/// Balance type used by the staking system.
 	type Balance: Sub<Output = Self::Balance>
@@ -41,7 +41,9 @@ pub trait DelegateeSupport {
 	/// AccountId type used by the staking system.
 	type AccountId: Clone + sp_std::fmt::Debug;
 
-	/// Balance of `delegatee` which is available for stake.
+	/// Balance of `delegatee` which can be staked.
+	///
+	/// Similar to free balance for a normal account.
 	fn stakeable_balance(delegatee: &Self::AccountId) -> Self::Balance;
 
 	/// Returns true if `delegatee` is restricted to update which account they can receive their

From 639985dd779ec7a486963140e2217e0572dd99ee Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 1 Mar 2024 04:15:19 +0100
Subject: [PATCH 192/202] fmt

---
 substrate/primitives/staking/src/delegation.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index 6c893bfec70f0..e51a48fddf3a3 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -102,8 +102,8 @@ pub trait DelegatedStakeInterface: StakingInterface {
 
 	/// Withdraw or revoke delegation to `delegatee`.
 	///
-	/// If there are `delegatee` funds upto `amount` available to withdraw, then those funds would be
-	/// released to the `delegator`
+	/// If there are `delegatee` funds upto `amount` available to withdraw, then those funds would
+	/// be released to the `delegator`
 	fn withdraw_delegation(
 		delegator: &Self::AccountId,
 		delegatee: &Self::AccountId,

From 85682617645fb805a8da82cad9d3a461535442b4 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 21 Mar 2024 10:25:23 +0100
Subject: [PATCH 193/202] fix imports

---
 Cargo.lock                              | 1 +
 substrate/frame/staking/src/ledger.rs   | 5 +----
 substrate/primitives/staking/Cargo.toml | 2 ++
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 61d9823e93b69..fc3a1904e8bdb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -19125,6 +19125,7 @@ dependencies = [
  "serde",
  "sp-core",
  "sp-runtime",
+ "sp-std 14.0.0",
 ]
 
 [[package]]
diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs
index c9710e711019b..29f19a1b2b8d5 100644
--- a/substrate/frame/staking/src/ledger.rs
+++ b/substrate/frame/staking/src/ledger.rs
@@ -31,11 +31,8 @@
 //! performed through the methods exposed by the [`StakingLedger`] implementation in order to ensure
 //! state consistency.
 
+use frame_support::{defensive, ensure, traits::Defensive};
 use sp_staking::{StakingAccount, StakingInterface};
-use frame_support::{
-	defensive, ensure,
-	traits::{Defensive, LockableCurrency, WithdrawReasons},
-};
 use sp_std::prelude::*;
 
 use crate::{
diff --git a/substrate/primitives/staking/Cargo.toml b/substrate/primitives/staking/Cargo.toml
index 6304551b8e60e..21346fbaca538 100644
--- a/substrate/primitives/staking/Cargo.toml
+++ b/substrate/primitives/staking/Cargo.toml
@@ -23,6 +23,7 @@ impl-trait-for-tuples = "0.2.2"
 
 sp-core = { path = "../core", default-features = false }
 sp-runtime = { path = "../runtime", default-features = false }
+sp-std = { path = "../std", default-features = false }
 
 [features]
 default = ["std"]
@@ -32,5 +33,6 @@ std = [
 	"serde/std",
 	"sp-core/std",
 	"sp-runtime/std",
+	"sp-std/std",
 ]
 runtime-benchmarks = ["sp-runtime/runtime-benchmarks"]

From 2b861f498d8d4c4c2b75ed8045fe67f6c3dd9444 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 28 Mar 2024 13:11:12 +0100
Subject: [PATCH 194/202] merge from master

---
 .github/workflows/subsystem-benchmarks.yml    |  42 ++
 .gitlab-ci.yml                                |   7 +
 .gitlab/pipeline/publish.yml                  |  76 ++-
 .gitlab/pipeline/test.yml                     |   6 +
 .gitlab/pipeline/zombienet.yml                |   2 +-
 Cargo.lock                                    |  21 +
 Cargo.toml                                    |   1 +
 .../pallets/outbound-queue/src/mock.rs        |   1 +
 bridges/snowbridge/pallets/system/src/mock.rs |   1 +
 .../consensus/aura/src/collators/lookahead.rs |  39 +-
 cumulus/pallets/parachain-system/src/mock.rs  |   1 +
 .../chain-specs/coretime-westend.json         |   3 +-
 .../emulated/chains/relays/westend/Cargo.toml |   1 -
 .../emulated/common/src/impls.rs              |   6 +-
 .../assets/asset-hub-rococo/src/tests/send.rs |   8 +-
 .../assets/asset-hub-rococo/src/tests/swap.rs |   4 +-
 .../asset-hub-westend/src/tests/send.rs       |   8 +-
 .../asset-hub-westend/src/tests/swap.rs       |   4 +-
 .../bridge-hub-rococo/src/tests/send_xcm.rs   |   7 +-
 .../bridge-hub-rococo/src/tests/snowbridge.rs |  18 +-
 .../bridges/bridge-hub-westend/Cargo.toml     |   1 +
 .../bridge-hub-westend/src/tests/send_xcm.rs  |   7 +-
 .../assets/asset-hub-rococo/src/lib.rs        |   1 +
 .../src/weights/pallet_xcm.rs                 | 112 ++--
 .../assets/asset-hub-westend/src/lib.rs       |   1 +
 .../src/weights/pallet_xcm.rs                 | 114 ++--
 .../bridge-hubs/bridge-hub-rococo/src/lib.rs  |   1 +
 .../src/weights/pallet_xcm.rs                 | 108 ++--
 .../bridge-hubs/bridge-hub-westend/src/lib.rs |   1 +
 .../src/weights/pallet_xcm.rs                 | 108 ++--
 .../collectives-westend/src/lib.rs            |   1 +
 .../src/weights/pallet_xcm.rs                 | 106 ++--
 .../contracts/contracts-rococo/src/lib.rs     |   1 +
 .../coretime/coretime-rococo/src/lib.rs       |   1 +
 .../src/weights/pallet_broker.rs              | 158 ++---
 .../coretime-rococo/src/weights/pallet_xcm.rs | 102 ++--
 .../coretime/coretime-westend/src/lib.rs      |   1 +
 .../src/weights/pallet_broker.rs              | 160 ++---
 .../src/weights/pallet_xcm.rs                 | 102 ++--
 .../glutton/glutton-westend/src/lib.rs        |   1 +
 .../runtimes/people/people-rococo/src/lib.rs  |   1 +
 .../people-rococo/src/weights/pallet_xcm.rs   | 102 ++--
 .../runtimes/people/people-westend/src/lib.rs |   1 +
 .../people-westend/src/weights/pallet_xcm.rs  | 102 ++--
 .../runtimes/starters/shell/src/lib.rs        |   1 +
 .../runtimes/testing/penpal/src/lib.rs        |   1 +
 .../testing/rococo-parachain/src/lib.rs       |   1 +
 .../node/collation-generation/src/error.rs    |   2 +
 polkadot/node/collation-generation/src/lib.rs | 183 +++---
 .../node/collation-generation/src/tests.rs    | 261 +++++++-
 polkadot/node/core/approval-voting/src/lib.rs |   6 +-
 .../approval-voting/src/persisted_entries.rs  |   2 +-
 .../node/core/approval-voting/src/tests.rs    | 167 +++++
 ...ilability-distribution-regression-bench.rs |   7 +
 .../availability-recovery-regression-bench.rs |   7 +
 .../src/collator_side/mod.rs                  | 129 ++--
 .../src/collator_side/tests/mod.rs            |   1 +
 .../tests/prospective_parachains.rs           |   2 +
 .../src/collator_side/validators_buffer.rs    |  18 +-
 polkadot/node/primitives/src/lib.rs           |   6 +-
 polkadot/node/service/Cargo.toml              |   3 +
 polkadot/node/service/src/chain_spec.rs       |   7 +-
 polkadot/node/service/src/fake_runtime_api.rs |  21 +-
 polkadot/node/subsystem-bench/Cargo.toml      |   1 +
 .../subsystem-bench/src/lib/environment.rs    |   2 +-
 polkadot/node/subsystem-bench/src/lib/lib.rs  |   1 +
 .../node/subsystem-bench/src/lib/usage.rs     |  28 +
 .../node/subsystem-bench/src/lib/utils.rs     |  75 +--
 polkadot/node/subsystem-types/src/messages.rs |   2 +
 polkadot/node/subsystem-util/src/lib.rs       |   3 +-
 .../test-parachains/adder/collator/Cargo.toml |   2 +-
 .../undying/collator/Cargo.toml               |   2 +-
 .../runtime/parachains/src/coretime/mod.rs    |  20 +
 polkadot/runtime/parachains/src/mock.rs       |   1 +
 polkadot/runtime/rococo/Cargo.toml            |   2 +
 polkadot/runtime/rococo/src/impls.rs          |   9 +-
 polkadot/runtime/rococo/src/lib.rs            |  66 +-
 .../runtime/rococo/src/weights/pallet_xcm.rs  | 110 ++--
 polkadot/runtime/test-runtime/src/lib.rs      |  34 +-
 polkadot/runtime/westend/Cargo.toml           |   2 +
 polkadot/runtime/westend/src/impls.rs         |   9 +-
 polkadot/runtime/westend/src/lib.rs           |  64 +-
 polkadot/runtime/westend/src/tests.rs         |   1 -
 .../westend/src/weights/pallet_staking.rs     | 286 +++++----
 .../runtime/westend/src/weights/pallet_xcm.rs | 108 ++--
 polkadot/xcm/pallet-xcm/Cargo.toml            |   2 +
 polkadot/xcm/pallet-xcm/src/benchmarking.rs   |  29 +
 polkadot/xcm/pallet-xcm/src/lib.rs            | 234 +++++--
 polkadot/xcm/pallet-xcm/src/tests/mod.rs      |  77 ++-
 polkadot/xcm/src/lib.rs                       |  13 +
 polkadot/xcm/src/v4/mod.rs                    |  20 +-
 polkadot/xcm/xcm-builder/src/controller.rs    |  39 +-
 polkadot/xcm/xcm-builder/src/lib.rs           |   2 +-
 .../xcm-fee-payment-runtime-api/Cargo.toml    |  40 ++
 .../xcm-fee-payment-runtime-api/src/lib.rs    |  99 +++
 .../xcm-simulator/example/src/relay_chain.rs  |   1 +
 .../xcm-simulator/fuzzer/src/relay_chain.rs   |   1 +
 prdoc/pr_3607.prdoc                           |  26 +
 prdoc/pr_3706.prdoc                           |  20 +
 prdoc/pr_3714.prdoc                           |  10 +
 prdoc/pr_3718.prdoc                           |  13 +
 prdoc/pr_3749.prdoc                           |  47 ++
 prdoc/pr_3795.prdoc                           |  14 +
 prdoc/pr_3817.prdoc                           |  23 +
 prdoc/pr_3844.prdoc                           |  25 +
 prdoc/pr_3849.prdoc                           |  13 +
 prdoc/pr_3850.prdoc                           |  15 +
 prdoc/schema_user.json                        |   8 +-
 substrate/bin/node/runtime/src/lib.rs         |   1 +
 .../authority-discovery/src/interval.rs       |  20 +-
 .../client/authority-discovery/src/worker.rs  |  28 +-
 substrate/frame/balances/src/impl_currency.rs |  13 +-
 .../balances/src/tests/currency_tests.rs      |  22 +-
 substrate/frame/broker/src/benchmarking.rs    |  17 +
 .../frame/broker/src/dispatchable_impls.rs    |  18 +
 substrate/frame/broker/src/lib.rs             |   8 +
 substrate/frame/broker/src/weights.rs         | 368 ++++++-----
 .../contracts/mock-network/src/relay_chain.rs |   1 +
 .../frame/contracts/mock-network/src/tests.rs |  40 +-
 substrate/frame/contracts/src/lib.rs          |   3 +
 substrate/frame/contracts/src/wasm/runtime.rs |  54 +-
 substrate/frame/contracts/uapi/src/host.rs    |   2 +-
 .../election-provider-multi-phase/src/lib.rs  |   2 -
 .../message-queue/src/integration_test.rs     |   1 +
 substrate/frame/message-queue/src/lib.rs      |  22 +-
 substrate/frame/message-queue/src/mock.rs     |   1 +
 substrate/frame/message-queue/src/tests.rs    |  42 ++
 substrate/frame/referenda/src/lib.rs          |  12 +
 substrate/frame/referenda/src/tests.rs        |  16 +
 substrate/frame/scheduler/src/lib.rs          |  14 +
 substrate/frame/scheduler/src/tests.rs        |   4 +
 substrate/frame/staking/Cargo.toml            |   2 +-
 substrate/frame/staking/src/benchmarking.rs   |   9 +
 substrate/frame/staking/src/lib.rs            |  14 +
 substrate/frame/staking/src/mock.rs           | 115 ++--
 substrate/frame/staking/src/pallet/impls.rs   |  60 +-
 substrate/frame/staking/src/pallet/mod.rs     | 121 +++-
 substrate/frame/staking/src/tests.rs          | 446 +++++++++++++-
 substrate/frame/staking/src/weights.rs        | 577 ++++++++++--------
 substrate/frame/support/src/traits.rs         |   4 +-
 .../frame/support/src/traits/schedule.rs      |  18 +-
 .../support/src/traits/tokens/currency.rs     |   2 +-
 .../src/traits/tokens/currency/lockable.rs    |   6 +
 .../api/proc-macro/src/impl_runtime_apis.rs   |   2 +-
 templates/parachain/node/src/service.rs       |   4 +-
 templates/parachain/runtime/src/apis.rs       | 275 +++++++++
 templates/parachain/runtime/src/lib.rs        | 238 +-------
 147 files changed, 4642 insertions(+), 1933 deletions(-)
 create mode 100644 .github/workflows/subsystem-benchmarks.yml
 create mode 100644 polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml
 create mode 100644 polkadot/xcm/xcm-fee-payment-runtime-api/src/lib.rs
 create mode 100644 prdoc/pr_3607.prdoc
 create mode 100644 prdoc/pr_3706.prdoc
 create mode 100644 prdoc/pr_3714.prdoc
 create mode 100644 prdoc/pr_3718.prdoc
 create mode 100644 prdoc/pr_3749.prdoc
 create mode 100644 prdoc/pr_3795.prdoc
 create mode 100644 prdoc/pr_3817.prdoc
 create mode 100644 prdoc/pr_3844.prdoc
 create mode 100644 prdoc/pr_3849.prdoc
 create mode 100644 prdoc/pr_3850.prdoc
 create mode 100644 templates/parachain/runtime/src/apis.rs

diff --git a/.github/workflows/subsystem-benchmarks.yml b/.github/workflows/subsystem-benchmarks.yml
new file mode 100644
index 0000000000000..37a9e0f4680c3
--- /dev/null
+++ b/.github/workflows/subsystem-benchmarks.yml
@@ -0,0 +1,42 @@
+# The actions takes json file as input and runs github-action-benchmark for it.
+
+on:
+  workflow_dispatch:
+    inputs:
+      benchmark-data-dir-path:
+        description: "Path to the benchmark data directory"
+        required: true
+        type: string
+      output-file-path:
+        description: "Path to the benchmark data file"
+        required: true
+        type: string
+
+jobs:
+  subsystem-benchmarks:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout Sources
+        uses: actions/checkout@v4.1.2
+        with:
+          fetch-depth: 0
+          ref: "gh-pages"
+
+      - name: Copy bench results
+        id: step_one
+        run: |
+          cp bench/gitlab/${{ github.event.inputs.output-file-path }} ${{ github.event.inputs.output-file-path }}
+
+      - name: Switch branch
+        id: step_two
+        run: |
+          git checkout master
+
+      - name: Store benchmark result
+        uses: benchmark-action/github-action-benchmark@v1
+        with:
+          tool: "customSmallerIsBetter"
+          output-file-path: ${{ github.event.inputs.output-file-path }}
+          benchmark-data-dir-path: "bench/${{ github.event.inputs.benchmark-data-dir-path }}"
+          github-token: ${{ secrets.GITHUB_TOKEN }}
+          auto-push: true
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 7f8796ca51248..93a6ccb9f8fba 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -147,6 +147,13 @@ default:
     - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs
     - if: $CI_COMMIT_REF_NAME =~ /^gh-readonly-queue.*$/ # merge queues
 
+.publish-gh-pages-refs:
+  rules:
+    - if: $CI_PIPELINE_SOURCE == "pipeline"
+      when: never
+    - if: $CI_PIPELINE_SOURCE == "web" && $CI_COMMIT_REF_NAME == "master"
+    - if: $CI_COMMIT_REF_NAME == "master"
+
 # handle the specific case where benches could store incorrect bench data because of the downstream staging runs
 # exclude cargo-check-benches from such runs
 .test-refs-check-benches:
diff --git a/.gitlab/pipeline/publish.yml b/.gitlab/pipeline/publish.yml
index b73acb560f67f..a37ba012a8a76 100644
--- a/.gitlab/pipeline/publish.yml
+++ b/.gitlab/pipeline/publish.yml
@@ -3,16 +3,13 @@
 
 publish-rustdoc:
   stage: publish
-  extends: .kubernetes-env
+  extends:
+    - .kubernetes-env
+    - .publish-gh-pages-refs
   variables:
     CI_IMAGE: node:18
     GIT_DEPTH: 100
     RUSTDOCS_DEPLOY_REFS: "master"
-  rules:
-    - if: $CI_PIPELINE_SOURCE == "pipeline"
-      when: never
-    - if: $CI_PIPELINE_SOURCE == "web" && $CI_COMMIT_REF_NAME == "master"
-    - if: $CI_COMMIT_REF_NAME == "master"
   needs:
     - job: build-rustdoc
       artifacts: true
@@ -60,9 +57,76 @@ publish-rustdoc:
     - git commit -m "___Updated docs for ${CI_COMMIT_REF_NAME}___" ||
       echo "___Nothing to commit___"
     - git push origin gh-pages --force
+    # artificial sleep to publish gh-pages
+    - sleep 300
+  after_script:
+    - rm -rf .git/ ./*
+
+publish-subsystem-benchmarks:
+  stage: publish
+  variables:
+    CI_IMAGE: "paritytech/tools:latest"
+  extends:
+    - .kubernetes-env
+    - .publish-gh-pages-refs
+  needs:
+    - job: subsystem-regression-tests
+      artifacts: true
+    - job: publish-rustdoc
+      artifacts: false
+  script:
+    # setup ssh
+    - eval $(ssh-agent)
+    - ssh-add - <<< ${GITHUB_SSH_PRIV_KEY}
+    - mkdir ~/.ssh && touch ~/.ssh/known_hosts
+    - ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts
+    # Set git config
+    - rm -rf .git/config
+    - git config user.email "devops-team@parity.io"
+    - git config user.name "${GITHUB_USER}"
+    - git config remote.origin.url "git@github.com:/paritytech/${CI_PROJECT_NAME}.git"
+    - git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
+    - git fetch origin gh-pages
+    # Push result to github
+    - git checkout gh-pages --force
+    - mkdir -p bench/gitlab/ || echo "Directory exists"
+    - rm -rf bench/gitlab/*.json || echo "No json files"
+    - cp -r charts/*.json bench/gitlab/
+    - git add bench/gitlab/
+    - git commit -m "Add json files with benchmark results for ${CI_COMMIT_REF_NAME}"
+    - git push origin gh-pages
+    # artificial sleep to publish gh-pages
+    - sleep 300
+  allow_failure: true
   after_script:
     - rm -rf .git/ ./*
 
+trigger_workflow:
+  stage: deploy
+  extends:
+    - .kubernetes-env
+    - .publish-gh-pages-refs
+  needs:
+    - job: publish-subsystem-benchmarks
+      artifacts: false
+    - job: subsystem-regression-tests
+      artifacts: true
+  script:
+    - echo "Triggering workflow"
+    - |
+      for benchmark in $(ls charts/*.json); do
+        export bencmark_name=$(basename $benchmark)
+        echo "Benchmark: $bencmark_name"
+        export benchmark_dir=$(echo $bencmark_name | sed 's/\.json//')
+        curl -q -X POST \
+              -H "Accept: application/vnd.github.v3+json" \
+              -H "Authorization: token $GITHUB_TOKEN" \
+               https://api.github.com/repos/paritytech/${CI_PROJECT_NAME}/actions/workflows/subsystem-benchmarks.yml/dispatches \
+                -d '{"ref":"refs/heads/master","inputs":{"benchmark-data-dir-path":"'$benchmark_dir'","output-file-path":"'$bencmark_name'"}}'
+        sleep 300
+      done
+  allow_failure: true
+
 # note: images are used not only in zombienet but also in rococo, wococo and versi
 .build-push-image:
   image: $BUILDAH_IMAGE
diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml
index 476ac6333f587..af261a893da50 100644
--- a/.gitlab/pipeline/test.yml
+++ b/.gitlab/pipeline/test.yml
@@ -497,6 +497,12 @@ test-syscalls:
 
 subsystem-regression-tests:
   stage: test
+  artifacts:
+    name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}"
+    when: always
+    expire_in: 1 days
+    paths:
+      - charts/
   extends:
     - .docker-env
     - .common-refs
diff --git a/.gitlab/pipeline/zombienet.yml b/.gitlab/pipeline/zombienet.yml
index 8d308714fab3c..82341eb709fee 100644
--- a/.gitlab/pipeline/zombienet.yml
+++ b/.gitlab/pipeline/zombienet.yml
@@ -1,7 +1,7 @@
 .zombienet-refs:
   extends: .build-refs
   variables:
-    ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.95"
+    ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.98"
 
 include:
   # substrate tests
diff --git a/Cargo.lock b/Cargo.lock
index 133d8ba4cc68c..95b7a46db6c40 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2148,6 +2148,7 @@ dependencies = [
  "pallet-message-queue",
  "pallet-xcm",
  "parachains-common",
+ "parity-scale-codec",
  "rococo-westend-system-emulated-network",
  "sp-runtime",
  "staging-xcm",
@@ -11211,6 +11212,7 @@ dependencies = [
  "staging-xcm",
  "staging-xcm-builder",
  "staging-xcm-executor",
+ "xcm-fee-payment-runtime-api",
 ]
 
 [[package]]
@@ -13563,12 +13565,14 @@ dependencies = [
  "sp-transaction-pool",
  "sp-version",
  "sp-weights",
+ "staging-xcm",
  "substrate-prometheus-endpoint",
  "tempfile",
  "thiserror",
  "tracing-gum",
  "westend-runtime",
  "westend-runtime-constants",
+ "xcm-fee-payment-runtime-api",
 ]
 
 [[package]]
@@ -13667,6 +13671,7 @@ dependencies = [
  "sc-service",
  "schnorrkel 0.11.4",
  "serde",
+ "serde_json",
  "serde_yaml",
  "sha1",
  "sp-application-crypto",
@@ -15138,6 +15143,7 @@ dependencies = [
  "substrate-wasm-builder",
  "tiny-keccak",
  "tokio",
+ "xcm-fee-payment-runtime-api",
 ]
 
 [[package]]
@@ -21993,6 +21999,7 @@ dependencies = [
  "tiny-keccak",
  "tokio",
  "westend-runtime-constants",
+ "xcm-fee-payment-runtime-api",
 ]
 
 [[package]]
@@ -22466,6 +22473,20 @@ dependencies = [
  "staging-xcm-executor",
 ]
 
+[[package]]
+name = "xcm-fee-payment-runtime-api"
+version = "0.1.0"
+dependencies = [
+ "frame-support",
+ "parity-scale-codec",
+ "scale-info",
+ "sp-api",
+ "sp-runtime",
+ "sp-std 14.0.0",
+ "sp-weights",
+ "staging-xcm",
+]
+
 [[package]]
 name = "xcm-procedural"
 version = "7.0.0"
diff --git a/Cargo.toml b/Cargo.toml
index 5d6faf4ff17ca..2966e45fbec03 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -214,6 +214,7 @@ members = [
 	"polkadot/xcm/xcm-builder",
 	"polkadot/xcm/xcm-executor",
 	"polkadot/xcm/xcm-executor/integration-tests",
+	"polkadot/xcm/xcm-fee-payment-runtime-api",
 	"polkadot/xcm/xcm-simulator",
 	"polkadot/xcm/xcm-simulator/example",
 	"polkadot/xcm/xcm-simulator/fuzzer",
diff --git a/bridges/snowbridge/pallets/outbound-queue/src/mock.rs b/bridges/snowbridge/pallets/outbound-queue/src/mock.rs
index 67877a05c79a1..5eeeeead14001 100644
--- a/bridges/snowbridge/pallets/outbound-queue/src/mock.rs
+++ b/bridges/snowbridge/pallets/outbound-queue/src/mock.rs
@@ -69,6 +69,7 @@ impl pallet_message_queue::Config for Test {
 	type HeapSize = HeapSize;
 	type MaxStale = MaxStale;
 	type ServiceWeight = ServiceWeight;
+	type IdleMaxServiceWeight = ();
 	type QueuePausedQuery = ();
 }
 
diff --git a/bridges/snowbridge/pallets/system/src/mock.rs b/bridges/snowbridge/pallets/system/src/mock.rs
index 0312456c98233..687072a49e2e5 100644
--- a/bridges/snowbridge/pallets/system/src/mock.rs
+++ b/bridges/snowbridge/pallets/system/src/mock.rs
@@ -148,6 +148,7 @@ impl pallet_message_queue::Config for Test {
 	type HeapSize = HeapSize;
 	type MaxStale = MaxStale;
 	type ServiceWeight = ServiceWeight;
+	type IdleMaxServiceWeight = ();
 	type QueuePausedQuery = ();
 }
 
diff --git a/cumulus/client/consensus/aura/src/collators/lookahead.rs b/cumulus/client/consensus/aura/src/collators/lookahead.rs
index 161f10d55a193..580058336174d 100644
--- a/cumulus/client/consensus/aura/src/collators/lookahead.rs
+++ b/cumulus/client/consensus/aura/src/collators/lookahead.rs
@@ -49,7 +49,7 @@ use polkadot_node_subsystem::messages::{
 	CollationGenerationMessage, RuntimeApiMessage, RuntimeApiRequest,
 };
 use polkadot_overseer::Handle as OverseerHandle;
-use polkadot_primitives::{CollatorPair, Id as ParaId, OccupiedCoreAssumption};
+use polkadot_primitives::{CollatorPair, CoreIndex, Id as ParaId, OccupiedCoreAssumption};
 
 use futures::{channel::oneshot, prelude::*};
 use sc_client_api::{backend::AuxStore, BlockBackend, BlockOf};
@@ -184,7 +184,15 @@ where
 		while let Some(relay_parent_header) = import_notifications.next().await {
 			let relay_parent = relay_parent_header.hash();
 
-			if !is_para_scheduled(relay_parent, params.para_id, &mut params.overseer_handle).await {
+			// TODO: Currently we use just the first core here, but for elastic scaling
+			// we iterate and build on all of the cores returned.
+			let core_index = if let Some(core_index) =
+				cores_scheduled_for_para(relay_parent, params.para_id, &mut params.overseer_handle)
+					.await
+					.get(0)
+			{
+				*core_index
+			} else {
 				tracing::trace!(
 					target: crate::LOG_TARGET,
 					?relay_parent,
@@ -193,7 +201,7 @@ where
 				);
 
 				continue
-			}
+			};
 
 			let max_pov_size = match params
 				.relay_client
@@ -396,6 +404,7 @@ where
 										parent_head: parent_header.encode().into(),
 										validation_code_hash,
 										result_sender: None,
+										core_index,
 									},
 								),
 								"SubmitCollation",
@@ -480,14 +489,12 @@ async fn max_ancestry_lookback(
 	}
 }
 
-// Checks if there exists a scheduled core for the para at the provided relay parent.
-//
-// Falls back to `false` in case of an error.
-async fn is_para_scheduled(
+// Return all the cores assigned to the para at the provided relay parent.
+async fn cores_scheduled_for_para(
 	relay_parent: PHash,
 	para_id: ParaId,
 	overseer_handle: &mut OverseerHandle,
-) -> bool {
+) -> Vec<CoreIndex> {
 	let (tx, rx) = oneshot::channel();
 	let request = RuntimeApiRequest::AvailabilityCores(tx);
 	overseer_handle
@@ -503,7 +510,7 @@ async fn is_para_scheduled(
 				?relay_parent,
 				"Failed to query availability cores runtime API",
 			);
-			return false
+			return Vec::new()
 		},
 		Err(oneshot::Canceled) => {
 			tracing::error!(
@@ -511,9 +518,19 @@ async fn is_para_scheduled(
 				?relay_parent,
 				"Sender for availability cores runtime request dropped",
 			);
-			return false
+			return Vec::new()
 		},
 	};
 
-	cores.iter().any(|core| core.para_id() == Some(para_id))
+	cores
+		.iter()
+		.enumerate()
+		.filter_map(|(index, core)| {
+			if core.para_id() == Some(para_id) {
+				Some(CoreIndex(index as u32))
+			} else {
+				None
+			}
+		})
+		.collect()
 }
diff --git a/cumulus/pallets/parachain-system/src/mock.rs b/cumulus/pallets/parachain-system/src/mock.rs
index 0b1d536ba7cd9..fe89dfe68c67e 100644
--- a/cumulus/pallets/parachain-system/src/mock.rs
+++ b/cumulus/pallets/parachain-system/src/mock.rs
@@ -125,6 +125,7 @@ impl pallet_message_queue::Config for Test {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MaxWeight;
+	type IdleMaxServiceWeight = ();
 	type WeightInfo = ();
 }
 
diff --git a/cumulus/parachains/chain-specs/coretime-westend.json b/cumulus/parachains/chain-specs/coretime-westend.json
index c79fd582348b0..adb35b8a349f6 100644
--- a/cumulus/parachains/chain-specs/coretime-westend.json
+++ b/cumulus/parachains/chain-specs/coretime-westend.json
@@ -4,7 +4,8 @@
   "chainType": "Live",
   "bootNodes": [
     "/dns/westend-coretime-collator-node-0.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWP93Dzk8T7GWxyWw9jhLcz8Pksokk3R9vL2eEH337bNkT",
-    "/dns/westend-coretime-collator-node-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWMh2imeAzsZKGQgm2cv6Uoep3GBYtwGfujt1bs5YfVzkH"
+    "/dns/westend-coretime-collator-node-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWMh2imeAzsZKGQgm2cv6Uoep3GBYtwGfujt1bs5YfVzkH",
+    "/dns/boot.metaspan.io/tcp/33019/p2p/12D3KooWCa1uNnEZqiqJY9jkKNQxwSLGPeZ5MjWHhjQMGwga9JMM"
   ],
   "telemetryEndpoints": null,
   "protocolId": null,
diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml
index 20aedb50e6a18..12a3ad60e0e04 100644
--- a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml
+++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml
@@ -11,7 +11,6 @@ publish = false
 workspace = true
 
 [dependencies]
-
 # Substrate
 sp-core = { path = "../../../../../../../substrate/primitives/core", default-features = false }
 sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false }
diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs
index ae69bf991e5a4..618c3addc5d0c 100644
--- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs
+++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs
@@ -362,7 +362,7 @@ macro_rules! impl_send_transact_helpers_for_relay_chain {
 					recipient: $crate::impls::ParaId,
 					call: $crate::impls::DoubleEncoded<()>
 				) {
-					use $crate::impls::{bx, Chain, RelayChain};
+					use $crate::impls::{bx, Chain, RelayChain, Encode};
 
 					<Self as $crate::impls::TestExt>::execute_with(|| {
 						let root_origin = <Self as Chain>::RuntimeOrigin::root();
@@ -370,10 +370,10 @@ macro_rules! impl_send_transact_helpers_for_relay_chain {
 						let xcm = $crate::impls::xcm_transact_unpaid_execution(call, $crate::impls::OriginKind::Superuser);
 
 						// Send XCM `Transact`
-						$crate::impls::assert_ok!(<Self as [<$chain RelayPallet>]>::XcmPallet::send(
+						$crate::impls::assert_ok!(<Self as [<$chain RelayPallet>]>::XcmPallet::send_blob(
 							root_origin,
 							bx!(destination.into()),
-							bx!(xcm),
+							xcm.encode().try_into().unwrap(),
 						));
 						Self::assert_xcm_pallet_sent();
 					});
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs
index 364fbd0d439f6..1d120f1dc4c7e 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs
@@ -75,10 +75,10 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_system_assets_works() {
 	)]);
 
 	PenpalA::execute_with(|| {
-		assert_ok!(<PenpalA as PenpalAPallet>::PolkadotXcm::send(
+		assert_ok!(<PenpalA as PenpalAPallet>::PolkadotXcm::send_blob(
 			root_origin,
 			bx!(system_para_destination),
-			bx!(xcm),
+			xcm.encode().try_into().unwrap(),
 		));
 
 		PenpalA::assert_xcm_pallet_sent();
@@ -159,10 +159,10 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() {
 	)]);
 
 	PenpalA::execute_with(|| {
-		assert_ok!(<PenpalA as PenpalAPallet>::PolkadotXcm::send(
+		assert_ok!(<PenpalA as PenpalAPallet>::PolkadotXcm::send_blob(
 			root_origin,
 			bx!(system_para_destination),
-			bx!(xcm),
+			xcm.encode().try_into().unwrap(),
 		));
 
 		PenpalA::assert_xcm_pallet_sent();
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs
index 87f0b3d9f90a6..e13300b7c1142 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs
@@ -370,10 +370,10 @@ fn pay_xcm_fee_with_some_asset_swapped_for_native() {
 			penpal.clone(),
 		);
 
-		assert_ok!(<PenpalA as PenpalAPallet>::PolkadotXcm::send(
+		assert_ok!(<PenpalA as PenpalAPallet>::PolkadotXcm::send_blob(
 			penpal_root,
 			bx!(asset_hub_location),
-			bx!(xcm),
+			xcm.encode().try_into().unwrap(),
 		));
 
 		PenpalA::assert_xcm_pallet_sent();
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs
index eb0e985cc0ce6..f218b539c3879 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs
@@ -75,10 +75,10 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_system_assets_works() {
 	)]);
 
 	PenpalA::execute_with(|| {
-		assert_ok!(<PenpalA as PenpalAPallet>::PolkadotXcm::send(
+		assert_ok!(<PenpalA as PenpalAPallet>::PolkadotXcm::send_blob(
 			root_origin,
 			bx!(system_para_destination),
-			bx!(xcm),
+			xcm.encode().try_into().unwrap(),
 		));
 
 		PenpalA::assert_xcm_pallet_sent();
@@ -159,10 +159,10 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() {
 	)]);
 
 	PenpalA::execute_with(|| {
-		assert_ok!(<PenpalA as PenpalAPallet>::PolkadotXcm::send(
+		assert_ok!(<PenpalA as PenpalAPallet>::PolkadotXcm::send_blob(
 			root_origin,
 			bx!(system_para_destination),
-			bx!(xcm),
+			xcm.encode().try_into().unwrap(),
 		));
 
 		PenpalA::assert_xcm_pallet_sent();
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs
index 04740d3115834..aa673c03483af 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs
@@ -369,10 +369,10 @@ fn pay_xcm_fee_with_some_asset_swapped_for_native() {
 			penpal.clone(),
 		);
 
-		assert_ok!(<PenpalA as PenpalAPallet>::PolkadotXcm::send(
+		assert_ok!(<PenpalA as PenpalAPallet>::PolkadotXcm::send_blob(
 			penpal_root,
 			bx!(asset_hub_location),
-			bx!(xcm),
+			xcm.encode().try_into().unwrap(),
 		));
 
 		PenpalA::assert_xcm_pallet_sent();
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs
index a1d871cdb618f..4bd041dc03f42 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs
@@ -14,6 +14,7 @@
 // limitations under the License.
 
 use crate::tests::*;
+use codec::Encode;
 
 #[test]
 fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable() {
@@ -26,7 +27,7 @@ fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable
 
 	let remote_xcm = Xcm(vec![ClearOrigin]);
 
-	let xcm = VersionedXcm::from(Xcm(vec![
+	let xcm = VersionedXcm::from(Xcm::<()>(vec![
 		UnpaidExecution { weight_limit, check_origin },
 		ExportMessage {
 			network: WestendId.into(),
@@ -38,10 +39,10 @@ fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable
 	// Rococo Global Consensus
 	// Send XCM message from Relay Chain to Bridge Hub source Parachain
 	Rococo::execute_with(|| {
-		assert_ok!(<Rococo as RococoPallet>::XcmPallet::send(
+		assert_ok!(<Rococo as RococoPallet>::XcmPallet::send_blob(
 			sudo_origin,
 			bx!(destination),
-			bx!(xcm),
+			xcm.encode().try_into().unwrap(),
 		));
 
 		type RuntimeEvent = <Rococo as Chain>::RuntimeEvent;
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs
index 26b82375e07f7..caaf24e00a8ae 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs
@@ -83,7 +83,7 @@ fn create_agent() {
 
 	let create_agent_call = SnowbridgeControl::Control(ControlCall::CreateAgent {});
 	// Construct XCM to create an agent for para 1001
-	let remote_xcm = VersionedXcm::from(Xcm(vec![
+	let remote_xcm = VersionedXcm::from(Xcm::<()>(vec![
 		UnpaidExecution { weight_limit: Unlimited, check_origin: None },
 		DescendOrigin(Parachain(origin_para).into()),
 		Transact {
@@ -96,10 +96,10 @@ fn create_agent() {
 	// Rococo Global Consensus
 	// Send XCM message from Relay Chain to Bridge Hub source Parachain
 	Rococo::execute_with(|| {
-		assert_ok!(<Rococo as RococoPallet>::XcmPallet::send(
+		assert_ok!(<Rococo as RococoPallet>::XcmPallet::send_blob(
 			sudo_origin,
 			bx!(destination),
-			bx!(remote_xcm),
+			remote_xcm.encode().try_into().unwrap(),
 		));
 
 		type RuntimeEvent = <Rococo as Chain>::RuntimeEvent;
@@ -141,7 +141,7 @@ fn create_channel() {
 
 	let create_agent_call = SnowbridgeControl::Control(ControlCall::CreateAgent {});
 	// Construct XCM to create an agent for para 1001
-	let create_agent_xcm = VersionedXcm::from(Xcm(vec![
+	let create_agent_xcm = VersionedXcm::from(Xcm::<()>(vec![
 		UnpaidExecution { weight_limit: Unlimited, check_origin: None },
 		DescendOrigin(Parachain(origin_para).into()),
 		Transact {
@@ -154,7 +154,7 @@ fn create_channel() {
 	let create_channel_call =
 		SnowbridgeControl::Control(ControlCall::CreateChannel { mode: OperatingMode::Normal });
 	// Construct XCM to create a channel for para 1001
-	let create_channel_xcm = VersionedXcm::from(Xcm(vec![
+	let create_channel_xcm = VersionedXcm::from(Xcm::<()>(vec![
 		UnpaidExecution { weight_limit: Unlimited, check_origin: None },
 		DescendOrigin(Parachain(origin_para).into()),
 		Transact {
@@ -167,16 +167,16 @@ fn create_channel() {
 	// Rococo Global Consensus
 	// Send XCM message from Relay Chain to Bridge Hub source Parachain
 	Rococo::execute_with(|| {
-		assert_ok!(<Rococo as RococoPallet>::XcmPallet::send(
+		assert_ok!(<Rococo as RococoPallet>::XcmPallet::send_blob(
 			sudo_origin.clone(),
 			bx!(destination.clone()),
-			bx!(create_agent_xcm),
+			create_agent_xcm.encode().try_into().unwrap(),
 		));
 
-		assert_ok!(<Rococo as RococoPallet>::XcmPallet::send(
+		assert_ok!(<Rococo as RococoPallet>::XcmPallet::send_blob(
 			sudo_origin,
 			bx!(destination),
-			bx!(create_channel_xcm),
+			create_channel_xcm.encode().try_into().unwrap(),
 		));
 
 		type RuntimeEvent = <Rococo as Chain>::RuntimeEvent;
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml
index 9059d841a489c..9c45a7adeb4e5 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml
@@ -11,6 +11,7 @@ publish = false
 workspace = true
 
 [dependencies]
+codec = { package = "parity-scale-codec", version = "3.6.0" }
 
 # Substrate
 frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false }
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs
index b01be5e8dc84b..f69747c17704c 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs
@@ -14,6 +14,7 @@
 // limitations under the License.
 
 use crate::tests::*;
+use codec::Encode;
 
 #[test]
 fn send_xcm_from_westend_relay_to_rococo_asset_hub_should_fail_on_not_applicable() {
@@ -26,7 +27,7 @@ fn send_xcm_from_westend_relay_to_rococo_asset_hub_should_fail_on_not_applicable
 
 	let remote_xcm = Xcm(vec![ClearOrigin]);
 
-	let xcm = VersionedXcm::from(Xcm(vec![
+	let xcm = VersionedXcm::from(Xcm::<()>(vec![
 		UnpaidExecution { weight_limit, check_origin },
 		ExportMessage {
 			network: RococoId,
@@ -38,10 +39,10 @@ fn send_xcm_from_westend_relay_to_rococo_asset_hub_should_fail_on_not_applicable
 	// Westend Global Consensus
 	// Send XCM message from Relay Chain to Bridge Hub source Parachain
 	Westend::execute_with(|| {
-		assert_ok!(<Westend as WestendPallet>::XcmPallet::send(
+		assert_ok!(<Westend as WestendPallet>::XcmPallet::send_blob(
 			sudo_origin,
 			bx!(destination),
-			bx!(xcm),
+			xcm.encode().try_into().unwrap(),
 		));
 
 		type RuntimeEvent = <Westend as Chain>::RuntimeEvent;
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs
index 689d8d56c48ba..293416ab2a9aa 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs
@@ -660,6 +660,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl parachain_info::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs
index 51b6543bae82b..e0e231d7da279 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024
 
 // Executed Command:
@@ -64,8 +64,30 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `145`
 		//  Estimated: `3610`
-		// Minimum execution time: 22_136_000 picoseconds.
-		Weight::from_parts(22_518_000, 0)
+		// Minimum execution time: 21_224_000 picoseconds.
+		Weight::from_parts(21_821_000, 0)
+			.saturating_add(Weight::from_parts(0, 3610))
+			.saturating_add(T::DbWeight::get().reads(6))
+			.saturating_add(T::DbWeight::get().writes(2))
+	}
+	/// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
+	/// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
+	/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
+	/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
+	/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
+	/// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
+	/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	fn send_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `145`
+		//  Estimated: `3610`
+		// Minimum execution time: 21_474_000 picoseconds.
+		Weight::from_parts(22_072_000, 0)
 			.saturating_add(Weight::from_parts(0, 3610))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -90,8 +112,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `145`
 		//  Estimated: `3610`
-		// Minimum execution time: 92_277_000 picoseconds.
-		Weight::from_parts(94_843_000, 0)
+		// Minimum execution time: 90_677_000 picoseconds.
+		Weight::from_parts(93_658_000, 0)
 			.saturating_add(Weight::from_parts(0, 3610))
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -118,8 +140,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `400`
 		//  Estimated: `6196`
-		// Minimum execution time: 120_110_000 picoseconds.
-		Weight::from_parts(122_968_000, 0)
+		// Minimum execution time: 116_767_000 picoseconds.
+		Weight::from_parts(118_843_000, 0)
 			.saturating_add(Weight::from_parts(0, 6196))
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(5))
@@ -148,8 +170,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `496`
 		//  Estimated: `6208`
-		// Minimum execution time: 143_116_000 picoseconds.
-		Weight::from_parts(147_355_000, 0)
+		// Minimum execution time: 137_983_000 picoseconds.
+		Weight::from_parts(141_396_000, 0)
 			.saturating_add(Weight::from_parts(0, 6208))
 			.saturating_add(T::DbWeight::get().reads(12))
 			.saturating_add(T::DbWeight::get().writes(7))
@@ -164,14 +186,24 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		Weight::from_parts(18_446_744_073_709_551_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 	}
+	/// Storage: `Benchmark::Override` (r:0 w:0)
+	/// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	fn execute_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 18_446_744_073_709_551_000 picoseconds.
+		Weight::from_parts(18_446_744_073_709_551_000, 0)
+			.saturating_add(Weight::from_parts(0, 0))
+	}
 	/// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1)
 	/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	fn force_xcm_version() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 6_517_000 picoseconds.
-		Weight::from_parts(6_756_000, 0)
+		// Minimum execution time: 6_232_000 picoseconds.
+		Weight::from_parts(6_507_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -181,8 +213,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_894_000 picoseconds.
-		Weight::from_parts(2_024_000, 0)
+		// Minimum execution time: 1_884_000 picoseconds.
+		Weight::from_parts(2_016_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -208,8 +240,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `145`
 		//  Estimated: `3610`
-		// Minimum execution time: 27_314_000 picoseconds.
-		Weight::from_parts(28_787_000, 0)
+		// Minimum execution time: 26_637_000 picoseconds.
+		Weight::from_parts(27_616_000, 0)
 			.saturating_add(Weight::from_parts(0, 3610))
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(5))
@@ -234,8 +266,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `363`
 		//  Estimated: `3828`
-		// Minimum execution time: 29_840_000 picoseconds.
-		Weight::from_parts(30_589_000, 0)
+		// Minimum execution time: 28_668_000 picoseconds.
+		Weight::from_parts(29_413_000, 0)
 			.saturating_add(Weight::from_parts(0, 3828))
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -246,8 +278,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_893_000 picoseconds.
-		Weight::from_parts(2_017_000, 0)
+		// Minimum execution time: 1_990_000 picoseconds.
+		Weight::from_parts(2_114_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -257,8 +289,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `159`
 		//  Estimated: `13524`
-		// Minimum execution time: 19_211_000 picoseconds.
-		Weight::from_parts(19_552_000, 0)
+		// Minimum execution time: 18_856_000 picoseconds.
+		Weight::from_parts(19_430_000, 0)
 			.saturating_add(Weight::from_parts(0, 13524))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -269,8 +301,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `163`
 		//  Estimated: `13528`
-		// Minimum execution time: 19_177_000 picoseconds.
-		Weight::from_parts(19_704_000, 0)
+		// Minimum execution time: 19_068_000 picoseconds.
+		Weight::from_parts(19_434_000, 0)
 			.saturating_add(Weight::from_parts(0, 13528))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -281,8 +313,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `173`
 		//  Estimated: `16013`
-		// Minimum execution time: 20_449_000 picoseconds.
-		Weight::from_parts(21_075_000, 0)
+		// Minimum execution time: 21_055_000 picoseconds.
+		Weight::from_parts(21_379_000, 0)
 			.saturating_add(Weight::from_parts(0, 16013))
 			.saturating_add(T::DbWeight::get().reads(6))
 	}
@@ -304,8 +336,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `212`
 		//  Estimated: `6152`
-		// Minimum execution time: 26_578_000 picoseconds.
-		Weight::from_parts(27_545_000, 0)
+		// Minimum execution time: 25_736_000 picoseconds.
+		Weight::from_parts(26_423_000, 0)
 			.saturating_add(Weight::from_parts(0, 6152))
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -316,8 +348,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `206`
 		//  Estimated: `11096`
-		// Minimum execution time: 11_646_000 picoseconds.
-		Weight::from_parts(11_944_000, 0)
+		// Minimum execution time: 11_853_000 picoseconds.
+		Weight::from_parts(12_215_000, 0)
 			.saturating_add(Weight::from_parts(0, 11096))
 			.saturating_add(T::DbWeight::get().reads(4))
 	}
@@ -327,8 +359,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `170`
 		//  Estimated: `13535`
-		// Minimum execution time: 19_301_000 picoseconds.
-		Weight::from_parts(19_664_000, 0)
+		// Minimum execution time: 19_418_000 picoseconds.
+		Weight::from_parts(19_794_000, 0)
 			.saturating_add(Weight::from_parts(0, 13535))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -351,8 +383,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `212`
 		//  Estimated: `13577`
-		// Minimum execution time: 35_715_000 picoseconds.
-		Weight::from_parts(36_915_000, 0)
+		// Minimum execution time: 34_719_000 picoseconds.
+		Weight::from_parts(35_260_000, 0)
 			.saturating_add(Weight::from_parts(0, 13577))
 			.saturating_add(T::DbWeight::get().reads(11))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -365,8 +397,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `103`
 		//  Estimated: `1588`
-		// Minimum execution time: 4_871_000 picoseconds.
-		Weight::from_parts(5_066_000, 0)
+		// Minimum execution time: 4_937_000 picoseconds.
+		Weight::from_parts(5_203_000, 0)
 			.saturating_add(Weight::from_parts(0, 1588))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -377,8 +409,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `7740`
 		//  Estimated: `11205`
-		// Minimum execution time: 25_150_000 picoseconds.
-		Weight::from_parts(26_119_000, 0)
+		// Minimum execution time: 26_064_000 picoseconds.
+		Weight::from_parts(26_497_000, 0)
 			.saturating_add(Weight::from_parts(0, 11205))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -389,8 +421,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `160`
 		//  Estimated: `3625`
-		// Minimum execution time: 38_248_000 picoseconds.
-		Weight::from_parts(39_122_000, 0)
+		// Minimum execution time: 37_132_000 picoseconds.
+		Weight::from_parts(37_868_000, 0)
 			.saturating_add(Weight::from_parts(0, 3625))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs
index 48106b5f302d4..e92e801e9f522 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs
@@ -641,6 +641,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl cumulus_pallet_aura_ext::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs
index 71facff87d35f..299e4b8b3cd17 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024
 
 // Executed Command:
@@ -64,8 +64,30 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `145`
 		//  Estimated: `3610`
-		// Minimum execution time: 21_630_000 picoseconds.
-		Weight::from_parts(22_306_000, 0)
+		// Minimum execution time: 21_722_000 picoseconds.
+		Weight::from_parts(22_253_000, 0)
+			.saturating_add(Weight::from_parts(0, 3610))
+			.saturating_add(T::DbWeight::get().reads(6))
+			.saturating_add(T::DbWeight::get().writes(2))
+	}
+	/// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
+	/// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
+	/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
+	/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
+	/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
+	/// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
+	/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	fn send_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `145`
+		//  Estimated: `3610`
+		// Minimum execution time: 21_694_000 picoseconds.
+		Weight::from_parts(22_326_000, 0)
 			.saturating_add(Weight::from_parts(0, 3610))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -90,8 +112,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `145`
 		//  Estimated: `3610`
-		// Minimum execution time: 91_802_000 picoseconds.
-		Weight::from_parts(93_672_000, 0)
+		// Minimum execution time: 94_422_000 picoseconds.
+		Weight::from_parts(96_997_000, 0)
 			.saturating_add(Weight::from_parts(0, 3610))
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -118,8 +140,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `367`
 		//  Estimated: `6196`
-		// Minimum execution time: 118_930_000 picoseconds.
-		Weight::from_parts(122_306_000, 0)
+		// Minimum execution time: 123_368_000 picoseconds.
+		Weight::from_parts(125_798_000, 0)
 			.saturating_add(Weight::from_parts(0, 6196))
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(5))
@@ -148,8 +170,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `496`
 		//  Estimated: `6208`
-		// Minimum execution time: 140_527_000 picoseconds.
-		Weight::from_parts(144_501_000, 0)
+		// Minimum execution time: 142_033_000 picoseconds.
+		Weight::from_parts(145_702_000, 0)
 			.saturating_add(Weight::from_parts(0, 6208))
 			.saturating_add(T::DbWeight::get().reads(12))
 			.saturating_add(T::DbWeight::get().writes(7))
@@ -158,8 +180,16 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 7_556_000 picoseconds.
-		Weight::from_parts(7_798_000, 0)
+		// Minimum execution time: 7_558_000 picoseconds.
+		Weight::from_parts(7_916_000, 0)
+			.saturating_add(Weight::from_parts(0, 0))
+	}
+	fn execute_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 7_978_000 picoseconds.
+		Weight::from_parts(8_210_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 	}
 	/// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1)
@@ -168,8 +198,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 6_373_000 picoseconds.
-		Weight::from_parts(6_603_000, 0)
+		// Minimum execution time: 6_439_000 picoseconds.
+		Weight::from_parts(6_711_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -179,8 +209,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_941_000 picoseconds.
-		Weight::from_parts(2_088_000, 0)
+		// Minimum execution time: 1_982_000 picoseconds.
+		Weight::from_parts(2_260_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -206,8 +236,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `145`
 		//  Estimated: `3610`
-		// Minimum execution time: 27_080_000 picoseconds.
-		Weight::from_parts(27_820_000, 0)
+		// Minimum execution time: 27_120_000 picoseconds.
+		Weight::from_parts(28_048_000, 0)
 			.saturating_add(Weight::from_parts(0, 3610))
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(5))
@@ -232,8 +262,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `363`
 		//  Estimated: `3828`
-		// Minimum execution time: 28_850_000 picoseconds.
-		Weight::from_parts(29_506_000, 0)
+		// Minimum execution time: 29_354_000 picoseconds.
+		Weight::from_parts(30_205_000, 0)
 			.saturating_add(Weight::from_parts(0, 3828))
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -244,8 +274,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_033_000 picoseconds.
-		Weight::from_parts(2_201_000, 0)
+		// Minimum execution time: 1_926_000 picoseconds.
+		Weight::from_parts(2_013_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -255,8 +285,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `159`
 		//  Estimated: `13524`
-		// Minimum execution time: 18_844_000 picoseconds.
-		Weight::from_parts(19_197_000, 0)
+		// Minimum execution time: 18_611_000 picoseconds.
+		Weight::from_parts(19_120_000, 0)
 			.saturating_add(Weight::from_parts(0, 13524))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -267,8 +297,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `163`
 		//  Estimated: `13528`
-		// Minimum execution time: 18_940_000 picoseconds.
-		Weight::from_parts(19_450_000, 0)
+		// Minimum execution time: 18_373_000 picoseconds.
+		Weight::from_parts(18_945_000, 0)
 			.saturating_add(Weight::from_parts(0, 13528))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -279,8 +309,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `173`
 		//  Estimated: `16013`
-		// Minimum execution time: 20_521_000 picoseconds.
-		Weight::from_parts(21_076_000, 0)
+		// Minimum execution time: 20_459_000 picoseconds.
+		Weight::from_parts(20_951_000, 0)
 			.saturating_add(Weight::from_parts(0, 16013))
 			.saturating_add(T::DbWeight::get().reads(6))
 	}
@@ -302,8 +332,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `212`
 		//  Estimated: `6152`
-		// Minimum execution time: 26_007_000 picoseconds.
-		Weight::from_parts(26_448_000, 0)
+		// Minimum execution time: 26_003_000 picoseconds.
+		Weight::from_parts(26_678_000, 0)
 			.saturating_add(Weight::from_parts(0, 6152))
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -314,8 +344,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `206`
 		//  Estimated: `11096`
-		// Minimum execution time: 11_584_000 picoseconds.
-		Weight::from_parts(12_080_000, 0)
+		// Minimum execution time: 11_557_000 picoseconds.
+		Weight::from_parts(11_868_000, 0)
 			.saturating_add(Weight::from_parts(0, 11096))
 			.saturating_add(T::DbWeight::get().reads(4))
 	}
@@ -325,8 +355,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `170`
 		//  Estimated: `13535`
-		// Minimum execution time: 19_157_000 picoseconds.
-		Weight::from_parts(19_513_000, 0)
+		// Minimum execution time: 18_710_000 picoseconds.
+		Weight::from_parts(19_240_000, 0)
 			.saturating_add(Weight::from_parts(0, 13535))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -349,8 +379,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `212`
 		//  Estimated: `13577`
-		// Minimum execution time: 34_878_000 picoseconds.
-		Weight::from_parts(35_623_000, 0)
+		// Minimum execution time: 34_393_000 picoseconds.
+		Weight::from_parts(35_138_000, 0)
 			.saturating_add(Weight::from_parts(0, 13577))
 			.saturating_add(T::DbWeight::get().reads(11))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -363,8 +393,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `103`
 		//  Estimated: `1588`
-		// Minimum execution time: 3_900_000 picoseconds.
-		Weight::from_parts(4_161_000, 0)
+		// Minimum execution time: 4_043_000 picoseconds.
+		Weight::from_parts(4_216_000, 0)
 			.saturating_add(Weight::from_parts(0, 1588))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -375,8 +405,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `7740`
 		//  Estimated: `11205`
-		// Minimum execution time: 25_731_000 picoseconds.
-		Weight::from_parts(26_160_000, 0)
+		// Minimum execution time: 25_410_000 picoseconds.
+		Weight::from_parts(26_019_000, 0)
 			.saturating_add(Weight::from_parts(0, 11205))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -387,8 +417,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `160`
 		//  Estimated: `3625`
-		// Minimum execution time: 37_251_000 picoseconds.
-		Weight::from_parts(38_075_000, 0)
+		// Minimum execution time: 38_850_000 picoseconds.
+		Weight::from_parts(39_593_000, 0)
 			.saturating_add(Weight::from_parts(0, 3625))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs
index 3980fa0d501a1..f0aa4f8e91ccc 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs
@@ -387,6 +387,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl cumulus_pallet_aura_ext::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs
index a732e1a573439..adfaa9ea2028e 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024
 
 // Executed Command:
@@ -64,8 +64,30 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `38`
 		//  Estimated: `3503`
-		// Minimum execution time: 18_513_000 picoseconds.
-		Weight::from_parts(19_156_000, 0)
+		// Minimum execution time: 18_732_000 picoseconds.
+		Weight::from_parts(19_386_000, 0)
+			.saturating_add(Weight::from_parts(0, 3503))
+			.saturating_add(T::DbWeight::get().reads(6))
+			.saturating_add(T::DbWeight::get().writes(2))
+	}
+	/// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
+	/// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
+	/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
+	/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
+	/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
+	/// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
+	/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	fn send_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `38`
+		//  Estimated: `3503`
+		// Minimum execution time: 18_943_000 picoseconds.
+		Weight::from_parts(19_455_000, 0)
 			.saturating_add(Weight::from_parts(0, 3503))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -90,8 +112,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `70`
 		//  Estimated: `3593`
-		// Minimum execution time: 88_096_000 picoseconds.
-		Weight::from_parts(89_732_000, 0)
+		// Minimum execution time: 88_917_000 picoseconds.
+		Weight::from_parts(91_611_000, 0)
 			.saturating_add(Weight::from_parts(0, 3593))
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -126,8 +148,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `70`
 		//  Estimated: `3593`
-		// Minimum execution time: 88_239_000 picoseconds.
-		Weight::from_parts(89_729_000, 0)
+		// Minimum execution time: 88_587_000 picoseconds.
+		Weight::from_parts(90_303_000, 0)
 			.saturating_add(Weight::from_parts(0, 3593))
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -142,14 +164,24 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		Weight::from_parts(18_446_744_073_709_551_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 	}
+	/// Storage: `Benchmark::Override` (r:0 w:0)
+	/// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	fn execute_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 18_446_744_073_709_551_000 picoseconds.
+		Weight::from_parts(18_446_744_073_709_551_000, 0)
+			.saturating_add(Weight::from_parts(0, 0))
+	}
 	/// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1)
 	/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	fn force_xcm_version() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 5_955_000 picoseconds.
-		Weight::from_parts(6_266_000, 0)
+		// Minimum execution time: 5_856_000 picoseconds.
+		Weight::from_parts(6_202_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -159,8 +191,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_868_000 picoseconds.
-		Weight::from_parts(1_961_000, 0)
+		// Minimum execution time: 1_797_000 picoseconds.
+		Weight::from_parts(1_970_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -186,8 +218,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `38`
 		//  Estimated: `3503`
-		// Minimum execution time: 24_388_000 picoseconds.
-		Weight::from_parts(25_072_000, 0)
+		// Minimum execution time: 24_479_000 picoseconds.
+		Weight::from_parts(25_058_000, 0)
 			.saturating_add(Weight::from_parts(0, 3503))
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(5))
@@ -212,8 +244,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `255`
 		//  Estimated: `3720`
-		// Minimum execution time: 26_762_000 picoseconds.
-		Weight::from_parts(27_631_000, 0)
+		// Minimum execution time: 27_282_000 picoseconds.
+		Weight::from_parts(27_924_000, 0)
 			.saturating_add(Weight::from_parts(0, 3720))
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -224,8 +256,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_856_000 picoseconds.
-		Weight::from_parts(2_033_000, 0)
+		// Minimum execution time: 1_801_000 picoseconds.
+		Weight::from_parts(1_988_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -235,8 +267,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `89`
 		//  Estimated: `13454`
-		// Minimum execution time: 17_718_000 picoseconds.
-		Weight::from_parts(18_208_000, 0)
+		// Minimum execution time: 16_509_000 picoseconds.
+		Weight::from_parts(16_939_000, 0)
 			.saturating_add(Weight::from_parts(0, 13454))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -247,8 +279,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `93`
 		//  Estimated: `13458`
-		// Minimum execution time: 17_597_000 picoseconds.
-		Weight::from_parts(18_090_000, 0)
+		// Minimum execution time: 16_140_000 picoseconds.
+		Weight::from_parts(16_843_000, 0)
 			.saturating_add(Weight::from_parts(0, 13458))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -259,8 +291,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `15946`
-		// Minimum execution time: 19_533_000 picoseconds.
-		Weight::from_parts(20_164_000, 0)
+		// Minimum execution time: 18_160_000 picoseconds.
+		Weight::from_parts(18_948_000, 0)
 			.saturating_add(Weight::from_parts(0, 15946))
 			.saturating_add(T::DbWeight::get().reads(6))
 	}
@@ -282,8 +314,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `6046`
-		// Minimum execution time: 24_958_000 picoseconds.
-		Weight::from_parts(25_628_000, 0)
+		// Minimum execution time: 24_409_000 picoseconds.
+		Weight::from_parts(25_261_000, 0)
 			.saturating_add(Weight::from_parts(0, 6046))
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -294,8 +326,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `136`
 		//  Estimated: `11026`
-		// Minimum execution time: 12_209_000 picoseconds.
-		Weight::from_parts(12_612_000, 0)
+		// Minimum execution time: 10_848_000 picoseconds.
+		Weight::from_parts(11_241_000, 0)
 			.saturating_add(Weight::from_parts(0, 11026))
 			.saturating_add(T::DbWeight::get().reads(4))
 	}
@@ -305,8 +337,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `100`
 		//  Estimated: `13465`
-		// Minimum execution time: 17_844_000 picoseconds.
-		Weight::from_parts(18_266_000, 0)
+		// Minimum execution time: 16_609_000 picoseconds.
+		Weight::from_parts(17_044_000, 0)
 			.saturating_add(Weight::from_parts(0, 13465))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -329,8 +361,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `13471`
-		// Minimum execution time: 34_131_000 picoseconds.
-		Weight::from_parts(34_766_000, 0)
+		// Minimum execution time: 32_500_000 picoseconds.
+		Weight::from_parts(33_475_000, 0)
 			.saturating_add(Weight::from_parts(0, 13471))
 			.saturating_add(T::DbWeight::get().reads(11))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -343,8 +375,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `32`
 		//  Estimated: `1517`
-		// Minimum execution time: 3_525_000 picoseconds.
-		Weight::from_parts(3_724_000, 0)
+		// Minimum execution time: 3_484_000 picoseconds.
+		Weight::from_parts(3_673_000, 0)
 			.saturating_add(Weight::from_parts(0, 1517))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -355,8 +387,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `7669`
 		//  Estimated: `11134`
-		// Minimum execution time: 24_975_000 picoseconds.
-		Weight::from_parts(25_517_000, 0)
+		// Minimum execution time: 25_225_000 picoseconds.
+		Weight::from_parts(25_731_000, 0)
 			.saturating_add(Weight::from_parts(0, 11134))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -367,8 +399,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `90`
 		//  Estimated: `3555`
-		// Minimum execution time: 33_761_000 picoseconds.
-		Weight::from_parts(34_674_000, 0)
+		// Minimum execution time: 33_961_000 picoseconds.
+		Weight::from_parts(34_818_000, 0)
 			.saturating_add(Weight::from_parts(0, 3555))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs
index 9bdea6b9a7dd7..3b759301d0edc 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs
@@ -348,6 +348,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl cumulus_pallet_aura_ext::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs
index a78ff2355efaf..9cf4c61466a1b 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-03-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024
 
 // Executed Command:
@@ -64,8 +64,30 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `38`
 		//  Estimated: `3503`
-		// Minimum execution time: 19_527_000 picoseconds.
-		Weight::from_parts(19_839_000, 0)
+		// Minimum execution time: 19_702_000 picoseconds.
+		Weight::from_parts(20_410_000, 0)
+			.saturating_add(Weight::from_parts(0, 3503))
+			.saturating_add(T::DbWeight::get().reads(6))
+			.saturating_add(T::DbWeight::get().writes(2))
+	}
+	/// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
+	/// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
+	/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
+	/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
+	/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
+	/// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
+	/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	fn send_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `38`
+		//  Estimated: `3503`
+		// Minimum execution time: 19_525_000 picoseconds.
+		Weight::from_parts(20_071_000, 0)
 			.saturating_add(Weight::from_parts(0, 3503))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -90,8 +112,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `107`
 		//  Estimated: `3593`
-		// Minimum execution time: 90_938_000 picoseconds.
-		Weight::from_parts(92_822_000, 0)
+		// Minimum execution time: 91_793_000 picoseconds.
+		Weight::from_parts(93_761_000, 0)
 			.saturating_add(Weight::from_parts(0, 3593))
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -126,8 +148,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `107`
 		//  Estimated: `3593`
-		// Minimum execution time: 90_133_000 picoseconds.
-		Weight::from_parts(92_308_000, 0)
+		// Minimum execution time: 91_819_000 picoseconds.
+		Weight::from_parts(93_198_000, 0)
 			.saturating_add(Weight::from_parts(0, 3593))
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -142,14 +164,24 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		Weight::from_parts(18_446_744_073_709_551_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 	}
+	/// Storage: `Benchmark::Override` (r:0 w:0)
+	/// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	fn execute_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 18_446_744_073_709_551_000 picoseconds.
+		Weight::from_parts(18_446_744_073_709_551_000, 0)
+			.saturating_add(Weight::from_parts(0, 0))
+	}
 	/// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1)
 	/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	fn force_xcm_version() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 6_205_000 picoseconds.
-		Weight::from_parts(6_595_000, 0)
+		// Minimum execution time: 6_183_000 picoseconds.
+		Weight::from_parts(6_598_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -159,8 +191,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_927_000 picoseconds.
-		Weight::from_parts(2_062_000, 0)
+		// Minimum execution time: 1_987_000 picoseconds.
+		Weight::from_parts(2_076_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -186,8 +218,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `38`
 		//  Estimated: `3503`
-		// Minimum execution time: 25_078_000 picoseconds.
-		Weight::from_parts(25_782_000, 0)
+		// Minimum execution time: 25_375_000 picoseconds.
+		Weight::from_parts(26_165_000, 0)
 			.saturating_add(Weight::from_parts(0, 3503))
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(5))
@@ -212,8 +244,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `255`
 		//  Estimated: `3720`
-		// Minimum execution time: 28_188_000 picoseconds.
-		Weight::from_parts(28_826_000, 0)
+		// Minimum execution time: 28_167_000 picoseconds.
+		Weight::from_parts(28_792_000, 0)
 			.saturating_add(Weight::from_parts(0, 3720))
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -224,8 +256,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_886_000 picoseconds.
-		Weight::from_parts(1_991_000, 0)
+		// Minimum execution time: 2_039_000 picoseconds.
+		Weight::from_parts(2_211_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -235,8 +267,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `89`
 		//  Estimated: `13454`
-		// Minimum execution time: 17_443_000 picoseconds.
-		Weight::from_parts(17_964_000, 0)
+		// Minimum execution time: 17_127_000 picoseconds.
+		Weight::from_parts(17_519_000, 0)
 			.saturating_add(Weight::from_parts(0, 13454))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -247,8 +279,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `93`
 		//  Estimated: `13458`
-		// Minimum execution time: 17_357_000 picoseconds.
-		Weight::from_parts(18_006_000, 0)
+		// Minimum execution time: 16_701_000 picoseconds.
+		Weight::from_parts(17_250_000, 0)
 			.saturating_add(Weight::from_parts(0, 13458))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -259,8 +291,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `15946`
-		// Minimum execution time: 18_838_000 picoseconds.
-		Weight::from_parts(19_688_000, 0)
+		// Minimum execution time: 18_795_000 picoseconds.
+		Weight::from_parts(19_302_000, 0)
 			.saturating_add(Weight::from_parts(0, 15946))
 			.saturating_add(T::DbWeight::get().reads(6))
 	}
@@ -282,8 +314,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `6046`
-		// Minimum execution time: 25_517_000 picoseconds.
-		Weight::from_parts(26_131_000, 0)
+		// Minimum execution time: 25_007_000 picoseconds.
+		Weight::from_parts(25_786_000, 0)
 			.saturating_add(Weight::from_parts(0, 6046))
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -294,8 +326,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `136`
 		//  Estimated: `11026`
-		// Minimum execution time: 11_587_000 picoseconds.
-		Weight::from_parts(11_963_000, 0)
+		// Minimum execution time: 11_534_000 picoseconds.
+		Weight::from_parts(11_798_000, 0)
 			.saturating_add(Weight::from_parts(0, 11026))
 			.saturating_add(T::DbWeight::get().reads(4))
 	}
@@ -305,8 +337,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `100`
 		//  Estimated: `13465`
-		// Minimum execution time: 17_490_000 picoseconds.
-		Weight::from_parts(18_160_000, 0)
+		// Minimum execution time: 17_357_000 picoseconds.
+		Weight::from_parts(17_629_000, 0)
 			.saturating_add(Weight::from_parts(0, 13465))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -329,8 +361,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `13471`
-		// Minimum execution time: 34_088_000 picoseconds.
-		Weight::from_parts(34_598_000, 0)
+		// Minimum execution time: 33_487_000 picoseconds.
+		Weight::from_parts(34_033_000, 0)
 			.saturating_add(Weight::from_parts(0, 13471))
 			.saturating_add(T::DbWeight::get().reads(11))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -343,8 +375,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `32`
 		//  Estimated: `1517`
-		// Minimum execution time: 3_566_000 picoseconds.
-		Weight::from_parts(3_754_000, 0)
+		// Minimum execution time: 3_688_000 picoseconds.
+		Weight::from_parts(3_854_000, 0)
 			.saturating_add(Weight::from_parts(0, 1517))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -355,8 +387,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `7669`
 		//  Estimated: `11134`
-		// Minimum execution time: 25_078_000 picoseconds.
-		Weight::from_parts(25_477_000, 0)
+		// Minimum execution time: 26_336_000 picoseconds.
+		Weight::from_parts(26_873_000, 0)
 			.saturating_add(Weight::from_parts(0, 11134))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -367,8 +399,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `90`
 		//  Estimated: `3555`
-		// Minimum execution time: 34_661_000 picoseconds.
-		Weight::from_parts(35_411_000, 0)
+		// Minimum execution time: 34_633_000 picoseconds.
+		Weight::from_parts(35_171_000, 0)
 			.saturating_add(Weight::from_parts(0, 3555))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs
index d3f588bf25ff2..e1c2e1a6237b1 100644
--- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs
+++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs
@@ -423,6 +423,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl cumulus_pallet_aura_ext::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs
index 5d427d850046f..0edd5dfff2b8b 100644
--- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs
+++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-westend-dev")`, DB CACHE: 1024
 
 // Executed Command:
@@ -64,8 +64,30 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `145`
 		//  Estimated: `3610`
-		// Minimum execution time: 21_813_000 picoseconds.
-		Weight::from_parts(22_332_000, 0)
+		// Minimum execution time: 21_911_000 picoseconds.
+		Weight::from_parts(22_431_000, 0)
+			.saturating_add(Weight::from_parts(0, 3610))
+			.saturating_add(T::DbWeight::get().reads(6))
+			.saturating_add(T::DbWeight::get().writes(2))
+	}
+	/// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
+	/// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
+	/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
+	/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
+	/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
+	/// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
+	/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	fn send_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `145`
+		//  Estimated: `3610`
+		// Minimum execution time: 22_143_000 picoseconds.
+		Weight::from_parts(22_843_000, 0)
 			.saturating_add(Weight::from_parts(0, 3610))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -90,8 +112,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `214`
 		//  Estimated: `3679`
-		// Minimum execution time: 93_243_000 picoseconds.
-		Weight::from_parts(95_650_000, 0)
+		// Minimum execution time: 96_273_000 picoseconds.
+		Weight::from_parts(98_351_000, 0)
 			.saturating_add(Weight::from_parts(0, 3679))
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -126,8 +148,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `214`
 		//  Estimated: `3679`
-		// Minimum execution time: 96_199_000 picoseconds.
-		Weight::from_parts(98_620_000, 0)
+		// Minimum execution time: 95_571_000 picoseconds.
+		Weight::from_parts(96_251_000, 0)
 			.saturating_add(Weight::from_parts(0, 3679))
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -142,14 +164,24 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		Weight::from_parts(18_446_744_073_709_551_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 	}
+	/// Storage: `Benchmark::Override` (r:0 w:0)
+	/// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	fn execute_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 18_446_744_073_709_551_000 picoseconds.
+		Weight::from_parts(18_446_744_073_709_551_000, 0)
+			.saturating_add(Weight::from_parts(0, 0))
+	}
 	/// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1)
 	/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	fn force_xcm_version() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 6_442_000 picoseconds.
-		Weight::from_parts(6_682_000, 0)
+		// Minimum execution time: 6_227_000 picoseconds.
+		Weight::from_parts(6_419_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -159,8 +191,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_833_000 picoseconds.
-		Weight::from_parts(1_973_000, 0)
+		// Minimum execution time: 1_851_000 picoseconds.
+		Weight::from_parts(1_940_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -186,8 +218,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `145`
 		//  Estimated: `3610`
-		// Minimum execution time: 27_318_000 picoseconds.
-		Weight::from_parts(28_224_000, 0)
+		// Minimum execution time: 27_449_000 picoseconds.
+		Weight::from_parts(28_513_000, 0)
 			.saturating_add(Weight::from_parts(0, 3610))
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(5))
@@ -212,8 +244,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `363`
 		//  Estimated: `3828`
-		// Minimum execution time: 29_070_000 picoseconds.
-		Weight::from_parts(30_205_000, 0)
+		// Minimum execution time: 29_477_000 picoseconds.
+		Weight::from_parts(30_251_000, 0)
 			.saturating_add(Weight::from_parts(0, 3828))
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -224,8 +256,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_904_000 picoseconds.
-		Weight::from_parts(2_033_000, 0)
+		// Minimum execution time: 1_894_000 picoseconds.
+		Weight::from_parts(2_009_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -235,8 +267,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `159`
 		//  Estimated: `13524`
-		// Minimum execution time: 18_348_000 picoseconds.
-		Weight::from_parts(18_853_000, 0)
+		// Minimum execution time: 17_991_000 picoseconds.
+		Weight::from_parts(18_651_000, 0)
 			.saturating_add(Weight::from_parts(0, 13524))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -247,8 +279,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `163`
 		//  Estimated: `13528`
-		// Minimum execution time: 17_964_000 picoseconds.
-		Weight::from_parts(18_548_000, 0)
+		// Minimum execution time: 18_321_000 picoseconds.
+		Weight::from_parts(18_701_000, 0)
 			.saturating_add(Weight::from_parts(0, 13528))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -259,8 +291,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `173`
 		//  Estimated: `16013`
-		// Minimum execution time: 19_708_000 picoseconds.
-		Weight::from_parts(20_157_000, 0)
+		// Minimum execution time: 19_762_000 picoseconds.
+		Weight::from_parts(20_529_000, 0)
 			.saturating_add(Weight::from_parts(0, 16013))
 			.saturating_add(T::DbWeight::get().reads(6))
 	}
@@ -282,8 +314,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `212`
 		//  Estimated: `6152`
-		// Minimum execution time: 26_632_000 picoseconds.
-		Weight::from_parts(27_314_000, 0)
+		// Minimum execution time: 26_927_000 picoseconds.
+		Weight::from_parts(27_629_000, 0)
 			.saturating_add(Weight::from_parts(0, 6152))
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -294,8 +326,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `206`
 		//  Estimated: `11096`
-		// Minimum execution time: 11_929_000 picoseconds.
-		Weight::from_parts(12_304_000, 0)
+		// Minimum execution time: 11_957_000 picoseconds.
+		Weight::from_parts(12_119_000, 0)
 			.saturating_add(Weight::from_parts(0, 11096))
 			.saturating_add(T::DbWeight::get().reads(4))
 	}
@@ -305,8 +337,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `170`
 		//  Estimated: `13535`
-		// Minimum execution time: 18_599_000 picoseconds.
-		Weight::from_parts(19_195_000, 0)
+		// Minimum execution time: 17_942_000 picoseconds.
+		Weight::from_parts(18_878_000, 0)
 			.saturating_add(Weight::from_parts(0, 13535))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -329,8 +361,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `212`
 		//  Estimated: `13577`
-		// Minimum execution time: 35_524_000 picoseconds.
-		Weight::from_parts(36_272_000, 0)
+		// Minimum execution time: 35_640_000 picoseconds.
+		Weight::from_parts(36_340_000, 0)
 			.saturating_add(Weight::from_parts(0, 13577))
 			.saturating_add(T::DbWeight::get().reads(11))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -344,7 +376,7 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		//  Measured:  `103`
 		//  Estimated: `1588`
 		// Minimum execution time: 4_044_000 picoseconds.
-		Weight::from_parts(4_238_000, 0)
+		Weight::from_parts(4_229_000, 0)
 			.saturating_add(Weight::from_parts(0, 1588))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -355,8 +387,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `7740`
 		//  Estimated: `11205`
-		// Minimum execution time: 25_741_000 picoseconds.
-		Weight::from_parts(26_301_000, 0)
+		// Minimum execution time: 26_262_000 picoseconds.
+		Weight::from_parts(26_842_000, 0)
 			.saturating_add(Weight::from_parts(0, 11205))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -367,8 +399,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `160`
 		//  Estimated: `3625`
-		// Minimum execution time: 35_925_000 picoseconds.
-		Weight::from_parts(36_978_000, 0)
+		// Minimum execution time: 36_775_000 picoseconds.
+		Weight::from_parts(37_265_000, 0)
 			.saturating_add(Weight::from_parts(0, 3625))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs
index e1586c7d9b29e..ec0a5f6fc96cd 100644
--- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs
+++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs
@@ -318,6 +318,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl cumulus_pallet_aura_ext::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs
index 86eb5cdfcaf5e..67f486893532b 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs
@@ -301,6 +301,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl parachain_info::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_broker.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_broker.rs
index 2d30ddc612cb9..89b1c4c86632f 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_broker.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_broker.rs
@@ -16,26 +16,24 @@
 
 //! Autogenerated weights for `pallet_broker`
 //!
-//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2024-01-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
+//! DATE: 2024-03-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-j8vvqcjr-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-rococo-dev")`, DB CACHE: 1024
 
 // Executed Command:
-// ./target/production/polkadot-parachain
+// target/production/polkadot-parachain
 // benchmark
 // pallet
-// --chain=coretime-rococo-dev
-// --wasm-execution=compiled
-// --pallet=pallet_broker
-// --no-storage-info
-// --no-median-slopes
-// --no-min-squares
-// --extrinsic=*
 // --steps=50
 // --repeat=20
-// --json
+// --extrinsic=*
+// --wasm-execution=compiled
+// --heap-pages=4096
+// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json
+// --pallet=pallet_broker
+// --chain=coretime-rococo-dev
 // --header=./cumulus/file_header.txt
 // --output=./cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/
 
@@ -56,8 +54,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_462_000 picoseconds.
-		Weight::from_parts(2_552_000, 0)
+		// Minimum execution time: 1_918_000 picoseconds.
+		Weight::from_parts(2_092_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -67,8 +65,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `10888`
 		//  Estimated: `13506`
-		// Minimum execution time: 25_494_000 picoseconds.
-		Weight::from_parts(26_063_000, 0)
+		// Minimum execution time: 21_943_000 picoseconds.
+		Weight::from_parts(22_570_000, 0)
 			.saturating_add(Weight::from_parts(0, 13506))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -79,8 +77,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `12090`
 		//  Estimated: `13506`
-		// Minimum execution time: 22_299_000 picoseconds.
-		Weight::from_parts(22_911_000, 0)
+		// Minimum execution time: 20_923_000 picoseconds.
+		Weight::from_parts(21_354_000, 0)
 			.saturating_add(Weight::from_parts(0, 13506))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -95,8 +93,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `466`
 		//  Estimated: `1951`
-		// Minimum execution time: 11_590_000 picoseconds.
-		Weight::from_parts(12_007_000, 0)
+		// Minimum execution time: 10_687_000 picoseconds.
+		Weight::from_parts(11_409_000, 0)
 			.saturating_add(Weight::from_parts(0, 1951))
 			.saturating_add(T::DbWeight::get().reads(3))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -124,11 +122,11 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `12567`
 		//  Estimated: `14052`
-		// Minimum execution time: 120_928_000 picoseconds.
-		Weight::from_parts(124_947_252, 0)
+		// Minimum execution time: 111_288_000 picoseconds.
+		Weight::from_parts(117_804_282, 0)
 			.saturating_add(Weight::from_parts(0, 14052))
-			// Standard Error: 435
-			.saturating_add(Weight::from_parts(1_246, 0).saturating_mul(n.into()))
+			// Standard Error: 391
+			.saturating_add(Weight::from_parts(1_243, 0).saturating_mul(n.into()))
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(66))
 	}
@@ -144,8 +142,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `316`
 		//  Estimated: `3593`
-		// Minimum execution time: 32_826_000 picoseconds.
-		Weight::from_parts(33_889_000, 0)
+		// Minimum execution time: 33_006_000 picoseconds.
+		Weight::from_parts(34_256_000, 0)
 			.saturating_add(Weight::from_parts(0, 3593))
 			.saturating_add(T::DbWeight::get().reads(3))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -166,8 +164,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `434`
 		//  Estimated: `4698`
-		// Minimum execution time: 57_362_000 picoseconds.
-		Weight::from_parts(58_994_000, 0)
+		// Minimum execution time: 61_473_000 picoseconds.
+		Weight::from_parts(66_476_000, 0)
 			.saturating_add(Weight::from_parts(0, 4698))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -178,8 +176,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `357`
 		//  Estimated: `3550`
-		// Minimum execution time: 13_982_000 picoseconds.
-		Weight::from_parts(14_447_000, 0)
+		// Minimum execution time: 13_771_000 picoseconds.
+		Weight::from_parts(14_374_000, 0)
 			.saturating_add(Weight::from_parts(0, 3550))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -190,8 +188,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `357`
 		//  Estimated: `3550`
-		// Minimum execution time: 15_070_000 picoseconds.
-		Weight::from_parts(15_735_000, 0)
+		// Minimum execution time: 15_162_000 picoseconds.
+		Weight::from_parts(15_742_000, 0)
 			.saturating_add(Weight::from_parts(0, 3550))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -202,8 +200,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `357`
 		//  Estimated: `3550`
-		// Minimum execution time: 16_527_000 picoseconds.
-		Weight::from_parts(16_894_000, 0)
+		// Minimum execution time: 16_196_000 picoseconds.
+		Weight::from_parts(16_796_000, 0)
 			.saturating_add(Weight::from_parts(0, 3550))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -220,8 +218,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `936`
 		//  Estimated: `4681`
-		// Minimum execution time: 25_493_000 picoseconds.
-		Weight::from_parts(26_091_000, 0)
+		// Minimum execution time: 25_653_000 picoseconds.
+		Weight::from_parts(27_006_000, 0)
 			.saturating_add(Weight::from_parts(0, 4681))
 			.saturating_add(T::DbWeight::get().reads(4))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -240,8 +238,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `1002`
 		//  Estimated: `5996`
-		// Minimum execution time: 31_498_000 picoseconds.
-		Weight::from_parts(32_560_000, 0)
+		// Minimum execution time: 31_114_000 picoseconds.
+		Weight::from_parts(32_235_000, 0)
 			.saturating_add(Weight::from_parts(0, 5996))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(5))
@@ -257,11 +255,11 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `652`
 		//  Estimated: `6196 + m * (2520 ±0)`
-		// Minimum execution time: 57_183_000 picoseconds.
-		Weight::from_parts(58_024_898, 0)
+		// Minimum execution time: 57_280_000 picoseconds.
+		Weight::from_parts(58_127_480, 0)
 			.saturating_add(Weight::from_parts(0, 6196))
-			// Standard Error: 35_831
-			.saturating_add(Weight::from_parts(1_384_446, 0).saturating_mul(m.into()))
+			// Standard Error: 41_670
+			.saturating_add(Weight::from_parts(1_203_066, 0).saturating_mul(m.into()))
 			.saturating_add(T::DbWeight::get().reads(3))
 			.saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into())))
 			.saturating_add(T::DbWeight::get().writes(5))
@@ -283,8 +281,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `215`
 		//  Estimated: `3680`
-		// Minimum execution time: 59_762_000 picoseconds.
-		Weight::from_parts(61_114_000, 0)
+		// Minimum execution time: 59_968_000 picoseconds.
+		Weight::from_parts(62_315_000, 0)
 			.saturating_add(Weight::from_parts(0, 3680))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -297,8 +295,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `465`
 		//  Estimated: `3550`
-		// Minimum execution time: 41_473_000 picoseconds.
-		Weight::from_parts(44_155_000, 0)
+		// Minimum execution time: 50_887_000 picoseconds.
+		Weight::from_parts(57_366_000, 0)
 			.saturating_add(Weight::from_parts(0, 3550))
 			.saturating_add(T::DbWeight::get().reads(2))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -313,8 +311,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `463`
 		//  Estimated: `3533`
-		// Minimum execution time: 56_672_000 picoseconds.
-		Weight::from_parts(58_086_000, 0)
+		// Minimum execution time: 84_472_000 picoseconds.
+		Weight::from_parts(96_536_000, 0)
 			.saturating_add(Weight::from_parts(0, 3533))
 			.saturating_add(T::DbWeight::get().reads(3))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -331,8 +329,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `857`
 		//  Estimated: `3593`
-		// Minimum execution time: 64_460_000 picoseconds.
-		Weight::from_parts(65_894_000, 0)
+		// Minimum execution time: 96_371_000 picoseconds.
+		Weight::from_parts(104_659_000, 0)
 			.saturating_add(Weight::from_parts(0, 3593))
 			.saturating_add(T::DbWeight::get().reads(4))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -345,8 +343,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `957`
 		//  Estimated: `4698`
-		// Minimum execution time: 37_447_000 picoseconds.
-		Weight::from_parts(42_318_000, 0)
+		// Minimum execution time: 51_741_000 picoseconds.
+		Weight::from_parts(54_461_000, 0)
 			.saturating_add(Weight::from_parts(0, 4698))
 			.saturating_add(T::DbWeight::get().reads(2))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -366,8 +364,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `74`
 		//  Estimated: `3539`
-		// Minimum execution time: 21_219_000 picoseconds.
-		Weight::from_parts(22_084_648, 0)
+		// Minimum execution time: 19_901_000 picoseconds.
+		Weight::from_parts(21_028_116, 0)
 			.saturating_add(Weight::from_parts(0, 3539))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -379,11 +377,11 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `266`
 		//  Estimated: `1487`
-		// Minimum execution time: 5_792_000 picoseconds.
-		Weight::from_parts(6_358_588, 0)
+		// Minimum execution time: 5_987_000 picoseconds.
+		Weight::from_parts(6_412_478, 0)
 			.saturating_add(Weight::from_parts(0, 1487))
-			// Standard Error: 20
-			.saturating_add(Weight::from_parts(26, 0).saturating_mul(n.into()))
+			// Standard Error: 16
+			.saturating_add(Weight::from_parts(47, 0).saturating_mul(n.into()))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -397,8 +395,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `447`
 		//  Estimated: `6196`
-		// Minimum execution time: 38_690_000 picoseconds.
-		Weight::from_parts(39_706_000, 0)
+		// Minimum execution time: 38_623_000 picoseconds.
+		Weight::from_parts(39_773_000, 0)
 			.saturating_add(Weight::from_parts(0, 6196))
 			.saturating_add(T::DbWeight::get().reads(4))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -414,15 +412,13 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 	/// Storage: `Broker::Workplan` (r:0 w:60)
 	/// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`)
 	/// The range of component `n` is `[0, 1000]`.
-	fn rotate_sale(n: u32, ) -> Weight {
+	fn rotate_sale(_n: u32, ) -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `12514`
 		//  Estimated: `13506`
-		// Minimum execution time: 93_531_000 picoseconds.
-		Weight::from_parts(95_836_318, 0)
+		// Minimum execution time: 97_074_000 picoseconds.
+		Weight::from_parts(101_247_740, 0)
 			.saturating_add(Weight::from_parts(0, 13506))
-			// Standard Error: 113
-			.saturating_add(Weight::from_parts(329, 0).saturating_mul(n.into()))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(65))
 	}
@@ -434,8 +430,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `42`
 		//  Estimated: `3493`
-		// Minimum execution time: 6_506_000 picoseconds.
-		Weight::from_parts(6_783_000, 0)
+		// Minimum execution time: 6_317_000 picoseconds.
+		Weight::from_parts(6_521_000, 0)
 			.saturating_add(Weight::from_parts(0, 3493))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -458,8 +454,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `1321`
 		//  Estimated: `4786`
-		// Minimum execution time: 31_927_000 picoseconds.
-		Weight::from_parts(32_748_000, 0)
+		// Minimum execution time: 32_575_000 picoseconds.
+		Weight::from_parts(33_299_000, 0)
 			.saturating_add(Weight::from_parts(0, 4786))
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -478,8 +474,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `74`
 		//  Estimated: `3539`
-		// Minimum execution time: 15_682_000 picoseconds.
-		Weight::from_parts(16_012_000, 0)
+		// Minimum execution time: 15_256_000 picoseconds.
+		Weight::from_parts(15_927_000, 0)
 			.saturating_add(Weight::from_parts(0, 3539))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -490,8 +486,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_147_000 picoseconds.
-		Weight::from_parts(2_281_000, 0)
+		// Minimum execution time: 1_783_000 picoseconds.
+		Weight::from_parts(1_904_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -509,10 +505,22 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `398`
 		//  Estimated: `3863`
-		// Minimum execution time: 12_015_000 picoseconds.
-		Weight::from_parts(12_619_000, 0)
+		// Minimum execution time: 12_307_000 picoseconds.
+		Weight::from_parts(12_967_000, 0)
 			.saturating_add(Weight::from_parts(0, 3863))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
+	/// Storage: `Broker::Leases` (r:1 w:1)
+	/// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(401), added: 896, mode: `MaxEncodedLen`)
+	fn swap_leases() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `470`
+		//  Estimated: `1886`
+		// Minimum execution time: 6_597_000 picoseconds.
+		Weight::from_parts(6_969_000, 0)
+			.saturating_add(Weight::from_parts(0, 1886))
+			.saturating_add(T::DbWeight::get().reads(1))
+			.saturating_add(T::DbWeight::get().writes(1))
+	}
 }
diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs
index c5d315467c1ed..df0044089c8f6 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-rococo-dev")`, DB CACHE: 1024
 
 // Executed Command:
@@ -62,8 +62,28 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `74`
 		//  Estimated: `3539`
-		// Minimum execution time: 35_051_000 picoseconds.
-		Weight::from_parts(35_200_000, 0)
+		// Minimum execution time: 18_767_000 picoseconds.
+		Weight::from_parts(19_420_000, 0)
+			.saturating_add(Weight::from_parts(0, 3539))
+			.saturating_add(T::DbWeight::get().reads(5))
+			.saturating_add(T::DbWeight::get().writes(2))
+	}
+	/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
+	/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
+	/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
+	/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
+	/// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
+	/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	fn send_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `74`
+		//  Estimated: `3539`
+		// Minimum execution time: 19_184_000 picoseconds.
+		Weight::from_parts(19_695_000, 0)
 			.saturating_add(Weight::from_parts(0, 3539))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -84,8 +104,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `3571`
-		// Minimum execution time: 56_235_000 picoseconds.
-		Weight::from_parts(58_178_000, 0)
+		// Minimum execution time: 58_120_000 picoseconds.
+		Weight::from_parts(59_533_000, 0)
 			.saturating_add(Weight::from_parts(0, 3571))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -120,14 +140,24 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		Weight::from_parts(18_446_744_073_709_551_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 	}
+	/// Storage: `Benchmark::Override` (r:0 w:0)
+	/// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	fn execute_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 18_446_744_073_709_551_000 picoseconds.
+		Weight::from_parts(18_446_744_073_709_551_000, 0)
+			.saturating_add(Weight::from_parts(0, 0))
+	}
 	/// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1)
 	/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	fn force_xcm_version() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 6_226_000 picoseconds.
-		Weight::from_parts(6_403_000, 0)
+		// Minimum execution time: 6_074_000 picoseconds.
+		Weight::from_parts(6_398_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -137,8 +167,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_020_000 picoseconds.
-		Weight::from_parts(2_100_000, 0)
+		// Minimum execution time: 2_036_000 picoseconds.
+		Weight::from_parts(2_180_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -162,8 +192,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `74`
 		//  Estimated: `3539`
-		// Minimum execution time: 24_387_000 picoseconds.
-		Weight::from_parts(24_814_000, 0)
+		// Minimum execution time: 25_014_000 picoseconds.
+		Weight::from_parts(25_374_000, 0)
 			.saturating_add(Weight::from_parts(0, 3539))
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(5))
@@ -186,8 +216,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `292`
 		//  Estimated: `3757`
-		// Minimum execution time: 27_039_000 picoseconds.
-		Weight::from_parts(27_693_000, 0)
+		// Minimum execution time: 27_616_000 picoseconds.
+		Weight::from_parts(28_499_000, 0)
 			.saturating_add(Weight::from_parts(0, 3757))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -198,8 +228,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_920_000 picoseconds.
-		Weight::from_parts(2_082_000, 0)
+		// Minimum execution time: 2_061_000 picoseconds.
+		Weight::from_parts(2_153_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -209,8 +239,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `89`
 		//  Estimated: `13454`
-		// Minimum execution time: 17_141_000 picoseconds.
-		Weight::from_parts(17_500_000, 0)
+		// Minimum execution time: 16_592_000 picoseconds.
+		Weight::from_parts(16_900_000, 0)
 			.saturating_add(Weight::from_parts(0, 13454))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -221,8 +251,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `93`
 		//  Estimated: `13458`
-		// Minimum execution time: 17_074_000 picoseconds.
-		Weight::from_parts(17_431_000, 0)
+		// Minimum execution time: 16_694_000 picoseconds.
+		Weight::from_parts(16_905_000, 0)
 			.saturating_add(Weight::from_parts(0, 13458))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -233,8 +263,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `15946`
-		// Minimum execution time: 19_139_000 picoseconds.
-		Weight::from_parts(19_474_000, 0)
+		// Minimum execution time: 17_779_000 picoseconds.
+		Weight::from_parts(18_490_000, 0)
 			.saturating_add(Weight::from_parts(0, 15946))
 			.saturating_add(T::DbWeight::get().reads(6))
 	}
@@ -254,8 +284,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `142`
 		//  Estimated: `6082`
-		// Minimum execution time: 24_346_000 picoseconds.
-		Weight::from_parts(25_318_000, 0)
+		// Minimum execution time: 24_526_000 picoseconds.
+		Weight::from_parts(25_182_000, 0)
 			.saturating_add(Weight::from_parts(0, 6082))
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -266,8 +296,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `136`
 		//  Estimated: `11026`
-		// Minimum execution time: 11_777_000 picoseconds.
-		Weight::from_parts(12_051_000, 0)
+		// Minimum execution time: 10_467_000 picoseconds.
+		Weight::from_parts(10_934_000, 0)
 			.saturating_add(Weight::from_parts(0, 11026))
 			.saturating_add(T::DbWeight::get().reads(4))
 	}
@@ -277,8 +307,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `100`
 		//  Estimated: `13465`
-		// Minimum execution time: 17_538_000 picoseconds.
-		Weight::from_parts(17_832_000, 0)
+		// Minimum execution time: 16_377_000 picoseconds.
+		Weight::from_parts(17_114_000, 0)
 			.saturating_add(Weight::from_parts(0, 13465))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -299,8 +329,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `142`
 		//  Estimated: `13507`
-		// Minimum execution time: 33_623_000 picoseconds.
-		Weight::from_parts(34_186_000, 0)
+		// Minimum execution time: 32_575_000 picoseconds.
+		Weight::from_parts(33_483_000, 0)
 			.saturating_add(Weight::from_parts(0, 13507))
 			.saturating_add(T::DbWeight::get().reads(10))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -313,8 +343,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `32`
 		//  Estimated: `1517`
-		// Minimum execution time: 3_363_000 picoseconds.
-		Weight::from_parts(3_511_000, 0)
+		// Minimum execution time: 3_604_000 picoseconds.
+		Weight::from_parts(3_744_000, 0)
 			.saturating_add(Weight::from_parts(0, 1517))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -325,8 +355,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `7669`
 		//  Estimated: `11134`
-		// Minimum execution time: 23_969_000 picoseconds.
-		Weight::from_parts(24_347_000, 0)
+		// Minimum execution time: 23_983_000 picoseconds.
+		Weight::from_parts(24_404_000, 0)
 			.saturating_add(Weight::from_parts(0, 11134))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -337,8 +367,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `90`
 		//  Estimated: `3555`
-		// Minimum execution time: 34_071_000 picoseconds.
-		Weight::from_parts(35_031_000, 0)
+		// Minimum execution time: 34_446_000 picoseconds.
+		Weight::from_parts(35_465_000, 0)
 			.saturating_add(Weight::from_parts(0, 3555))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs
index c31e474cc2f17..609ea5a38a897 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs
@@ -301,6 +301,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl parachain_info::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_broker.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_broker.rs
index 8727b9633b1f0..13d5fcf3898bc 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_broker.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_broker.rs
@@ -17,25 +17,23 @@
 //! Autogenerated weights for `pallet_broker`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-02-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-03-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-westend-dev")`, DB CACHE: 1024
 
 // Executed Command:
-// ./target/production/polkadot-parachain
+// target/production/polkadot-parachain
 // benchmark
 // pallet
-// --chain=coretime-westend-dev
-// --wasm-execution=compiled
-// --pallet=pallet_broker
-// --no-storage-info
-// --no-median-slopes
-// --no-min-squares
-// --extrinsic=*
 // --steps=50
 // --repeat=20
-// --json
+// --extrinsic=*
+// --wasm-execution=compiled
+// --heap-pages=4096
+// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json
+// --pallet=pallet_broker
+// --chain=coretime-westend-dev
 // --header=./cumulus/file_header.txt
 // --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/
 
@@ -56,8 +54,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_944_000 picoseconds.
-		Weight::from_parts(2_045_000, 0)
+		// Minimum execution time: 1_897_000 picoseconds.
+		Weight::from_parts(2_053_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -67,8 +65,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `10888`
 		//  Estimated: `13506`
-		// Minimum execution time: 21_158_000 picoseconds.
-		Weight::from_parts(21_572_000, 0)
+		// Minimum execution time: 22_550_000 picoseconds.
+		Weight::from_parts(22_871_000, 0)
 			.saturating_add(Weight::from_parts(0, 13506))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -79,8 +77,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `12090`
 		//  Estimated: `13506`
-		// Minimum execution time: 20_497_000 picoseconds.
-		Weight::from_parts(20_995_000, 0)
+		// Minimum execution time: 21_170_000 picoseconds.
+		Weight::from_parts(21_645_000, 0)
 			.saturating_add(Weight::from_parts(0, 13506))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -95,8 +93,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `146`
 		//  Estimated: `1631`
-		// Minimum execution time: 10_280_000 picoseconds.
-		Weight::from_parts(10_686_000, 0)
+		// Minimum execution time: 10_494_000 picoseconds.
+		Weight::from_parts(10_942_000, 0)
 			.saturating_add(Weight::from_parts(0, 1631))
 			.saturating_add(T::DbWeight::get().reads(3))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -120,15 +118,13 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 	/// Storage: `Broker::Workplan` (r:0 w:20)
 	/// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`)
 	/// The range of component `n` is `[0, 1000]`.
-	fn start_sales(n: u32, ) -> Weight {
+	fn start_sales(_n: u32, ) -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `12247`
 		//  Estimated: `13732`
-		// Minimum execution time: 61_020_000 picoseconds.
-		Weight::from_parts(63_240_622, 0)
+		// Minimum execution time: 61_014_000 picoseconds.
+		Weight::from_parts(63_267_651, 0)
 			.saturating_add(Weight::from_parts(0, 13732))
-			// Standard Error: 102
-			.saturating_add(Weight::from_parts(255, 0).saturating_mul(n.into()))
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(26))
 	}
@@ -144,8 +140,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `316`
 		//  Estimated: `3593`
-		// Minimum execution time: 30_627_000 picoseconds.
-		Weight::from_parts(31_648_000, 0)
+		// Minimum execution time: 30_931_000 picoseconds.
+		Weight::from_parts(31_941_000, 0)
 			.saturating_add(Weight::from_parts(0, 3593))
 			.saturating_add(T::DbWeight::get().reads(3))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -166,8 +162,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `434`
 		//  Estimated: `4698`
-		// Minimum execution time: 57_701_000 picoseconds.
-		Weight::from_parts(59_825_000, 0)
+		// Minimum execution time: 57_466_000 picoseconds.
+		Weight::from_parts(65_042_000, 0)
 			.saturating_add(Weight::from_parts(0, 4698))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -178,8 +174,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `357`
 		//  Estimated: `3550`
-		// Minimum execution time: 12_898_000 picoseconds.
-		Weight::from_parts(13_506_000, 0)
+		// Minimum execution time: 12_799_000 picoseconds.
+		Weight::from_parts(13_401_000, 0)
 			.saturating_add(Weight::from_parts(0, 3550))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -190,8 +186,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `357`
 		//  Estimated: `3550`
-		// Minimum execution time: 14_284_000 picoseconds.
-		Weight::from_parts(14_791_000, 0)
+		// Minimum execution time: 14_107_000 picoseconds.
+		Weight::from_parts(14_630_000, 0)
 			.saturating_add(Weight::from_parts(0, 3550))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -202,8 +198,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `357`
 		//  Estimated: `3550`
-		// Minimum execution time: 15_570_000 picoseconds.
-		Weight::from_parts(16_158_000, 0)
+		// Minimum execution time: 15_254_000 picoseconds.
+		Weight::from_parts(16_062_000, 0)
 			.saturating_add(Weight::from_parts(0, 3550))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -220,8 +216,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `735`
 		//  Estimated: `4681`
-		// Minimum execution time: 23_329_000 picoseconds.
-		Weight::from_parts(24_196_000, 0)
+		// Minimum execution time: 23_557_000 picoseconds.
+		Weight::from_parts(24_382_000, 0)
 			.saturating_add(Weight::from_parts(0, 4681))
 			.saturating_add(T::DbWeight::get().reads(4))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -240,8 +236,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `801`
 		//  Estimated: `5996`
-		// Minimum execution time: 29_288_000 picoseconds.
-		Weight::from_parts(30_066_000, 0)
+		// Minimum execution time: 29_371_000 picoseconds.
+		Weight::from_parts(30_200_000, 0)
 			.saturating_add(Weight::from_parts(0, 5996))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(5))
@@ -257,11 +253,11 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `652`
 		//  Estimated: `6196 + m * (2520 ±0)`
-		// Minimum execution time: 54_833_000 picoseconds.
-		Weight::from_parts(55_577_423, 0)
+		// Minimum execution time: 54_331_000 picoseconds.
+		Weight::from_parts(55_322_165, 0)
 			.saturating_add(Weight::from_parts(0, 6196))
-			// Standard Error: 35_105
-			.saturating_add(Weight::from_parts(1_267_911, 0).saturating_mul(m.into()))
+			// Standard Error: 35_225
+			.saturating_add(Weight::from_parts(1_099_614, 0).saturating_mul(m.into()))
 			.saturating_add(T::DbWeight::get().reads(3))
 			.saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into())))
 			.saturating_add(T::DbWeight::get().writes(5))
@@ -283,8 +279,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `215`
 		//  Estimated: `3680`
-		// Minimum execution time: 55_289_000 picoseconds.
-		Weight::from_parts(56_552_000, 0)
+		// Minimum execution time: 53_789_000 picoseconds.
+		Weight::from_parts(55_439_000, 0)
 			.saturating_add(Weight::from_parts(0, 3680))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -297,8 +293,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `465`
 		//  Estimated: `3550`
-		// Minimum execution time: 39_736_000 picoseconds.
-		Weight::from_parts(41_346_000, 0)
+		// Minimum execution time: 43_941_000 picoseconds.
+		Weight::from_parts(49_776_000, 0)
 			.saturating_add(Weight::from_parts(0, 3550))
 			.saturating_add(T::DbWeight::get().reads(2))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -313,8 +309,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `463`
 		//  Estimated: `3533`
-		// Minimum execution time: 57_319_000 picoseconds.
-		Weight::from_parts(60_204_000, 0)
+		// Minimum execution time: 64_917_000 picoseconds.
+		Weight::from_parts(70_403_000, 0)
 			.saturating_add(Weight::from_parts(0, 3533))
 			.saturating_add(T::DbWeight::get().reads(3))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -331,8 +327,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `857`
 		//  Estimated: `3593`
-		// Minimum execution time: 85_216_000 picoseconds.
-		Weight::from_parts(91_144_000, 0)
+		// Minimum execution time: 72_633_000 picoseconds.
+		Weight::from_parts(79_305_000, 0)
 			.saturating_add(Weight::from_parts(0, 3593))
 			.saturating_add(T::DbWeight::get().reads(4))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -345,8 +341,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `556`
 		//  Estimated: `4698`
-		// Minimum execution time: 32_331_000 picoseconds.
-		Weight::from_parts(39_877_000, 0)
+		// Minimum execution time: 36_643_000 picoseconds.
+		Weight::from_parts(48_218_000, 0)
 			.saturating_add(Weight::from_parts(0, 4698))
 			.saturating_add(T::DbWeight::get().reads(2))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -362,28 +358,28 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 	/// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
 	/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
 	/// The range of component `n` is `[0, 1000]`.
-	fn request_core_count(n: u32, ) -> Weight {
+	fn request_core_count(_n: u32, ) -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `74`
 		//  Estimated: `3539`
-		// Minimum execution time: 18_128_000 picoseconds.
-		Weight::from_parts(19_061_234, 0)
+		// Minimum execution time: 17_617_000 picoseconds.
+		Weight::from_parts(18_904_788, 0)
 			.saturating_add(Weight::from_parts(0, 3539))
-			// Standard Error: 48
-			.saturating_add(Weight::from_parts(141, 0).saturating_mul(n.into()))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
 	/// Storage: `Broker::CoreCountInbox` (r:1 w:1)
 	/// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`)
 	/// The range of component `n` is `[0, 1000]`.
-	fn process_core_count(_n: u32, ) -> Weight {
+	fn process_core_count(n: u32, ) -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `266`
 		//  Estimated: `1487`
-		// Minimum execution time: 5_368_000 picoseconds.
-		Weight::from_parts(5_837_005, 0)
+		// Minimum execution time: 5_575_000 picoseconds.
+		Weight::from_parts(5_887_598, 0)
 			.saturating_add(Weight::from_parts(0, 1487))
+			// Standard Error: 16
+			.saturating_add(Weight::from_parts(41, 0).saturating_mul(n.into()))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -397,8 +393,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `447`
 		//  Estimated: `6196`
-		// Minimum execution time: 36_047_000 picoseconds.
-		Weight::from_parts(37_101_000, 0)
+		// Minimum execution time: 36_415_000 picoseconds.
+		Weight::from_parts(37_588_000, 0)
 			.saturating_add(Weight::from_parts(0, 6196))
 			.saturating_add(T::DbWeight::get().reads(4))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -414,13 +410,15 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 	/// Storage: `Broker::Workplan` (r:0 w:20)
 	/// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`)
 	/// The range of component `n` is `[0, 1000]`.
-	fn rotate_sale(_n: u32, ) -> Weight {
+	fn rotate_sale(n: u32, ) -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `12194`
 		//  Estimated: `13506`
-		// Minimum execution time: 48_158_000 picoseconds.
-		Weight::from_parts(49_891_920, 0)
+		// Minimum execution time: 48_362_000 picoseconds.
+		Weight::from_parts(49_616_106, 0)
 			.saturating_add(Weight::from_parts(0, 13506))
+			// Standard Error: 61
+			.saturating_add(Weight::from_parts(59, 0).saturating_mul(n.into()))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(25))
 	}
@@ -432,8 +430,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `42`
 		//  Estimated: `3493`
-		// Minimum execution time: 5_911_000 picoseconds.
-		Weight::from_parts(6_173_000, 0)
+		// Minimum execution time: 6_148_000 picoseconds.
+		Weight::from_parts(6_374_000, 0)
 			.saturating_add(Weight::from_parts(0, 3493))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -456,8 +454,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `1321`
 		//  Estimated: `4786`
-		// Minimum execution time: 30_140_000 picoseconds.
-		Weight::from_parts(30_912_000, 0)
+		// Minimum execution time: 30_267_000 picoseconds.
+		Weight::from_parts(30_825_000, 0)
 			.saturating_add(Weight::from_parts(0, 4786))
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -476,8 +474,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `74`
 		//  Estimated: `3539`
-		// Minimum execution time: 13_684_000 picoseconds.
-		Weight::from_parts(14_252_000, 0)
+		// Minimum execution time: 13_491_000 picoseconds.
+		Weight::from_parts(13_949_000, 0)
 			.saturating_add(Weight::from_parts(0, 3539))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -488,8 +486,8 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_718_000 picoseconds.
-		Weight::from_parts(1_843_000, 0)
+		// Minimum execution time: 1_711_000 picoseconds.
+		Weight::from_parts(1_913_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -507,10 +505,22 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `398`
 		//  Estimated: `3863`
-		// Minimum execution time: 11_771_000 picoseconds.
-		Weight::from_parts(12_120_000, 0)
+		// Minimum execution time: 12_035_000 picoseconds.
+		Weight::from_parts(12_383_000, 0)
 			.saturating_add(Weight::from_parts(0, 3863))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
+	/// Storage: `Broker::Leases` (r:1 w:1)
+	/// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(81), added: 576, mode: `MaxEncodedLen`)
+	fn swap_leases() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `150`
+		//  Estimated: `1566`
+		// Minimum execution time: 6_142_000 picoseconds.
+		Weight::from_parts(6_538_000, 0)
+			.saturating_add(Weight::from_parts(0, 1566))
+			.saturating_add(T::DbWeight::get().reads(1))
+			.saturating_add(T::DbWeight::get().writes(1))
+	}
 }
diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs
index 0082db3099d02..a1701c5f1c2ce 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-westend-dev")`, DB CACHE: 1024
 
 // Executed Command:
@@ -62,8 +62,28 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `74`
 		//  Estimated: `3539`
-		// Minimum execution time: 18_410_000 picoseconds.
-		Weight::from_parts(18_657_000, 0)
+		// Minimum execution time: 17_681_000 picoseconds.
+		Weight::from_parts(18_350_000, 0)
+			.saturating_add(Weight::from_parts(0, 3539))
+			.saturating_add(T::DbWeight::get().reads(5))
+			.saturating_add(T::DbWeight::get().writes(2))
+	}
+	/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
+	/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
+	/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
+	/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
+	/// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
+	/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	fn send_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `74`
+		//  Estimated: `3539`
+		// Minimum execution time: 18_091_000 picoseconds.
+		Weight::from_parts(18_327_000, 0)
 			.saturating_add(Weight::from_parts(0, 3539))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -84,8 +104,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `3571`
-		// Minimum execution time: 56_616_000 picoseconds.
-		Weight::from_parts(57_751_000, 0)
+		// Minimum execution time: 54_943_000 picoseconds.
+		Weight::from_parts(56_519_000, 0)
 			.saturating_add(Weight::from_parts(0, 3571))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -120,14 +140,24 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		Weight::from_parts(18_446_744_073_709_551_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 	}
+	/// Storage: `Benchmark::Override` (r:0 w:0)
+	/// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	fn execute_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 18_446_744_073_709_551_000 picoseconds.
+		Weight::from_parts(18_446_744_073_709_551_000, 0)
+			.saturating_add(Weight::from_parts(0, 0))
+	}
 	/// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1)
 	/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	fn force_xcm_version() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 6_014_000 picoseconds.
-		Weight::from_parts(6_412_000, 0)
+		// Minimum execution time: 5_887_000 picoseconds.
+		Weight::from_parts(6_101_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -137,8 +167,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_844_000 picoseconds.
-		Weight::from_parts(1_957_000, 0)
+		// Minimum execution time: 1_940_000 picoseconds.
+		Weight::from_parts(2_022_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -162,8 +192,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `74`
 		//  Estimated: `3539`
-		// Minimum execution time: 24_067_000 picoseconds.
-		Weight::from_parts(24_553_000, 0)
+		// Minimum execution time: 23_165_000 picoseconds.
+		Weight::from_parts(23_800_000, 0)
 			.saturating_add(Weight::from_parts(0, 3539))
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(5))
@@ -186,8 +216,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `292`
 		//  Estimated: `3757`
-		// Minimum execution time: 27_023_000 picoseconds.
-		Weight::from_parts(27_620_000, 0)
+		// Minimum execution time: 26_506_000 picoseconds.
+		Weight::from_parts(27_180_000, 0)
 			.saturating_add(Weight::from_parts(0, 3757))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -198,8 +228,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_866_000 picoseconds.
-		Weight::from_parts(1_984_000, 0)
+		// Minimum execution time: 1_868_000 picoseconds.
+		Weight::from_parts(2_002_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -209,8 +239,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `89`
 		//  Estimated: `13454`
-		// Minimum execution time: 16_425_000 picoseconds.
-		Weight::from_parts(16_680_000, 0)
+		// Minimum execution time: 16_138_000 picoseconds.
+		Weight::from_parts(16_447_000, 0)
 			.saturating_add(Weight::from_parts(0, 13454))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -221,8 +251,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `93`
 		//  Estimated: `13458`
-		// Minimum execution time: 16_171_000 picoseconds.
-		Weight::from_parts(16_564_000, 0)
+		// Minimum execution time: 16_099_000 picoseconds.
+		Weight::from_parts(16_592_000, 0)
 			.saturating_add(Weight::from_parts(0, 13458))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -233,8 +263,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `15946`
-		// Minimum execution time: 17_785_000 picoseconds.
-		Weight::from_parts(18_123_000, 0)
+		// Minimum execution time: 17_972_000 picoseconds.
+		Weight::from_parts(18_379_000, 0)
 			.saturating_add(Weight::from_parts(0, 15946))
 			.saturating_add(T::DbWeight::get().reads(6))
 	}
@@ -254,8 +284,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `142`
 		//  Estimated: `6082`
-		// Minimum execution time: 23_903_000 picoseconds.
-		Weight::from_parts(24_769_000, 0)
+		// Minimum execution time: 23_554_000 picoseconds.
+		Weight::from_parts(24_446_000, 0)
 			.saturating_add(Weight::from_parts(0, 6082))
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -266,8 +296,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `136`
 		//  Estimated: `11026`
-		// Minimum execution time: 10_617_000 picoseconds.
-		Weight::from_parts(10_843_000, 0)
+		// Minimum execution time: 10_541_000 picoseconds.
+		Weight::from_parts(10_894_000, 0)
 			.saturating_add(Weight::from_parts(0, 11026))
 			.saturating_add(T::DbWeight::get().reads(4))
 	}
@@ -277,8 +307,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `100`
 		//  Estimated: `13465`
-		// Minimum execution time: 16_656_000 picoseconds.
-		Weight::from_parts(17_106_000, 0)
+		// Minimum execution time: 16_404_000 picoseconds.
+		Weight::from_parts(16_818_000, 0)
 			.saturating_add(Weight::from_parts(0, 13465))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -299,8 +329,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `142`
 		//  Estimated: `13507`
-		// Minimum execution time: 31_721_000 picoseconds.
-		Weight::from_parts(32_547_000, 0)
+		// Minimum execution time: 31_617_000 picoseconds.
+		Weight::from_parts(32_336_000, 0)
 			.saturating_add(Weight::from_parts(0, 13507))
 			.saturating_add(T::DbWeight::get().reads(10))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -313,8 +343,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `32`
 		//  Estimated: `1517`
-		// Minimum execution time: 3_439_000 picoseconds.
-		Weight::from_parts(3_619_000, 0)
+		// Minimum execution time: 3_328_000 picoseconds.
+		Weight::from_parts(3_501_000, 0)
 			.saturating_add(Weight::from_parts(0, 1517))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -325,8 +355,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `7669`
 		//  Estimated: `11134`
-		// Minimum execution time: 24_657_000 picoseconds.
-		Weight::from_parts(24_971_000, 0)
+		// Minimum execution time: 23_571_000 picoseconds.
+		Weight::from_parts(24_312_000, 0)
 			.saturating_add(Weight::from_parts(0, 11134))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -337,8 +367,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `90`
 		//  Estimated: `3555`
-		// Minimum execution time: 34_028_000 picoseconds.
-		Weight::from_parts(34_697_000, 0)
+		// Minimum execution time: 32_879_000 picoseconds.
+		Weight::from_parts(33_385_000, 0)
 			.saturating_add(Weight::from_parts(0, 3555))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs
index cee17cdc7b05d..ca1a915ba740a 100644
--- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs
+++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs
@@ -212,6 +212,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl parachain_info::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs
index cd5f1ad327280..7c9427a249396 100644
--- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs
+++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs
@@ -282,6 +282,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 	type WeightInfo = weights::pallet_message_queue::WeightInfo<Runtime>;
 }
 
diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs
index fabce29b5fd94..ac494fdc719f4 100644
--- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs
+++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("people-rococo-dev")`, DB CACHE: 1024
 
 // Executed Command:
@@ -62,8 +62,28 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `38`
 		//  Estimated: `3503`
-		// Minimum execution time: 17_830_000 picoseconds.
-		Weight::from_parts(18_411_000, 0)
+		// Minimum execution time: 17_935_000 picoseconds.
+		Weight::from_parts(18_482_000, 0)
+			.saturating_add(Weight::from_parts(0, 3503))
+			.saturating_add(T::DbWeight::get().reads(5))
+			.saturating_add(T::DbWeight::get().writes(2))
+	}
+	/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
+	/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
+	/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
+	/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
+	/// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
+	/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	fn send_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `38`
+		//  Estimated: `3503`
+		// Minimum execution time: 18_311_000 picoseconds.
+		Weight::from_parts(18_850_000, 0)
 			.saturating_add(Weight::from_parts(0, 3503))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -84,8 +104,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `70`
 		//  Estimated: `3535`
-		// Minimum execution time: 55_456_000 picoseconds.
-		Weight::from_parts(56_808_000, 0)
+		// Minimum execution time: 56_182_000 picoseconds.
+		Weight::from_parts(58_136_000, 0)
 			.saturating_add(Weight::from_parts(0, 3535))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -120,14 +140,24 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		Weight::from_parts(18_446_744_073_709_551_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 	}
+	/// Storage: `Benchmark::Override` (r:0 w:0)
+	/// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	fn execute_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 18_446_744_073_709_551_000 picoseconds.
+		Weight::from_parts(18_446_744_073_709_551_000, 0)
+			.saturating_add(Weight::from_parts(0, 0))
+	}
 	/// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1)
 	/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	fn force_xcm_version() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 5_996_000 picoseconds.
-		Weight::from_parts(6_154_000, 0)
+		// Minimum execution time: 5_979_000 picoseconds.
+		Weight::from_parts(6_289_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -137,8 +167,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_768_000 picoseconds.
-		Weight::from_parts(1_914_000, 0)
+		// Minimum execution time: 1_853_000 picoseconds.
+		Weight::from_parts(2_045_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -162,8 +192,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `38`
 		//  Estimated: `3503`
-		// Minimum execution time: 24_120_000 picoseconds.
-		Weight::from_parts(24_745_000, 0)
+		// Minimum execution time: 23_827_000 picoseconds.
+		Weight::from_parts(24_493_000, 0)
 			.saturating_add(Weight::from_parts(0, 3503))
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(5))
@@ -186,8 +216,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `255`
 		//  Estimated: `3720`
-		// Minimum execution time: 26_630_000 picoseconds.
-		Weight::from_parts(27_289_000, 0)
+		// Minimum execution time: 26_755_000 picoseconds.
+		Weight::from_parts(27_125_000, 0)
 			.saturating_add(Weight::from_parts(0, 3720))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -198,8 +228,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_821_000 picoseconds.
-		Weight::from_parts(1_946_000, 0)
+		// Minimum execution time: 1_898_000 picoseconds.
+		Weight::from_parts(2_028_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -209,8 +239,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `89`
 		//  Estimated: `13454`
-		// Minimum execution time: 16_586_000 picoseconds.
-		Weight::from_parts(16_977_000, 0)
+		// Minimum execution time: 16_300_000 picoseconds.
+		Weight::from_parts(16_995_000, 0)
 			.saturating_add(Weight::from_parts(0, 13454))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -221,8 +251,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `93`
 		//  Estimated: `13458`
-		// Minimum execution time: 16_923_000 picoseconds.
-		Weight::from_parts(17_415_000, 0)
+		// Minimum execution time: 16_495_000 picoseconds.
+		Weight::from_parts(16_950_000, 0)
 			.saturating_add(Weight::from_parts(0, 13458))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -233,8 +263,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `15946`
-		// Minimum execution time: 18_596_000 picoseconds.
-		Weight::from_parts(18_823_000, 0)
+		// Minimum execution time: 18_153_000 picoseconds.
+		Weight::from_parts(18_595_000, 0)
 			.saturating_add(Weight::from_parts(0, 15946))
 			.saturating_add(T::DbWeight::get().reads(6))
 	}
@@ -254,8 +284,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `6046`
-		// Minimum execution time: 23_817_000 picoseconds.
-		Weight::from_parts(24_520_000, 0)
+		// Minimum execution time: 23_387_000 picoseconds.
+		Weight::from_parts(24_677_000, 0)
 			.saturating_add(Weight::from_parts(0, 6046))
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -266,8 +296,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `136`
 		//  Estimated: `11026`
-		// Minimum execution time: 11_042_000 picoseconds.
-		Weight::from_parts(11_578_000, 0)
+		// Minimum execution time: 10_939_000 picoseconds.
+		Weight::from_parts(11_210_000, 0)
 			.saturating_add(Weight::from_parts(0, 11026))
 			.saturating_add(T::DbWeight::get().reads(4))
 	}
@@ -277,8 +307,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `100`
 		//  Estimated: `13465`
-		// Minimum execution time: 17_306_000 picoseconds.
-		Weight::from_parts(17_817_000, 0)
+		// Minimum execution time: 16_850_000 picoseconds.
+		Weight::from_parts(17_195_000, 0)
 			.saturating_add(Weight::from_parts(0, 13465))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -299,8 +329,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `13471`
-		// Minimum execution time: 32_141_000 picoseconds.
-		Weight::from_parts(32_954_000, 0)
+		// Minimum execution time: 31_931_000 picoseconds.
+		Weight::from_parts(32_494_000, 0)
 			.saturating_add(Weight::from_parts(0, 13471))
 			.saturating_add(T::DbWeight::get().reads(10))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -313,8 +343,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `32`
 		//  Estimated: `1517`
-		// Minimum execution time: 3_410_000 picoseconds.
-		Weight::from_parts(3_556_000, 0)
+		// Minimum execution time: 3_514_000 picoseconds.
+		Weight::from_parts(3_709_000, 0)
 			.saturating_add(Weight::from_parts(0, 1517))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -325,8 +355,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `7669`
 		//  Estimated: `11134`
-		// Minimum execution time: 25_021_000 picoseconds.
-		Weight::from_parts(25_240_000, 0)
+		// Minimum execution time: 24_863_000 picoseconds.
+		Weight::from_parts(25_293_000, 0)
 			.saturating_add(Weight::from_parts(0, 11134))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -337,8 +367,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `90`
 		//  Estimated: `3555`
-		// Minimum execution time: 33_801_000 picoseconds.
-		Weight::from_parts(34_655_000, 0)
+		// Minimum execution time: 33_799_000 picoseconds.
+		Weight::from_parts(34_665_000, 0)
 			.saturating_add(Weight::from_parts(0, 3555))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs
index e840a40f5acdf..3e331e5e8ebf1 100644
--- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs
+++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs
@@ -282,6 +282,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 	type WeightInfo = weights::pallet_message_queue::WeightInfo<Runtime>;
 }
 
diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs
index c337289243b74..62a9c802808c0 100644
--- a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs
+++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("people-westend-dev")`, DB CACHE: 1024
 
 // Executed Command:
@@ -62,8 +62,28 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `38`
 		//  Estimated: `3503`
-		// Minimum execution time: 17_856_000 picoseconds.
-		Weight::from_parts(18_473_000, 0)
+		// Minimum execution time: 17_450_000 picoseconds.
+		Weight::from_parts(17_913_000, 0)
+			.saturating_add(Weight::from_parts(0, 3503))
+			.saturating_add(T::DbWeight::get().reads(5))
+			.saturating_add(T::DbWeight::get().writes(2))
+	}
+	/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
+	/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
+	/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
+	/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
+	/// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
+	/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	fn send_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `38`
+		//  Estimated: `3503`
+		// Minimum execution time: 18_082_000 picoseconds.
+		Weight::from_parts(18_293_000, 0)
 			.saturating_add(Weight::from_parts(0, 3503))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -84,8 +104,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `70`
 		//  Estimated: `3535`
-		// Minimum execution time: 56_112_000 picoseconds.
-		Weight::from_parts(57_287_000, 0)
+		// Minimum execution time: 54_939_000 picoseconds.
+		Weight::from_parts(55_721_000, 0)
 			.saturating_add(Weight::from_parts(0, 3535))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -120,14 +140,24 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		Weight::from_parts(18_446_744_073_709_551_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 	}
+	/// Storage: `Benchmark::Override` (r:0 w:0)
+	/// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	fn execute_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 18_446_744_073_709_551_000 picoseconds.
+		Weight::from_parts(18_446_744_073_709_551_000, 0)
+			.saturating_add(Weight::from_parts(0, 0))
+	}
 	/// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1)
 	/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	fn force_xcm_version() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 6_186_000 picoseconds.
-		Weight::from_parts(6_420_000, 0)
+		// Minimum execution time: 5_789_000 picoseconds.
+		Weight::from_parts(5_995_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -137,8 +167,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_824_000 picoseconds.
-		Weight::from_parts(1_999_000, 0)
+		// Minimum execution time: 1_795_000 picoseconds.
+		Weight::from_parts(1_924_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -162,8 +192,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `38`
 		//  Estimated: `3503`
-		// Minimum execution time: 23_833_000 picoseconds.
-		Weight::from_parts(24_636_000, 0)
+		// Minimum execution time: 23_445_000 picoseconds.
+		Weight::from_parts(23_906_000, 0)
 			.saturating_add(Weight::from_parts(0, 3503))
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(5))
@@ -186,8 +216,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `255`
 		//  Estimated: `3720`
-		// Minimum execution time: 26_557_000 picoseconds.
-		Weight::from_parts(27_275_000, 0)
+		// Minimum execution time: 26_590_000 picoseconds.
+		Weight::from_parts(27_056_000, 0)
 			.saturating_add(Weight::from_parts(0, 3720))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -198,8 +228,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_921_000 picoseconds.
-		Weight::from_parts(2_040_000, 0)
+		// Minimum execution time: 1_889_000 picoseconds.
+		Weight::from_parts(1_962_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -209,8 +239,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `89`
 		//  Estimated: `13454`
-		// Minimum execution time: 16_832_000 picoseconds.
-		Weight::from_parts(17_312_000, 0)
+		// Minimum execution time: 16_408_000 picoseconds.
+		Weight::from_parts(16_877_000, 0)
 			.saturating_add(Weight::from_parts(0, 13454))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -221,8 +251,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `93`
 		//  Estimated: `13458`
-		// Minimum execution time: 16_687_000 picoseconds.
-		Weight::from_parts(17_123_000, 0)
+		// Minimum execution time: 16_791_000 picoseconds.
+		Weight::from_parts(17_111_000, 0)
 			.saturating_add(Weight::from_parts(0, 13458))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -233,8 +263,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `15946`
-		// Minimum execution time: 18_164_000 picoseconds.
-		Weight::from_parts(18_580_000, 0)
+		// Minimum execution time: 18_355_000 picoseconds.
+		Weight::from_parts(19_110_000, 0)
 			.saturating_add(Weight::from_parts(0, 15946))
 			.saturating_add(T::DbWeight::get().reads(6))
 	}
@@ -254,8 +284,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `6046`
-		// Minimum execution time: 23_577_000 picoseconds.
-		Weight::from_parts(24_324_000, 0)
+		// Minimum execution time: 23_354_000 picoseconds.
+		Weight::from_parts(23_999_000, 0)
 			.saturating_add(Weight::from_parts(0, 6046))
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -266,8 +296,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `136`
 		//  Estimated: `11026`
-		// Minimum execution time: 11_014_000 picoseconds.
-		Weight::from_parts(11_223_000, 0)
+		// Minimum execution time: 11_065_000 picoseconds.
+		Weight::from_parts(11_302_000, 0)
 			.saturating_add(Weight::from_parts(0, 11026))
 			.saturating_add(T::DbWeight::get().reads(4))
 	}
@@ -277,8 +307,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `100`
 		//  Estimated: `13465`
-		// Minimum execution time: 16_887_000 picoseconds.
-		Weight::from_parts(17_361_000, 0)
+		// Minimum execution time: 16_998_000 picoseconds.
+		Weight::from_parts(17_509_000, 0)
 			.saturating_add(Weight::from_parts(0, 13465))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -299,8 +329,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `13471`
-		// Minimum execution time: 31_705_000 picoseconds.
-		Weight::from_parts(32_166_000, 0)
+		// Minimum execution time: 31_068_000 picoseconds.
+		Weight::from_parts(31_978_000, 0)
 			.saturating_add(Weight::from_parts(0, 13471))
 			.saturating_add(T::DbWeight::get().reads(10))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -313,8 +343,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `32`
 		//  Estimated: `1517`
-		// Minimum execution time: 3_568_000 picoseconds.
-		Weight::from_parts(3_669_000, 0)
+		// Minimum execution time: 3_478_000 picoseconds.
+		Weight::from_parts(3_595_000, 0)
 			.saturating_add(Weight::from_parts(0, 1517))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -325,8 +355,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `7669`
 		//  Estimated: `11134`
-		// Minimum execution time: 24_823_000 picoseconds.
-		Weight::from_parts(25_344_000, 0)
+		// Minimum execution time: 24_962_000 picoseconds.
+		Weight::from_parts(25_404_000, 0)
 			.saturating_add(Weight::from_parts(0, 11134))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -337,8 +367,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `90`
 		//  Estimated: `3555`
-		// Minimum execution time: 34_516_000 picoseconds.
-		Weight::from_parts(35_478_000, 0)
+		// Minimum execution time: 32_685_000 picoseconds.
+		Weight::from_parts(33_592_000, 0)
 			.saturating_add(Weight::from_parts(0, 3555))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
diff --git a/cumulus/parachains/runtimes/starters/shell/src/lib.rs b/cumulus/parachains/runtimes/starters/shell/src/lib.rs
index 0f4957fd802b4..ad79d6849bd5f 100644
--- a/cumulus/parachains/runtimes/starters/shell/src/lib.rs
+++ b/cumulus/parachains/runtimes/starters/shell/src/lib.rs
@@ -232,6 +232,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl cumulus_pallet_aura_ext::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs
index 1d404feac3db1..0a55d2dcfe53e 100644
--- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs
+++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs
@@ -540,6 +540,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 }
 
 impl cumulus_pallet_aura_ext::Config for Runtime {}
diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs
index c600614198176..034d16267d450 100644
--- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs
+++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs
@@ -320,6 +320,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = ();
 }
 
 impl cumulus_pallet_aura_ext::Config for Runtime {}
diff --git a/polkadot/node/collation-generation/src/error.rs b/polkadot/node/collation-generation/src/error.rs
index ac5db6cd7f285..852c50f306825 100644
--- a/polkadot/node/collation-generation/src/error.rs
+++ b/polkadot/node/collation-generation/src/error.rs
@@ -28,6 +28,8 @@ pub enum Error {
 	Util(#[from] polkadot_node_subsystem_util::Error),
 	#[error(transparent)]
 	Erasure(#[from] polkadot_erasure_coding::Error),
+	#[error("Parachain backing state not available in runtime.")]
+	MissingParaBackingState,
 }
 
 pub type Result<T> = std::result::Result<T, Error>;
diff --git a/polkadot/node/collation-generation/src/lib.rs b/polkadot/node/collation-generation/src/lib.rs
index 3b1a8f5ff2305..3164f6078bc07 100644
--- a/polkadot/node/collation-generation/src/lib.rs
+++ b/polkadot/node/collation-generation/src/lib.rs
@@ -44,8 +44,8 @@ use polkadot_node_subsystem::{
 };
 use polkadot_node_subsystem_util::{
 	has_required_runtime, request_async_backing_params, request_availability_cores,
-	request_claim_queue, request_persisted_validation_data, request_validation_code,
-	request_validation_code_hash, request_validators,
+	request_claim_queue, request_para_backing_state, request_persisted_validation_data,
+	request_validation_code, request_validation_code_hash, request_validators,
 };
 use polkadot_primitives::{
 	collator_signature_payload, CandidateCommitments, CandidateDescriptor, CandidateReceipt,
@@ -212,6 +212,7 @@ async fn handle_new_activations<Context>(
 	if config.collator.is_none() {
 		return Ok(())
 	}
+	let para_id = config.para_id;
 
 	let _overall_timer = metrics.time_new_activations();
 
@@ -225,25 +226,23 @@ async fn handle_new_activations<Context>(
 		);
 
 		let availability_cores = availability_cores??;
-		let n_validators = validators??.len();
 		let async_backing_params = async_backing_params?.ok();
+		let n_validators = validators??.len();
 		let maybe_claim_queue = fetch_claim_queue(ctx.sender(), relay_parent).await?;
 
-		for (core_idx, core) in availability_cores.into_iter().enumerate() {
-			let _availability_core_timer = metrics.time_new_activations_availability_core();
+		// The loop bellow will fill in cores that the para is allowed to build on.
+		let mut cores_to_build_on = Vec::new();
 
-			let (scheduled_core, assumption) = match core {
-				CoreState::Scheduled(scheduled_core) =>
-					(scheduled_core, OccupiedCoreAssumption::Free),
+		for (core_idx, core) in availability_cores.into_iter().enumerate() {
+			let scheduled_core = match core {
+				CoreState::Scheduled(scheduled_core) => scheduled_core,
 				CoreState::Occupied(occupied_core) => match async_backing_params {
 					Some(params) if params.max_candidate_depth >= 1 => {
 						// maximum candidate depth when building on top of a block
 						// pending availability is necessarily 1 - the depth of the
 						// pending block is 0 so the child has depth 1.
 
-						// TODO [now]: this assumes that next up == current.
-						// in practice we should only set `OccupiedCoreAssumption::Included`
-						// when the candidate occupying the core is also of the same para.
+						// Use claim queue if available, or fallback to `next_up_on_available`
 						let res = match maybe_claim_queue {
 							Some(ref claim_queue) => {
 								// read what's in the claim queue for this core
@@ -257,8 +256,7 @@ async fn handle_new_activations<Context>(
 								// `next_up_on_available`
 								occupied_core.next_up_on_available
 							},
-						}
-						.map(|scheduled| (scheduled, OccupiedCoreAssumption::Included));
+						};
 
 						match res {
 							Some(res) => res,
@@ -279,7 +277,7 @@ async fn handle_new_activations<Context>(
 					gum::trace!(
 						target: LOG_TARGET,
 						core_idx = %core_idx,
-						"core is free. Keep going.",
+						"core is not assigned to any para. Keep going.",
 					);
 					continue
 				},
@@ -294,64 +292,90 @@ async fn handle_new_activations<Context>(
 					their_para = %scheduled_core.para_id,
 					"core is not assigned to our para. Keep going.",
 				);
-				continue
+			} else {
+				// Accumulate cores for building collation(s) outside the loop.
+				cores_to_build_on.push(CoreIndex(core_idx as u32));
 			}
+		}
 
-			// we get validation data and validation code synchronously for each core instead of
-			// within the subtask loop, because we have only a single mutable handle to the
-			// context, so the work can't really be distributed
-
-			let validation_data = match request_persisted_validation_data(
-				relay_parent,
-				scheduled_core.para_id,
-				assumption,
-				ctx.sender(),
-			)
-			.await
-			.await??
-			{
-				Some(v) => v,
-				None => {
-					gum::trace!(
-						target: LOG_TARGET,
-						core_idx = %core_idx,
-						relay_parent = ?relay_parent,
-						our_para = %config.para_id,
-						their_para = %scheduled_core.para_id,
-						"validation data is not available",
-					);
-					continue
-				},
-			};
+		// Skip to next relay parent if there is no core assigned to us.
+		if cores_to_build_on.is_empty() {
+			continue
+		}
 
-			let validation_code_hash = match obtain_validation_code_hash_with_assumption(
-				relay_parent,
-				scheduled_core.para_id,
-				assumption,
-				ctx.sender(),
-			)
-			.await?
-			{
-				Some(v) => v,
-				None => {
-					gum::trace!(
-						target: LOG_TARGET,
-						core_idx = %core_idx,
-						relay_parent = ?relay_parent,
-						our_para = %config.para_id,
-						their_para = %scheduled_core.para_id,
-						"validation code hash is not found.",
-					);
-					continue
-				},
-			};
+		let para_backing_state =
+			request_para_backing_state(relay_parent, config.para_id, ctx.sender())
+				.await
+				.await??
+				.ok_or(crate::error::Error::MissingParaBackingState)?;
+
+		// We are being very optimistic here, but one of the cores could pend availability some more
+		// block, ore even time out.
+		// For timeout assumption the collator can't really know because it doesn't receive bitfield
+		// gossip.
+		let assumption = if para_backing_state.pending_availability.is_empty() {
+			OccupiedCoreAssumption::Free
+		} else {
+			OccupiedCoreAssumption::Included
+		};
+
+		gum::debug!(
+			target: LOG_TARGET,
+			relay_parent = ?relay_parent,
+			our_para = %config.para_id,
+			?assumption,
+			"Occupied core(s) assumption",
+		);
+
+		let mut validation_data = match request_persisted_validation_data(
+			relay_parent,
+			config.para_id,
+			assumption,
+			ctx.sender(),
+		)
+		.await
+		.await??
+		{
+			Some(v) => v,
+			None => {
+				gum::debug!(
+					target: LOG_TARGET,
+					relay_parent = ?relay_parent,
+					our_para = %config.para_id,
+					"validation data is not available",
+				);
+				continue
+			},
+		};
 
-			let task_config = config.clone();
-			let metrics = metrics.clone();
-			let mut task_sender = ctx.sender().clone();
-			ctx.spawn(
-				"collation-builder",
-				Box::pin(async move {
+		let validation_code_hash = match obtain_validation_code_hash_with_assumption(
+			relay_parent,
+			config.para_id,
+			assumption,
+			ctx.sender(),
+		)
+		.await?
+		{
+			Some(v) => v,
+			None => {
+				gum::debug!(
+					target: LOG_TARGET,
+					relay_parent = ?relay_parent,
+					our_para = %config.para_id,
+					"validation code hash is not found.",
+				);
+				continue
+			},
+		};
+
+		let task_config = config.clone();
+		let metrics = metrics.clone();
+		let mut task_sender = ctx.sender().clone();
+
+		ctx.spawn(
+			"chained-collation-builder",
+			Box::pin(async move {
+				for core_index in cores_to_build_on {
 					let collator_fn = match task_config.collator.as_ref() {
 						Some(x) => x,
 						None => return,
@@ -363,21 +387,23 @@ async fn handle_new_activations<Context>(
 							None => {
 								gum::debug!(
 									target: LOG_TARGET,
-									para_id = %scheduled_core.para_id,
+									?para_id,
 									"collator returned no collation on collate",
 								);
 								return
 							},
 						};
 
+					let parent_head = collation.head_data.clone();
 					construct_and_distribute_receipt(
 						PreparedCollation {
 							collation,
-							para_id: scheduled_core.para_id,
+							para_id,
 							relay_parent,
-							validation_data,
+							validation_data: validation_data.clone(),
 							validation_code_hash,
 							n_validators,
+							core_index,
 						},
 						task_config.key.clone(),
 						&mut task_sender,
@@ -385,9 +411,13 @@ async fn handle_new_activations<Context>(
 						&metrics,
 					)
 					.await;
-				}),
-			)?;
-		}
+
+					// Chain the collations. All else stays the same as we build the chained
+					// collation on same relay parent.
+					validation_data.parent_head = parent_head;
+				}
+			}),
+		)?;
 	}
 
 	Ok(())
@@ -408,6 +438,7 @@ async fn handle_submit_collation<Context>(
 		parent_head,
 		validation_code_hash,
 		result_sender,
+		core_index,
 	} = params;
 
 	let validators = request_validators(relay_parent, ctx.sender()).await.await??;
@@ -444,6 +475,7 @@ async fn handle_submit_collation<Context>(
 		validation_data,
 		validation_code_hash,
 		n_validators,
+		core_index,
 	};
 
 	construct_and_distribute_receipt(
@@ -465,6 +497,7 @@ struct PreparedCollation {
 	validation_data: PersistedValidationData,
 	validation_code_hash: ValidationCodeHash,
 	n_validators: usize,
+	core_index: CoreIndex,
 }
 
 /// Takes a prepared collation, along with its context, and produces a candidate receipt
@@ -483,6 +516,7 @@ async fn construct_and_distribute_receipt(
 		validation_data,
 		validation_code_hash,
 		n_validators,
+		core_index,
 	} = collation;
 
 	let persisted_validation_data_hash = validation_data.hash();
@@ -578,6 +612,7 @@ async fn construct_and_distribute_receipt(
 			pov,
 			parent_head_data,
 			result_sender,
+			core_index,
 		})
 		.await;
 }
diff --git a/polkadot/node/collation-generation/src/tests.rs b/polkadot/node/collation-generation/src/tests.rs
index 9b16980e6af43..3cb3e61a35a1c 100644
--- a/polkadot/node/collation-generation/src/tests.rs
+++ b/polkadot/node/collation-generation/src/tests.rs
@@ -30,13 +30,16 @@ use polkadot_node_subsystem::{
 use polkadot_node_subsystem_test_helpers::{subsystem_test_harness, TestSubsystemContextHandle};
 use polkadot_node_subsystem_util::TimeoutExt;
 use polkadot_primitives::{
-	AsyncBackingParams, CollatorPair, HeadData, Id as ParaId, Id, PersistedValidationData,
+	async_backing::{BackingState, CandidatePendingAvailability},
+	AsyncBackingParams, BlockNumber, CollatorPair, HeadData, PersistedValidationData,
 	ScheduledCore, ValidationCode,
 };
 use rstest::rstest;
 use sp_keyring::sr25519::Keyring as Sr25519Keyring;
 use std::pin::Pin;
-use test_helpers::{dummy_candidate_descriptor, dummy_hash, dummy_head_data, dummy_validator};
+use test_helpers::{
+	dummy_candidate_descriptor, dummy_hash, dummy_head_data, dummy_validator, make_candidate,
+};
 
 type VirtualOverseer = TestSubsystemContextHandle<CollationGenerationMessage>;
 
@@ -105,9 +108,9 @@ impl Future for TestCollator {
 
 impl Unpin for TestCollator {}
 
-async fn overseer_recv(overseer: &mut VirtualOverseer) -> AllMessages {
-	const TIMEOUT: std::time::Duration = std::time::Duration::from_millis(2000);
+const TIMEOUT: std::time::Duration = std::time::Duration::from_millis(2000);
 
+async fn overseer_recv(overseer: &mut VirtualOverseer) -> AllMessages {
 	overseer
 		.recv()
 		.timeout(TIMEOUT)
@@ -135,6 +138,41 @@ fn scheduled_core_for<Id: Into<ParaId>>(para_id: Id) -> ScheduledCore {
 	ScheduledCore { para_id: para_id.into(), collator: None }
 }
 
+fn dummy_candidate_pending_availability(
+	para_id: ParaId,
+	candidate_relay_parent: Hash,
+	relay_parent_number: BlockNumber,
+) -> CandidatePendingAvailability {
+	let (candidate, _pvd) = make_candidate(
+		candidate_relay_parent,
+		relay_parent_number,
+		para_id,
+		dummy_head_data(),
+		HeadData(vec![1]),
+		ValidationCode(vec![1, 2, 3]).hash(),
+	);
+	let candidate_hash = candidate.hash();
+
+	CandidatePendingAvailability {
+		candidate_hash,
+		descriptor: candidate.descriptor,
+		commitments: candidate.commitments,
+		relay_parent_number,
+		max_pov_size: 5 * 1024 * 1024,
+	}
+}
+
+fn dummy_backing_state(pending_availability: Vec<CandidatePendingAvailability>) -> BackingState {
+	let constraints = helpers::dummy_constraints(
+		0,
+		vec![0],
+		dummy_head_data(),
+		ValidationCodeHash::from(Hash::repeat_byte(42)),
+	);
+
+	BackingState { constraints, pending_availability }
+}
+
 #[rstest]
 #[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT - 1)]
 #[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT)]
@@ -176,6 +214,12 @@ fn requests_availability_per_relay_parent(#[case] runtime_version: u32) {
 				))) if runtime_version >= RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT => {
 					tx.send(Ok(BTreeMap::new())).unwrap();
 				},
+				Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request(
+					_hash,
+					RuntimeApiRequest::ParaBackingState(_para_id, tx),
+				))) => {
+					tx.send(Ok(Some(dummy_backing_state(vec![])))).unwrap();
+				},
 				Some(msg) => panic!("didn't expect any other overseer requests given no availability cores; got {:?}", msg),
 			}
 		}
@@ -273,6 +317,12 @@ fn requests_validation_data_for_scheduled_matches(#[case] runtime_version: u32)
 				))) if runtime_version >= RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT => {
 					tx.send(Ok(BTreeMap::new())).unwrap();
 				},
+				Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request(
+					_hash,
+					RuntimeApiRequest::ParaBackingState(_para_id, tx),
+				))) => {
+					tx.send(Ok(Some(dummy_backing_state(vec![])))).unwrap();
+				},
 				Some(msg) => {
 					panic!("didn't expect any other overseer requests; got {:?}", msg)
 				},
@@ -384,6 +434,12 @@ fn sends_distribute_collation_message(#[case] runtime_version: u32) {
 				))) if runtime_version >= RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT => {
 					tx.send(Ok(BTreeMap::new())).unwrap();
 				},
+				Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request(
+					_hash,
+					RuntimeApiRequest::ParaBackingState(_para_id, tx),
+				))) => {
+					tx.send(Ok(Some(dummy_backing_state(vec![])))).unwrap();
+				},
 				Some(msg @ AllMessages::CollatorProtocol(_)) => {
 					inner_to_collator_protocol.lock().await.push(msg);
 				},
@@ -564,6 +620,12 @@ fn fallback_when_no_validation_code_hash_api(#[case] runtime_version: u32) {
 					let res = BTreeMap::<CoreIndex, VecDeque<ParaId>>::new();
 					tx.send(Ok(res)).unwrap();
 				},
+				Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request(
+					_hash,
+					RuntimeApiRequest::ParaBackingState(_para_id, tx),
+				))) => {
+					tx.send(Ok(Some(dummy_backing_state(vec![])))).unwrap();
+				},
 				Some(msg) => {
 					panic!("didn't expect any other overseer requests; got {:?}", msg)
 				},
@@ -611,6 +673,7 @@ fn submit_collation_is_no_op_before_initialization() {
 					parent_head: vec![1, 2, 3].into(),
 					validation_code_hash: Hash::repeat_byte(1).into(),
 					result_sender: None,
+					core_index: CoreIndex(0),
 				}),
 			})
 			.await;
@@ -647,6 +710,7 @@ fn submit_collation_leads_to_distribution() {
 					parent_head: vec![1, 2, 3].into(),
 					validation_code_hash,
 					result_sender: None,
+					core_index: CoreIndex(0),
 				}),
 			})
 			.await;
@@ -721,6 +785,9 @@ fn distribute_collation_for_occupied_core_with_async_backing_enabled(#[case] run
 	test_harness(|mut virtual_overseer| async move {
 		helpers::initialize_collator(&mut virtual_overseer, para_id).await;
 		helpers::activate_new_head(&mut virtual_overseer, activated_hash).await;
+
+		let pending_availability =
+			vec![dummy_candidate_pending_availability(para_id, activated_hash, 1)];
 		helpers::handle_runtime_calls_on_new_head_activation(
 			&mut virtual_overseer,
 			activated_hash,
@@ -728,14 +795,140 @@ fn distribute_collation_for_occupied_core_with_async_backing_enabled(#[case] run
 			cores,
 			runtime_version,
 			claim_queue,
+			pending_availability,
+		)
+		.await;
+		helpers::handle_core_processing_for_a_leaf(
+			&mut virtual_overseer,
+			activated_hash,
+			para_id,
+			// `CoreState` is `Occupied` => `OccupiedCoreAssumption` is `Included`
+			OccupiedCoreAssumption::Included,
+			1,
+		)
+		.await;
+
+		virtual_overseer
+	});
+}
+
+// There are variable number of cores of cores in `Occupied` state and async backing is enabled.
+// On new head activation `CollationGeneration` should produce and distribute a new collation
+// with proper assumption about the para candidate chain availability at next block.
+#[rstest]
+#[case(0)]
+#[case(1)]
+#[case(2)]
+fn distribute_collation_for_occupied_cores_with_async_backing_enabled_and_elastic_scaling(
+	#[case] candidates_pending_avail: u32,
+) {
+	let activated_hash: Hash = [1; 32].into();
+	let para_id = ParaId::from(5);
+
+	let cores = (0..candidates_pending_avail)
+		.into_iter()
+		.map(|idx| {
+			CoreState::Occupied(polkadot_primitives::OccupiedCore {
+				next_up_on_available: Some(ScheduledCore { para_id, collator: None }),
+				occupied_since: 0,
+				time_out_at: 10,
+				next_up_on_time_out: Some(ScheduledCore { para_id, collator: None }),
+				availability: Default::default(), // doesn't matter
+				group_responsible: polkadot_primitives::GroupIndex(idx as u32),
+				candidate_hash: Default::default(),
+				candidate_descriptor: dummy_candidate_descriptor(dummy_hash()),
+			})
+		})
+		.collect::<Vec<_>>();
+
+	let pending_availability = (0..candidates_pending_avail)
+		.into_iter()
+		.map(|_idx| dummy_candidate_pending_availability(para_id, activated_hash, 0))
+		.collect::<Vec<_>>();
+
+	let claim_queue = cores
+		.iter()
+		.enumerate()
+		.map(|(idx, _core)| (CoreIndex::from(idx as u32), VecDeque::from([para_id])))
+		.collect::<BTreeMap<_, _>>();
+	let total_cores = cores.len();
+
+	test_harness(|mut virtual_overseer| async move {
+		helpers::initialize_collator(&mut virtual_overseer, para_id).await;
+		helpers::activate_new_head(&mut virtual_overseer, activated_hash).await;
+		helpers::handle_runtime_calls_on_new_head_activation(
+			&mut virtual_overseer,
+			activated_hash,
+			AsyncBackingParams { max_candidate_depth: 1, allowed_ancestry_len: 1 },
+			cores,
+			// Using latest runtime with the fancy claim queue exposed.
+			RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT,
+			claim_queue,
+			pending_availability,
 		)
 		.await;
+
 		helpers::handle_core_processing_for_a_leaf(
 			&mut virtual_overseer,
 			activated_hash,
 			para_id,
 			// `CoreState` is `Occupied` => `OccupiedCoreAssumption` is `Included`
 			OccupiedCoreAssumption::Included,
+			total_cores,
+		)
+		.await;
+
+		virtual_overseer
+	});
+}
+
+// There are variable number of cores of cores in `Free` state and async backing is enabled.
+// On new head activation `CollationGeneration` should produce and distribute a new collation
+// with proper assumption about the para candidate chain availability at next block.
+#[rstest]
+#[case(0)]
+#[case(1)]
+#[case(2)]
+fn distribute_collation_for_free_cores_with_async_backing_enabled_and_elastic_scaling(
+	#[case] candidates_pending_avail: u32,
+) {
+	let activated_hash: Hash = [1; 32].into();
+	let para_id = ParaId::from(5);
+
+	let cores = (0..candidates_pending_avail)
+		.into_iter()
+		.map(|_idx| CoreState::Scheduled(ScheduledCore { para_id, collator: None }))
+		.collect::<Vec<_>>();
+
+	let claim_queue = cores
+		.iter()
+		.enumerate()
+		.map(|(idx, _core)| (CoreIndex::from(idx as u32), VecDeque::from([para_id])))
+		.collect::<BTreeMap<_, _>>();
+	let total_cores = cores.len();
+
+	test_harness(|mut virtual_overseer| async move {
+		helpers::initialize_collator(&mut virtual_overseer, para_id).await;
+		helpers::activate_new_head(&mut virtual_overseer, activated_hash).await;
+		helpers::handle_runtime_calls_on_new_head_activation(
+			&mut virtual_overseer,
+			activated_hash,
+			AsyncBackingParams { max_candidate_depth: 1, allowed_ancestry_len: 1 },
+			cores,
+			// Using latest runtime with the fancy claim queue exposed.
+			RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT,
+			claim_queue,
+			vec![],
+		)
+		.await;
+
+		helpers::handle_core_processing_for_a_leaf(
+			&mut virtual_overseer,
+			activated_hash,
+			para_id,
+			// `CoreState` is `Free` => `OccupiedCoreAssumption` is `Free`
+			OccupiedCoreAssumption::Free,
+			total_cores,
 		)
 		.await;
 
@@ -777,6 +970,7 @@ fn no_collation_is_distributed_for_occupied_core_with_async_backing_disabled(
 			cores,
 			runtime_version,
 			claim_queue,
+			vec![],
 		)
 		.await;
 
@@ -785,8 +979,38 @@ fn no_collation_is_distributed_for_occupied_core_with_async_backing_disabled(
 }
 
 mod helpers {
+	use polkadot_primitives::{
+		async_backing::{Constraints, InboundHrmpLimitations},
+		BlockNumber,
+	};
+
 	use super::*;
 
+	// A set for dummy constraints for `ParaBackingState``
+	pub(crate) fn dummy_constraints(
+		min_relay_parent_number: BlockNumber,
+		valid_watermarks: Vec<BlockNumber>,
+		required_parent: HeadData,
+		validation_code_hash: ValidationCodeHash,
+	) -> Constraints {
+		Constraints {
+			min_relay_parent_number,
+			max_pov_size: 5 * 1024 * 1024,
+			max_code_size: 1_000_000,
+			ump_remaining: 10,
+			ump_remaining_bytes: 1_000,
+			max_ump_num_per_candidate: 10,
+			dmp_remaining_messages: vec![],
+			hrmp_inbound: InboundHrmpLimitations { valid_watermarks },
+			hrmp_channels_out: vec![],
+			max_hrmp_num_per_candidate: 0,
+			required_parent,
+			validation_code_hash,
+			upgrade_restriction: None,
+			future_validation_code: None,
+		}
+	}
+
 	// Sends `Initialize` with a collator config
 	pub async fn initialize_collator(virtual_overseer: &mut VirtualOverseer, para_id: ParaId) {
 		virtual_overseer
@@ -822,7 +1046,8 @@ mod helpers {
 		async_backing_params: AsyncBackingParams,
 		cores: Vec<CoreState>,
 		runtime_version: u32,
-		claim_queue: BTreeMap<CoreIndex, VecDeque<Id>>,
+		claim_queue: BTreeMap<CoreIndex, VecDeque<ParaId>>,
+		pending_availability: Vec<CandidatePendingAvailability>,
 	) {
 		assert_matches!(
 			overseer_recv(virtual_overseer).await,
@@ -857,6 +1082,25 @@ mod helpers {
 			}
 		);
 
+		// Process the `ParaBackingState` message, and return some dummy state.
+		let message = overseer_recv(virtual_overseer).await;
+		let para_id = match message {
+			AllMessages::RuntimeApi(RuntimeApiMessage::Request(
+				_,
+				RuntimeApiRequest::ParaBackingState(p_id, _),
+			)) => p_id,
+			_ => panic!("received unexpected message {:?}", message),
+		};
+
+		assert_matches!(
+			message,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(parent, RuntimeApiRequest::ParaBackingState(p_id, tx))
+			) if parent == activated_hash && p_id == para_id => {
+				tx.send(Ok(Some(dummy_backing_state(pending_availability)))).unwrap();
+			}
+		);
+
 		assert_matches!(
 			overseer_recv(virtual_overseer).await,
 			AllMessages::RuntimeApi(RuntimeApiMessage::Request(
@@ -889,7 +1133,14 @@ mod helpers {
 		activated_hash: Hash,
 		para_id: ParaId,
 		expected_occupied_core_assumption: OccupiedCoreAssumption,
+		cores_assigned: usize,
 	) {
+		// Expect no messages if no cores is assigned to the para
+		if cores_assigned == 0 {
+			assert!(overseer_recv(virtual_overseer).timeout(TIMEOUT / 2).await.is_none());
+			return
+		}
+
 		// Some hardcoded data - if needed, extract to parameters
 		let validation_code_hash = ValidationCodeHash::from(Hash::repeat_byte(42));
 		let parent_head = HeadData::from(vec![1, 2, 3]);
diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs
index 1a62c9ee55e6e..76b3d476e28f5 100644
--- a/polkadot/node/core/approval-voting/src/lib.rs
+++ b/polkadot/node/core/approval-voting/src/lib.rs
@@ -1285,10 +1285,10 @@ fn cores_to_candidate_indices(
 
 	// Map from core index to candidate index.
 	for claimed_core_index in core_indices.iter_ones() {
-		// Candidates are sorted by core index.
-		if let Ok(candidate_index) = block_entry
+		if let Some(candidate_index) = block_entry
 			.candidates()
-			.binary_search_by_key(&(claimed_core_index as u32), |(core_index, _)| core_index.0)
+			.iter()
+			.position(|(core_index, _)| core_index.0 == claimed_core_index as u32)
 		{
 			candidate_indices.push(candidate_index as _);
 		}
diff --git a/polkadot/node/core/approval-voting/src/persisted_entries.rs b/polkadot/node/core/approval-voting/src/persisted_entries.rs
index b924a1b52ccf4..6eeb99cb99ffa 100644
--- a/polkadot/node/core/approval-voting/src/persisted_entries.rs
+++ b/polkadot/node/core/approval-voting/src/persisted_entries.rs
@@ -454,7 +454,7 @@ pub struct BlockEntry {
 	slot: Slot,
 	relay_vrf_story: RelayVRFStory,
 	// The candidates included as-of this block and the index of the core they are
-	// leaving. Sorted ascending by core index.
+	// leaving.
 	candidates: Vec<(CoreIndex, CandidateHash)>,
 	// A bitfield where the i'th bit corresponds to the i'th candidate in `candidates`.
 	// The i'th bit is `true` iff the candidate has been approved in the context of this
diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs
index a3013eab46dd6..1483af5658537 100644
--- a/polkadot/node/core/approval-voting/src/tests.rs
+++ b/polkadot/node/core/approval-voting/src/tests.rs
@@ -2479,6 +2479,173 @@ fn subsystem_import_checked_approval_sets_one_block_bit_at_a_time() {
 	});
 }
 
+// See https://github.com/paritytech/polkadot-sdk/issues/3826
+#[test]
+fn inclusion_events_can_be_unordered_by_core_index() {
+	let assignment_criteria = Box::new(MockAssignmentCriteria(
+		|| {
+			let mut assignments = HashMap::new();
+			for core in 0..3 {
+				let _ = assignments.insert(
+					CoreIndex(core),
+					approval_db::v2::OurAssignment {
+						cert: garbage_assignment_cert_v2(
+							AssignmentCertKindV2::RelayVRFModuloCompact {
+								core_bitfield: vec![CoreIndex(0), CoreIndex(1), CoreIndex(2)]
+									.try_into()
+									.unwrap(),
+							},
+						),
+						tranche: 0,
+						validator_index: ValidatorIndex(0),
+						triggered: false,
+					}
+					.into(),
+				);
+			}
+			assignments
+		},
+		|_| Ok(0),
+	));
+	let config = HarnessConfigBuilder::default().assignment_criteria(assignment_criteria).build();
+	let store = config.backend();
+
+	test_harness(config, |test_harness| async move {
+		let TestHarness {
+			mut virtual_overseer,
+			clock,
+			sync_oracle_handle: _sync_oracle_handle,
+			..
+		} = test_harness;
+
+		assert_matches!(
+			overseer_recv(&mut virtual_overseer).await,
+			AllMessages::ChainApi(ChainApiMessage::FinalizedBlockNumber(rx)) => {
+				rx.send(Ok(0)).unwrap();
+			}
+		);
+
+		let block_hash = Hash::repeat_byte(0x01);
+
+		let candidate_receipt0 = {
+			let mut receipt = dummy_candidate_receipt(block_hash);
+			receipt.descriptor.para_id = ParaId::from(0_u32);
+			receipt
+		};
+		let candidate_receipt1 = {
+			let mut receipt = dummy_candidate_receipt(block_hash);
+			receipt.descriptor.para_id = ParaId::from(1_u32);
+			receipt
+		};
+		let candidate_receipt2 = {
+			let mut receipt = dummy_candidate_receipt(block_hash);
+			receipt.descriptor.para_id = ParaId::from(2_u32);
+			receipt
+		};
+		let candidate_index0 = 0;
+		let candidate_index1 = 1;
+		let candidate_index2 = 2;
+
+		let validator0 = ValidatorIndex(0);
+		let validator1 = ValidatorIndex(1);
+		let validator2 = ValidatorIndex(2);
+		let validator3 = ValidatorIndex(3);
+
+		let validators = vec![
+			Sr25519Keyring::Alice,
+			Sr25519Keyring::Bob,
+			Sr25519Keyring::Charlie,
+			Sr25519Keyring::Dave,
+			Sr25519Keyring::Eve,
+		];
+		let session_info = SessionInfo {
+			validator_groups: IndexedVec::<GroupIndex, Vec<ValidatorIndex>>::from(vec![
+				vec![validator0, validator1],
+				vec![validator2],
+				vec![validator3],
+			]),
+			needed_approvals: 1,
+			zeroth_delay_tranche_width: 1,
+			relay_vrf_modulo_samples: 1,
+			n_delay_tranches: 1,
+			no_show_slots: 1,
+			..session_info(&validators)
+		};
+
+		ChainBuilder::new()
+			.add_block(
+				block_hash,
+				ChainBuilder::GENESIS_HASH,
+				1,
+				BlockConfig {
+					slot: Slot::from(0),
+					candidates: Some(vec![
+						(candidate_receipt0.clone(), CoreIndex(2), GroupIndex(2)),
+						(candidate_receipt1.clone(), CoreIndex(1), GroupIndex(0)),
+						(candidate_receipt2.clone(), CoreIndex(0), GroupIndex(1)),
+					]),
+					session_info: Some(session_info),
+					end_syncing: true,
+				},
+			)
+			.build(&mut virtual_overseer)
+			.await;
+
+		assert_eq!(clock.inner.lock().next_wakeup().unwrap(), 2);
+		clock.inner.lock().wakeup_all(100);
+
+		assert_eq!(clock.inner.lock().wakeups.len(), 0);
+
+		futures_timer::Delay::new(Duration::from_millis(100)).await;
+
+		// Assignment is distributed only once from `approval-voting`
+		assert_matches!(
+			overseer_recv(&mut virtual_overseer).await,
+			AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeAssignment(
+				_,
+				c_indices,
+			)) => {
+				assert_eq!(c_indices, vec![candidate_index0, candidate_index1, candidate_index2].try_into().unwrap());
+			}
+		);
+
+		// Candidate 0
+		recover_available_data(&mut virtual_overseer).await;
+		fetch_validation_code(&mut virtual_overseer).await;
+
+		// Candidate 1
+		recover_available_data(&mut virtual_overseer).await;
+		fetch_validation_code(&mut virtual_overseer).await;
+
+		// Candidate 2
+		recover_available_data(&mut virtual_overseer).await;
+		fetch_validation_code(&mut virtual_overseer).await;
+
+		// Check if assignment was triggered for candidate 0.
+		let candidate_entry =
+			store.load_candidate_entry(&candidate_receipt0.hash()).unwrap().unwrap();
+		let our_assignment =
+			candidate_entry.approval_entry(&block_hash).unwrap().our_assignment().unwrap();
+		assert!(our_assignment.triggered());
+
+		// Check if assignment was triggered for candidate 1.
+		let candidate_entry =
+			store.load_candidate_entry(&candidate_receipt1.hash()).unwrap().unwrap();
+		let our_assignment =
+			candidate_entry.approval_entry(&block_hash).unwrap().our_assignment().unwrap();
+		assert!(our_assignment.triggered());
+
+		// Check if assignment was triggered for candidate 2.
+		let candidate_entry =
+			store.load_candidate_entry(&candidate_receipt2.hash()).unwrap().unwrap();
+		let our_assignment =
+			candidate_entry.approval_entry(&block_hash).unwrap().our_assignment().unwrap();
+		assert!(our_assignment.triggered());
+
+		virtual_overseer
+	});
+}
+
 fn approved_ancestor_test(
 	skip_approval: impl Fn(BlockNumber) -> bool,
 	approved_height: BlockNumber,
diff --git a/polkadot/node/network/availability-distribution/benches/availability-distribution-regression-bench.rs b/polkadot/node/network/availability-distribution/benches/availability-distribution-regression-bench.rs
index 019eb1222082a..c33674a8f2f92 100644
--- a/polkadot/node/network/availability-distribution/benches/availability-distribution-regression-bench.rs
+++ b/polkadot/node/network/availability-distribution/benches/availability-distribution-regression-bench.rs
@@ -27,6 +27,7 @@ use polkadot_subsystem_bench::{
 	availability::{benchmark_availability_write, prepare_test, TestState},
 	configuration::TestConfiguration,
 	usage::BenchmarkUsage,
+	utils::save_to_file,
 };
 use std::io::Write;
 
@@ -60,7 +61,13 @@ fn main() -> Result<(), String> {
 		})
 		.collect();
 	println!("\rDone!{}", " ".repeat(BENCH_COUNT));
+
 	let average_usage = BenchmarkUsage::average(&usages);
+	save_to_file(
+		"charts/availability-distribution-regression-bench.json",
+		average_usage.to_chart_json().map_err(|e| e.to_string())?,
+	)
+	.map_err(|e| e.to_string())?;
 	println!("{}", average_usage);
 
 	// We expect no variance for received and sent
diff --git a/polkadot/node/network/availability-recovery/benches/availability-recovery-regression-bench.rs b/polkadot/node/network/availability-recovery/benches/availability-recovery-regression-bench.rs
index 5e8b81be82dd2..46a38516898f2 100644
--- a/polkadot/node/network/availability-recovery/benches/availability-recovery-regression-bench.rs
+++ b/polkadot/node/network/availability-recovery/benches/availability-recovery-regression-bench.rs
@@ -28,6 +28,7 @@ use polkadot_subsystem_bench::{
 	},
 	configuration::TestConfiguration,
 	usage::BenchmarkUsage,
+	utils::save_to_file,
 };
 use std::io::Write;
 
@@ -58,7 +59,13 @@ fn main() -> Result<(), String> {
 		})
 		.collect();
 	println!("\rDone!{}", " ".repeat(BENCH_COUNT));
+
 	let average_usage = BenchmarkUsage::average(&usages);
+	save_to_file(
+		"charts/availability-recovery-regression-bench.json",
+		average_usage.to_chart_json().map_err(|e| e.to_string())?,
+	)
+	.map_err(|e| e.to_string())?;
 	println!("{}", average_usage);
 
 	// We expect no variance for received and sent
diff --git a/polkadot/node/network/collator-protocol/src/collator_side/mod.rs b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs
index 9f306f288a162..e6aa55235b7a8 100644
--- a/polkadot/node/network/collator-protocol/src/collator_side/mod.rs
+++ b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs
@@ -203,20 +203,40 @@ struct PeerData {
 	version: CollationVersion,
 }
 
+/// A type wrapping a collation and it's designated core index.
+struct CollationWithCoreIndex(Collation, CoreIndex);
+
+impl CollationWithCoreIndex {
+	/// Returns inner collation ref.
+	pub fn collation(&self) -> &Collation {
+		&self.0
+	}
+
+	/// Returns inner collation mut ref.
+	pub fn collation_mut(&mut self) -> &mut Collation {
+		&mut self.0
+	}
+
+	/// Returns inner core index.
+	pub fn core_index(&self) -> &CoreIndex {
+		&self.1
+	}
+}
+
 struct PerRelayParent {
 	prospective_parachains_mode: ProspectiveParachainsMode,
-	/// Validators group responsible for backing candidates built
+	/// Per core index validators group responsible for backing candidates built
 	/// on top of this relay parent.
-	validator_group: ValidatorGroup,
+	validator_group: HashMap<CoreIndex, ValidatorGroup>,
 	/// Distributed collations.
-	collations: HashMap<CandidateHash, Collation>,
+	collations: HashMap<CandidateHash, CollationWithCoreIndex>,
 }
 
 impl PerRelayParent {
 	fn new(mode: ProspectiveParachainsMode) -> Self {
 		Self {
 			prospective_parachains_mode: mode,
-			validator_group: ValidatorGroup::default(),
+			validator_group: HashMap::default(),
 			collations: HashMap::new(),
 		}
 	}
@@ -350,6 +370,7 @@ async fn distribute_collation<Context>(
 	pov: PoV,
 	parent_head_data: HeadData,
 	result_sender: Option<oneshot::Sender<CollationSecondedSignal>>,
+	core_index: CoreIndex,
 ) -> Result<()> {
 	let candidate_relay_parent = receipt.descriptor.relay_parent;
 	let candidate_hash = receipt.hash();
@@ -422,7 +443,22 @@ async fn distribute_collation<Context>(
 		);
 	}
 
-	let our_core = our_cores[0];
+	// Double check that the specified `core_index` is among the ones our para has assignments for.
+	if !our_cores.iter().any(|assigned_core| assigned_core == &core_index) {
+		gum::warn!(
+			target: LOG_TARGET,
+			para_id = %id,
+			relay_parent = ?candidate_relay_parent,
+			cores = ?our_cores,
+			?core_index,
+			"Attempting to distribute collation for a core we are not assigned to ",
+		);
+
+		return Ok(())
+	}
+
+	let our_core = core_index;
+
 	// Determine the group on that core.
 	//
 	// When prospective parachains are disabled, candidate relay parent here is
@@ -464,10 +500,12 @@ async fn distribute_collation<Context>(
 		"Accepted collation, connecting to validators."
 	);
 
-	let validators_at_relay_parent = &mut per_relay_parent.validator_group.validators;
-	if validators_at_relay_parent.is_empty() {
-		*validators_at_relay_parent = validators;
-	}
+	// Insert validator group for the `core_index` at relay parent.
+	per_relay_parent.validator_group.entry(core_index).or_insert_with(|| {
+		let mut group = ValidatorGroup::default();
+		group.validators = validators;
+		group
+	});
 
 	// Update a set of connected validators if necessary.
 	connect_to_validators(ctx, &state.validator_groups_buf).await;
@@ -484,7 +522,10 @@ async fn distribute_collation<Context>(
 
 	per_relay_parent.collations.insert(
 		candidate_hash,
-		Collation { receipt, pov, parent_head_data, status: CollationStatus::Created },
+		CollationWithCoreIndex(
+			Collation { receipt, pov, parent_head_data, status: CollationStatus::Created },
+			core_index,
+		),
 	);
 
 	// If prospective parachains are disabled, a leaf should be known to peer.
@@ -690,7 +731,10 @@ async fn advertise_collation<Context>(
 	advertisement_timeouts: &mut FuturesUnordered<ResetInterestTimeout>,
 	metrics: &Metrics,
 ) {
-	for (candidate_hash, collation) in per_relay_parent.collations.iter_mut() {
+	for (candidate_hash, collation_and_core) in per_relay_parent.collations.iter_mut() {
+		let core_index = *collation_and_core.core_index();
+		let collation = collation_and_core.collation_mut();
+
 		// Check that peer will be able to request the collation.
 		if let CollationVersion::V1 = protocol_version {
 			if per_relay_parent.prospective_parachains_mode.is_enabled() {
@@ -704,11 +748,17 @@ async fn advertise_collation<Context>(
 			}
 		}
 
-		let should_advertise =
-			per_relay_parent
-				.validator_group
-				.should_advertise_to(candidate_hash, peer_ids, &peer);
+		let Some(validator_group) = per_relay_parent.validator_group.get_mut(&core_index) else {
+			gum::debug!(
+				target: LOG_TARGET,
+				?relay_parent,
+				?core_index,
+				"Skipping advertising to validator, validator group for core not found",
+			);
+			return
+		};
 
+		let should_advertise = validator_group.should_advertise_to(candidate_hash, peer_ids, &peer);
 		match should_advertise {
 			ShouldAdvertiseTo::Yes => {},
 			ShouldAdvertiseTo::NotAuthority | ShouldAdvertiseTo::AlreadyAdvertised => {
@@ -756,9 +806,7 @@ async fn advertise_collation<Context>(
 		))
 		.await;
 
-		per_relay_parent
-			.validator_group
-			.advertised_to_peer(candidate_hash, &peer_ids, peer);
+		validator_group.advertised_to_peer(candidate_hash, &peer_ids, peer);
 
 		advertisement_timeouts.push(ResetInterestTimeout::new(
 			*candidate_hash,
@@ -790,6 +838,7 @@ async fn process_msg<Context>(
 			pov,
 			parent_head_data,
 			result_sender,
+			core_index,
 		} => {
 			let _span1 = state
 				.span_per_relay_parent
@@ -820,6 +869,7 @@ async fn process_msg<Context>(
 						pov,
 						parent_head_data,
 						result_sender,
+						core_index,
 					)
 					.await?;
 				},
@@ -1053,7 +1103,7 @@ async fn handle_incoming_request<Context>(
 			};
 			let mode = per_relay_parent.prospective_parachains_mode;
 
-			let collation = match &req {
+			let collation_with_core = match &req {
 				VersionedCollationRequest::V1(_) if !mode.is_enabled() =>
 					per_relay_parent.collations.values_mut().next(),
 				VersionedCollationRequest::V2(req) =>
@@ -1070,22 +1120,24 @@ async fn handle_incoming_request<Context>(
 					return Ok(())
 				},
 			};
-			let (receipt, pov, parent_head_data) = if let Some(collation) = collation {
-				collation.status.advance_to_requested();
-				(
-					collation.receipt.clone(),
-					collation.pov.clone(),
-					collation.parent_head_data.clone(),
-				)
-			} else {
-				gum::warn!(
-					target: LOG_TARGET,
-					relay_parent = %relay_parent,
-					"received a `RequestCollation` for a relay parent we don't have collation stored.",
-				);
+			let (receipt, pov, parent_head_data) =
+				if let Some(collation_with_core) = collation_with_core {
+					let collation = collation_with_core.collation_mut();
+					collation.status.advance_to_requested();
+					(
+						collation.receipt.clone(),
+						collation.pov.clone(),
+						collation.parent_head_data.clone(),
+					)
+				} else {
+					gum::warn!(
+						target: LOG_TARGET,
+						relay_parent = %relay_parent,
+						"received a `RequestCollation` for a relay parent we don't have collation stored.",
+					);
 
-				return Ok(())
-			};
+					return Ok(())
+				};
 
 			state.metrics.on_collation_sent_requested();
 
@@ -1340,7 +1392,9 @@ where
 				.remove(removed)
 				.map(|per_relay_parent| per_relay_parent.collations)
 				.unwrap_or_default();
-			for collation in collations.into_values() {
+			for collation_with_core in collations.into_values() {
+				let collation = collation_with_core.collation();
+
 				let candidate_hash = collation.receipt.hash();
 				state.collation_result_senders.remove(&candidate_hash);
 				state.validator_groups_buf.remove_candidate(&candidate_hash);
@@ -1477,7 +1531,7 @@ async fn run_inner<Context>(
 					continue
 				};
 
-				let next_collation = {
+				let next_collation_with_core = {
 					let per_relay_parent = match state.per_relay_parent.get(&relay_parent) {
 						Some(per_relay_parent) => per_relay_parent,
 						None => continue,
@@ -1497,7 +1551,8 @@ async fn run_inner<Context>(
 					}
 				};
 
-				if let Some(collation) = next_collation {
+				if let Some(collation_with_core) = next_collation_with_core {
+					let collation = collation_with_core.collation();
 					let receipt = collation.receipt.clone();
 					let pov = collation.pov.clone();
 					let parent_head_data = collation.parent_head_data.clone();
diff --git a/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs b/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs
index 38e6780eb7d20..bcf0b34e631f9 100644
--- a/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs
+++ b/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs
@@ -377,6 +377,7 @@ async fn distribute_collation_with_receipt(
 			pov: pov.clone(),
 			parent_head_data: HeadData(vec![1, 2, 3]),
 			result_sender: None,
+			core_index: CoreIndex(0),
 		},
 	)
 	.await;
diff --git a/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs b/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs
index e419cd5444f5a..707053545630a 100644
--- a/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs
+++ b/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs
@@ -277,6 +277,7 @@ fn distribute_collation_from_implicit_view() {
 					pov: pov.clone(),
 					parent_head_data: HeadData(vec![1, 2, 3]),
 					result_sender: None,
+					core_index: CoreIndex(0),
 				},
 			)
 			.await;
@@ -358,6 +359,7 @@ fn distribute_collation_up_to_limit() {
 					pov: pov.clone(),
 					parent_head_data: HeadData(vec![1, 2, 3]),
 					result_sender: None,
+					core_index: CoreIndex(0),
 				},
 			)
 			.await;
diff --git a/polkadot/node/network/collator-protocol/src/collator_side/validators_buffer.rs b/polkadot/node/network/collator-protocol/src/collator_side/validators_buffer.rs
index 1533f2eda5a57..fbb3ff4328a51 100644
--- a/polkadot/node/network/collator-protocol/src/collator_side/validators_buffer.rs
+++ b/polkadot/node/network/collator-protocol/src/collator_side/validators_buffer.rs
@@ -45,14 +45,22 @@ use futures::FutureExt;
 use polkadot_node_network_protocol::PeerId;
 use polkadot_primitives::{AuthorityDiscoveryId, CandidateHash, GroupIndex, SessionIndex};
 
+/// Elastic scaling: how many candidates per relay chain block the collator supports building.
+pub const MAX_CHAINED_CANDIDATES_PER_RCB: NonZeroUsize = match NonZeroUsize::new(3) {
+	Some(cap) => cap,
+	None => panic!("max candidates per rcb cannot be zero"),
+};
+
 /// The ring buffer stores at most this many unique validator groups.
 ///
 /// This value should be chosen in way that all groups assigned to our para
-/// in the view can fit into the buffer.
-pub const VALIDATORS_BUFFER_CAPACITY: NonZeroUsize = match NonZeroUsize::new(3) {
-	Some(cap) => cap,
-	None => panic!("buffer capacity must be non-zero"),
-};
+/// in the view can fit into the buffer multiplied by amount of candidates we support per relay
+/// chain block in the case of elastic scaling.
+pub const VALIDATORS_BUFFER_CAPACITY: NonZeroUsize =
+	match NonZeroUsize::new(3 * MAX_CHAINED_CANDIDATES_PER_RCB.get()) {
+		Some(cap) => cap,
+		None => panic!("buffer capacity must be non-zero"),
+	};
 
 /// Unique identifier of a validators group.
 #[derive(Debug)]
diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs
index b102cf06c38f6..b127d87d4ea4d 100644
--- a/polkadot/node/primitives/src/lib.rs
+++ b/polkadot/node/primitives/src/lib.rs
@@ -31,8 +31,8 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
 
 use polkadot_primitives::{
 	BlakeTwo256, BlockNumber, CandidateCommitments, CandidateHash, CollatorPair,
-	CommittedCandidateReceipt, CompactStatement, EncodeAs, Hash, HashT, HeadData, Id as ParaId,
-	PersistedValidationData, SessionIndex, Signed, UncheckedSigned, ValidationCode,
+	CommittedCandidateReceipt, CompactStatement, CoreIndex, EncodeAs, Hash, HashT, HeadData,
+	Id as ParaId, PersistedValidationData, SessionIndex, Signed, UncheckedSigned, ValidationCode,
 	ValidationCodeHash, ValidatorIndex, MAX_CODE_SIZE, MAX_POV_SIZE,
 };
 pub use sp_consensus_babe::{
@@ -524,6 +524,8 @@ pub struct SubmitCollationParams {
 	/// okay to just drop it. However, if it is called, it should be called with the signed
 	/// statement of a parachain validator seconding the collation.
 	pub result_sender: Option<futures::channel::oneshot::Sender<CollationSecondedSignal>>,
+	/// The core index on which the resulting candidate should be backed
+	pub core_index: CoreIndex,
 }
 
 /// This is the data we keep available for each candidate included in the relay chain.
diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml
index e2bccfa551090..5a42443c84c89 100644
--- a/polkadot/node/service/Cargo.toml
+++ b/polkadot/node/service/Cargo.toml
@@ -142,6 +142,9 @@ polkadot-node-core-pvf-checker = { path = "../core/pvf-checker", optional = true
 polkadot-node-core-runtime-api = { path = "../core/runtime-api", optional = true }
 polkadot-statement-distribution = { path = "../network/statement-distribution", optional = true }
 
+xcm = { package = "staging-xcm", path = "../../xcm" }
+xcm-fee-payment-runtime-api = { path = "../../xcm/xcm-fee-payment-runtime-api" }
+
 [dev-dependencies]
 polkadot-test-client = { path = "../test/client" }
 polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" }
diff --git a/polkadot/node/service/src/chain_spec.rs b/polkadot/node/service/src/chain_spec.rs
index 1c44b17b6fd24..c03ce1db0943d 100644
--- a/polkadot/node/service/src/chain_spec.rs
+++ b/polkadot/node/service/src/chain_spec.rs
@@ -123,7 +123,8 @@ fn default_parachains_host_configuration(
 ) -> polkadot_runtime_parachains::configuration::HostConfiguration<polkadot_primitives::BlockNumber>
 {
 	use polkadot_primitives::{
-		vstaging::node_features::FeatureIndex, AsyncBackingParams, MAX_CODE_SIZE, MAX_POV_SIZE,
+		vstaging::{node_features::FeatureIndex, ApprovalVotingParams},
+		AsyncBackingParams, MAX_CODE_SIZE, MAX_POV_SIZE,
 	};
 
 	polkadot_runtime_parachains::configuration::HostConfiguration {
@@ -158,7 +159,8 @@ fn default_parachains_host_configuration(
 			allowed_ancestry_len: 2,
 		},
 		node_features: bitvec::vec::BitVec::from_element(
-			1u8 << (FeatureIndex::ElasticScalingMVP as usize),
+			1u8 << (FeatureIndex::ElasticScalingMVP as usize) |
+				1u8 << (FeatureIndex::EnableAssignmentsV2 as usize),
 		),
 		scheduler_params: SchedulerParams {
 			lookahead: 2,
@@ -166,6 +168,7 @@ fn default_parachains_host_configuration(
 			paras_availability_period: 4,
 			..Default::default()
 		},
+		approval_voting_params: ApprovalVotingParams { max_approval_coalesce_count: 5 },
 		..Default::default()
 	}
 }
diff --git a/polkadot/node/service/src/fake_runtime_api.rs b/polkadot/node/service/src/fake_runtime_api.rs
index 085ea93fdc785..c6cfb7a27d042 100644
--- a/polkadot/node/service/src/fake_runtime_api.rs
+++ b/polkadot/node/service/src/fake_runtime_api.rs
@@ -30,6 +30,7 @@ use polkadot_primitives::{
 	ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash,
 	ValidatorId, ValidatorIndex, ValidatorSignature,
 };
+
 use sp_core::OpaqueMetadata;
 use sp_runtime::{
 	traits::Block as BlockT,
@@ -39,7 +40,7 @@ use sp_runtime::{
 use sp_version::RuntimeVersion;
 use sp_weights::Weight;
 use std::collections::BTreeMap;
-
+use xcm::{VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm};
 sp_api::decl_runtime_apis! {
 	/// This runtime API is only implemented for the test runtime!
 	pub trait GetLastTimestamp {
@@ -396,4 +397,22 @@ sp_api::impl_runtime_apis! {
 			unimplemented!()
 		}
 	}
+
+	impl xcm_fee_payment_runtime_api::XcmPaymentApi<Block> for Runtime {
+		fn query_acceptable_payment_assets(_: xcm::Version) -> Result<Vec<VersionedAssetId>, xcm_fee_payment_runtime_api::Error> {
+			unimplemented!()
+		}
+
+		fn query_weight_to_asset_fee(_: Weight, _: VersionedAssetId) -> Result<u128, xcm_fee_payment_runtime_api::Error> {
+			unimplemented!()
+		}
+
+		fn query_xcm_weight(_: VersionedXcm<()>) -> Result<Weight, xcm_fee_payment_runtime_api::Error> {
+			unimplemented!()
+		}
+
+		fn query_delivery_fees(_: VersionedLocation, _: VersionedXcm<()>) -> Result<VersionedAssets, xcm_fee_payment_runtime_api::Error> {
+			unimplemented!()
+		}
+	}
 }
diff --git a/polkadot/node/subsystem-bench/Cargo.toml b/polkadot/node/subsystem-bench/Cargo.toml
index 05907e428f92a..b494f05180d1b 100644
--- a/polkadot/node/subsystem-bench/Cargo.toml
+++ b/polkadot/node/subsystem-bench/Cargo.toml
@@ -71,6 +71,7 @@ prometheus_endpoint = { package = "substrate-prometheus-endpoint", path = "../..
 prometheus = { version = "0.13.0", default-features = false }
 serde = { workspace = true, default-features = true }
 serde_yaml = { workspace = true }
+serde_json = { workspace = true }
 
 polkadot-node-core-approval-voting = { path = "../core/approval-voting" }
 polkadot-approval-distribution = { path = "../network/approval-distribution" }
diff --git a/polkadot/node/subsystem-bench/src/lib/environment.rs b/polkadot/node/subsystem-bench/src/lib/environment.rs
index 2d80d75a14aaa..42955d0302232 100644
--- a/polkadot/node/subsystem-bench/src/lib/environment.rs
+++ b/polkadot/node/subsystem-bench/src/lib/environment.rs
@@ -404,7 +404,7 @@ impl TestEnvironment {
 		let total_cpu = test_env_cpu_metrics.sum_by("substrate_tasks_polling_duration_sum");
 
 		usage.push(ResourceUsage {
-			resource_name: "Test environment".to_string(),
+			resource_name: "test-environment".to_string(),
 			total: total_cpu,
 			per_block: total_cpu / num_blocks,
 		});
diff --git a/polkadot/node/subsystem-bench/src/lib/lib.rs b/polkadot/node/subsystem-bench/src/lib/lib.rs
index d06f2822a8958..ef2724abc9892 100644
--- a/polkadot/node/subsystem-bench/src/lib/lib.rs
+++ b/polkadot/node/subsystem-bench/src/lib/lib.rs
@@ -26,3 +26,4 @@ pub(crate) mod keyring;
 pub(crate) mod mock;
 pub(crate) mod network;
 pub mod usage;
+pub mod utils;
diff --git a/polkadot/node/subsystem-bench/src/lib/usage.rs b/polkadot/node/subsystem-bench/src/lib/usage.rs
index 7172969a8f920..59296746ec3d4 100644
--- a/polkadot/node/subsystem-bench/src/lib/usage.rs
+++ b/polkadot/node/subsystem-bench/src/lib/usage.rs
@@ -82,6 +82,27 @@ impl BenchmarkUsage {
 			_ => None,
 		}
 	}
+
+	// Prepares a json string for a graph representation
+	// See: https://github.com/benchmark-action/github-action-benchmark?tab=readme-ov-file#examples
+	pub fn to_chart_json(&self) -> color_eyre::eyre::Result<String> {
+		let chart = self
+			.network_usage
+			.iter()
+			.map(|v| ChartItem {
+				name: v.resource_name.clone(),
+				unit: "KiB".to_string(),
+				value: v.per_block,
+			})
+			.chain(self.cpu_usage.iter().map(|v| ChartItem {
+				name: v.resource_name.clone(),
+				unit: "seconds".to_string(),
+				value: v.per_block,
+			}))
+			.collect::<Vec<_>>();
+
+		Ok(serde_json::to_string(&chart)?)
+	}
 }
 
 fn check_usage(
@@ -151,3 +172,10 @@ impl ResourceUsage {
 }
 
 type ResourceUsageCheck<'a> = (&'a str, f64, f64);
+
+#[derive(Debug, Serialize)]
+pub struct ChartItem {
+	pub name: String,
+	pub unit: String,
+	pub value: f64,
+}
diff --git a/polkadot/node/subsystem-bench/src/lib/utils.rs b/polkadot/node/subsystem-bench/src/lib/utils.rs
index cd206d8f32233..b3cd3a88b6c13 100644
--- a/polkadot/node/subsystem-bench/src/lib/utils.rs
+++ b/polkadot/node/subsystem-bench/src/lib/utils.rs
@@ -16,61 +16,26 @@
 
 //! Test utils
 
-use crate::usage::BenchmarkUsage;
-use std::io::{stdout, Write};
-
-pub struct WarmUpOptions<'a> {
-	/// The maximum number of runs considered for warming up.
-	pub warm_up: usize,
-	/// The number of runs considered for benchmarking.
-	pub bench: usize,
-	/// The difference in CPU usage between runs considered as normal
-	pub precision: f64,
-	/// The subsystems whose CPU usage is checked during warm-up cycles
-	pub subsystems: &'a [&'a str],
-}
-
-impl<'a> WarmUpOptions<'a> {
-	pub fn new(subsystems: &'a [&'a str]) -> Self {
-		Self { warm_up: 100, bench: 3, precision: 0.02, subsystems }
-	}
-}
-
-pub fn warm_up_and_benchmark(
-	options: WarmUpOptions,
-	run: impl Fn() -> BenchmarkUsage,
-) -> Result<BenchmarkUsage, String> {
-	println!("Warming up...");
-	let mut usages = Vec::with_capacity(options.bench);
-
-	for n in 1..=options.warm_up {
-		let curr = run();
-		if let Some(prev) = usages.last() {
-			let diffs = options
-				.subsystems
-				.iter()
-				.map(|&v| {
-					curr.cpu_usage_diff(prev, v)
-						.ok_or(format!("{} not found in benchmark {:?}", v, prev))
-				})
-				.collect::<Result<Vec<f64>, String>>()?;
-			if !diffs.iter().all(|&v| v < options.precision) {
-				usages.clear();
-			}
-		}
-		usages.push(curr);
-		print!("\r{}%", n * 100 / options.warm_up);
-		if usages.len() == options.bench {
-			println!("\rTook {} runs to warm up", n.saturating_sub(options.bench));
-			break;
-		}
-		stdout().flush().unwrap();
-	}
-
-	if usages.len() != options.bench {
-		println!("Didn't warm up after {} runs", options.warm_up);
-		return Err("Can't warm up".to_string())
+use std::{fs::File, io::Write};
+
+// Saves a given string to a file
+pub fn save_to_file(path: &str, value: String) -> color_eyre::eyre::Result<()> {
+	let output = std::process::Command::new(env!("CARGO"))
+		.arg("locate-project")
+		.arg("--workspace")
+		.arg("--message-format=plain")
+		.output()
+		.unwrap()
+		.stdout;
+	let workspace_dir = std::path::Path::new(std::str::from_utf8(&output).unwrap().trim())
+		.parent()
+		.unwrap();
+	let path = workspace_dir.join(path);
+	if let Some(dir) = path.parent() {
+		std::fs::create_dir_all(dir)?;
 	}
+	let mut file = File::create(path)?;
+	file.write_all(value.as_bytes())?;
 
-	Ok(BenchmarkUsage::average(&usages))
+	Ok(())
 }
diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs
index 5d05d2b56ed08..d84b0b6dd1412 100644
--- a/polkadot/node/subsystem-types/src/messages.rs
+++ b/polkadot/node/subsystem-types/src/messages.rs
@@ -228,6 +228,8 @@ pub enum CollatorProtocolMessage {
 		/// The result sender should be informed when at least one parachain validator seconded the
 		/// collation. It is also completely okay to just drop the sender.
 		result_sender: Option<oneshot::Sender<CollationSecondedSignal>>,
+		/// The core index where the candidate should be backed.
+		core_index: CoreIndex,
 	},
 	/// Report a collator as having provided an invalid collation. This should lead to disconnect
 	/// and blacklist of the collator.
diff --git a/polkadot/node/subsystem-util/src/lib.rs b/polkadot/node/subsystem-util/src/lib.rs
index 6ff09ed5f2200..83b046f0bf0ac 100644
--- a/polkadot/node/subsystem-util/src/lib.rs
+++ b/polkadot/node/subsystem-util/src/lib.rs
@@ -30,7 +30,7 @@ use polkadot_node_subsystem::{
 	messages::{RuntimeApiMessage, RuntimeApiRequest, RuntimeApiSender},
 	overseer, SubsystemSender,
 };
-use polkadot_primitives::{slashing, CoreIndex, ExecutorParams};
+use polkadot_primitives::{async_backing::BackingState, slashing, CoreIndex, ExecutorParams};
 
 pub use overseer::{
 	gen::{OrchestraError as OverseerError, Timeout},
@@ -308,6 +308,7 @@ specialize_requests! {
 	fn request_disabled_validators() -> Vec<ValidatorIndex>; DisabledValidators;
 	fn request_async_backing_params() -> AsyncBackingParams; AsyncBackingParams;
 	fn request_claim_queue() -> BTreeMap<CoreIndex, VecDeque<ParaId>>; ClaimQueue;
+	fn request_para_backing_state(para_id: ParaId) -> Option<BackingState>; ParaBackingState;
 }
 
 /// Requests executor parameters from the runtime effective at given relay-parent. First obtains
diff --git a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml
index cb283c271191f..30bce806f9ffa 100644
--- a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml
+++ b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml
@@ -24,7 +24,7 @@ log = { workspace = true, default-features = true }
 test-parachain-adder = { path = ".." }
 polkadot-primitives = { path = "../../../../primitives" }
 polkadot-cli = { path = "../../../../cli" }
-polkadot-service = { path = "../../../../node/service", features = ["rococo-native"] }
+polkadot-service = { path = "../../../../node/service", features = ["elastic-scaling-experimental", "rococo-native"] }
 polkadot-node-primitives = { path = "../../../../node/primitives" }
 polkadot-node-subsystem = { path = "../../../../node/subsystem" }
 
diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml
index 238b98a66801c..bede10a7673be 100644
--- a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml
+++ b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml
@@ -24,7 +24,7 @@ log = { workspace = true, default-features = true }
 test-parachain-undying = { path = ".." }
 polkadot-primitives = { path = "../../../../primitives" }
 polkadot-cli = { path = "../../../../cli" }
-polkadot-service = { path = "../../../../node/service", features = ["rococo-native"] }
+polkadot-service = { path = "../../../../node/service", features = ["elastic-scaling-experimental", "rococo-native"] }
 polkadot-node-primitives = { path = "../../../../node/primitives" }
 polkadot-node-subsystem = { path = "../../../../node/subsystem" }
 
diff --git a/polkadot/runtime/parachains/src/coretime/mod.rs b/polkadot/runtime/parachains/src/coretime/mod.rs
index eb9646d7e869d..9095cd90ae0cf 100644
--- a/polkadot/runtime/parachains/src/coretime/mod.rs
+++ b/polkadot/runtime/parachains/src/coretime/mod.rs
@@ -83,6 +83,8 @@ enum CoretimeCalls {
 	SetLease(pallet_broker::TaskId, pallet_broker::Timeslice),
 	#[codec(index = 19)]
 	NotifyCoreCount(u16),
+	#[codec(index = 99)]
+	SwapLeases(ParaId, ParaId),
 }
 
 #[frame_support::pallet]
@@ -233,6 +235,24 @@ impl<T: Config> Pallet<T> {
 			}
 		}
 	}
+
+	// Handle legacy swaps in coretime. Notifies broker parachain that a lease swap has occurred via
+	// XCM message. This function is meant to be used in an implementation of `OnSwap` trait.
+	pub fn on_legacy_lease_swap(one: ParaId, other: ParaId) {
+		let message = Xcm(vec![
+			Instruction::UnpaidExecution {
+				weight_limit: WeightLimit::Unlimited,
+				check_origin: None,
+			},
+			mk_coretime_call(crate::coretime::CoretimeCalls::SwapLeases(one, other)),
+		]);
+		if let Err(err) = send_xcm::<T::SendXcm>(
+			Location::new(0, [Junction::Parachain(T::BrokerId::get())]),
+			message,
+		) {
+			log::error!("Sending `SwapLeases` to coretime chain failed: {:?}", err);
+		}
+	}
 }
 
 impl<T: Config> OnNewSession<BlockNumberFor<T>> for Pallet<T> {
diff --git a/polkadot/runtime/parachains/src/mock.rs b/polkadot/runtime/parachains/src/mock.rs
index 7ed62a392e4e5..461b9f4b431ac 100644
--- a/polkadot/runtime/parachains/src/mock.rs
+++ b/polkadot/runtime/parachains/src/mock.rs
@@ -365,6 +365,7 @@ impl pallet_message_queue::Config for Test {
 	type HeapSize = ConstU32<65536>;
 	type MaxStale = ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = ();
 }
 
 parameter_types! {
diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml
index 3dc59cc172817..6f63a93cebe50 100644
--- a/polkadot/runtime/rococo/Cargo.toml
+++ b/polkadot/runtime/rococo/Cargo.toml
@@ -104,6 +104,7 @@ polkadot-parachain-primitives = { path = "../../parachain", default-features = f
 xcm = { package = "staging-xcm", path = "../../xcm", default-features = false }
 xcm-executor = { package = "staging-xcm-executor", path = "../../xcm/xcm-executor", default-features = false }
 xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", default-features = false }
+xcm-fee-payment-runtime-api = { path = "../../xcm/xcm-fee-payment-runtime-api", default-features = false }
 
 [dev-dependencies]
 tiny-keccak = { version = "2.0.2", features = ["keccak"] }
@@ -208,6 +209,7 @@ std = [
 	"tx-pool-api/std",
 	"xcm-builder/std",
 	"xcm-executor/std",
+	"xcm-fee-payment-runtime-api/std",
 	"xcm/std",
 ]
 runtime-benchmarks = [
diff --git a/polkadot/runtime/rococo/src/impls.rs b/polkadot/runtime/rococo/src/impls.rs
index ac7100d785837..cf364b6ac7942 100644
--- a/polkadot/runtime/rococo/src/impls.rs
+++ b/polkadot/runtime/rococo/src/impls.rs
@@ -167,11 +167,16 @@ where
 			},
 		]);
 
+		let encoded_versioned_xcm =
+			VersionedXcm::V4(program).encode().try_into().map_err(|error| {
+				log::error!(target: "runtime::on_reap_identity", "XCM too large, error: {:?}", error);
+				pallet_xcm::Error::<Runtime>::XcmTooLarge
+			})?;
 		// send
-		let _ = <pallet_xcm::Pallet<Runtime>>::send(
+		let _ = <pallet_xcm::Pallet<Runtime>>::send_blob(
 			RawOrigin::Root.into(),
 			Box::new(VersionedLocation::V4(destination)),
-			Box::new(VersionedXcm::V4(program)),
+			encoded_versioned_xcm,
 		)?;
 		Ok(())
 	}
diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs
index 90824a2f6f084..c41ffdbe72db4 100644
--- a/polkadot/runtime/rococo/src/lib.rs
+++ b/polkadot/runtime/rococo/src/lib.rs
@@ -38,7 +38,7 @@ use runtime_common::{
 		LocatableAssetConverter, ToAuthor, VersionedLocatableAsset, VersionedLocationConverter,
 	},
 	paras_registrar, paras_sudo_wrapper, prod_or_fast, slots,
-	traits::Leaser,
+	traits::{Leaser, OnSwap},
 	BlockHashCount, BlockLength, SlowAdjustingFeeUpdate,
 };
 use scale_info::TypeInfo;
@@ -75,7 +75,7 @@ use frame_support::{
 		InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage,
 		ProcessMessageError, StorageMapShim, WithdrawReasons,
 	},
-	weights::{ConstantMultiplier, WeightMeter},
+	weights::{ConstantMultiplier, WeightMeter, WeightToFee as _},
 	PalletId,
 };
 use frame_system::{EnsureRoot, EnsureSigned};
@@ -98,7 +98,10 @@ use sp_staking::SessionIndex;
 #[cfg(any(feature = "std", test))]
 use sp_version::NativeVersion;
 use sp_version::RuntimeVersion;
-use xcm::{latest::prelude::*, VersionedLocation};
+use xcm::{
+	latest::prelude::*, IntoVersion, VersionedAssetId, VersionedAssets, VersionedLocation,
+	VersionedXcm,
+};
 use xcm_builder::PayOverXcm;
 
 pub use frame_system::Call as SystemCall;
@@ -123,6 +126,7 @@ use governance::{
 	pallet_custom_origins, AuctionAdmin, Fellows, GeneralAdmin, LeaseAdmin, Treasurer,
 	TreasurySpender,
 };
+use xcm_fee_payment_runtime_api::Error as XcmPaymentApiError;
 
 #[cfg(test)]
 mod tests;
@@ -216,7 +220,7 @@ pub struct OriginPrivilegeCmp;
 impl PrivilegeCmp<OriginCaller> for OriginPrivilegeCmp {
 	fn cmp_privilege(left: &OriginCaller, right: &OriginCaller) -> Option<Ordering> {
 		if left == right {
-			return Some(Ordering::Equal)
+			return Some(Ordering::Equal);
 		}
 
 		match (left, right) {
@@ -983,6 +987,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = MessageQueueHeapSize;
 	type MaxStale = MessageQueueMaxStale;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 	#[cfg(not(feature = "runtime-benchmarks"))]
 	type MessageProcessor = MessageProcessor;
 	#[cfg(feature = "runtime-benchmarks")]
@@ -1078,7 +1083,7 @@ impl paras_registrar::Config for Runtime {
 	type RuntimeOrigin = RuntimeOrigin;
 	type RuntimeEvent = RuntimeEvent;
 	type Currency = Balances;
-	type OnSwap = (Crowdloan, Slots);
+	type OnSwap = (Crowdloan, Slots, SwapLeases);
 	type ParaDeposit = ParaDeposit;
 	type DataDepositPerByte = DataDepositPerByte;
 	type WeightInfo = weights::runtime_common_paras_registrar::WeightInfo<Runtime>;
@@ -1306,6 +1311,14 @@ impl pallet_asset_rate::Config for Runtime {
 	type BenchmarkHelper = runtime_common::impls::benchmarks::AssetRateArguments;
 }
 
+// Notify `coretime` pallet when a lease swap occurs
+pub struct SwapLeases;
+impl OnSwap for SwapLeases {
+	fn on_swap(one: ParaId, other: ParaId) {
+		coretime::Pallet::<Runtime>::on_legacy_lease_swap(one, other);
+	}
+}
+
 construct_runtime! {
 	pub enum Runtime
 	{
@@ -1485,11 +1498,11 @@ pub mod migrations {
 			let now = frame_system::Pallet::<Runtime>::block_number();
 			let lease = slots::Pallet::<Runtime>::lease(para);
 			if lease.is_empty() {
-				return None
+				return None;
 			}
 			// Lease not yet started, ignore:
 			if lease.iter().any(Option::is_none) {
-				return None
+				return None;
 			}
 			let (index, _) =
 				<slots::Pallet<Runtime> as Leaser<BlockNumber>>::lease_period_index(now)?;
@@ -1551,7 +1564,7 @@ pub mod migrations {
 		fn pre_upgrade() -> Result<sp_std::vec::Vec<u8>, sp_runtime::TryRuntimeError> {
 			if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC {
 				log::warn!(target: "runtime::session_keys", "Skipping session keys migration pre-upgrade check due to spec version (already applied?)");
-				return Ok(Vec::new())
+				return Ok(Vec::new());
 			}
 
 			log::info!(target: "runtime::session_keys", "Collecting pre-upgrade session keys state");
@@ -1580,7 +1593,7 @@ pub mod migrations {
 		fn on_runtime_upgrade() -> Weight {
 			if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC {
 				log::info!("Skipping session keys upgrade: already applied");
-				return <Runtime as frame_system::Config>::DbWeight::get().reads(1)
+				return <Runtime as frame_system::Config>::DbWeight::get().reads(1);
 			}
 			log::trace!("Upgrading session keys");
 			Session::upgrade_keys::<OldSessionKeys, _>(transform_session_keys);
@@ -1593,7 +1606,7 @@ pub mod migrations {
 		) -> Result<(), sp_runtime::TryRuntimeError> {
 			if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC {
 				log::warn!(target: "runtime::session_keys", "Skipping session keys migration post-upgrade check due to spec version (already applied?)");
-				return Ok(())
+				return Ok(());
 			}
 
 			let key_ids = SessionKeys::key_ids();
@@ -1777,6 +1790,37 @@ sp_api::impl_runtime_apis! {
 		}
 	}
 
+	impl xcm_fee_payment_runtime_api::XcmPaymentApi<Block> for Runtime {
+		fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result<Vec<VersionedAssetId>, XcmPaymentApiError> {
+			if !matches!(xcm_version, 3 | 4) {
+				return Err(XcmPaymentApiError::UnhandledXcmVersion);
+			}
+			Ok([VersionedAssetId::V4(xcm_config::TokenLocation::get().into())]
+				.into_iter()
+				.filter_map(|asset| asset.into_version(xcm_version).ok())
+				.collect())
+		}
+
+		fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result<u128, XcmPaymentApiError> {
+			let local_asset = VersionedAssetId::V4(xcm_config::TokenLocation::get().into());
+			let asset = asset
+				.into_version(4)
+				.map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?;
+
+			if  asset != local_asset { return Err(XcmPaymentApiError::AssetNotFound); }
+
+			Ok(WeightToFee::weight_to_fee(&weight))
+		}
+
+		fn query_xcm_weight(message: VersionedXcm<()>) -> Result<Weight, XcmPaymentApiError> {
+			XcmPallet::query_xcm_weight(message)
+		}
+
+		fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result<VersionedAssets, XcmPaymentApiError> {
+			XcmPallet::query_delivery_fees(destination, message)
+		}
+	}
+
 	impl sp_api::Metadata<Block> for Runtime {
 		fn metadata() -> OpaqueMetadata {
 			OpaqueMetadata::new(Runtime::metadata().into())
@@ -2485,7 +2529,7 @@ mod remote_tests {
 	#[tokio::test]
 	async fn run_migrations() {
 		if var("RUN_MIGRATION_TESTS").is_err() {
-			return
+			return;
 		}
 
 		sp_tracing::try_init_simple();
diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs
index 5544ca44658cc..42972baa1c830 100644
--- a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs
+++ b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024
 
 // Executed Command:
@@ -60,8 +60,26 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `180`
 		//  Estimated: `3645`
-		// Minimum execution time: 25_043_000 picoseconds.
-		Weight::from_parts(25_682_000, 0)
+		// Minimum execution time: 24_724_000 picoseconds.
+		Weight::from_parts(25_615_000, 0)
+			.saturating_add(Weight::from_parts(0, 3645))
+			.saturating_add(T::DbWeight::get().reads(4))
+			.saturating_add(T::DbWeight::get().writes(2))
+	}
+	/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
+	/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `XcmPallet::SupportedVersion` (r:1 w:0)
+	/// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	fn send_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `180`
+		//  Estimated: `3645`
+		// Minimum execution time: 24_709_000 picoseconds.
+		Weight::from_parts(25_326_000, 0)
 			.saturating_add(Weight::from_parts(0, 3645))
 			.saturating_add(T::DbWeight::get().reads(4))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -80,8 +98,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `180`
 		//  Estimated: `3645`
-		// Minimum execution time: 107_570_000 picoseconds.
-		Weight::from_parts(109_878_000, 0)
+		// Minimum execution time: 106_600_000 picoseconds.
+		Weight::from_parts(110_781_000, 0)
 			.saturating_add(Weight::from_parts(0, 3645))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -100,8 +118,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `232`
 		//  Estimated: `3697`
-		// Minimum execution time: 106_341_000 picoseconds.
-		Weight::from_parts(109_135_000, 0)
+		// Minimum execution time: 103_030_000 picoseconds.
+		Weight::from_parts(106_018_000, 0)
 			.saturating_add(Weight::from_parts(0, 3697))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -120,8 +138,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `180`
 		//  Estimated: `3645`
-		// Minimum execution time: 108_372_000 picoseconds.
-		Weight::from_parts(112_890_000, 0)
+		// Minimum execution time: 107_017_000 picoseconds.
+		Weight::from_parts(109_214_000, 0)
 			.saturating_add(Weight::from_parts(0, 3645))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -130,8 +148,16 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 6_957_000 picoseconds.
-		Weight::from_parts(7_417_000, 0)
+		// Minimum execution time: 6_864_000 picoseconds.
+		Weight::from_parts(7_135_000, 0)
+			.saturating_add(Weight::from_parts(0, 0))
+	}
+	fn execute_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 6_955_000 picoseconds.
+		Weight::from_parts(7_165_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 	}
 	/// Storage: `XcmPallet::SupportedVersion` (r:0 w:1)
@@ -140,8 +166,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 7_053_000 picoseconds.
-		Weight::from_parts(7_462_000, 0)
+		// Minimum execution time: 6_827_000 picoseconds.
+		Weight::from_parts(7_211_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -149,8 +175,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_918_000 picoseconds.
-		Weight::from_parts(2_037_000, 0)
+		// Minimum execution time: 1_788_000 picoseconds.
+		Weight::from_parts(2_021_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 	}
 	/// Storage: `XcmPallet::VersionNotifiers` (r:1 w:1)
@@ -171,8 +197,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `180`
 		//  Estimated: `3645`
-		// Minimum execution time: 30_417_000 picoseconds.
-		Weight::from_parts(31_191_000, 0)
+		// Minimum execution time: 30_627_000 picoseconds.
+		Weight::from_parts(31_350_000, 0)
 			.saturating_add(Weight::from_parts(0, 3645))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(5))
@@ -193,8 +219,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `360`
 		//  Estimated: `3825`
-		// Minimum execution time: 36_666_000 picoseconds.
-		Weight::from_parts(37_779_000, 0)
+		// Minimum execution time: 36_688_000 picoseconds.
+		Weight::from_parts(37_345_000, 0)
 			.saturating_add(Weight::from_parts(0, 3825))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -205,8 +231,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_869_000 picoseconds.
-		Weight::from_parts(2_003_000, 0)
+		// Minimum execution time: 1_829_000 picoseconds.
+		Weight::from_parts(1_986_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -216,8 +242,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `22`
 		//  Estimated: `13387`
-		// Minimum execution time: 16_188_000 picoseconds.
-		Weight::from_parts(16_435_000, 0)
+		// Minimum execution time: 16_104_000 picoseconds.
+		Weight::from_parts(16_464_000, 0)
 			.saturating_add(Weight::from_parts(0, 13387))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -228,8 +254,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `26`
 		//  Estimated: `13391`
-		// Minimum execution time: 16_431_000 picoseconds.
-		Weight::from_parts(16_935_000, 0)
+		// Minimum execution time: 16_267_000 picoseconds.
+		Weight::from_parts(16_675_000, 0)
 			.saturating_add(Weight::from_parts(0, 13391))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -240,8 +266,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `40`
 		//  Estimated: `15880`
-		// Minimum execution time: 18_460_000 picoseconds.
-		Weight::from_parts(18_885_000, 0)
+		// Minimum execution time: 18_487_000 picoseconds.
+		Weight::from_parts(19_102_000, 0)
 			.saturating_add(Weight::from_parts(0, 15880))
 			.saturating_add(T::DbWeight::get().reads(6))
 	}
@@ -259,8 +285,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `216`
 		//  Estimated: `6156`
-		// Minimum execution time: 29_623_000 picoseconds.
-		Weight::from_parts(30_661_000, 0)
+		// Minimum execution time: 29_603_000 picoseconds.
+		Weight::from_parts(31_002_000, 0)
 			.saturating_add(Weight::from_parts(0, 6156))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -271,8 +297,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `69`
 		//  Estimated: `10959`
-		// Minimum execution time: 12_043_000 picoseconds.
-		Weight::from_parts(12_360_000, 0)
+		// Minimum execution time: 12_183_000 picoseconds.
+		Weight::from_parts(12_587_000, 0)
 			.saturating_add(Weight::from_parts(0, 10959))
 			.saturating_add(T::DbWeight::get().reads(4))
 	}
@@ -282,8 +308,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `33`
 		//  Estimated: `13398`
-		// Minimum execution time: 16_511_000 picoseconds.
-		Weight::from_parts(17_011_000, 0)
+		// Minimum execution time: 16_372_000 picoseconds.
+		Weight::from_parts(16_967_000, 0)
 			.saturating_add(Weight::from_parts(0, 13398))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -302,8 +328,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `216`
 		//  Estimated: `13581`
-		// Minimum execution time: 39_041_000 picoseconds.
-		Weight::from_parts(39_883_000, 0)
+		// Minimum execution time: 38_904_000 picoseconds.
+		Weight::from_parts(39_983_000, 0)
 			.saturating_add(Weight::from_parts(0, 13581))
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -316,8 +342,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `1485`
-		// Minimum execution time: 2_030_000 picoseconds.
-		Weight::from_parts(2_150_000, 0)
+		// Minimum execution time: 2_067_000 picoseconds.
+		Weight::from_parts(2_195_000, 0)
 			.saturating_add(Weight::from_parts(0, 1485))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -328,8 +354,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `7576`
 		//  Estimated: `11041`
-		// Minimum execution time: 22_615_000 picoseconds.
-		Weight::from_parts(23_008_000, 0)
+		// Minimum execution time: 23_982_000 picoseconds.
+		Weight::from_parts(24_409_000, 0)
 			.saturating_add(Weight::from_parts(0, 11041))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -340,8 +366,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `23`
 		//  Estimated: `3488`
-		// Minimum execution time: 34_438_000 picoseconds.
-		Weight::from_parts(35_514_000, 0)
+		// Minimum execution time: 33_430_000 picoseconds.
+		Weight::from_parts(34_433_000, 0)
 			.saturating_add(Weight::from_parts(0, 3488))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs
index 8a3cd9309dbd8..62c3741c56d6e 100644
--- a/polkadot/runtime/test-runtime/src/lib.rs
+++ b/polkadot/runtime/test-runtime/src/lib.rs
@@ -27,10 +27,11 @@ use sp_std::{collections::btree_map::BTreeMap, prelude::*};
 use polkadot_runtime_parachains::{
 	assigner_parachains as parachains_assigner_parachains,
 	configuration as parachains_configuration, disputes as parachains_disputes,
-	disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp,
-	inclusion as parachains_inclusion, initializer as parachains_initializer,
-	origin as parachains_origin, paras as parachains_paras,
-	paras_inherent as parachains_paras_inherent, runtime_api_impl::v7 as runtime_impl,
+	disputes::slashing as parachains_slashing,
+	dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion,
+	initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras,
+	paras_inherent as parachains_paras_inherent,
+	runtime_api_impl::{v7 as runtime_impl, vstaging as staging_runtime_impl},
 	scheduler as parachains_scheduler, session_info as parachains_session_info,
 	shared as parachains_shared,
 };
@@ -829,6 +830,7 @@ sp_api::impl_runtime_apis! {
 		}
 	}
 
+	#[api_version(10)]
 	impl primitives::runtime_api::ParachainHost<Block> for Runtime {
 		fn validators() -> Vec<ValidatorId> {
 			runtime_impl::validators::<Runtime>()
@@ -956,6 +958,30 @@ sp_api::impl_runtime_apis! {
 				key_ownership_proof,
 			)
 		}
+
+		fn minimum_backing_votes() -> u32 {
+			runtime_impl::minimum_backing_votes::<Runtime>()
+		}
+
+		fn para_backing_state(para_id: ParaId) -> Option<primitives::async_backing::BackingState> {
+			runtime_impl::backing_state::<Runtime>(para_id)
+		}
+
+		fn async_backing_params() -> primitives::AsyncBackingParams {
+			runtime_impl::async_backing_params::<Runtime>()
+		}
+
+		fn approval_voting_params() -> primitives::vstaging::ApprovalVotingParams {
+			staging_runtime_impl::approval_voting_params::<Runtime>()
+		}
+
+		fn disabled_validators() -> Vec<ValidatorIndex> {
+			staging_runtime_impl::disabled_validators::<Runtime>()
+		}
+
+		fn node_features() -> primitives::vstaging::NodeFeatures {
+			staging_runtime_impl::node_features::<Runtime>()
+		}
 	}
 
 	impl beefy_primitives::BeefyApi<Block, BeefyId> for Runtime {
diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml
index fcead1dd0b532..587a6c9a59051 100644
--- a/polkadot/runtime/westend/Cargo.toml
+++ b/polkadot/runtime/westend/Cargo.toml
@@ -114,6 +114,7 @@ runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parac
 xcm = { package = "staging-xcm", path = "../../xcm", default-features = false }
 xcm-executor = { package = "staging-xcm-executor", path = "../../xcm/xcm-executor", default-features = false }
 xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", default-features = false }
+xcm-fee-payment-runtime-api = { path = "../../xcm/xcm-fee-payment-runtime-api", default-features = false }
 
 [dev-dependencies]
 hex-literal = "0.4.1"
@@ -227,6 +228,7 @@ std = [
 	"westend-runtime-constants/std",
 	"xcm-builder/std",
 	"xcm-executor/std",
+	"xcm-fee-payment-runtime-api/std",
 	"xcm/std",
 ]
 runtime-benchmarks = [
diff --git a/polkadot/runtime/westend/src/impls.rs b/polkadot/runtime/westend/src/impls.rs
index 71e6b696a20a0..d8741c939a507 100644
--- a/polkadot/runtime/westend/src/impls.rs
+++ b/polkadot/runtime/westend/src/impls.rs
@@ -167,11 +167,16 @@ where
 			},
 		]);
 
+		let encoded_versioned_xcm =
+			VersionedXcm::V4(program).encode().try_into().map_err(|error| {
+				log::error!(target: "runtime::on_reap_identity", "XCM too large, error: {:?}", error);
+				pallet_xcm::Error::<Runtime>::XcmTooLarge
+			})?;
 		// send
-		let _ = <pallet_xcm::Pallet<Runtime>>::send(
+		let _ = <pallet_xcm::Pallet<Runtime>>::send_blob(
 			RawOrigin::Root.into(),
 			Box::new(VersionedLocation::V4(destination)),
-			Box::new(VersionedXcm::V4(program)),
+			encoded_versioned_xcm,
 		)?;
 		Ok(())
 	}
diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs
index 664044b713eef..e6381513170f8 100644
--- a/polkadot/runtime/westend/src/lib.rs
+++ b/polkadot/runtime/westend/src/lib.rs
@@ -35,7 +35,7 @@ use frame_support::{
 		InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, ProcessMessage,
 		ProcessMessageError, WithdrawReasons,
 	},
-	weights::{ConstantMultiplier, WeightMeter},
+	weights::{ConstantMultiplier, WeightMeter, WeightToFee as _},
 	PalletId,
 };
 use frame_system::{EnsureRoot, EnsureSigned};
@@ -62,7 +62,7 @@ use runtime_common::{
 		LocatableAssetConverter, ToAuthor, VersionedLocatableAsset, VersionedLocationConverter,
 	},
 	paras_registrar, paras_sudo_wrapper, prod_or_fast, slots,
-	traits::Leaser,
+	traits::{Leaser, OnSwap},
 	BalanceToU256, BlockHashCount, BlockLength, CurrencyToVote, SlowAdjustingFeeUpdate,
 	U256ToBalance,
 };
@@ -101,11 +101,13 @@ use sp_std::{collections::btree_map::BTreeMap, prelude::*};
 use sp_version::NativeVersion;
 use sp_version::RuntimeVersion;
 use xcm::{
-	latest::{InteriorLocation, Junction, Junction::PalletInstance},
-	VersionedLocation,
+	latest::prelude::*, IntoVersion, VersionedAssetId, VersionedAssets, VersionedLocation,
+	VersionedXcm,
 };
 use xcm_builder::PayOverXcm;
 
+use xcm_fee_payment_runtime_api::Error as XcmPaymentApiError;
+
 pub use frame_system::Call as SystemCall;
 pub use pallet_balances::Call as BalancesCall;
 pub use pallet_election_provider_multi_phase::{Call as EPMCall, GeometricDepositBase};
@@ -1188,6 +1190,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = MessageQueueHeapSize;
 	type MaxStale = MessageQueueMaxStale;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = MessageQueueServiceWeight;
 	#[cfg(not(feature = "runtime-benchmarks"))]
 	type MessageProcessor = MessageProcessor;
 	#[cfg(feature = "runtime-benchmarks")]
@@ -1302,7 +1305,7 @@ impl paras_registrar::Config for Runtime {
 	type RuntimeOrigin = RuntimeOrigin;
 	type RuntimeEvent = RuntimeEvent;
 	type Currency = Balances;
-	type OnSwap = (Crowdloan, Slots);
+	type OnSwap = (Crowdloan, Slots, SwapLeases);
 	type ParaDeposit = ParaDeposit;
 	type DataDepositPerByte = RegistrarDataDepositPerByte;
 	type WeightInfo = weights::runtime_common_paras_registrar::WeightInfo<Runtime>;
@@ -1414,6 +1417,14 @@ impl pallet_asset_rate::Config for Runtime {
 	type BenchmarkHelper = runtime_common::impls::benchmarks::AssetRateArguments;
 }
 
+// Notify `coretime` pallet when a lease swap occurs
+pub struct SwapLeases;
+impl OnSwap for SwapLeases {
+	fn on_swap(one: ParaId, other: ParaId) {
+		coretime::Pallet::<Runtime>::on_legacy_lease_swap(one, other);
+	}
+}
+
 #[frame_support::runtime(legacy_ordering)]
 mod runtime {
 	#[runtime::runtime]
@@ -1659,11 +1670,11 @@ pub mod migrations {
 			let now = frame_system::Pallet::<Runtime>::block_number();
 			let lease = slots::Pallet::<Runtime>::lease(para);
 			if lease.is_empty() {
-				return None
+				return None;
 			}
 			// Lease not yet started, ignore:
 			if lease.iter().any(Option::is_none) {
-				return None
+				return None;
 			}
 			let (index, _) =
 				<slots::Pallet<Runtime> as Leaser<BlockNumber>>::lease_period_index(now)?;
@@ -1685,7 +1696,7 @@ pub mod migrations {
 		fn pre_upgrade() -> Result<sp_std::vec::Vec<u8>, sp_runtime::TryRuntimeError> {
 			if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC {
 				log::warn!(target: "runtime::session_keys", "Skipping session keys migration pre-upgrade check due to spec version (already applied?)");
-				return Ok(Vec::new())
+				return Ok(Vec::new());
 			}
 
 			log::info!(target: "runtime::session_keys", "Collecting pre-upgrade session keys state");
@@ -1714,7 +1725,7 @@ pub mod migrations {
 		fn on_runtime_upgrade() -> Weight {
 			if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC {
 				log::warn!("Skipping session keys upgrade: already applied");
-				return <Runtime as frame_system::Config>::DbWeight::get().reads(1)
+				return <Runtime as frame_system::Config>::DbWeight::get().reads(1);
 			}
 			log::info!("Upgrading session keys");
 			Session::upgrade_keys::<OldSessionKeys, _>(transform_session_keys);
@@ -1727,7 +1738,7 @@ pub mod migrations {
 		) -> Result<(), sp_runtime::TryRuntimeError> {
 			if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC {
 				log::warn!(target: "runtime::session_keys", "Skipping session keys migration post-upgrade check due to spec version (already applied?)");
-				return Ok(())
+				return Ok(());
 			}
 
 			let key_ids = SessionKeys::key_ids();
@@ -2324,6 +2335,37 @@ sp_api::impl_runtime_apis! {
 		}
 	}
 
+	impl xcm_fee_payment_runtime_api::XcmPaymentApi<Block> for Runtime {
+		fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result<Vec<VersionedAssetId>, XcmPaymentApiError> {
+			if !matches!(xcm_version, 3 | 4) {
+				return Err(XcmPaymentApiError::UnhandledXcmVersion);
+			}
+			Ok([VersionedAssetId::V4(xcm_config::TokenLocation::get().into())]
+				.into_iter()
+				.filter_map(|asset| asset.into_version(xcm_version).ok())
+				.collect())
+		}
+
+		fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result<u128, XcmPaymentApiError> {
+			let local_asset = VersionedAssetId::V4(xcm_config::TokenLocation::get().into());
+			let asset = asset
+				.into_version(4)
+				.map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?;
+
+			if  asset != local_asset { return Err(XcmPaymentApiError::AssetNotFound); }
+
+			Ok(WeightToFee::weight_to_fee(&weight))
+		}
+
+		fn query_xcm_weight(message: VersionedXcm<()>) -> Result<Weight, XcmPaymentApiError> {
+			XcmPallet::query_xcm_weight(message)
+		}
+
+		fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result<VersionedAssets, XcmPaymentApiError> {
+			XcmPallet::query_delivery_fees(destination, message)
+		}
+	}
+
 	impl pallet_nomination_pools_runtime_api::NominationPoolsApi<
 		Block,
 		AccountId,
@@ -2642,7 +2684,7 @@ mod remote_tests {
 	#[tokio::test]
 	async fn run_migrations() {
 		if var("RUN_MIGRATION_TESTS").is_err() {
-			return
+			return;
 		}
 
 		sp_tracing::try_init_simple();
diff --git a/polkadot/runtime/westend/src/tests.rs b/polkadot/runtime/westend/src/tests.rs
index 9f99631605903..bdd599d2b7524 100644
--- a/polkadot/runtime/westend/src/tests.rs
+++ b/polkadot/runtime/westend/src/tests.rs
@@ -21,7 +21,6 @@ use std::collections::HashSet;
 use crate::*;
 use frame_support::traits::WhitelistedStorageKeys;
 use sp_core::hexdisplay::HexDisplay;
-use xcm::latest::prelude::*;
 
 #[test]
 fn remove_keys_weight_is_sensible() {
diff --git a/polkadot/runtime/westend/src/weights/pallet_staking.rs b/polkadot/runtime/westend/src/weights/pallet_staking.rs
index 7a641e36a126b..393fa0b37176a 100644
--- a/polkadot/runtime/westend/src/weights/pallet_staking.rs
+++ b/polkadot/runtime/westend/src/weights/pallet_staking.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_staking`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-01-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-03-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-8idpd4bs-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024
 
 // Executed Command:
@@ -50,22 +50,22 @@ pub struct WeightInfo<T>(PhantomData<T>);
 impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// Storage: `Staking::Bonded` (r:1 w:1)
 	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Ledger` (r:1 w:1)
+	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Locks` (r:1 w:1)
 	/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Freezes` (r:1 w:0)
 	/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Ledger` (r:0 w:1)
-	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Payee` (r:0 w:1)
 	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
 	fn bond() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `894`
+		//  Measured:  `1009`
 		//  Estimated: `4764`
-		// Minimum execution time: 37_340_000 picoseconds.
-		Weight::from_parts(38_930_000, 0)
+		// Minimum execution time: 40_585_000 picoseconds.
+		Weight::from_parts(41_800_000, 0)
 			.saturating_add(Weight::from_parts(0, 4764))
-			.saturating_add(T::DbWeight::get().reads(3))
+			.saturating_add(T::DbWeight::get().reads(4))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
 	/// Storage: `Staking::Bonded` (r:1 w:0)
@@ -84,22 +84,22 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `1921`
 		//  Estimated: `8877`
-		// Minimum execution time: 80_630_000 picoseconds.
-		Weight::from_parts(82_196_000, 0)
+		// Minimum execution time: 81_809_000 picoseconds.
+		Weight::from_parts(84_387_000, 0)
 			.saturating_add(Weight::from_parts(0, 8877))
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(7))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:1)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:0)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Nominators` (r:1 w:0)
 	/// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::MinNominatorBond` (r:1 w:0)
 	/// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::CurrentEra` (r:1 w:0)
 	/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Bonded` (r:1 w:0)
-	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Locks` (r:1 w:1)
 	/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Freezes` (r:1 w:0)
@@ -112,43 +112,45 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `2128`
 		//  Estimated: `8877`
-		// Minimum execution time: 83_523_000 picoseconds.
-		Weight::from_parts(86_639_000, 0)
+		// Minimum execution time: 89_419_000 picoseconds.
+		Weight::from_parts(91_237_000, 0)
 			.saturating_add(Weight::from_parts(0, 8877))
 			.saturating_add(T::DbWeight::get().reads(12))
 			.saturating_add(T::DbWeight::get().writes(7))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:1)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::CurrentEra` (r:1 w:0)
-	/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Bonded` (r:1 w:0)
 	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::CurrentEra` (r:1 w:0)
+	/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Locks` (r:1 w:1)
 	/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Freezes` (r:1 w:0)
 	/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`)
+	/// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0)
+	/// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`)
 	/// The range of component `s` is `[0, 100]`.
 	fn withdraw_unbonded_update(s: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1075`
+		//  Measured:  `1223`
 		//  Estimated: `4764`
-		// Minimum execution time: 38_636_000 picoseconds.
-		Weight::from_parts(40_399_283, 0)
+		// Minimum execution time: 45_152_000 picoseconds.
+		Weight::from_parts(46_460_819, 0)
 			.saturating_add(Weight::from_parts(0, 4764))
-			// Standard Error: 869
-			.saturating_add(Weight::from_parts(37_752, 0).saturating_mul(s.into()))
-			.saturating_add(T::DbWeight::get().reads(5))
+			// Standard Error: 972
+			.saturating_add(Weight::from_parts(55_473, 0).saturating_mul(s.into()))
+			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:1)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:1)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::CurrentEra` (r:1 w:0)
 	/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::SlashingSpans` (r:1 w:1)
 	/// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`)
-	/// Storage: `Staking::Bonded` (r:1 w:1)
-	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Locks` (r:1 w:1)
 	/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Freezes` (r:1 w:0)
@@ -174,11 +176,11 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `2127 + s * (4 ±0)`
 		//  Estimated: `6248 + s * (4 ±0)`
-		// Minimum execution time: 81_301_000 picoseconds.
-		Weight::from_parts(88_609_205, 0)
+		// Minimum execution time: 82_762_000 picoseconds.
+		Weight::from_parts(91_035_077, 0)
 			.saturating_add(Weight::from_parts(0, 6248))
-			// Standard Error: 3_388
-			.saturating_add(Weight::from_parts(1_253_692, 0).saturating_mul(s.into()))
+			// Standard Error: 3_771
+			.saturating_add(Weight::from_parts(1_217_871, 0).saturating_mul(s.into()))
 			.saturating_add(T::DbWeight::get().reads(13))
 			.saturating_add(T::DbWeight::get().writes(11))
 			.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into())))
@@ -186,6 +188,8 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:0)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:0)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::MinValidatorBond` (r:1 w:0)
 	/// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::MinCommission` (r:1 w:0)
@@ -196,8 +200,6 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Nominators` (r:1 w:0)
 	/// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Bonded` (r:1 w:0)
-	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListNodes` (r:1 w:1)
 	/// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListBags` (r:1 w:1)
@@ -210,33 +212,37 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `1301`
 		//  Estimated: `4556`
-		// Minimum execution time: 47_292_000 picoseconds.
-		Weight::from_parts(48_566_000, 0)
+		// Minimum execution time: 50_555_000 picoseconds.
+		Weight::from_parts(52_052_000, 0)
 			.saturating_add(Weight::from_parts(0, 4556))
 			.saturating_add(T::DbWeight::get().reads(11))
 			.saturating_add(T::DbWeight::get().writes(5))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:0)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:0)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Nominators` (r:128 w:128)
 	/// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`)
 	/// The range of component `k` is `[1, 128]`.
 	fn kick(k: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1243 + k * (569 ±0)`
+		//  Measured:  `1778 + k * (572 ±0)`
 		//  Estimated: `4556 + k * (3033 ±0)`
-		// Minimum execution time: 28_840_000 picoseconds.
-		Weight::from_parts(27_510_817, 0)
+		// Minimum execution time: 35_037_000 picoseconds.
+		Weight::from_parts(35_081_878, 0)
 			.saturating_add(Weight::from_parts(0, 4556))
-			// Standard Error: 6_603
-			.saturating_add(Weight::from_parts(6_268_853, 0).saturating_mul(k.into()))
-			.saturating_add(T::DbWeight::get().reads(1))
+			// Standard Error: 5_473
+			.saturating_add(Weight::from_parts(6_667_924, 0).saturating_mul(k.into()))
+			.saturating_add(T::DbWeight::get().reads(2))
 			.saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into())))
 			.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into())))
 			.saturating_add(Weight::from_parts(0, 3033).saturating_mul(k.into()))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:0)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:0)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::MinNominatorBond` (r:1 w:0)
 	/// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Nominators` (r:1 w:1)
@@ -247,8 +253,6 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::CurrentEra` (r:1 w:0)
 	/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Bonded` (r:1 w:0)
-	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListNodes` (r:2 w:2)
 	/// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListBags` (r:1 w:1)
@@ -262,11 +266,11 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `1797 + n * (102 ±0)`
 		//  Estimated: `6248 + n * (2520 ±0)`
-		// Minimum execution time: 57_537_000 picoseconds.
-		Weight::from_parts(55_854_233, 0)
+		// Minimum execution time: 62_098_000 picoseconds.
+		Weight::from_parts(60_154_061, 0)
 			.saturating_add(Weight::from_parts(0, 6248))
-			// Standard Error: 14_427
-			.saturating_add(Weight::from_parts(3_844_957, 0).saturating_mul(n.into()))
+			// Standard Error: 19_257
+			.saturating_add(Weight::from_parts(3_839_855, 0).saturating_mul(n.into()))
 			.saturating_add(T::DbWeight::get().reads(12))
 			.saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into())))
 			.saturating_add(T::DbWeight::get().writes(6))
@@ -274,6 +278,8 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:0)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:0)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Validators` (r:1 w:0)
 	/// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Nominators` (r:1 w:1)
@@ -288,12 +294,12 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	fn chill() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1581`
+		//  Measured:  `1747`
 		//  Estimated: `6248`
-		// Minimum execution time: 49_997_000 picoseconds.
-		Weight::from_parts(51_266_000, 0)
+		// Minimum execution time: 54_993_000 picoseconds.
+		Weight::from_parts(56_698_000, 0)
 			.saturating_add(Weight::from_parts(0, 6248))
-			.saturating_add(T::DbWeight::get().reads(8))
+			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(6))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:0)
@@ -306,40 +312,40 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `865`
 		//  Estimated: `4556`
-		// Minimum execution time: 15_342_000 picoseconds.
-		Weight::from_parts(15_970_000, 0)
+		// Minimum execution time: 18_100_000 picoseconds.
+		Weight::from_parts(18_547_000, 0)
 			.saturating_add(Weight::from_parts(0, 4556))
 			.saturating_add(T::DbWeight::get().reads(2))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:0)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Payee` (r:1 w:1)
-	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Bonded` (r:1 w:0)
 	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Payee` (r:1 w:1)
+	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
 	fn update_payee() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `932`
 		//  Estimated: `4556`
-		// Minimum execution time: 20_719_000 picoseconds.
-		Weight::from_parts(21_373_000, 0)
+		// Minimum execution time: 23_428_000 picoseconds.
+		Weight::from_parts(24_080_000, 0)
 			.saturating_add(Weight::from_parts(0, 4556))
 			.saturating_add(T::DbWeight::get().reads(3))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
 	/// Storage: `Staking::Bonded` (r:1 w:1)
 	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Ledger` (r:1 w:2)
+	/// Storage: `Staking::Ledger` (r:2 w:2)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
 	fn set_controller() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `865`
-		//  Estimated: `4556`
-		// Minimum execution time: 18_237_000 picoseconds.
-		Weight::from_parts(18_896_000, 0)
-			.saturating_add(Weight::from_parts(0, 4556))
-			.saturating_add(T::DbWeight::get().reads(2))
+		//  Estimated: `8122`
+		// Minimum execution time: 21_159_000 picoseconds.
+		Weight::from_parts(21_706_000, 0)
+			.saturating_add(Weight::from_parts(0, 8122))
+			.saturating_add(T::DbWeight::get().reads(3))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
 	/// Storage: `Staking::ValidatorCount` (r:0 w:1)
@@ -348,8 +354,8 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_946_000 picoseconds.
-		Weight::from_parts(2_131_000, 0)
+		// Minimum execution time: 1_910_000 picoseconds.
+		Weight::from_parts(2_003_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -359,8 +365,8 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 6_840_000 picoseconds.
-		Weight::from_parts(7_208_000, 0)
+		// Minimum execution time: 7_076_000 picoseconds.
+		Weight::from_parts(7_349_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -370,8 +376,8 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 6_812_000 picoseconds.
-		Weight::from_parts(7_254_000, 0)
+		// Minimum execution time: 7_067_000 picoseconds.
+		Weight::from_parts(7_389_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -381,8 +387,8 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 6_787_000 picoseconds.
-		Weight::from_parts(7_206_000, 0)
+		// Minimum execution time: 7_148_000 picoseconds.
+		Weight::from_parts(7_446_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -393,32 +399,32 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_045_000 picoseconds.
-		Weight::from_parts(2_281_841, 0)
+		// Minimum execution time: 2_025_000 picoseconds.
+		Weight::from_parts(2_229_953, 0)
 			.saturating_add(Weight::from_parts(0, 0))
-			// Standard Error: 70
-			.saturating_add(Weight::from_parts(11_592, 0).saturating_mul(v.into()))
+			// Standard Error: 67
+			.saturating_add(Weight::from_parts(11_785, 0).saturating_mul(v.into()))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
-	/// Storage: `Staking::Ledger` (r:751 w:1502)
+	/// Storage: `Staking::Ledger` (r:1502 w:1502)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:751 w:751)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Payee` (r:751 w:0)
 	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Bonded` (r:0 w:751)
-	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// The range of component `i` is `[0, 751]`.
 	fn deprecate_controller_batch(i: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `668 + i * (148 ±0)`
-		//  Estimated: `990 + i * (3566 ±0)`
-		// Minimum execution time: 1_657_000 picoseconds.
-		Weight::from_parts(1_702_000, 0)
+		//  Measured:  `680 + i * (227 ±0)`
+		//  Estimated: `990 + i * (7132 ±0)`
+		// Minimum execution time: 4_321_000 picoseconds.
+		Weight::from_parts(4_407_000, 0)
 			.saturating_add(Weight::from_parts(0, 990))
-			// Standard Error: 20_041
-			.saturating_add(Weight::from_parts(13_165_254, 0).saturating_mul(i.into()))
-			.saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(i.into())))
+			// Standard Error: 37_239
+			.saturating_add(Weight::from_parts(21_300_598, 0).saturating_mul(i.into()))
+			.saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(i.into())))
 			.saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(i.into())))
-			.saturating_add(Weight::from_parts(0, 3566).saturating_mul(i.into()))
+			.saturating_add(Weight::from_parts(0, 7132).saturating_mul(i.into()))
 	}
 	/// Storage: `Staking::SlashingSpans` (r:1 w:1)
 	/// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -453,11 +459,11 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `2127 + s * (4 ±0)`
 		//  Estimated: `6248 + s * (4 ±0)`
-		// Minimum execution time: 78_774_000 picoseconds.
-		Weight::from_parts(85_770_713, 0)
+		// Minimum execution time: 78_908_000 picoseconds.
+		Weight::from_parts(84_886_373, 0)
 			.saturating_add(Weight::from_parts(0, 6248))
-			// Standard Error: 2_815
-			.saturating_add(Weight::from_parts(1_244_494, 0).saturating_mul(s.into()))
+			// Standard Error: 3_376
+			.saturating_add(Weight::from_parts(1_217_850, 0).saturating_mul(s.into()))
 			.saturating_add(T::DbWeight::get().reads(13))
 			.saturating_add(T::DbWeight::get().writes(12))
 			.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into())))
@@ -470,11 +476,11 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `66639`
 		//  Estimated: `70104`
-		// Minimum execution time: 129_905_000 picoseconds.
-		Weight::from_parts(932_195_554, 0)
+		// Minimum execution time: 136_389_000 picoseconds.
+		Weight::from_parts(1_207_241_524, 0)
 			.saturating_add(Weight::from_parts(0, 70104))
-			// Standard Error: 57_492
-			.saturating_add(Weight::from_parts(4_826_754, 0).saturating_mul(s.into()))
+			// Standard Error: 77_138
+			.saturating_add(Weight::from_parts(6_443_948, 0).saturating_mul(s.into()))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -511,11 +517,11 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `8249 + n * (396 ±0)`
 		//  Estimated: `10779 + n * (3774 ±0)`
-		// Minimum execution time: 127_094_000 picoseconds.
-		Weight::from_parts(160_088_053, 0)
+		// Minimum execution time: 130_222_000 picoseconds.
+		Weight::from_parts(167_236_150, 0)
 			.saturating_add(Weight::from_parts(0, 10779))
-			// Standard Error: 32_978
-			.saturating_add(Weight::from_parts(39_845_710, 0).saturating_mul(n.into()))
+			// Standard Error: 34_051
+			.saturating_add(Weight::from_parts(39_899_917, 0).saturating_mul(n.into()))
 			.saturating_add(T::DbWeight::get().reads(14))
 			.saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into())))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -539,11 +545,11 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `1922 + l * (5 ±0)`
 		//  Estimated: `8877`
-		// Minimum execution time: 75_672_000 picoseconds.
-		Weight::from_parts(78_708_335, 0)
+		// Minimum execution time: 79_136_000 picoseconds.
+		Weight::from_parts(82_129_497, 0)
 			.saturating_add(Weight::from_parts(0, 8877))
-			// Standard Error: 3_387
-			.saturating_add(Weight::from_parts(37_084, 0).saturating_mul(l.into()))
+			// Standard Error: 3_867
+			.saturating_add(Weight::from_parts(75_156, 0).saturating_mul(l.into()))
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(7))
 	}
@@ -578,11 +584,11 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `2127 + s * (4 ±0)`
 		//  Estimated: `6248 + s * (4 ±0)`
-		// Minimum execution time: 87_991_000 picoseconds.
-		Weight::from_parts(90_272_005, 0)
+		// Minimum execution time: 89_375_000 picoseconds.
+		Weight::from_parts(91_224_907, 0)
 			.saturating_add(Weight::from_parts(0, 6248))
-			// Standard Error: 2_815
-			.saturating_add(Weight::from_parts(1_232_322, 0).saturating_mul(s.into()))
+			// Standard Error: 3_424
+			.saturating_add(Weight::from_parts(1_219_542, 0).saturating_mul(s.into()))
 			.saturating_add(T::DbWeight::get().reads(12))
 			.saturating_add(T::DbWeight::get().writes(11))
 			.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into())))
@@ -627,14 +633,14 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	fn new_era(v: u32, n: u32, ) -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0 + n * (716 ±0) + v * (3594 ±0)`
-		//  Estimated: `456136 + n * (3566 ±0) + v * (3566 ±0)`
-		// Minimum execution time: 528_862_000 picoseconds.
-		Weight::from_parts(534_620_000, 0)
+		//  Estimated: `456136 + n * (3566 ±4) + v * (3566 ±0)`
+		// Minimum execution time: 520_905_000 picoseconds.
+		Weight::from_parts(523_771_000, 0)
 			.saturating_add(Weight::from_parts(0, 456136))
-			// Standard Error: 2_005_553
-			.saturating_add(Weight::from_parts(65_586_008, 0).saturating_mul(v.into()))
-			// Standard Error: 199_842
-			.saturating_add(Weight::from_parts(18_155_389, 0).saturating_mul(n.into()))
+			// Standard Error: 2_142_714
+			.saturating_add(Weight::from_parts(68_631_588, 0).saturating_mul(v.into()))
+			// Standard Error: 213_509
+			.saturating_add(Weight::from_parts(19_343_025, 0).saturating_mul(n.into()))
 			.saturating_add(T::DbWeight::get().reads(184))
 			.saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into())))
 			.saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into())))
@@ -665,13 +671,13 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `3108 + n * (907 ±0) + v * (391 ±0)`
 		//  Estimated: `456136 + n * (3566 ±0) + v * (3566 ±0)`
-		// Minimum execution time: 33_532_110_000 picoseconds.
-		Weight::from_parts(33_926_321_000, 0)
+		// Minimum execution time: 36_848_619_000 picoseconds.
+		Weight::from_parts(37_362_442_000, 0)
 			.saturating_add(Weight::from_parts(0, 456136))
-			// Standard Error: 374_134
-			.saturating_add(Weight::from_parts(4_627_629, 0).saturating_mul(v.into()))
-			// Standard Error: 374_134
-			.saturating_add(Weight::from_parts(4_068_168, 0).saturating_mul(n.into()))
+			// Standard Error: 415_031
+			.saturating_add(Weight::from_parts(5_204_987, 0).saturating_mul(v.into()))
+			// Standard Error: 415_031
+			.saturating_add(Weight::from_parts(4_132_636, 0).saturating_mul(n.into()))
 			.saturating_add(T::DbWeight::get().reads(179))
 			.saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into())))
 			.saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into())))
@@ -688,11 +694,11 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `946 + v * (50 ±0)`
 		//  Estimated: `3510 + v * (2520 ±0)`
-		// Minimum execution time: 2_395_956_000 picoseconds.
-		Weight::from_parts(88_416_870, 0)
+		// Minimum execution time: 2_512_817_000 picoseconds.
+		Weight::from_parts(119_401_374, 0)
 			.saturating_add(Weight::from_parts(0, 3510))
-			// Standard Error: 8_731
-			.saturating_add(Weight::from_parts(4_750_956, 0).saturating_mul(v.into()))
+			// Standard Error: 8_463
+			.saturating_add(Weight::from_parts(4_860_364, 0).saturating_mul(v.into()))
 			.saturating_add(T::DbWeight::get().reads(2))
 			.saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into())))
 			.saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into()))
@@ -715,8 +721,8 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 3_761_000 picoseconds.
-		Weight::from_parts(4_013_000, 0)
+		// Minimum execution time: 3_686_000 picoseconds.
+		Weight::from_parts(3_881_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(7))
 	}
@@ -738,8 +744,8 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 3_325_000 picoseconds.
-		Weight::from_parts(3_519_000, 0)
+		// Minimum execution time: 3_143_000 picoseconds.
+		Weight::from_parts(3_424_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(7))
 	}
@@ -769,8 +775,8 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `1870`
 		//  Estimated: `6248`
-		// Minimum execution time: 63_583_000 picoseconds.
-		Weight::from_parts(65_917_000, 0)
+		// Minimum execution time: 66_946_000 picoseconds.
+		Weight::from_parts(69_382_000, 0)
 			.saturating_add(Weight::from_parts(0, 6248))
 			.saturating_add(T::DbWeight::get().reads(12))
 			.saturating_add(T::DbWeight::get().writes(6))
@@ -783,8 +789,8 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `658`
 		//  Estimated: `3510`
-		// Minimum execution time: 10_975_000 picoseconds.
-		Weight::from_parts(11_328_000, 0)
+		// Minimum execution time: 11_278_000 picoseconds.
+		Weight::from_parts(11_603_000, 0)
 			.saturating_add(Weight::from_parts(0, 3510))
 			.saturating_add(T::DbWeight::get().reads(2))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -795,9 +801,29 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_954_000 picoseconds.
-		Weight::from_parts(2_081_000, 0)
+		// Minimum execution time: 1_963_000 picoseconds.
+		Weight::from_parts(2_077_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
+	/// Storage: `Balances::Locks` (r:1 w:1)
+	/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
+	/// Storage: `System::Account` (r:1 w:1)
+	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:1)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Ledger` (r:1 w:1)
+	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Balances::Freezes` (r:1 w:0)
+	/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`)
+	fn restore_ledger() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `1014`
+		//  Estimated: `4764`
+		// Minimum execution time: 40_258_000 picoseconds.
+		Weight::from_parts(41_210_000, 0)
+			.saturating_add(Weight::from_parts(0, 4764))
+			.saturating_add(T::DbWeight::get().reads(5))
+			.saturating_add(T::DbWeight::get().writes(4))
+	}
 }
diff --git a/polkadot/runtime/westend/src/weights/pallet_xcm.rs b/polkadot/runtime/westend/src/weights/pallet_xcm.rs
index 10725cecf2499..80bc551ba1e26 100644
--- a/polkadot/runtime/westend/src/weights/pallet_xcm.rs
+++ b/polkadot/runtime/westend/src/weights/pallet_xcm.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024
 
 // Executed Command:
@@ -60,8 +60,26 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `147`
 		//  Estimated: `3612`
-		// Minimum execution time: 25_725_000 picoseconds.
-		Weight::from_parts(26_174_000, 0)
+		// Minimum execution time: 24_535_000 picoseconds.
+		Weight::from_parts(25_618_000, 0)
+			.saturating_add(Weight::from_parts(0, 3612))
+			.saturating_add(T::DbWeight::get().reads(4))
+			.saturating_add(T::DbWeight::get().writes(2))
+	}
+	/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
+	/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `XcmPallet::SupportedVersion` (r:1 w:0)
+	/// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	fn send_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `147`
+		//  Estimated: `3612`
+		// Minimum execution time: 25_376_000 picoseconds.
+		Weight::from_parts(26_180_000, 0)
 			.saturating_add(Weight::from_parts(0, 3612))
 			.saturating_add(T::DbWeight::get().reads(4))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -80,8 +98,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `250`
 		//  Estimated: `6196`
-		// Minimum execution time: 113_140_000 picoseconds.
-		Weight::from_parts(116_204_000, 0)
+		// Minimum execution time: 108_786_000 picoseconds.
+		Weight::from_parts(112_208_000, 0)
 			.saturating_add(Weight::from_parts(0, 6196))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -100,8 +118,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `302`
 		//  Estimated: `6196`
-		// Minimum execution time: 108_571_000 picoseconds.
-		Weight::from_parts(110_650_000, 0)
+		// Minimum execution time: 105_190_000 picoseconds.
+		Weight::from_parts(107_140_000, 0)
 			.saturating_add(Weight::from_parts(0, 6196))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -120,8 +138,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `250`
 		//  Estimated: `6196`
-		// Minimum execution time: 111_836_000 picoseconds.
-		Weight::from_parts(114_435_000, 0)
+		// Minimum execution time: 109_027_000 picoseconds.
+		Weight::from_parts(111_404_000, 0)
 			.saturating_add(Weight::from_parts(0, 6196))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -136,14 +154,24 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		Weight::from_parts(18_446_744_073_709_551_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 	}
+	/// Storage: `Benchmark::Override` (r:0 w:0)
+	/// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	fn execute_blob() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 18_446_744_073_709_551_000 picoseconds.
+		Weight::from_parts(18_446_744_073_709_551_000, 0)
+			.saturating_add(Weight::from_parts(0, 0))
+	}
 	/// Storage: `XcmPallet::SupportedVersion` (r:0 w:1)
 	/// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	fn force_xcm_version() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 7_160_000 picoseconds.
-		Weight::from_parts(7_477_000, 0)
+		// Minimum execution time: 6_668_000 picoseconds.
+		Weight::from_parts(7_013_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -151,8 +179,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_934_000 picoseconds.
-		Weight::from_parts(2_053_000, 0)
+		// Minimum execution time: 1_740_000 picoseconds.
+		Weight::from_parts(1_884_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 	}
 	/// Storage: `XcmPallet::VersionNotifiers` (r:1 w:1)
@@ -173,8 +201,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `147`
 		//  Estimated: `3612`
-		// Minimum execution time: 31_123_000 picoseconds.
-		Weight::from_parts(31_798_000, 0)
+		// Minimum execution time: 30_200_000 picoseconds.
+		Weight::from_parts(30_768_000, 0)
 			.saturating_add(Weight::from_parts(0, 3612))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(5))
@@ -195,8 +223,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `327`
 		//  Estimated: `3792`
-		// Minimum execution time: 35_175_000 picoseconds.
-		Weight::from_parts(36_098_000, 0)
+		// Minimum execution time: 33_928_000 picoseconds.
+		Weight::from_parts(35_551_000, 0)
 			.saturating_add(Weight::from_parts(0, 3792))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -207,8 +235,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_974_000 picoseconds.
-		Weight::from_parts(2_096_000, 0)
+		// Minimum execution time: 1_759_000 picoseconds.
+		Weight::from_parts(1_880_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -218,8 +246,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `22`
 		//  Estimated: `13387`
-		// Minimum execution time: 16_626_000 picoseconds.
-		Weight::from_parts(17_170_000, 0)
+		// Minimum execution time: 16_507_000 picoseconds.
+		Weight::from_parts(17_219_000, 0)
 			.saturating_add(Weight::from_parts(0, 13387))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -230,8 +258,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `26`
 		//  Estimated: `13391`
-		// Minimum execution time: 16_937_000 picoseconds.
-		Weight::from_parts(17_447_000, 0)
+		// Minimum execution time: 16_633_000 picoseconds.
+		Weight::from_parts(16_889_000, 0)
 			.saturating_add(Weight::from_parts(0, 13391))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -242,8 +270,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `40`
 		//  Estimated: `15880`
-		// Minimum execution time: 19_157_000 picoseconds.
-		Weight::from_parts(19_659_000, 0)
+		// Minimum execution time: 19_297_000 picoseconds.
+		Weight::from_parts(19_820_000, 0)
 			.saturating_add(Weight::from_parts(0, 15880))
 			.saturating_add(T::DbWeight::get().reads(6))
 	}
@@ -261,8 +289,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `183`
 		//  Estimated: `6123`
-		// Minimum execution time: 30_699_000 picoseconds.
-		Weight::from_parts(31_537_000, 0)
+		// Minimum execution time: 30_364_000 picoseconds.
+		Weight::from_parts(31_122_000, 0)
 			.saturating_add(Weight::from_parts(0, 6123))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(3))
@@ -273,8 +301,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `69`
 		//  Estimated: `10959`
-		// Minimum execution time: 12_303_000 picoseconds.
-		Weight::from_parts(12_670_000, 0)
+		// Minimum execution time: 11_997_000 picoseconds.
+		Weight::from_parts(12_392_000, 0)
 			.saturating_add(Weight::from_parts(0, 10959))
 			.saturating_add(T::DbWeight::get().reads(4))
 	}
@@ -284,8 +312,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `33`
 		//  Estimated: `13398`
-		// Minimum execution time: 17_129_000 picoseconds.
-		Weight::from_parts(17_668_000, 0)
+		// Minimum execution time: 16_894_000 picoseconds.
+		Weight::from_parts(17_452_000, 0)
 			.saturating_add(Weight::from_parts(0, 13398))
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -304,8 +332,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `183`
 		//  Estimated: `13548`
-		// Minimum execution time: 39_960_000 picoseconds.
-		Weight::from_parts(41_068_000, 0)
+		// Minimum execution time: 39_864_000 picoseconds.
+		Weight::from_parts(40_859_000, 0)
 			.saturating_add(Weight::from_parts(0, 13548))
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
@@ -318,8 +346,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `1485`
-		// Minimum execution time: 2_333_000 picoseconds.
-		Weight::from_parts(2_504_000, 0)
+		// Minimum execution time: 2_363_000 picoseconds.
+		Weight::from_parts(2_519_000, 0)
 			.saturating_add(Weight::from_parts(0, 1485))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(2))
@@ -330,8 +358,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `7576`
 		//  Estimated: `11041`
-		// Minimum execution time: 22_932_000 picoseconds.
-		Weight::from_parts(23_307_000, 0)
+		// Minimum execution time: 22_409_000 picoseconds.
+		Weight::from_parts(22_776_000, 0)
 			.saturating_add(Weight::from_parts(0, 11041))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
@@ -342,8 +370,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `23`
 		//  Estimated: `3488`
-		// Minimum execution time: 34_558_000 picoseconds.
-		Weight::from_parts(35_299_000, 0)
+		// Minimum execution time: 33_551_000 picoseconds.
+		Weight::from_parts(34_127_000, 0)
 			.saturating_add(Weight::from_parts(0, 3488))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml
index 4840b6127f554..08307c34f8a99 100644
--- a/polkadot/xcm/pallet-xcm/Cargo.toml
+++ b/polkadot/xcm/pallet-xcm/Cargo.toml
@@ -26,6 +26,7 @@ sp-std = { path = "../../../substrate/primitives/std", default-features = false
 xcm = { package = "staging-xcm", path = "..", default-features = false }
 xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false }
 xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder", default-features = false }
+xcm-fee-payment-runtime-api = { path = "../xcm-fee-payment-runtime-api", default-features = false }
 
 # marked optional, used in benchmarking
 frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true }
@@ -54,6 +55,7 @@ std = [
 	"sp-std/std",
 	"xcm-builder/std",
 	"xcm-executor/std",
+	"xcm-fee-payment-runtime-api/std",
 	"xcm/std",
 ]
 runtime-benchmarks = [
diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs
index ed42f93692b40..e2903d592dc18 100644
--- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs
+++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs
@@ -16,6 +16,7 @@
 
 use super::*;
 use bounded_collections::{ConstU32, WeakBoundedVec};
+use codec::Encode;
 use frame_benchmarking::{benchmarks, whitelisted_caller, BenchmarkError, BenchmarkResult};
 use frame_support::{
 	traits::fungible::{Inspect, Mutate},
@@ -108,6 +109,21 @@ benchmarks! {
 		let versioned_msg = VersionedXcm::from(msg);
 	}: _<RuntimeOrigin<T>>(send_origin, Box::new(versioned_dest), Box::new(versioned_msg))
 
+	send_blob {
+		let send_origin =
+			T::SendXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
+		if T::SendXcmOrigin::try_origin(send_origin.clone()).is_err() {
+			return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))
+		}
+		let msg = Xcm::<()>(vec![ClearOrigin]);
+		let versioned_dest: VersionedLocation = T::reachable_dest().ok_or(
+			BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)),
+		)?
+		.into();
+		let versioned_msg = VersionedXcm::from(msg);
+		let encoded_versioned_msg = versioned_msg.encode().try_into().unwrap();
+	}: _<RuntimeOrigin<T>>(send_origin, Box::new(versioned_dest), encoded_versioned_msg)
+
 	teleport_assets {
 		let (asset, destination) = T::teleportable_asset_and_dest().ok_or(
 			BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)),
@@ -227,6 +243,19 @@ benchmarks! {
 		let versioned_msg = VersionedXcm::from(msg);
 	}: _<RuntimeOrigin<T>>(execute_origin, Box::new(versioned_msg), Weight::MAX)
 
+	execute_blob {
+		let execute_origin =
+			T::ExecuteXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
+		let origin_location = T::ExecuteXcmOrigin::try_origin(execute_origin.clone())
+			.map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
+		let msg = Xcm(vec![ClearOrigin]);
+		if !T::XcmExecuteFilter::contains(&(origin_location, msg.clone())) {
+			return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))
+		}
+		let versioned_msg = VersionedXcm::from(msg);
+		let encoded_versioned_msg = versioned_msg.encode().try_into().unwrap();
+	}: _<RuntimeOrigin<T>>(execute_origin, encoded_versioned_msg, Weight::MAX)
+
 	force_xcm_version {
 		let loc = T::reachable_dest().ok_or(
 			BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)),
diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs
index 8a9e5288f2e12..29b61988f73c8 100644
--- a/polkadot/xcm/pallet-xcm/src/lib.rs
+++ b/polkadot/xcm/pallet-xcm/src/lib.rs
@@ -50,8 +50,8 @@ use sp_runtime::{
 use sp_std::{boxed::Box, marker::PhantomData, prelude::*, result::Result, vec};
 use xcm::{latest::QueryResponseInfo, prelude::*};
 use xcm_builder::{
-	ExecuteController, ExecuteControllerWeightInfo, QueryController, QueryControllerWeightInfo,
-	SendController, SendControllerWeightInfo,
+	ExecuteController, ExecuteControllerWeightInfo, MaxXcmEncodedSize, QueryController,
+	QueryControllerWeightInfo, SendController, SendControllerWeightInfo,
 };
 use xcm_executor::{
 	traits::{
@@ -61,6 +61,7 @@ use xcm_executor::{
 	},
 	AssetsInHolding,
 };
+use xcm_fee_payment_runtime_api::Error as FeePaymentError;
 
 #[cfg(any(feature = "try-runtime", test))]
 use sp_runtime::TryRuntimeError;
@@ -86,6 +87,8 @@ pub trait WeightInfo {
 	fn new_query() -> Weight;
 	fn take_response() -> Weight;
 	fn claim_assets() -> Weight;
+	fn execute_blob() -> Weight;
+	fn send_blob() -> Weight;
 }
 
 /// fallback implementation
@@ -170,6 +173,14 @@ impl WeightInfo for TestWeightInfo {
 	fn claim_assets() -> Weight {
 		Weight::from_parts(100_000_000, 0)
 	}
+
+	fn execute_blob() -> Weight {
+		Weight::from_parts(100_000_000, 0)
+	}
+
+	fn send_blob() -> Weight {
+		Weight::from_parts(100_000_000, 0)
+	}
 }
 
 #[frame_support::pallet]
@@ -285,76 +296,49 @@ pub mod pallet {
 	}
 
 	impl<T: Config> ExecuteControllerWeightInfo for Pallet<T> {
-		fn execute() -> Weight {
-			T::WeightInfo::execute()
+		fn execute_blob() -> Weight {
+			T::WeightInfo::execute_blob()
 		}
 	}
 
 	impl<T: Config> ExecuteController<OriginFor<T>, <T as Config>::RuntimeCall> for Pallet<T> {
 		type WeightInfo = Self;
-		fn execute(
+		fn execute_blob(
 			origin: OriginFor<T>,
-			message: Box<VersionedXcm<<T as Config>::RuntimeCall>>,
+			encoded_message: BoundedVec<u8, MaxXcmEncodedSize>,
 			max_weight: Weight,
 		) -> Result<Weight, DispatchErrorWithPostInfo> {
-			log::trace!(target: "xcm::pallet_xcm::execute", "message {:?}, max_weight {:?}", message, max_weight);
-			let outcome = (|| {
-				let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
-				let mut hash = message.using_encoded(sp_io::hashing::blake2_256);
-				let message = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
-				let value = (origin_location, message);
-				ensure!(T::XcmExecuteFilter::contains(&value), Error::<T>::Filtered);
-				let (origin_location, message) = value;
-				Ok(T::XcmExecutor::prepare_and_execute(
-					origin_location,
-					message,
-					&mut hash,
-					max_weight,
-					max_weight,
-				))
-			})()
-			.map_err(|e: DispatchError| {
-				e.with_weight(<Self::WeightInfo as ExecuteControllerWeightInfo>::execute())
-			})?;
-
-			Self::deposit_event(Event::Attempted { outcome: outcome.clone() });
-			let weight_used = outcome.weight_used();
-			outcome.ensure_complete().map_err(|error| {
-				log::error!(target: "xcm::pallet_xcm::execute", "XCM execution failed with error {:?}", error);
-				Error::<T>::LocalExecutionIncomplete.with_weight(
-					weight_used.saturating_add(
-						<Self::WeightInfo as ExecuteControllerWeightInfo>::execute(),
-					),
-				)
-			})?;
-			Ok(weight_used)
+			let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
+			let message =
+				VersionedXcm::<<T as Config>::RuntimeCall>::decode(&mut &encoded_message[..])
+					.map_err(|error| {
+						log::error!(target: "xcm::execute_blob", "Unable to decode XCM, error: {:?}", error);
+						Error::<T>::UnableToDecode
+					})?;
+			Self::execute_base(origin_location, Box::new(message), max_weight)
 		}
 	}
 
 	impl<T: Config> SendControllerWeightInfo for Pallet<T> {
-		fn send() -> Weight {
-			T::WeightInfo::send()
+		fn send_blob() -> Weight {
+			T::WeightInfo::send_blob()
 		}
 	}
 
 	impl<T: Config> SendController<OriginFor<T>> for Pallet<T> {
 		type WeightInfo = Self;
-		fn send(
+		fn send_blob(
 			origin: OriginFor<T>,
 			dest: Box<VersionedLocation>,
-			message: Box<VersionedXcm<()>>,
+			encoded_message: BoundedVec<u8, MaxXcmEncodedSize>,
 		) -> Result<XcmHash, DispatchError> {
 			let origin_location = T::SendXcmOrigin::ensure_origin(origin)?;
-			let interior: Junctions =
-				origin_location.clone().try_into().map_err(|_| Error::<T>::InvalidOrigin)?;
-			let dest = Location::try_from(*dest).map_err(|()| Error::<T>::BadVersion)?;
-			let message: Xcm<()> = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
-
-			let message_id = Self::send_xcm(interior, dest.clone(), message.clone())
-				.map_err(Error::<T>::from)?;
-			let e = Event::Sent { origin: origin_location, destination: dest, message, message_id };
-			Self::deposit_event(e);
-			Ok(message_id)
+			let message =
+				VersionedXcm::<()>::decode(&mut &encoded_message[..]).map_err(|error| {
+					log::error!(target: "xcm::send_blob", "Unable to decode XCM, error: {:?}", error);
+					Error::<T>::UnableToDecode
+				})?;
+			Self::send_base(origin_location, dest, Box::new(message))
 		}
 	}
 
@@ -561,6 +545,11 @@ pub mod pallet {
 		TooManyReserves,
 		/// Local XCM execution incomplete.
 		LocalExecutionIncomplete,
+		/// Could not decode XCM.
+		UnableToDecode,
+		/// XCM encoded length is too large.
+		/// Returned when an XCM encoded length is larger than `MaxXcmEncodedSize`.
+		XcmTooLarge,
 	}
 
 	impl<T: Config> From<SendError> for Error<T> {
@@ -898,8 +887,64 @@ pub mod pallet {
 		}
 	}
 
+	impl<T: Config> Pallet<T> {
+		/// Underlying logic for both [`execute_blob`] and [`execute`].
+		fn execute_base(
+			origin_location: Location,
+			message: Box<VersionedXcm<<T as Config>::RuntimeCall>>,
+			max_weight: Weight,
+		) -> Result<Weight, DispatchErrorWithPostInfo> {
+			log::trace!(target: "xcm::pallet_xcm::execute", "message {:?}, max_weight {:?}", message, max_weight);
+			let outcome = (|| {
+				let mut hash = message.using_encoded(sp_io::hashing::blake2_256);
+				let message = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
+				let value = (origin_location, message);
+				ensure!(T::XcmExecuteFilter::contains(&value), Error::<T>::Filtered);
+				let (origin_location, message) = value;
+				Ok(T::XcmExecutor::prepare_and_execute(
+					origin_location,
+					message,
+					&mut hash,
+					max_weight,
+					max_weight,
+				))
+			})()
+			.map_err(|e: DispatchError| e.with_weight(T::WeightInfo::execute()))?;
+
+			Self::deposit_event(Event::Attempted { outcome: outcome.clone() });
+			let weight_used = outcome.weight_used();
+			outcome.ensure_complete().map_err(|error| {
+				log::error!(target: "xcm::pallet_xcm::execute", "XCM execution failed with error {:?}", error);
+				Error::<T>::LocalExecutionIncomplete
+					.with_weight(weight_used.saturating_add(T::WeightInfo::execute()))
+			})?;
+			Ok(weight_used)
+		}
+
+		/// Underlying logic for both [`send_blob`] and [`send`].
+		fn send_base(
+			origin_location: Location,
+			dest: Box<VersionedLocation>,
+			message: Box<VersionedXcm<()>>,
+		) -> Result<XcmHash, DispatchError> {
+			let interior: Junctions =
+				origin_location.clone().try_into().map_err(|_| Error::<T>::InvalidOrigin)?;
+			let dest = Location::try_from(*dest).map_err(|()| Error::<T>::BadVersion)?;
+			let message: Xcm<()> = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
+
+			let message_id = Self::send_xcm(interior, dest.clone(), message.clone())
+				.map_err(Error::<T>::from)?;
+			let e = Event::Sent { origin: origin_location, destination: dest, message, message_id };
+			Self::deposit_event(e);
+			Ok(message_id)
+		}
+	}
+
 	#[pallet::call]
 	impl<T: Config> Pallet<T> {
+		/// WARNING: DEPRECATED. `send` will be removed after June 2024. Use `send_blob` instead.
+		#[allow(deprecated)]
+		#[deprecated(note = "`send` will be removed after June 2024. Use `send_blob` instead.")]
 		#[pallet::call_index(0)]
 		#[pallet::weight(T::WeightInfo::send())]
 		pub fn send(
@@ -907,7 +952,8 @@ pub mod pallet {
 			dest: Box<VersionedLocation>,
 			message: Box<VersionedXcm<()>>,
 		) -> DispatchResult {
-			<Self as SendController<_>>::send(origin, dest, message)?;
+			let origin_location = T::SendXcmOrigin::ensure_origin(origin)?;
+			Self::send_base(origin_location, dest, message)?;
 			Ok(())
 		}
 
@@ -1030,6 +1076,13 @@ pub mod pallet {
 		/// No more than `max_weight` will be used in its attempted execution. If this is less than
 		/// the maximum amount of weight that the message could take to be executed, then no
 		/// execution attempt will be made.
+		///
+		/// WARNING: DEPRECATED. `execute` will be removed after June 2024. Use `execute_blob`
+		/// instead.
+		#[allow(deprecated)]
+		#[deprecated(
+			note = "`execute` will be removed after June 2024. Use `execute_blob` instead."
+		)]
 		#[pallet::call_index(3)]
 		#[pallet::weight(max_weight.saturating_add(T::WeightInfo::execute()))]
 		pub fn execute(
@@ -1037,8 +1090,8 @@ pub mod pallet {
 			message: Box<VersionedXcm<<T as Config>::RuntimeCall>>,
 			max_weight: Weight,
 		) -> DispatchResultWithPostInfo {
-			let weight_used =
-				<Self as ExecuteController<_, _>>::execute(origin, message, max_weight)?;
+			let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
+			let weight_used = Self::execute_base(origin_location, message, max_weight)?;
 			Ok(Some(weight_used.saturating_add(T::WeightInfo::execute())).into())
 		}
 
@@ -1449,6 +1502,48 @@ pub mod pallet {
 			})?;
 			Ok(())
 		}
+
+		/// Execute an XCM from a local, signed, origin.
+		///
+		/// An event is deposited indicating whether the message could be executed completely
+		/// or only partially.
+		///
+		/// No more than `max_weight` will be used in its attempted execution. If this is less than
+		/// the maximum amount of weight that the message could take to be executed, then no
+		/// execution attempt will be made.
+		///
+		/// The message is passed in encoded. It needs to be decodable as a [`VersionedXcm`].
+		#[pallet::call_index(13)]
+		#[pallet::weight(T::WeightInfo::execute_blob())]
+		pub fn execute_blob(
+			origin: OriginFor<T>,
+			encoded_message: BoundedVec<u8, MaxXcmEncodedSize>,
+			max_weight: Weight,
+		) -> DispatchResultWithPostInfo {
+			let weight_used = <Self as ExecuteController<_, _>>::execute_blob(
+				origin,
+				encoded_message,
+				max_weight,
+			)?;
+			Ok(Some(weight_used.saturating_add(T::WeightInfo::execute_blob())).into())
+		}
+
+		/// Send an XCM from a local, signed, origin.
+		///
+		/// The destination, `dest`, will receive this message with a `DescendOrigin` instruction
+		/// that makes the origin of the message be the origin on this system.
+		///
+		/// The message is passed in encoded. It needs to be decodable as a [`VersionedXcm`].
+		#[pallet::call_index(14)]
+		#[pallet::weight(T::WeightInfo::send_blob())]
+		pub fn send_blob(
+			origin: OriginFor<T>,
+			dest: Box<VersionedLocation>,
+			encoded_message: BoundedVec<u8, MaxXcmEncodedSize>,
+		) -> DispatchResult {
+			<Self as SendController<_>>::send_blob(origin, dest, encoded_message)?;
+			Ok(())
+		}
 	}
 }
 
@@ -2363,6 +2458,37 @@ impl<T: Config> Pallet<T> {
 		AccountIdConversion::<T::AccountId>::into_account_truncating(&ID)
 	}
 
+	pub fn query_xcm_weight(message: VersionedXcm<()>) -> Result<Weight, FeePaymentError> {
+		let message =
+			Xcm::<()>::try_from(message).map_err(|_| FeePaymentError::VersionedConversionFailed)?;
+
+		T::Weigher::weight(&mut message.into()).map_err(|()| {
+			log::error!(target: "xcm::pallet_xcm::query_xcm_weight", "Error when querying XCM weight");
+			FeePaymentError::WeightNotComputable
+		})
+	}
+
+	pub fn query_delivery_fees(
+		destination: VersionedLocation,
+		message: VersionedXcm<()>,
+	) -> Result<VersionedAssets, FeePaymentError> {
+		let result_version = destination.identify_version().max(message.identify_version());
+
+		let destination =
+			destination.try_into().map_err(|_| FeePaymentError::VersionedConversionFailed)?;
+
+		let message = message.try_into().map_err(|_| FeePaymentError::VersionedConversionFailed)?;
+
+		let (_, fees) = validate_send::<T::XcmRouter>(destination, message).map_err(|error| {
+			log::error!(target: "xcm::pallet_xcm::query_delivery_fees", "Error when querying delivery fees: {:?}", error);
+			FeePaymentError::Unroutable
+		})?;
+
+		VersionedAssets::from(fees)
+			.into_version(result_version)
+			.map_err(|_| FeePaymentError::VersionedConversionFailed)
+	}
+
 	/// Create a new expectation of a query response with the querier being here.
 	fn do_new_query(
 		responder: impl Into<Location>,
diff --git a/polkadot/xcm/pallet-xcm/src/tests/mod.rs b/polkadot/xcm/pallet-xcm/src/tests/mod.rs
index 13022d9a8b1f6..763d768e154a5 100644
--- a/polkadot/xcm/pallet-xcm/src/tests/mod.rs
+++ b/polkadot/xcm/pallet-xcm/src/tests/mod.rs
@@ -20,10 +20,10 @@ pub(crate) mod assets_transfer;
 
 use crate::{
 	mock::*, pallet::SupportedVersion, AssetTraps, Config, CurrentMigration, Error,
-	ExecuteControllerWeightInfo, LatestVersionedLocation, Pallet, Queries, QueryStatus,
-	VersionDiscoveryQueue, VersionMigrationStage, VersionNotifiers, VersionNotifyTargets,
-	WeightInfo,
+	LatestVersionedLocation, Pallet, Queries, QueryStatus, VersionDiscoveryQueue,
+	VersionMigrationStage, VersionNotifiers, VersionNotifyTargets, WeightInfo,
 };
+use codec::Encode;
 use frame_support::{
 	assert_err_ignore_postinfo, assert_noop, assert_ok,
 	traits::{Currency, Hooks},
@@ -305,11 +305,12 @@ fn send_works() {
 		]);
 
 		let versioned_dest = Box::new(RelayLocation::get().into());
-		let versioned_message = Box::new(VersionedXcm::from(message.clone()));
-		assert_ok!(XcmPallet::send(
+		let versioned_message = VersionedXcm::from(message.clone());
+		let encoded_versioned_message = versioned_message.encode().try_into().unwrap();
+		assert_ok!(XcmPallet::send_blob(
 			RuntimeOrigin::signed(ALICE),
 			versioned_dest,
-			versioned_message
+			encoded_versioned_message
 		));
 		let sent_message = Xcm(Some(DescendOrigin(sender.clone().try_into().unwrap()))
 			.into_iter()
@@ -341,16 +342,16 @@ fn send_fails_when_xcm_router_blocks() {
 	];
 	new_test_ext_with_balances(balances).execute_with(|| {
 		let sender: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into();
-		let message = Xcm(vec![
+		let message = Xcm::<()>(vec![
 			ReserveAssetDeposited((Parent, SEND_AMOUNT).into()),
 			buy_execution((Parent, SEND_AMOUNT)),
 			DepositAsset { assets: AllCounted(1).into(), beneficiary: sender },
 		]);
 		assert_noop!(
-			XcmPallet::send(
+			XcmPallet::send_blob(
 				RuntimeOrigin::signed(ALICE),
 				Box::new(Location::ancestor(8).into()),
-				Box::new(VersionedXcm::from(message.clone())),
+				VersionedXcm::from(message.clone()).encode().try_into().unwrap(),
 			),
 			crate::Error::<Test>::SendFailure
 		);
@@ -371,13 +372,16 @@ fn execute_withdraw_to_deposit_works() {
 		let weight = BaseXcmWeight::get() * 3;
 		let dest: Location = Junction::AccountId32 { network: None, id: BOB.into() }.into();
 		assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE);
-		assert_ok!(XcmPallet::execute(
+		assert_ok!(XcmPallet::execute_blob(
 			RuntimeOrigin::signed(ALICE),
-			Box::new(VersionedXcm::from(Xcm(vec![
+			VersionedXcm::from(Xcm::<RuntimeCall>(vec![
 				WithdrawAsset((Here, SEND_AMOUNT).into()),
 				buy_execution((Here, SEND_AMOUNT)),
 				DepositAsset { assets: AllCounted(1).into(), beneficiary: dest },
-			]))),
+			]))
+			.encode()
+			.try_into()
+			.unwrap(),
 			weight
 		));
 		assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT);
@@ -399,18 +403,21 @@ fn trapped_assets_can_be_claimed() {
 		let weight = BaseXcmWeight::get() * 6;
 		let dest: Location = Junction::AccountId32 { network: None, id: BOB.into() }.into();
 
-		assert_ok!(XcmPallet::execute(
+		assert_ok!(XcmPallet::execute_blob(
 			RuntimeOrigin::signed(ALICE),
-			Box::new(VersionedXcm::from(Xcm(vec![
+			VersionedXcm::from(Xcm(vec![
 				WithdrawAsset((Here, SEND_AMOUNT).into()),
 				buy_execution((Here, SEND_AMOUNT)),
 				// Don't propagated the error into the result.
-				SetErrorHandler(Xcm(vec![ClearError])),
+				SetErrorHandler(Xcm::<RuntimeCall>(vec![ClearError])),
 				// This will make an error.
 				Trap(0),
 				// This would succeed, but we never get to it.
 				DepositAsset { assets: AllCounted(1).into(), beneficiary: dest.clone() },
-			]))),
+			]))
+			.encode()
+			.try_into()
+			.unwrap(),
 			weight
 		));
 		let source: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into();
@@ -437,13 +444,16 @@ fn trapped_assets_can_be_claimed() {
 		assert_eq!(trapped, expected);
 
 		let weight = BaseXcmWeight::get() * 3;
-		assert_ok!(XcmPallet::execute(
+		assert_ok!(XcmPallet::execute_blob(
 			RuntimeOrigin::signed(ALICE),
-			Box::new(VersionedXcm::from(Xcm(vec![
+			VersionedXcm::from(Xcm::<RuntimeCall>(vec![
 				ClaimAsset { assets: (Here, SEND_AMOUNT).into(), ticket: Here.into() },
 				buy_execution((Here, SEND_AMOUNT)),
 				DepositAsset { assets: AllCounted(1).into(), beneficiary: dest.clone() },
-			]))),
+			]))
+			.encode()
+			.try_into()
+			.unwrap(),
 			weight
 		));
 
@@ -453,13 +463,16 @@ fn trapped_assets_can_be_claimed() {
 
 		// Can't claim twice.
 		assert_err_ignore_postinfo!(
-			XcmPallet::execute(
+			XcmPallet::execute_blob(
 				RuntimeOrigin::signed(ALICE),
-				Box::new(VersionedXcm::from(Xcm(vec![
+				VersionedXcm::from(Xcm::<RuntimeCall>(vec![
 					ClaimAsset { assets: (Here, SEND_AMOUNT).into(), ticket: Here.into() },
 					buy_execution((Here, SEND_AMOUNT)),
 					DepositAsset { assets: AllCounted(1).into(), beneficiary: dest },
-				]))),
+				]))
+				.encode()
+				.try_into()
+				.unwrap(),
 				weight
 			),
 			Error::<Test>::LocalExecutionIncomplete
@@ -473,12 +486,13 @@ fn claim_assets_works() {
 	let balances = vec![(ALICE, INITIAL_BALANCE)];
 	new_test_ext_with_balances(balances).execute_with(|| {
 		// First trap some assets.
-		let trapping_program =
-			Xcm::builder_unsafe().withdraw_asset((Here, SEND_AMOUNT).into()).build();
+		let trapping_program = Xcm::<RuntimeCall>::builder_unsafe()
+			.withdraw_asset((Here, SEND_AMOUNT).into())
+			.build();
 		// Even though assets are trapped, the extrinsic returns success.
-		assert_ok!(XcmPallet::execute(
+		assert_ok!(XcmPallet::execute_blob(
 			RuntimeOrigin::signed(ALICE),
-			Box::new(VersionedXcm::V4(trapping_program)),
+			VersionedXcm::V4(trapping_program).encode().try_into().unwrap(),
 			BaseXcmWeight::get() * 2,
 		));
 		assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT);
@@ -531,9 +545,9 @@ fn incomplete_execute_reverts_side_effects() {
 		assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE);
 		let amount_to_send = INITIAL_BALANCE - ExistentialDeposit::get();
 		let assets: Assets = (Here, amount_to_send).into();
-		let result = XcmPallet::execute(
+		let result = XcmPallet::execute_blob(
 			RuntimeOrigin::signed(ALICE),
-			Box::new(VersionedXcm::from(Xcm(vec![
+			VersionedXcm::from(Xcm::<RuntimeCall>(vec![
 				// Withdraw + BuyExec + Deposit should work
 				WithdrawAsset(assets.clone()),
 				buy_execution(assets.inner()[0].clone()),
@@ -541,7 +555,10 @@ fn incomplete_execute_reverts_side_effects() {
 				// Withdrawing once more will fail because of InsufficientBalance, and we expect to
 				// revert the effects of the above instructions as well
 				WithdrawAsset(assets),
-			]))),
+			]))
+			.encode()
+			.try_into()
+			.unwrap(),
 			weight,
 		);
 		// all effects are reverted and balances unchanged for either sender or receiver
@@ -553,7 +570,7 @@ fn incomplete_execute_reverts_side_effects() {
 			Err(sp_runtime::DispatchErrorWithPostInfo {
 				post_info: frame_support::dispatch::PostDispatchInfo {
 					actual_weight: Some(
-						<Pallet<Test> as ExecuteControllerWeightInfo>::execute() + weight
+						<<Test as crate::Config>::WeightInfo>::execute_blob() + weight
 					),
 					pays_fee: frame_support::dispatch::Pays::Yes,
 				},
diff --git a/polkadot/xcm/src/lib.rs b/polkadot/xcm/src/lib.rs
index ba8d726aecff4..e836486e86e30 100644
--- a/polkadot/xcm/src/lib.rs
+++ b/polkadot/xcm/src/lib.rs
@@ -48,6 +48,9 @@ mod tests;
 
 /// Maximum nesting level for XCM decoding.
 pub const MAX_XCM_DECODE_DEPTH: u32 = 8;
+/// Maximum encoded size.
+/// See `decoding_respects_limit` test for more reasoning behind this value.
+pub const MAX_XCM_ENCODED_SIZE: u32 = 12402;
 
 /// A version of XCM.
 pub type Version = u32;
@@ -443,6 +446,16 @@ impl<C> IntoVersion for VersionedXcm<C> {
 	}
 }
 
+impl<C> IdentifyVersion for VersionedXcm<C> {
+	fn identify_version(&self) -> Version {
+		match self {
+			Self::V2(_) => v2::VERSION,
+			Self::V3(_) => v3::VERSION,
+			Self::V4(_) => v4::VERSION,
+		}
+	}
+}
+
 impl<RuntimeCall> From<v2::Xcm<RuntimeCall>> for VersionedXcm<RuntimeCall> {
 	fn from(x: v2::Xcm<RuntimeCall>) -> Self {
 		VersionedXcm::V2(x)
diff --git a/polkadot/xcm/src/v4/mod.rs b/polkadot/xcm/src/v4/mod.rs
index 30ee485589a28..6635408282e48 100644
--- a/polkadot/xcm/src/v4/mod.rs
+++ b/polkadot/xcm/src/v4/mod.rs
@@ -1488,7 +1488,21 @@ mod tests {
 		let encoded = big_xcm.encode();
 		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
 
-		let nested_xcm = Xcm::<()>(vec![
+		let mut many_assets = Assets::new();
+		for index in 0..MAX_ITEMS_IN_ASSETS {
+			many_assets.push((GeneralIndex(index as u128), 1u128).into());
+		}
+
+		let full_xcm_pass =
+			Xcm::<()>(vec![
+				TransferAsset { assets: many_assets, beneficiary: Here.into() };
+				MAX_INSTRUCTIONS_TO_DECODE as usize
+			]);
+		let encoded = full_xcm_pass.encode();
+		assert_eq!(encoded.len(), 12402);
+		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_ok());
+
+		let nested_xcm_fail = Xcm::<()>(vec![
 			DepositReserveAsset {
 				assets: All.into(),
 				dest: Here.into(),
@@ -1496,10 +1510,10 @@ mod tests {
 			};
 			(MAX_INSTRUCTIONS_TO_DECODE / 2) as usize
 		]);
-		let encoded = nested_xcm.encode();
+		let encoded = nested_xcm_fail.encode();
 		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
 
-		let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm); 64]);
+		let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm_fail); 64]);
 		let encoded = even_more_nested_xcm.encode();
 		assert_eq!(encoded.len(), 342530);
 		// This should not decode since the limit is 100
diff --git a/polkadot/xcm/xcm-builder/src/controller.rs b/polkadot/xcm/xcm-builder/src/controller.rs
index 04b19eaa58700..6bdde2a967de9 100644
--- a/polkadot/xcm/xcm-builder/src/controller.rs
+++ b/polkadot/xcm/xcm-builder/src/controller.rs
@@ -21,6 +21,7 @@
 use frame_support::{
 	dispatch::{DispatchErrorWithPostInfo, WithPostDispatchInfo},
 	pallet_prelude::DispatchError,
+	parameter_types, BoundedVec,
 };
 use sp_std::boxed::Box;
 use xcm::prelude::*;
@@ -41,8 +42,12 @@ impl<T, Origin, RuntimeCall, Timeout> Controller<Origin, RuntimeCall, Timeout> f
 
 /// Weight functions needed for [`ExecuteController`].
 pub trait ExecuteControllerWeightInfo {
-	/// Weight for [`ExecuteController::execute`]
-	fn execute() -> Weight;
+	/// Weight for [`ExecuteController::execute_blob`]
+	fn execute_blob() -> Weight;
+}
+
+parameter_types! {
+	pub const MaxXcmEncodedSize: u32 = xcm::MAX_XCM_ENCODED_SIZE;
 }
 
 /// Execute an XCM locally, for a given origin.
@@ -61,19 +66,19 @@ pub trait ExecuteController<Origin, RuntimeCall> {
 	/// # Parameters
 	///
 	/// - `origin`: the origin of the call.
-	/// - `message`: the XCM program to be executed.
+	/// - `msg`: the encoded XCM to be executed, should be decodable as a [`VersionedXcm`]
 	/// - `max_weight`: the maximum weight that can be consumed by the execution.
-	fn execute(
+	fn execute_blob(
 		origin: Origin,
-		message: Box<VersionedXcm<RuntimeCall>>,
+		message: BoundedVec<u8, MaxXcmEncodedSize>,
 		max_weight: Weight,
 	) -> Result<Weight, DispatchErrorWithPostInfo>;
 }
 
 /// Weight functions needed for [`SendController`].
 pub trait SendControllerWeightInfo {
-	/// Weight for [`SendController::send`]
-	fn send() -> Weight;
+	/// Weight for [`SendController::send_blob`]
+	fn send_blob() -> Weight;
 }
 
 /// Send an XCM from a given origin.
@@ -93,11 +98,11 @@ pub trait SendController<Origin> {
 	///
 	/// - `origin`: the origin of the call.
 	/// - `dest`: the destination of the message.
-	/// - `msg`: the XCM to be sent.
-	fn send(
+	/// - `msg`: the encoded XCM to be sent, should be decodable as a [`VersionedXcm`]
+	fn send_blob(
 		origin: Origin,
 		dest: Box<VersionedLocation>,
-		message: Box<VersionedXcm<()>>,
+		message: BoundedVec<u8, MaxXcmEncodedSize>,
 	) -> Result<XcmHash, DispatchError>;
 }
 
@@ -137,35 +142,35 @@ pub trait QueryController<Origin, Timeout>: QueryHandler {
 
 impl<Origin, RuntimeCall> ExecuteController<Origin, RuntimeCall> for () {
 	type WeightInfo = ();
-	fn execute(
+	fn execute_blob(
 		_origin: Origin,
-		_message: Box<VersionedXcm<RuntimeCall>>,
+		_message: BoundedVec<u8, MaxXcmEncodedSize>,
 		_max_weight: Weight,
 	) -> Result<Weight, DispatchErrorWithPostInfo> {
-		Err(DispatchError::Other("ExecuteController::execute not implemented")
+		Err(DispatchError::Other("ExecuteController::execute_blob not implemented")
 			.with_weight(Weight::zero()))
 	}
 }
 
 impl ExecuteControllerWeightInfo for () {
-	fn execute() -> Weight {
+	fn execute_blob() -> Weight {
 		Weight::zero()
 	}
 }
 
 impl<Origin> SendController<Origin> for () {
 	type WeightInfo = ();
-	fn send(
+	fn send_blob(
 		_origin: Origin,
 		_dest: Box<VersionedLocation>,
-		_message: Box<VersionedXcm<()>>,
+		_message: BoundedVec<u8, MaxXcmEncodedSize>,
 	) -> Result<XcmHash, DispatchError> {
 		Ok(Default::default())
 	}
 }
 
 impl SendControllerWeightInfo for () {
-	fn send() -> Weight {
+	fn send_blob() -> Weight {
 		Weight::zero()
 	}
 }
diff --git a/polkadot/xcm/xcm-builder/src/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs
index e2af8187136e8..46d0ad227bfdf 100644
--- a/polkadot/xcm/xcm-builder/src/lib.rs
+++ b/polkadot/xcm/xcm-builder/src/lib.rs
@@ -43,7 +43,7 @@ pub use barriers::{
 
 mod controller;
 pub use controller::{
-	Controller, ExecuteController, ExecuteControllerWeightInfo, QueryController,
+	Controller, ExecuteController, ExecuteControllerWeightInfo, MaxXcmEncodedSize, QueryController,
 	QueryControllerWeightInfo, QueryHandler, SendController, SendControllerWeightInfo,
 };
 
diff --git a/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml b/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml
new file mode 100644
index 0000000000000..682642d13c3a7
--- /dev/null
+++ b/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml
@@ -0,0 +1,40 @@
+[package]
+name = "xcm-fee-payment-runtime-api"
+version = "0.1.0"
+authors.workspace = true
+edition.workspace = true
+license = "Apache-2.0"
+repository.workspace = true
+description = "XCM fee payment runtime API"
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
+
+[dependencies]
+codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [
+	"derive",
+] }
+
+sp-api = { path = "../../../substrate/primitives/api", default-features = false }
+scale-info = { version = "2.10.0", default-features = false, features = [
+	"derive",
+	"serde",
+] }
+sp-std = { path = "../../../substrate/primitives/std", default-features = false }
+sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false }
+sp-weights = { path = "../../../substrate/primitives/weights", default-features = false }
+xcm = { package = "staging-xcm", path = "../", default-features = false }
+frame-support = { path = "../../../substrate/frame/support", default-features = false }
+
+[features]
+default = ["std"]
+std = [
+	"codec/std",
+	"frame-support/std",
+	"scale-info/std",
+	"sp-api/std",
+	"sp-runtime/std",
+	"sp-std/std",
+	"sp-weights/std",
+	"xcm/std",
+]
diff --git a/polkadot/xcm/xcm-fee-payment-runtime-api/src/lib.rs b/polkadot/xcm/xcm-fee-payment-runtime-api/src/lib.rs
new file mode 100644
index 0000000000000..20bf9236f1fbb
--- /dev/null
+++ b/polkadot/xcm/xcm-fee-payment-runtime-api/src/lib.rs
@@ -0,0 +1,99 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Substrate is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Substrate is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Runtime API definition for xcm transaction payment.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+use codec::{Decode, Encode};
+use frame_support::pallet_prelude::TypeInfo;
+use sp_std::vec::Vec;
+use sp_weights::Weight;
+use xcm::{Version, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm};
+
+sp_api::decl_runtime_apis! {
+	/// A trait of XCM payment API.
+	///
+	/// API provides functionality for obtaining:
+	///
+	/// * the weight required to execute an XCM message,
+	/// * a list of acceptable `AssetId`s for message execution payment,
+	/// * the cost of the weight in the specified acceptable `AssetId`.
+	/// * the fees for an XCM message delivery.
+	///
+	/// To determine the execution weight of the calls required for
+	/// [`xcm::latest::Instruction::Transact`] instruction, `TransactionPaymentCallApi` can be used.
+	pub trait XcmPaymentApi {
+		/// Returns a list of acceptable payment assets.
+		///
+		/// # Arguments
+		///
+		/// * `xcm_version`: Version.
+		fn query_acceptable_payment_assets(xcm_version: Version) -> Result<Vec<VersionedAssetId>, Error>;
+
+		/// Returns a weight needed to execute a XCM.
+		///
+		/// # Arguments
+		///
+		/// * `message`: `VersionedXcm`.
+		fn query_xcm_weight(message: VersionedXcm<()>) -> Result<Weight, Error>;
+
+		/// Converts a weight into a fee for the specified `AssetId`.
+		///
+		/// # Arguments
+		///
+		/// * `weight`: convertible `Weight`.
+		/// * `asset`: `VersionedAssetId`.
+		fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result<u128, Error>;
+
+		/// Get delivery fees for sending a specific `message` to a `destination`.
+		/// These always come in a specific asset, defined by the chain.
+		///
+		/// # Arguments
+		/// * `message`: The message that'll be sent, necessary because most delivery fees are based on the
+		///   size of the message.
+		/// * `destination`: The destination to send the message to. Different destinations may use
+		///   different senders that charge different fees.
+		fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result<VersionedAssets, Error>;
+	}
+}
+
+#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)]
+pub enum Error {
+	/// An API part is unsupported.
+	#[codec(index = 0)]
+	Unimplemented,
+
+	/// Converting a versioned data structure from one version to another failed.
+	#[codec(index = 1)]
+	VersionedConversionFailed,
+
+	/// XCM message weight calculation failed.
+	#[codec(index = 2)]
+	WeightNotComputable,
+
+	/// XCM version not able to be handled.
+	#[codec(index = 3)]
+	UnhandledXcmVersion,
+
+	/// The given asset is not handled as a fee asset.
+	#[codec(index = 4)]
+	AssetNotFound,
+
+	/// Destination is known to be unroutable.
+	#[codec(index = 5)]
+	Unroutable,
+}
diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs
index 377c77f30a473..286d0038e187a 100644
--- a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs
+++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs
@@ -275,6 +275,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = MessageQueueHeapSize;
 	type MaxStale = MessageQueueMaxStale;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = ();
 	type MessageProcessor = MessageProcessor;
 	type QueueChangeHandler = ();
 	type QueuePausedQuery = ();
diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs
index 3224df66cbe56..6790b535d1692 100644
--- a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs
+++ b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs
@@ -232,6 +232,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = MessageQueueHeapSize;
 	type MaxStale = MessageQueueMaxStale;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = ();
 	#[cfg(not(feature = "runtime-benchmarks"))]
 	type MessageProcessor = MessageProcessor;
 	#[cfg(feature = "runtime-benchmarks")]
diff --git a/prdoc/pr_3607.prdoc b/prdoc/pr_3607.prdoc
new file mode 100644
index 0000000000000..1a69b25ad255c
--- /dev/null
+++ b/prdoc/pr_3607.prdoc
@@ -0,0 +1,26 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: "XCM fee payment API"
+
+doc:
+  - audience: Runtime Dev
+    description: |
+      A runtime API was added for estimating the fees required for XCM execution and delivery.
+      This is the basic building block needed for UIs to accurately estimate fees.
+      An example implementation is shown in the PR. Ideally it's simple to implement, you only need to call existing parts of your XCM config.
+      The API looks like so:
+      ```rust
+            fn query_acceptable_payment_assets(xcm_version: Version) -> Result<Vec<VersionedAssetId>, Error>;
+            fn query_xcm_weight(message: VersionedXcm<Call>) -> Result<Weight, Error>;
+            fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result<u128, Error>;
+            fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result<VersionedAssets, Error>;
+      ```
+      The first three relate to XCM execution fees, given an XCM, you can query its weight, then which assets are acceptable for buying weight and convert weight to a number of those assets.
+      The last one takes in a destination and a message you want to send from the runtime you're executing this on, it will give you the delivery fees.
+
+crates:
+  - name: xcm-fee-payment-runtime-api
+  - name: rococo-runtime
+  - name: westend-runtime
+
diff --git a/prdoc/pr_3706.prdoc b/prdoc/pr_3706.prdoc
new file mode 100644
index 0000000000000..edeb08241bed1
--- /dev/null
+++ b/prdoc/pr_3706.prdoc
@@ -0,0 +1,20 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: Extrinsic to restore corrupted staking ledgers
+
+doc:
+  - audience: Runtime User
+    description: |
+      This PR adds a new extrinsic `Call::restore_ledger ` gated by `StakingAdmin` origin that restores a corrupted staking ledger. This extrinsic will be used to recover ledgers that were affected by the issue discussed in https://github.com/paritytech/polkadot-sdk/issues/3245.
+      The extrinsic will re-write the storage items associated with a stash account provided as input parameter. The data used to reset the ledger can be either i) fetched on-chain or ii) partially/totally set by the input parameters of the call.
+      
+      Changes introduced:
+        - Adds `Call::restore_ledger ` extrinsic to recover a corrupted ledger;
+        - Adds trait `frame_support::traits::currency::InspectLockableCurrency` to allow external pallets to read current locks given an account and lock ID;
+        - Implements the `InspectLockableCurrency` in the pallet-balances.
+        - Adds staking locks try-runtime checks (https://github.com/paritytech/polkadot-sdk/issues/3751)
+
+crates: 
+ - name: pallet-staking
+ - name: pallet-balances
diff --git a/prdoc/pr_3714.prdoc b/prdoc/pr_3714.prdoc
new file mode 100644
index 0000000000000..e276d0d2d3731
--- /dev/null
+++ b/prdoc/pr_3714.prdoc
@@ -0,0 +1,10 @@
+title: Handle legacy lease swaps on coretime
+
+doc:
+  - audience: Runtime Dev
+    description: |
+      When a `registar::swap` extrinsic is executed it swaps two leases on the relay chain but the
+      broker chain never knows about this swap. This change notifies the broker chain via a XCM
+      message for a swap so that it can update its state.
+crates:
+  - name: pallet-broker
diff --git a/prdoc/pr_3718.prdoc b/prdoc/pr_3718.prdoc
new file mode 100644
index 0000000000000..b2b24cc9704d9
--- /dev/null
+++ b/prdoc/pr_3718.prdoc
@@ -0,0 +1,13 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: Deprecate scheduler traits v1 and v2
+
+doc:
+  - audience: Runtime Dev
+    description: |
+        Add `#[deprecated]` attribute to scheduler traits v1 and v2 to deprecate old versions
+
+crates:
+    - name: frame-support
+    - name: pallet-scheduler
diff --git a/prdoc/pr_3749.prdoc b/prdoc/pr_3749.prdoc
new file mode 100644
index 0000000000000..1ebde9670e0f3
--- /dev/null
+++ b/prdoc/pr_3749.prdoc
@@ -0,0 +1,47 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: "pallet-xcm: deprecate execute and send in favor of execute_blob and send_blob"
+
+doc:
+  - audience: Runtime Dev
+    description: |
+      pallet-xcm's extrinsics `execute` and `send` have been marked as deprecated.
+      Please change their usage to the new `execute_blob` and `send_blob`.
+      The migration from the old extrinsic to the new is very simple.
+      If you have your message `xcm: VersionedXcm<Call>`, then instead of passing in
+      `Box::new(xcm)` to both `execute` and `send`, you would pass in
+      `xcm.encode().try_into()` and handle the potential error of its encoded length
+      being bigger than `MAX_XCM_ENCODED_SIZE`.
+
+      pallet-contracts takes the XCM encoded now as well. It follows the same API as
+      `execute_blob` and `send_blob`.
+  - audience: Runtime User
+    description: |
+      pallet-xcm has a new pair of extrinsics, `execute_blob` and `send_blob`.
+      These are meant to be used instead of `execute` and `send`, which are now deprecated
+      and will be removed eventually.
+      These new extrinsics just require you to input the encoded XCM.
+      There's a new utility in PolkadotJS Apps for encoding XCMs you can use:
+      https://polkadot.js.org/apps/#/utilities/xcm
+      Just pass in the encoded XCM to the new extrinsics and you're done.
+
+      pallet-contracts takes the XCM encoded now as well. It follows the same API as
+      `execute_blob` and `send_blob`.
+
+crates:
+- name: pallet-xcm
+- name: staging-xcm
+- name: staging-xcm-builder
+- name: pallet-contracts
+- name: asset-hub-rococo-runtime
+- name: asset-hub-westend-runtime
+- name: bridge-hub-rococo-runtime
+- name: bridge-hub-westend-runtime
+- name: collectives-westend-runtime
+- name: coretime-rococo-runtime
+- name: coretime-westend-runtime
+- name: people-rococo-runtime
+- name: people-westend-runtime
+- name: rococo-runtime
+- name: westend-runtime
diff --git a/prdoc/pr_3795.prdoc b/prdoc/pr_3795.prdoc
new file mode 100644
index 0000000000000..da01fcbec821c
--- /dev/null
+++ b/prdoc/pr_3795.prdoc
@@ -0,0 +1,14 @@
+title: Enable collators to build on multiple cores
+
+doc:
+  - audience: Node Dev
+    description: |
+      Introduces a `CoreIndex` parameter in `SubmitCollationParams`. This enables
+      the collators to make use of potentially multiple cores assigned at some relay
+      chain block. This extra parameter is used by the collator protocol and collation
+      generation subsystems to forward the collation to the approapriate backing group.
+
+crates:
+- name: polkadot-node-collation-generation
+- name: polkadot-collator-protocol
+  bump: minor
diff --git a/prdoc/pr_3817.prdoc b/prdoc/pr_3817.prdoc
new file mode 100644
index 0000000000000..bf9d397122f9d
--- /dev/null
+++ b/prdoc/pr_3817.prdoc
@@ -0,0 +1,23 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: Parachain Runtime API Implementations into mod apis Refactoring
+
+doc:
+  - audience: Runtime Dev
+    description: |
+        This PR introduces a refactoring to the runtime API implementations within the parachain template project. The primary changes include enhancing the visibility of `RUNTIME_API_VERSIONS` to `pub` in `impl_runtime_apis.rs`, centralizing API implementations in a new `apis.rs` file, and streamlining `lib.rs`. These changes aim to improve project structure, maintainability, and readability.
+        
+        Key Changes:
+        - `RUNTIME_API_VERSIONS` is now publicly accessible, enhancing module-wide visibility.
+        - Introduction of `apis.rs` centralizes runtime API implementations, promoting a cleaner and more navigable project structure.
+        - The main runtime library file, `lib.rs`, has been updated to reflect these structural changes, removing redundant API implementations and simplifying runtime configuration by pointing `VERSION` to the newly exposed `RUNTIME_API_VERSIONS` from `apis.rs`.
+        
+        Motivations:
+        - **Improved Project Structure**: Centralizing API implementations offers a more organized and understandable project layout.
+        - **Enhanced Readability**: The refactoring efforts aim to declutter `lib.rs`, facilitating easier comprehension for new contributors.
+
+crates: 
+  - name: sp-api-proc-macro
+  - name: parachain-template-node
+  - name: parachain-template-runtime
diff --git a/prdoc/pr_3844.prdoc b/prdoc/pr_3844.prdoc
new file mode 100644
index 0000000000000..a92092f91b207
--- /dev/null
+++ b/prdoc/pr_3844.prdoc
@@ -0,0 +1,25 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: Add the ability for MessageQueue to process enqueued messages on idle
+
+doc:
+  - audience: Runtime Dev
+    description: |
+        Add the option to use remaining weight on idle for processing enqueued messages.
+        This will increase the chances of the messages enqueued during inherent extrinsics to be processed in the same block. 
+        New config types is added on the message-queue `Config` trait:
+        - `IdleMaxServiceWeight`
+
+        example:
+            ```rust
+            parameter_types! {
+                // The maximum weight to be used from remaining weight for processing enqueued messages on idle
+                pub const IdleMaxServiceWeight: Weight = Some(Weight);
+            }
+
+            type IdleMaxServiceWeight = IdleMaxServiceWeight; // or `()` to not use this feature
+            ```
+
+crates:
+    - name: pallet-message-queue
diff --git a/prdoc/pr_3849.prdoc b/prdoc/pr_3849.prdoc
new file mode 100644
index 0000000000000..a1372b60ffc65
--- /dev/null
+++ b/prdoc/pr_3849.prdoc
@@ -0,0 +1,13 @@
+title: Unrequest a pre-image when it failed to execute
+
+doc:
+  - audience: Runtime User
+    description: |
+      When a referenda finished the proposal will be scheduled. When it is scheduled,
+      the pre-image is requested. The pre-image is unrequested after the proposal
+      was executed. However, if the proposal failed to execute it wasn't unrequested.
+      Thus, it could not be removed from the on-chain state. This issue is now solved
+      by ensuring to unrequest the pre-image when it failed to execute.
+
+crates:
+  - name: pallet-scheduler
diff --git a/prdoc/pr_3850.prdoc b/prdoc/pr_3850.prdoc
new file mode 100644
index 0000000000000..8f7ce16076e85
--- /dev/null
+++ b/prdoc/pr_3850.prdoc
@@ -0,0 +1,15 @@
+title: Detect incorrect pre-image length when submitting a referenda
+
+doc:
+  - audience: Runtime User
+    description: |
+      When submitting a referenda the `proposal` is passed as argument.
+      The `proposal` is most of the time a reference to a `pre-image` and
+      which also contains the length of the `pre-image`. This pull request
+      adds some logic to check that if the `pre-image` already exists and if
+      it exists, it ensures that the length is passed correctly. This prevents
+      that the referenda can not be executed because of a mismatch of this
+      length.
+
+crates:
+  - name: pallet-referenda
diff --git a/prdoc/schema_user.json b/prdoc/schema_user.json
index 1bd0b3b93ee45..593113cf32600 100644
--- a/prdoc/schema_user.json
+++ b/prdoc/schema_user.json
@@ -132,7 +132,8 @@
           }
         },
         "required": [
-          "name"
+          "name",
+          "bump"
         ]
       },
       "migration_db": {
@@ -187,6 +188,11 @@
             "const": "patch",
             "title": "Patch",
             "description": "A bump to the third leftmost non-zero digit of the version number."
+          },
+          {
+            "const": "none",
+            "title": "None",
+            "description": "This change requires no SemVer bump (e.g. change was a test or benchmark)."
           }
         ]
       },
diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs
index ca7e14f6eb169..a9606ac0bb759 100644
--- a/substrate/bin/node/runtime/src/lib.rs
+++ b/substrate/bin/node/runtime/src/lib.rs
@@ -1303,6 +1303,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = ConstU32<{ 64 * 1024 }>;
 	type MaxStale = ConstU32<128>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = ();
 }
 
 parameter_types! {
diff --git a/substrate/client/authority-discovery/src/interval.rs b/substrate/client/authority-discovery/src/interval.rs
index 23c7ce266e3bf..0eee0d159cd86 100644
--- a/substrate/client/authority-discovery/src/interval.rs
+++ b/substrate/client/authority-discovery/src/interval.rs
@@ -28,6 +28,7 @@ use std::{
 ///
 /// Doubles interval duration on each tick until the configured maximum is reached.
 pub struct ExpIncInterval {
+	start: Duration,
 	max: Duration,
 	next: Duration,
 	delay: Delay,
@@ -37,14 +38,29 @@ impl ExpIncInterval {
 	/// Create a new [`ExpIncInterval`].
 	pub fn new(start: Duration, max: Duration) -> Self {
 		let delay = Delay::new(start);
-		Self { max, next: start * 2, delay }
+		Self { start, max, next: start * 2, delay }
 	}
 
-	/// Fast forward the exponentially increasing interval to the configured maximum.
+	/// Fast forward the exponentially increasing interval to the configured maximum, if not already
+	/// set.
 	pub fn set_to_max(&mut self) {
+		if self.next == self.max {
+			return;
+		}
+
 		self.next = self.max;
 		self.delay = Delay::new(self.next);
 	}
+
+	/// Rewind the exponentially increasing interval to the configured start, if not already set.
+	pub fn set_to_start(&mut self) {
+		if self.next == self.start * 2 {
+			return;
+		}
+
+		self.next = self.start * 2;
+		self.delay = Delay::new(self.start);
+	}
 }
 
 impl Stream for ExpIncInterval {
diff --git a/substrate/client/authority-discovery/src/worker.rs b/substrate/client/authority-discovery/src/worker.rs
index b77f0241ec2fa..4ad7db5f7da94 100644
--- a/substrate/client/authority-discovery/src/worker.rs
+++ b/substrate/client/authority-discovery/src/worker.rs
@@ -129,6 +129,9 @@ pub struct Worker<Client, Network, Block, DhtEventStream> {
 	/// List of keys onto which addresses have been published at the latest publication.
 	/// Used to check whether they have changed.
 	latest_published_keys: HashSet<AuthorityId>,
+	/// List of the kademlia keys that have been published at the latest publication.
+	/// Used to associate DHT events with our published records.
+	latest_published_kad_keys: HashSet<KademliaKey>,
 
 	/// Same value as in the configuration.
 	publish_non_global_ips: bool,
@@ -265,6 +268,7 @@ where
 			publish_interval,
 			publish_if_changed_interval,
 			latest_published_keys: HashSet::new(),
+			latest_published_kad_keys: HashSet::new(),
 			publish_non_global_ips: config.publish_non_global_ips,
 			public_addresses,
 			strict_record_validation: config.strict_record_validation,
@@ -397,8 +401,17 @@ where
 			self.client.as_ref(),
 		).await?.into_iter().collect::<HashSet<_>>();
 
-		if only_if_changed && keys == self.latest_published_keys {
-			return Ok(())
+		if only_if_changed {
+			// If the authority keys did not change and the `publish_if_changed_interval` was
+			// triggered then do nothing.
+			if keys == self.latest_published_keys {
+				return Ok(())
+			}
+
+			// We have detected a change in the authority keys, reset the timers to
+			// publish and gather data faster.
+			self.publish_interval.set_to_start();
+			self.query_interval.set_to_start();
 		}
 
 		let addresses = serialize_addresses(self.addresses_to_publish());
@@ -422,6 +435,8 @@ where
 			keys_vec,
 		)?;
 
+		self.latest_published_kad_keys = kv_pairs.iter().map(|(k, _)| k.clone()).collect();
+
 		for (key, value) in kv_pairs.into_iter() {
 			self.network.put_value(key, value);
 		}
@@ -523,6 +538,10 @@ where
 				}
 			},
 			DhtEvent::ValuePut(hash) => {
+				if !self.latest_published_kad_keys.contains(&hash) {
+					return;
+				}
+
 				// Fast forward the exponentially increasing interval to the configured maximum. In
 				// case this was the first successful address publishing there is no need for a
 				// timely retry.
@@ -535,6 +554,11 @@ where
 				debug!(target: LOG_TARGET, "Successfully put hash '{:?}' on Dht.", hash)
 			},
 			DhtEvent::ValuePutFailed(hash) => {
+				if !self.latest_published_kad_keys.contains(&hash) {
+					// Not a value we have published or received multiple times.
+					return;
+				}
+
 				if let Some(metrics) = &self.metrics {
 					metrics.dht_event_received.with_label_values(&["value_put_failed"]).inc();
 				}
diff --git a/substrate/frame/balances/src/impl_currency.rs b/substrate/frame/balances/src/impl_currency.rs
index 1ac882ade70df..d5fe9934e239e 100644
--- a/substrate/frame/balances/src/impl_currency.rs
+++ b/substrate/frame/balances/src/impl_currency.rs
@@ -28,8 +28,8 @@ use frame_support::{
 		tokens::{fungible, BalanceStatus as Status, Fortitude::Polite, Precision::BestEffort},
 		Currency, DefensiveSaturating, ExistenceRequirement,
 		ExistenceRequirement::AllowDeath,
-		Get, Imbalance, LockIdentifier, LockableCurrency, NamedReservableCurrency,
-		ReservableCurrency, SignedImbalance, TryDrop, WithdrawReasons,
+		Get, Imbalance, InspectLockableCurrency, LockIdentifier, LockableCurrency,
+		NamedReservableCurrency, ReservableCurrency, SignedImbalance, TryDrop, WithdrawReasons,
 	},
 };
 use frame_system::pallet_prelude::BlockNumberFor;
@@ -918,3 +918,12 @@ where
 		Self::update_locks(who, &locks[..]);
 	}
 }
+
+impl<T: Config<I>, I: 'static> InspectLockableCurrency<T::AccountId> for Pallet<T, I> {
+	fn balance_locked(id: LockIdentifier, who: &T::AccountId) -> Self::Balance {
+		Self::locks(who)
+			.into_iter()
+			.filter(|l| l.id == id)
+			.fold(Zero::zero(), |acc, l| acc + l.amount)
+	}
+}
diff --git a/substrate/frame/balances/src/tests/currency_tests.rs b/substrate/frame/balances/src/tests/currency_tests.rs
index bd4ff762c748b..450b1a84aa878 100644
--- a/substrate/frame/balances/src/tests/currency_tests.rs
+++ b/substrate/frame/balances/src/tests/currency_tests.rs
@@ -24,8 +24,8 @@ use frame_support::{
 		BalanceStatus::{Free, Reserved},
 		Currency,
 		ExistenceRequirement::{self, AllowDeath, KeepAlive},
-		Hooks, LockIdentifier, LockableCurrency, NamedReservableCurrency, ReservableCurrency,
-		WithdrawReasons,
+		Hooks, InspectLockableCurrency, LockIdentifier, LockableCurrency, NamedReservableCurrency,
+		ReservableCurrency, WithdrawReasons,
 	},
 	StorageNoopGuard,
 };
@@ -88,6 +88,24 @@ fn basic_locking_should_work() {
 		});
 }
 
+#[test]
+fn inspect_lock_should_work() {
+	ExtBuilder::default()
+		.existential_deposit(1)
+		.monied(true)
+		.build_and_execute_with(|| {
+			Balances::set_lock(ID_1, &1, 10, WithdrawReasons::all());
+			Balances::set_lock(ID_2, &1, 10, WithdrawReasons::all());
+			Balances::set_lock(ID_1, &2, 20, WithdrawReasons::all());
+
+			assert_eq!(<Balances as InspectLockableCurrency<_>>::balance_locked(ID_1, &1), 10);
+			assert_eq!(<Balances as InspectLockableCurrency<_>>::balance_locked(ID_2, &1), 10);
+			assert_eq!(<Balances as InspectLockableCurrency<_>>::balance_locked(ID_1, &2), 20);
+			assert_eq!(<Balances as InspectLockableCurrency<_>>::balance_locked(ID_2, &2), 0);
+			assert_eq!(<Balances as InspectLockableCurrency<_>>::balance_locked(ID_1, &3), 0);
+		})
+}
+
 #[test]
 fn account_should_be_reaped() {
 	ExtBuilder::default()
diff --git a/substrate/frame/broker/src/benchmarking.rs b/substrate/frame/broker/src/benchmarking.rs
index 70f488e998cc8..98ac074ca9177 100644
--- a/substrate/frame/broker/src/benchmarking.rs
+++ b/substrate/frame/broker/src/benchmarking.rs
@@ -918,6 +918,23 @@ mod benches {
 		Ok(())
 	}
 
+	#[benchmark]
+	fn swap_leases() -> Result<(), BenchmarkError> {
+		let admin_origin =
+			T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
+
+		// Add two leases in `Leases`
+		let n = (T::MaxLeasedCores::get() / 2) as usize;
+		let mut leases = vec![LeaseRecordItem { task: 1, until: 10u32.into() }; n];
+		leases.extend(vec![LeaseRecordItem { task: 2, until: 20u32.into() }; n]);
+		Leases::<T>::put(BoundedVec::try_from(leases).unwrap());
+
+		#[extrinsic_call]
+		_(admin_origin as T::RuntimeOrigin, 1, 2);
+
+		Ok(())
+	}
+
 	// Implements a test for each benchmark. Execute with:
 	// `cargo test -p pallet-broker --features runtime-benchmarks`.
 	impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
diff --git a/substrate/frame/broker/src/dispatchable_impls.rs b/substrate/frame/broker/src/dispatchable_impls.rs
index f2451013251fb..74cda9c4f4cb4 100644
--- a/substrate/frame/broker/src/dispatchable_impls.rs
+++ b/substrate/frame/broker/src/dispatchable_impls.rs
@@ -437,4 +437,22 @@ impl<T: Config> Pallet<T> {
 		Self::deposit_event(Event::AllowedRenewalDropped { core, when });
 		Ok(())
 	}
+
+	pub(crate) fn do_swap_leases(id: TaskId, other: TaskId) -> DispatchResult {
+		let mut id_leases_count = 0;
+		let mut other_leases_count = 0;
+		Leases::<T>::mutate(|leases| {
+			leases.iter_mut().for_each(|lease| {
+				if lease.task == id {
+					lease.task = other;
+					id_leases_count += 1;
+				} else if lease.task == other {
+					lease.task = id;
+					other_leases_count += 1;
+				}
+			})
+		});
+
+		Ok(())
+	}
 }
diff --git a/substrate/frame/broker/src/lib.rs b/substrate/frame/broker/src/lib.rs
index f1b49a73a52d3..b9b5e309ca91e 100644
--- a/substrate/frame/broker/src/lib.rs
+++ b/substrate/frame/broker/src/lib.rs
@@ -786,5 +786,13 @@ pub mod pallet {
 			Self::do_notify_core_count(core_count)?;
 			Ok(())
 		}
+
+		#[pallet::call_index(99)]
+		#[pallet::weight(T::WeightInfo::swap_leases())]
+		pub fn swap_leases(origin: OriginFor<T>, id: TaskId, other: TaskId) -> DispatchResult {
+			T::AdminOrigin::ensure_origin_or_root(origin)?;
+			Self::do_swap_leases(id, other)?;
+			Ok(())
+		}
 	}
 }
diff --git a/substrate/frame/broker/src/weights.rs b/substrate/frame/broker/src/weights.rs
index a8f50eeee6e6c..a8b9fb598b8b4 100644
--- a/substrate/frame/broker/src/weights.rs
+++ b/substrate/frame/broker/src/weights.rs
@@ -17,10 +17,10 @@
 
 //! Autogenerated weights for `pallet_broker`
 //!
-//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2023-09-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
+//! DATE: 2024-03-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-pzhd7p6z-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024`
 
 // Executed Command:
@@ -76,6 +76,7 @@ pub trait WeightInfo {
 	fn request_revenue_info_at() -> Weight;
 	fn notify_core_count() -> Weight;
 	fn do_tick_base() -> Weight;
+	fn swap_leases() -> Weight;
 }
 
 /// Weights for `pallet_broker` using the Substrate node and recommended hardware.
@@ -87,8 +88,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 3_040_000 picoseconds.
-		Weight::from_parts(3_344_000, 0)
+		// Minimum execution time: 2_865_000 picoseconds.
+		Weight::from_parts(3_061_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Broker::Reservations` (r:1 w:1)
@@ -97,8 +98,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `5016`
 		//  Estimated: `7496`
-		// Minimum execution time: 21_259_000 picoseconds.
-		Weight::from_parts(22_110_000, 7496)
+		// Minimum execution time: 18_431_000 picoseconds.
+		Weight::from_parts(19_558_000, 7496)
 			.saturating_add(T::DbWeight::get().reads(1_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -108,8 +109,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `6218`
 		//  Estimated: `7496`
-		// Minimum execution time: 20_330_000 picoseconds.
-		Weight::from_parts(20_826_000, 7496)
+		// Minimum execution time: 17_724_000 picoseconds.
+		Weight::from_parts(18_688_000, 7496)
 			.saturating_add(T::DbWeight::get().reads(1_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -119,8 +120,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `239`
 		//  Estimated: `1526`
-		// Minimum execution time: 13_411_000 picoseconds.
-		Weight::from_parts(13_960_000, 1526)
+		// Minimum execution time: 10_513_000 picoseconds.
+		Weight::from_parts(11_138_000, 1526)
 			.saturating_add(T::DbWeight::get().reads(1_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -139,14 +140,12 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Storage: `Broker::Workplan` (r:0 w:10)
 	/// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`)
 	/// The range of component `n` is `[0, 1000]`.
-	fn start_sales(n: u32, ) -> Weight {
+	fn start_sales(_n: u32, ) -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `6330`
 		//  Estimated: `8499`
-		// Minimum execution time: 57_770_000 picoseconds.
-		Weight::from_parts(61_047_512, 8499)
-			// Standard Error: 165
-			.saturating_add(Weight::from_parts(3, 0).saturating_mul(n.into()))
+		// Minimum execution time: 50_864_000 picoseconds.
+		Weight::from_parts(54_000_280, 8499)
 			.saturating_add(T::DbWeight::get().reads(6_u64))
 			.saturating_add(T::DbWeight::get().writes(16_u64))
 	}
@@ -162,10 +161,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
 	fn purchase() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `568`
-		//  Estimated: `2053`
-		// Minimum execution time: 51_196_000 picoseconds.
-		Weight::from_parts(52_382_000, 2053)
+		//  Measured:  `635`
+		//  Estimated: `2120`
+		// Minimum execution time: 43_630_000 picoseconds.
+		Weight::from_parts(44_622_000, 2120)
 			.saturating_add(T::DbWeight::get().reads(4_u64))
 			.saturating_add(T::DbWeight::get().writes(2_u64))
 	}
@@ -185,10 +184,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`)
 	fn renew() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `686`
+		//  Measured:  `753`
 		//  Estimated: `4698`
-		// Minimum execution time: 71_636_000 picoseconds.
-		Weight::from_parts(73_679_000, 4698)
+		// Minimum execution time: 62_453_000 picoseconds.
+		Weight::from_parts(63_882_000, 4698)
 			.saturating_add(T::DbWeight::get().reads(6_u64))
 			.saturating_add(T::DbWeight::get().writes(4_u64))
 	}
@@ -198,8 +197,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `495`
 		//  Estimated: `3550`
-		// Minimum execution time: 19_182_000 picoseconds.
-		Weight::from_parts(19_775_000, 3550)
+		// Minimum execution time: 17_237_000 picoseconds.
+		Weight::from_parts(17_757_000, 3550)
 			.saturating_add(T::DbWeight::get().reads(1_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -209,21 +208,21 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `495`
 		//  Estimated: `3550`
-		// Minimum execution time: 20_688_000 picoseconds.
-		Weight::from_parts(21_557_000, 3550)
+		// Minimum execution time: 18_504_000 picoseconds.
+		Weight::from_parts(19_273_000, 3550)
 			.saturating_add(T::DbWeight::get().reads(1_u64))
 			.saturating_add(T::DbWeight::get().writes(2_u64))
 	}
-	/// Storage: `Broker::Regions` (r:1 w:2)
+	/// Storage: `Broker::Regions` (r:1 w:3)
 	/// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
 	fn interlace() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `495`
 		//  Estimated: `3550`
-		// Minimum execution time: 21_190_000 picoseconds.
-		Weight::from_parts(22_215_000, 3550)
+		// Minimum execution time: 20_477_000 picoseconds.
+		Weight::from_parts(21_328_000, 3550)
 			.saturating_add(T::DbWeight::get().reads(1_u64))
-			.saturating_add(T::DbWeight::get().writes(2_u64))
+			.saturating_add(T::DbWeight::get().writes(3_u64))
 	}
 	/// Storage: `Broker::Configuration` (r:1 w:0)
 	/// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`)
@@ -237,8 +236,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `740`
 		//  Estimated: `4681`
-		// Minimum execution time: 34_591_000 picoseconds.
-		Weight::from_parts(36_227_000, 4681)
+		// Minimum execution time: 31_815_000 picoseconds.
+		Weight::from_parts(32_700_000, 4681)
 			.saturating_add(T::DbWeight::get().reads(4_u64))
 			.saturating_add(T::DbWeight::get().writes(2_u64))
 	}
@@ -256,8 +255,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `775`
 		//  Estimated: `5996`
-		// Minimum execution time: 40_346_000 picoseconds.
-		Weight::from_parts(41_951_000, 5996)
+		// Minimum execution time: 38_313_000 picoseconds.
+		Weight::from_parts(38_985_000, 5996)
 			.saturating_add(T::DbWeight::get().reads(5_u64))
 			.saturating_add(T::DbWeight::get().writes(5_u64))
 	}
@@ -272,10 +271,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `859`
 		//  Estimated: `6196 + m * (2520 ±0)`
-		// Minimum execution time: 75_734_000 picoseconds.
-		Weight::from_parts(78_168_395, 6196)
-			// Standard Error: 63_180
-			.saturating_add(Weight::from_parts(1_076_259, 0).saturating_mul(m.into()))
+		// Minimum execution time: 70_170_000 picoseconds.
+		Weight::from_parts(71_245_388, 6196)
+			// Standard Error: 54_382
+			.saturating_add(Weight::from_parts(1_488_794, 0).saturating_mul(m.into()))
 			.saturating_add(T::DbWeight::get().reads(3_u64))
 			.saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into())))
 			.saturating_add(T::DbWeight::get().writes(5_u64))
@@ -287,8 +286,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `103`
 		//  Estimated: `3593`
-		// Minimum execution time: 46_383_000 picoseconds.
-		Weight::from_parts(47_405_000, 3593)
+		// Minimum execution time: 43_414_000 picoseconds.
+		Weight::from_parts(44_475_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -300,8 +299,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `603`
 		//  Estimated: `3550`
-		// Minimum execution time: 30_994_000 picoseconds.
-		Weight::from_parts(31_979_000, 3550)
+		// Minimum execution time: 31_327_000 picoseconds.
+		Weight::from_parts(32_050_000, 3550)
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -315,8 +314,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `601`
 		//  Estimated: `3533`
-		// Minimum execution time: 37_584_000 picoseconds.
-		Weight::from_parts(44_010_000, 3533)
+		// Minimum execution time: 41_315_000 picoseconds.
+		Weight::from_parts(42_421_000, 3533)
 			.saturating_add(T::DbWeight::get().reads(3_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -330,10 +329,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
 	fn drop_history() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `830`
+		//  Measured:  `995`
 		//  Estimated: `3593`
-		// Minimum execution time: 45_266_000 picoseconds.
-		Weight::from_parts(48_000_000, 3593)
+		// Minimum execution time: 49_707_000 picoseconds.
+		Weight::from_parts(51_516_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(4_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -343,10 +342,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Proof: `Broker::AllowedRenewals` (`max_values`: None, `max_size`: Some(1233), added: 3708, mode: `MaxEncodedLen`)
 	fn drop_renewal() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `525`
+		//  Measured:  `661`
 		//  Estimated: `4698`
-		// Minimum execution time: 25_365_000 picoseconds.
-		Weight::from_parts(26_920_000, 4698)
+		// Minimum execution time: 26_207_000 picoseconds.
+		Weight::from_parts(27_227_000, 4698)
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -355,22 +354,22 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 6_519_000 picoseconds.
-		Weight::from_parts(7_098_698, 0)
-			// Standard Error: 20
-			.saturating_add(Weight::from_parts(8, 0).saturating_mul(n.into()))
+		// Minimum execution time: 4_670_000 picoseconds.
+		Weight::from_parts(5_170_450, 0)
+			// Standard Error: 16
+			.saturating_add(Weight::from_parts(37, 0).saturating_mul(n.into()))
 	}
-	/// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1)
-	/// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1)
+	/// Storage: `Broker::CoreCountInbox` (r:1 w:1)
+	/// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`)
 	/// The range of component `n` is `[0, 1000]`.
 	fn process_core_count(n: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `98`
-		//  Estimated: `3563`
-		// Minimum execution time: 7_608_000 picoseconds.
-		Weight::from_parts(8_157_815, 3563)
-			// Standard Error: 26
-			.saturating_add(Weight::from_parts(48, 0).saturating_mul(n.into()))
+		//  Measured:  `404`
+		//  Estimated: `1487`
+		// Minimum execution time: 6_916_000 picoseconds.
+		Weight::from_parts(7_485_053, 1487)
+			// Standard Error: 23
+			.saturating_add(Weight::from_parts(30, 0).saturating_mul(n.into()))
 			.saturating_add(T::DbWeight::get().reads(1_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -386,10 +385,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
 	fn process_revenue() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `905`
-		//  Estimated: `4370`
-		// Minimum execution time: 59_993_000 picoseconds.
-		Weight::from_parts(61_752_000, 4370)
+		//  Measured:  `972`
+		//  Estimated: `4437`
+		// Minimum execution time: 50_987_000 picoseconds.
+		Weight::from_parts(52_303_000, 4437)
 			.saturating_add(T::DbWeight::get().reads(5_u64))
 			.saturating_add(T::DbWeight::get().writes(3_u64))
 	}
@@ -408,10 +407,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `6281`
 		//  Estimated: `8499`
-		// Minimum execution time: 41_863_000 picoseconds.
-		Weight::from_parts(44_033_031, 8499)
-			// Standard Error: 116
-			.saturating_add(Weight::from_parts(764, 0).saturating_mul(n.into()))
+		// Minimum execution time: 38_334_000 picoseconds.
+		Weight::from_parts(40_517_609, 8499)
+			// Standard Error: 90
+			.saturating_add(Weight::from_parts(338, 0).saturating_mul(n.into()))
 			.saturating_add(T::DbWeight::get().reads(5_u64))
 			.saturating_add(T::DbWeight::get().writes(15_u64))
 	}
@@ -423,8 +422,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `180`
 		//  Estimated: `3493`
-		// Minimum execution time: 9_588_000 picoseconds.
-		Weight::from_parts(9_925_000, 3493)
+		// Minimum execution time: 7_850_000 picoseconds.
+		Weight::from_parts(8_157_000, 3493)
 			.saturating_add(T::DbWeight::get().reads(1_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -436,8 +435,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `1423`
 		//  Estimated: `4681`
-		// Minimum execution time: 19_308_000 picoseconds.
-		Weight::from_parts(20_482_000, 4681)
+		// Minimum execution time: 17_313_000 picoseconds.
+		Weight::from_parts(17_727_000, 4681)
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(2_u64))
 	}
@@ -445,28 +444,46 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 147_000 picoseconds.
-		Weight::from_parts(184_000, 0)
+		// Minimum execution time: 171_000 picoseconds.
+		Weight::from_parts(196_000, 0)
 	}
+	/// Storage: `Broker::CoreCountInbox` (r:0 w:1)
+	/// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`)
 	fn notify_core_count() -> Weight {
-		T::DbWeight::get().reads_writes(1, 1)
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 2_413_000 picoseconds.
+		Weight::from_parts(2_587_000, 0)
+			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Broker::Status` (r:1 w:1)
 	/// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`)
 	/// Storage: `Broker::Configuration` (r:1 w:0)
 	/// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`)
-	/// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1)
-	/// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1)
+	/// Storage: `Broker::CoreCountInbox` (r:1 w:0)
+	/// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`)
 	/// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1)
 	/// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1)
 	fn do_tick_base() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `699`
-		//  Estimated: `4164`
-		// Minimum execution time: 19_824_000 picoseconds.
-		Weight::from_parts(20_983_000, 4164)
+		//  Measured:  `603`
+		//  Estimated: `4068`
+		// Minimum execution time: 13_121_000 picoseconds.
+		Weight::from_parts(13_685_000, 4068)
 			.saturating_add(T::DbWeight::get().reads(4_u64))
-			.saturating_add(T::DbWeight::get().writes(3_u64))
+			.saturating_add(T::DbWeight::get().writes(2_u64))
+	}
+	/// Storage: `Broker::Leases` (r:1 w:1)
+	/// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(41), added: 536, mode: `MaxEncodedLen`)
+	fn swap_leases() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `239`
+		//  Estimated: `1526`
+		// Minimum execution time: 6_847_000 picoseconds.
+		Weight::from_parts(7_185_000, 1526)
+			.saturating_add(T::DbWeight::get().reads(1_u64))
+			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
 }
 
@@ -478,8 +495,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 3_040_000 picoseconds.
-		Weight::from_parts(3_344_000, 0)
+		// Minimum execution time: 2_865_000 picoseconds.
+		Weight::from_parts(3_061_000, 0)
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Broker::Reservations` (r:1 w:1)
@@ -488,8 +505,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `5016`
 		//  Estimated: `7496`
-		// Minimum execution time: 21_259_000 picoseconds.
-		Weight::from_parts(22_110_000, 7496)
+		// Minimum execution time: 18_431_000 picoseconds.
+		Weight::from_parts(19_558_000, 7496)
 			.saturating_add(RocksDbWeight::get().reads(1_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -499,8 +516,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `6218`
 		//  Estimated: `7496`
-		// Minimum execution time: 20_330_000 picoseconds.
-		Weight::from_parts(20_826_000, 7496)
+		// Minimum execution time: 17_724_000 picoseconds.
+		Weight::from_parts(18_688_000, 7496)
 			.saturating_add(RocksDbWeight::get().reads(1_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -510,8 +527,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `239`
 		//  Estimated: `1526`
-		// Minimum execution time: 13_411_000 picoseconds.
-		Weight::from_parts(13_960_000, 1526)
+		// Minimum execution time: 10_513_000 picoseconds.
+		Weight::from_parts(11_138_000, 1526)
 			.saturating_add(RocksDbWeight::get().reads(1_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -530,14 +547,12 @@ impl WeightInfo for () {
 	/// Storage: `Broker::Workplan` (r:0 w:10)
 	/// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`)
 	/// The range of component `n` is `[0, 1000]`.
-	fn start_sales(n: u32, ) -> Weight {
+	fn start_sales(_n: u32, ) -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `6330`
 		//  Estimated: `8499`
-		// Minimum execution time: 57_770_000 picoseconds.
-		Weight::from_parts(61_047_512, 8499)
-			// Standard Error: 165
-			.saturating_add(Weight::from_parts(3, 0).saturating_mul(n.into()))
+		// Minimum execution time: 50_864_000 picoseconds.
+		Weight::from_parts(54_000_280, 8499)
 			.saturating_add(RocksDbWeight::get().reads(6_u64))
 			.saturating_add(RocksDbWeight::get().writes(16_u64))
 	}
@@ -553,10 +568,10 @@ impl WeightInfo for () {
 	/// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
 	fn purchase() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `568`
-		//  Estimated: `2053`
-		// Minimum execution time: 51_196_000 picoseconds.
-		Weight::from_parts(52_382_000, 2053)
+		//  Measured:  `635`
+		//  Estimated: `2120`
+		// Minimum execution time: 43_630_000 picoseconds.
+		Weight::from_parts(44_622_000, 2120)
 			.saturating_add(RocksDbWeight::get().reads(4_u64))
 			.saturating_add(RocksDbWeight::get().writes(2_u64))
 	}
@@ -576,10 +591,10 @@ impl WeightInfo for () {
 	/// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`)
 	fn renew() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `686`
+		//  Measured:  `753`
 		//  Estimated: `4698`
-		// Minimum execution time: 71_636_000 picoseconds.
-		Weight::from_parts(73_679_000, 4698)
+		// Minimum execution time: 62_453_000 picoseconds.
+		Weight::from_parts(63_882_000, 4698)
 			.saturating_add(RocksDbWeight::get().reads(6_u64))
 			.saturating_add(RocksDbWeight::get().writes(4_u64))
 	}
@@ -589,8 +604,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `495`
 		//  Estimated: `3550`
-		// Minimum execution time: 19_182_000 picoseconds.
-		Weight::from_parts(19_775_000, 3550)
+		// Minimum execution time: 17_237_000 picoseconds.
+		Weight::from_parts(17_757_000, 3550)
 			.saturating_add(RocksDbWeight::get().reads(1_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -600,21 +615,21 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `495`
 		//  Estimated: `3550`
-		// Minimum execution time: 20_688_000 picoseconds.
-		Weight::from_parts(21_557_000, 3550)
+		// Minimum execution time: 18_504_000 picoseconds.
+		Weight::from_parts(19_273_000, 3550)
 			.saturating_add(RocksDbWeight::get().reads(1_u64))
 			.saturating_add(RocksDbWeight::get().writes(2_u64))
 	}
-	/// Storage: `Broker::Regions` (r:1 w:2)
+	/// Storage: `Broker::Regions` (r:1 w:3)
 	/// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
 	fn interlace() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `495`
 		//  Estimated: `3550`
-		// Minimum execution time: 21_190_000 picoseconds.
-		Weight::from_parts(22_215_000, 3550)
+		// Minimum execution time: 20_477_000 picoseconds.
+		Weight::from_parts(21_328_000, 3550)
 			.saturating_add(RocksDbWeight::get().reads(1_u64))
-			.saturating_add(RocksDbWeight::get().writes(2_u64))
+			.saturating_add(RocksDbWeight::get().writes(3_u64))
 	}
 	/// Storage: `Broker::Configuration` (r:1 w:0)
 	/// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`)
@@ -628,8 +643,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `740`
 		//  Estimated: `4681`
-		// Minimum execution time: 34_591_000 picoseconds.
-		Weight::from_parts(36_227_000, 4681)
+		// Minimum execution time: 31_815_000 picoseconds.
+		Weight::from_parts(32_700_000, 4681)
 			.saturating_add(RocksDbWeight::get().reads(4_u64))
 			.saturating_add(RocksDbWeight::get().writes(2_u64))
 	}
@@ -647,8 +662,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `775`
 		//  Estimated: `5996`
-		// Minimum execution time: 40_346_000 picoseconds.
-		Weight::from_parts(41_951_000, 5996)
+		// Minimum execution time: 38_313_000 picoseconds.
+		Weight::from_parts(38_985_000, 5996)
 			.saturating_add(RocksDbWeight::get().reads(5_u64))
 			.saturating_add(RocksDbWeight::get().writes(5_u64))
 	}
@@ -663,10 +678,10 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `859`
 		//  Estimated: `6196 + m * (2520 ±0)`
-		// Minimum execution time: 75_734_000 picoseconds.
-		Weight::from_parts(78_168_395, 6196)
-			// Standard Error: 63_180
-			.saturating_add(Weight::from_parts(1_076_259, 0).saturating_mul(m.into()))
+		// Minimum execution time: 70_170_000 picoseconds.
+		Weight::from_parts(71_245_388, 6196)
+			// Standard Error: 54_382
+			.saturating_add(Weight::from_parts(1_488_794, 0).saturating_mul(m.into()))
 			.saturating_add(RocksDbWeight::get().reads(3_u64))
 			.saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into())))
 			.saturating_add(RocksDbWeight::get().writes(5_u64))
@@ -678,8 +693,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `103`
 		//  Estimated: `3593`
-		// Minimum execution time: 46_383_000 picoseconds.
-		Weight::from_parts(47_405_000, 3593)
+		// Minimum execution time: 43_414_000 picoseconds.
+		Weight::from_parts(44_475_000, 3593)
 			.saturating_add(RocksDbWeight::get().reads(1_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -691,8 +706,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `603`
 		//  Estimated: `3550`
-		// Minimum execution time: 30_994_000 picoseconds.
-		Weight::from_parts(31_979_000, 3550)
+		// Minimum execution time: 31_327_000 picoseconds.
+		Weight::from_parts(32_050_000, 3550)
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -706,8 +721,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `601`
 		//  Estimated: `3533`
-		// Minimum execution time: 37_584_000 picoseconds.
-		Weight::from_parts(44_010_000, 3533)
+		// Minimum execution time: 41_315_000 picoseconds.
+		Weight::from_parts(42_421_000, 3533)
 			.saturating_add(RocksDbWeight::get().reads(3_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -721,10 +736,10 @@ impl WeightInfo for () {
 	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
 	fn drop_history() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `830`
+		//  Measured:  `995`
 		//  Estimated: `3593`
-		// Minimum execution time: 45_266_000 picoseconds.
-		Weight::from_parts(48_000_000, 3593)
+		// Minimum execution time: 49_707_000 picoseconds.
+		Weight::from_parts(51_516_000, 3593)
 			.saturating_add(RocksDbWeight::get().reads(4_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -734,10 +749,10 @@ impl WeightInfo for () {
 	/// Proof: `Broker::AllowedRenewals` (`max_values`: None, `max_size`: Some(1233), added: 3708, mode: `MaxEncodedLen`)
 	fn drop_renewal() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `525`
+		//  Measured:  `661`
 		//  Estimated: `4698`
-		// Minimum execution time: 25_365_000 picoseconds.
-		Weight::from_parts(26_920_000, 4698)
+		// Minimum execution time: 26_207_000 picoseconds.
+		Weight::from_parts(27_227_000, 4698)
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -746,22 +761,22 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 6_519_000 picoseconds.
-		Weight::from_parts(7_098_698, 0)
-			// Standard Error: 20
-			.saturating_add(Weight::from_parts(8, 0).saturating_mul(n.into()))
+		// Minimum execution time: 4_670_000 picoseconds.
+		Weight::from_parts(5_170_450, 0)
+			// Standard Error: 16
+			.saturating_add(Weight::from_parts(37, 0).saturating_mul(n.into()))
 	}
-	/// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1)
-	/// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1)
+	/// Storage: `Broker::CoreCountInbox` (r:1 w:1)
+	/// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`)
 	/// The range of component `n` is `[0, 1000]`.
 	fn process_core_count(n: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `98`
-		//  Estimated: `3563`
-		// Minimum execution time: 7_608_000 picoseconds.
-		Weight::from_parts(8_157_815, 3563)
-			// Standard Error: 26
-			.saturating_add(Weight::from_parts(48, 0).saturating_mul(n.into()))
+		//  Measured:  `404`
+		//  Estimated: `1487`
+		// Minimum execution time: 6_916_000 picoseconds.
+		Weight::from_parts(7_485_053, 1487)
+			// Standard Error: 23
+			.saturating_add(Weight::from_parts(30, 0).saturating_mul(n.into()))
 			.saturating_add(RocksDbWeight::get().reads(1_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -777,10 +792,10 @@ impl WeightInfo for () {
 	/// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
 	fn process_revenue() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `905`
-		//  Estimated: `4370`
-		// Minimum execution time: 59_993_000 picoseconds.
-		Weight::from_parts(61_752_000, 4370)
+		//  Measured:  `972`
+		//  Estimated: `4437`
+		// Minimum execution time: 50_987_000 picoseconds.
+		Weight::from_parts(52_303_000, 4437)
 			.saturating_add(RocksDbWeight::get().reads(5_u64))
 			.saturating_add(RocksDbWeight::get().writes(3_u64))
 	}
@@ -799,10 +814,10 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `6281`
 		//  Estimated: `8499`
-		// Minimum execution time: 41_863_000 picoseconds.
-		Weight::from_parts(44_033_031, 8499)
-			// Standard Error: 116
-			.saturating_add(Weight::from_parts(764, 0).saturating_mul(n.into()))
+		// Minimum execution time: 38_334_000 picoseconds.
+		Weight::from_parts(40_517_609, 8499)
+			// Standard Error: 90
+			.saturating_add(Weight::from_parts(338, 0).saturating_mul(n.into()))
 			.saturating_add(RocksDbWeight::get().reads(5_u64))
 			.saturating_add(RocksDbWeight::get().writes(15_u64))
 	}
@@ -814,8 +829,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `180`
 		//  Estimated: `3493`
-		// Minimum execution time: 9_588_000 picoseconds.
-		Weight::from_parts(9_925_000, 3493)
+		// Minimum execution time: 7_850_000 picoseconds.
+		Weight::from_parts(8_157_000, 3493)
 			.saturating_add(RocksDbWeight::get().reads(1_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -827,8 +842,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `1423`
 		//  Estimated: `4681`
-		// Minimum execution time: 19_308_000 picoseconds.
-		Weight::from_parts(20_482_000, 4681)
+		// Minimum execution time: 17_313_000 picoseconds.
+		Weight::from_parts(17_727_000, 4681)
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(2_u64))
 	}
@@ -836,28 +851,45 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 147_000 picoseconds.
-		Weight::from_parts(184_000, 0)
+		// Minimum execution time: 171_000 picoseconds.
+		Weight::from_parts(196_000, 0)
 	}
+	/// Storage: `Broker::CoreCountInbox` (r:0 w:1)
+	/// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`)
 	fn notify_core_count() -> Weight {
-		RocksDbWeight::get().reads(1)
-			.saturating_add(RocksDbWeight::get().writes(1))
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 2_413_000 picoseconds.
+		Weight::from_parts(2_587_000, 0)
+			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Broker::Status` (r:1 w:1)
 	/// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`)
 	/// Storage: `Broker::Configuration` (r:1 w:0)
 	/// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`)
-	/// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1)
-	/// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1)
+	/// Storage: `Broker::CoreCountInbox` (r:1 w:0)
+	/// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`)
 	/// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1)
 	/// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1)
 	fn do_tick_base() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `699`
-		//  Estimated: `4164`
-		// Minimum execution time: 19_824_000 picoseconds.
-		Weight::from_parts(20_983_000, 4164)
+		//  Measured:  `603`
+		//  Estimated: `4068`
+		// Minimum execution time: 13_121_000 picoseconds.
+		Weight::from_parts(13_685_000, 4068)
 			.saturating_add(RocksDbWeight::get().reads(4_u64))
-			.saturating_add(RocksDbWeight::get().writes(3_u64))
+			.saturating_add(RocksDbWeight::get().writes(2_u64))
+	}
+	/// Storage: `Broker::Leases` (r:1 w:1)
+	/// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(41), added: 536, mode: `MaxEncodedLen`)
+	fn swap_leases() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `239`
+		//  Estimated: `1526`
+		// Minimum execution time: 6_847_000 picoseconds.
+		Weight::from_parts(7_185_000, 1526)
+			.saturating_add(RocksDbWeight::get().reads(1_u64))
+			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
 }
diff --git a/substrate/frame/contracts/mock-network/src/relay_chain.rs b/substrate/frame/contracts/mock-network/src/relay_chain.rs
index e2a8d3d1337bb..470304ed357ec 100644
--- a/substrate/frame/contracts/mock-network/src/relay_chain.rs
+++ b/substrate/frame/contracts/mock-network/src/relay_chain.rs
@@ -225,6 +225,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = MessageQueueHeapSize;
 	type MaxStale = MessageQueueMaxStale;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = ();
 	type MessageProcessor = MessageProcessor;
 	type QueueChangeHandler = ();
 	type WeightInfo = ();
diff --git a/substrate/frame/contracts/mock-network/src/tests.rs b/substrate/frame/contracts/mock-network/src/tests.rs
index d22221fe8ee05..39aa9bebc0f59 100644
--- a/substrate/frame/contracts/mock-network/src/tests.rs
+++ b/substrate/frame/contracts/mock-network/src/tests.rs
@@ -23,7 +23,6 @@ use crate::{
 };
 use codec::{Decode, Encode};
 use frame_support::{
-	assert_err,
 	pallet_prelude::Weight,
 	traits::{fungibles::Mutate, Currency},
 };
@@ -102,7 +101,7 @@ fn test_xcm_execute() {
 			0,
 			Weight::MAX,
 			None,
-			VersionedXcm::V4(message).encode(),
+			VersionedXcm::V4(message).encode().encode(),
 			DebugInfo::UnsafeDebug,
 			CollectEvents::UnsafeCollect,
 			Determinism::Enforced,
@@ -146,7 +145,7 @@ fn test_xcm_execute_incomplete() {
 			0,
 			Weight::MAX,
 			None,
-			VersionedXcm::V4(message).encode(),
+			VersionedXcm::V4(message).encode().encode(),
 			DebugInfo::UnsafeDebug,
 			CollectEvents::UnsafeCollect,
 			Determinism::Enforced,
@@ -160,37 +159,6 @@ fn test_xcm_execute_incomplete() {
 	});
 }
 
-#[test]
-fn test_xcm_execute_filtered_call() {
-	MockNet::reset();
-
-	let contract_addr = instantiate_test_contract("xcm_execute");
-
-	ParaA::execute_with(|| {
-		// `remark`  should be rejected, as it is not allowed by our CallFilter.
-		let call = parachain::RuntimeCall::System(frame_system::Call::remark { remark: vec![] });
-		let message: Xcm<parachain::RuntimeCall> = Xcm(vec![Transact {
-			origin_kind: OriginKind::Native,
-			require_weight_at_most: Weight::MAX,
-			call: call.encode().into(),
-		}]);
-
-		let result = ParachainContracts::bare_call(
-			ALICE,
-			contract_addr.clone(),
-			0,
-			Weight::MAX,
-			None,
-			VersionedXcm::V4(message).encode(),
-			DebugInfo::UnsafeDebug,
-			CollectEvents::UnsafeCollect,
-			Determinism::Enforced,
-		);
-
-		assert_err!(result.result, frame_system::Error::<parachain::Runtime>::CallFiltered);
-	});
-}
-
 #[test]
 fn test_xcm_execute_reentrant_call() {
 	MockNet::reset();
@@ -222,7 +190,7 @@ fn test_xcm_execute_reentrant_call() {
 			0,
 			Weight::MAX,
 			None,
-			VersionedXcm::V4(message).encode(),
+			VersionedXcm::V4(message).encode().encode(),
 			DebugInfo::UnsafeDebug,
 			CollectEvents::UnsafeCollect,
 			Determinism::Enforced,
@@ -258,7 +226,7 @@ fn test_xcm_send() {
 			0,
 			Weight::MAX,
 			None,
-			(dest, message).encode(),
+			(dest, message.encode()).encode(),
 			DebugInfo::UnsafeDebug,
 			CollectEvents::UnsafeCollect,
 			Determinism::Enforced,
diff --git a/substrate/frame/contracts/src/lib.rs b/substrate/frame/contracts/src/lib.rs
index 6433d4eecdc12..e14a4b8bcb874 100644
--- a/substrate/frame/contracts/src/lib.rs
+++ b/substrate/frame/contracts/src/lib.rs
@@ -298,6 +298,9 @@ pub mod pallet {
 		/// Therefore please make sure to be restrictive about which dispatchables are allowed
 		/// in order to not introduce a new DoS vector like memory allocation patterns that can
 		/// be exploited to drive the runtime into a panic.
+		///
+		/// This filter does not apply to XCM transact calls. To impose restrictions on XCM transact
+		/// calls, you must configure them separately within the XCM pallet itself.
 		type CallFilter: Contains<<Self as frame_system::Config>::RuntimeCall>;
 
 		/// Used to answer contracts' queries regarding the current weight price. This is **not**
diff --git a/substrate/frame/contracts/src/wasm/runtime.rs b/substrate/frame/contracts/src/wasm/runtime.rs
index 160dfa0d2f36e..28a08ab0224dd 100644
--- a/substrate/frame/contracts/src/wasm/runtime.rs
+++ b/substrate/frame/contracts/src/wasm/runtime.rs
@@ -25,12 +25,8 @@ use crate::{
 };
 use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen};
 use frame_support::{
-	dispatch::DispatchInfo,
-	ensure,
-	pallet_prelude::{DispatchResult, DispatchResultWithPostInfo},
-	parameter_types,
-	traits::Get,
-	weights::Weight,
+	dispatch::DispatchInfo, ensure, pallet_prelude::DispatchResultWithPostInfo, parameter_types,
+	traits::Get, weights::Weight,
 };
 use pallet_contracts_proc_macro::define_env;
 use pallet_contracts_uapi::{CallFlags, ReturnFlags};
@@ -41,9 +37,6 @@ use sp_runtime::{
 };
 use sp_std::{fmt, prelude::*};
 use wasmi::{core::HostError, errors::LinkerError, Linker, Memory, Store};
-use xcm::VersionedXcm;
-
-type CallOf<T> = <T as frame_system::Config>::RuntimeCall;
 
 /// The maximum nesting depth a contract can use when encoding types.
 const MAX_DECODE_NESTING: u32 = 256;
@@ -378,29 +371,6 @@ fn already_charged(_: u32) -> Option<RuntimeCosts> {
 	None
 }
 
-/// Ensure that the XCM program is executable, by checking that it does not contain any [`Transact`]
-/// instruction with a call that is not allowed by the CallFilter.
-fn ensure_executable<T: Config>(message: &VersionedXcm<CallOf<T>>) -> DispatchResult {
-	use frame_support::traits::Contains;
-	use xcm::prelude::{Transact, Xcm};
-
-	let mut message: Xcm<CallOf<T>> =
-		message.clone().try_into().map_err(|_| Error::<T>::XCMDecodeFailed)?;
-
-	message.iter_mut().try_for_each(|inst| -> DispatchResult {
-		let Transact { ref mut call, .. } = inst else { return Ok(()) };
-		let call = call.ensure_decoded().map_err(|_| Error::<T>::XCMDecodeFailed)?;
-
-		if !<T as Config>::CallFilter::contains(call) {
-			return Err(frame_system::Error::<T>::CallFiltered.into())
-		}
-
-		Ok(())
-	})?;
-
-	Ok(())
-}
-
 /// Can only be used for one call.
 pub struct Runtime<'a, E: Ext + 'a> {
 	ext: &'a mut E,
@@ -2112,16 +2082,13 @@ pub mod env {
 		msg_len: u32,
 	) -> Result<ReturnErrorCode, TrapReason> {
 		use frame_support::dispatch::DispatchInfo;
-		use xcm::VersionedXcm;
 		use xcm_builder::{ExecuteController, ExecuteControllerWeightInfo};
 
 		ctx.charge_gas(RuntimeCosts::CopyFromContract(msg_len))?;
-		let message: VersionedXcm<CallOf<E::T>> =
-			ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?;
-		ensure_executable::<E::T>(&message)?;
+		let message = ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?;
 
 		let execute_weight =
-			<<E::T as Config>::Xcm as ExecuteController<_, _>>::WeightInfo::execute();
+			<<E::T as Config>::Xcm as ExecuteController<_, _>>::WeightInfo::execute_blob();
 		let weight = ctx.ext.gas_meter().gas_left().max(execute_weight);
 		let dispatch_info = DispatchInfo { weight, ..Default::default() };
 
@@ -2130,9 +2097,9 @@ pub mod env {
 			RuntimeCosts::CallXcmExecute,
 			|ctx| {
 				let origin = crate::RawOrigin::Signed(ctx.ext.address().clone()).into();
-				let weight_used = <<E::T as Config>::Xcm>::execute(
+				let weight_used = <<E::T as Config>::Xcm>::execute_blob(
 					origin,
-					Box::new(message),
+					message,
 					weight.saturating_sub(execute_weight),
 				)?;
 
@@ -2152,19 +2119,18 @@ pub mod env {
 		msg_len: u32,
 		output_ptr: u32,
 	) -> Result<ReturnErrorCode, TrapReason> {
-		use xcm::{VersionedLocation, VersionedXcm};
+		use xcm::VersionedLocation;
 		use xcm_builder::{SendController, SendControllerWeightInfo};
 
 		ctx.charge_gas(RuntimeCosts::CopyFromContract(msg_len))?;
 		let dest: VersionedLocation = ctx.read_sandbox_memory_as(memory, dest_ptr)?;
 
-		let message: VersionedXcm<()> =
-			ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?;
-		let weight = <<E::T as Config>::Xcm as SendController<_>>::WeightInfo::send();
+		let message = ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?;
+		let weight = <<E::T as Config>::Xcm as SendController<_>>::WeightInfo::send_blob();
 		ctx.charge_gas(RuntimeCosts::CallRuntime(weight))?;
 		let origin = crate::RawOrigin::Signed(ctx.ext.address().clone()).into();
 
-		match <<E::T as Config>::Xcm>::send(origin, dest.into(), message.into()) {
+		match <<E::T as Config>::Xcm>::send_blob(origin, dest.into(), message) {
 			Ok(message_id) => {
 				ctx.write_sandbox_memory(memory, output_ptr, &message_id.encode())?;
 				Ok(ReturnErrorCode::Success)
diff --git a/substrate/frame/contracts/uapi/src/host.rs b/substrate/frame/contracts/uapi/src/host.rs
index 04f58895ab4f6..459cb59bead94 100644
--- a/substrate/frame/contracts/uapi/src/host.rs
+++ b/substrate/frame/contracts/uapi/src/host.rs
@@ -790,7 +790,7 @@ pub trait HostFn {
 	///
 	/// # Parameters
 	///
-	/// - `dest`: The XCM destination, should be decodable as [VersionedMultiLocation](https://paritytech.github.io/polkadot-sdk/master/staging_xcm/enum.VersionedMultiLocation.html),
+	/// - `dest`: The XCM destination, should be decodable as [MultiLocation](https://paritytech.github.io/polkadot-sdk/master/staging_xcm/enum.VersionedLocation.html),
 	///   traps otherwise.
 	/// - `msg`: The message, should be decodable as a [VersionedXcm](https://paritytech.github.io/polkadot-sdk/master/staging_xcm/enum.VersionedXcm.html),
 	///   traps otherwise.
diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs
index 31a79577d1f51..11577cd352623 100644
--- a/substrate/frame/election-provider-multi-phase/src/lib.rs
+++ b/substrate/frame/election-provider-multi-phase/src/lib.rs
@@ -586,10 +586,8 @@ pub mod pallet {
 		type EstimateCallFee: EstimateCallFee<Call<Self>, BalanceOf<Self>>;
 
 		/// Duration of the unsigned phase.
-		#[pallet::constant]
 		type UnsignedPhase: Get<BlockNumberFor<Self>>;
 		/// Duration of the signed phase.
-		#[pallet::constant]
 		type SignedPhase: Get<BlockNumberFor<Self>>;
 
 		/// The minimum amount of improvement to the solution score that defines a solution as
diff --git a/substrate/frame/message-queue/src/integration_test.rs b/substrate/frame/message-queue/src/integration_test.rs
index 26a330cc88e8e..14b8d2217eb2b 100644
--- a/substrate/frame/message-queue/src/integration_test.rs
+++ b/substrate/frame/message-queue/src/integration_test.rs
@@ -73,6 +73,7 @@ impl Config for Test {
 	type HeapSize = HeapSize;
 	type MaxStale = MaxStale;
 	type ServiceWeight = ServiceWeight;
+	type IdleMaxServiceWeight = ();
 }
 
 /// Simulates heavy usage by enqueueing and processing large amounts of messages.
diff --git a/substrate/frame/message-queue/src/lib.rs b/substrate/frame/message-queue/src/lib.rs
index 93cd760eeb96c..ec85c785f79eb 100644
--- a/substrate/frame/message-queue/src/lib.rs
+++ b/substrate/frame/message-queue/src/lib.rs
@@ -525,12 +525,21 @@ pub mod pallet {
 		type MaxStale: Get<u32>;
 
 		/// The amount of weight (if any) which should be provided to the message queue for
-		/// servicing enqueued items.
+		/// servicing enqueued items `on_initialize`.
 		///
 		/// This may be legitimately `None` in the case that you will call
-		/// `ServiceQueues::service_queues` manually.
+		/// `ServiceQueues::service_queues` manually or set [`Self::IdleMaxServiceWeight`] to have
+		/// it run in `on_idle`.
 		#[pallet::constant]
 		type ServiceWeight: Get<Option<Weight>>;
+
+		/// The maximum amount of weight (if any) to be used from remaining weight `on_idle` which
+		/// should be provided to the message queue for servicing enqueued items `on_idle`.
+		/// Useful for parachains to process messages at the same block they are received.
+		///
+		/// If `None`, it will not call `ServiceQueues::service_queues` in `on_idle`.
+		#[pallet::constant]
+		type IdleMaxServiceWeight: Get<Option<Weight>>;
 	}
 
 	#[pallet::event]
@@ -643,6 +652,15 @@ pub mod pallet {
 			}
 		}
 
+		fn on_idle(_n: BlockNumberFor<T>, remaining_weight: Weight) -> Weight {
+			if let Some(weight_limit) = T::IdleMaxServiceWeight::get() {
+				// Make use of the remaining weight to process enqueued messages.
+				Self::service_queues(weight_limit.min(remaining_weight))
+			} else {
+				Weight::zero()
+			}
+		}
+
 		#[cfg(feature = "try-runtime")]
 		fn try_state(_: BlockNumberFor<T>) -> Result<(), sp_runtime::TryRuntimeError> {
 			Self::do_try_state()
diff --git a/substrate/frame/message-queue/src/mock.rs b/substrate/frame/message-queue/src/mock.rs
index f22f318b8ef12..1281de6b0a66f 100644
--- a/substrate/frame/message-queue/src/mock.rs
+++ b/substrate/frame/message-queue/src/mock.rs
@@ -56,6 +56,7 @@ impl Config for Test {
 	type HeapSize = HeapSize;
 	type MaxStale = MaxStale;
 	type ServiceWeight = ServiceWeight;
+	type IdleMaxServiceWeight = ServiceWeight;
 }
 
 /// Mocked `WeightInfo` impl with allows to set the weight per call.
diff --git a/substrate/frame/message-queue/src/tests.rs b/substrate/frame/message-queue/src/tests.rs
index 1f6e7777f0125..d6788847d5717 100644
--- a/substrate/frame/message-queue/src/tests.rs
+++ b/substrate/frame/message-queue/src/tests.rs
@@ -1838,3 +1838,45 @@ fn with_service_mutex_works() {
 	with_service_mutex(|| called = 3).unwrap();
 	assert_eq!(called, 3);
 }
+
+#[test]
+fn process_enqueued_on_idle() {
+	use MessageOrigin::*;
+	build_and_execute::<Test>(|| {
+		// Some messages enqueued on previous block.
+		MessageQueue::enqueue_messages(vec![msg("a"), msg("ab"), msg("abc")].into_iter(), Here);
+		assert_eq!(BookStateFor::<Test>::iter().count(), 1);
+
+		// Process enqueued messages from previous block.
+		Pallet::<Test>::on_initialize(1);
+		assert_eq!(
+			MessagesProcessed::take(),
+			vec![(b"a".to_vec(), Here), (b"ab".to_vec(), Here), (b"abc".to_vec(), Here),]
+		);
+
+		MessageQueue::enqueue_messages(vec![msg("x"), msg("xy"), msg("xyz")].into_iter(), There);
+		assert_eq!(BookStateFor::<Test>::iter().count(), 2);
+
+		// Enough weight to process on idle.
+		Pallet::<Test>::on_idle(1, Weight::from_parts(100, 100));
+		assert_eq!(
+			MessagesProcessed::take(),
+			vec![(b"x".to_vec(), There), (b"xy".to_vec(), There), (b"xyz".to_vec(), There)]
+		);
+	})
+}
+
+#[test]
+fn process_enqueued_on_idle_requires_enough_weight() {
+	use MessageOrigin::*;
+	build_and_execute::<Test>(|| {
+		Pallet::<Test>::on_initialize(1);
+
+		MessageQueue::enqueue_messages(vec![msg("x"), msg("xy"), msg("xyz")].into_iter(), There);
+		assert_eq!(BookStateFor::<Test>::iter().count(), 1);
+
+		// Not enough weight to process on idle.
+		Pallet::<Test>::on_idle(1, Weight::from_parts(0, 0));
+		assert_eq!(MessagesProcessed::take(), vec![]);
+	})
+}
diff --git a/substrate/frame/referenda/src/lib.rs b/substrate/frame/referenda/src/lib.rs
index e616056c3022a..fbe27e1a47847 100644
--- a/substrate/frame/referenda/src/lib.rs
+++ b/substrate/frame/referenda/src/lib.rs
@@ -424,6 +424,8 @@ pub mod pallet {
 		BadStatus,
 		/// The preimage does not exist.
 		PreimageNotExist,
+		/// The preimage is stored with a different length than the one provided.
+		PreimageStoredWithDifferentLength,
 	}
 
 	#[pallet::hooks]
@@ -462,6 +464,16 @@ pub mod pallet {
 			let proposal_origin = *proposal_origin;
 			let who = T::SubmitOrigin::ensure_origin(origin, &proposal_origin)?;
 
+			// If the pre-image is already stored, ensure that it has the same length as given in
+			// `proposal`.
+			if let (Some(preimage_len), Some(proposal_len)) =
+				(proposal.lookup_hash().and_then(|h| T::Preimages::len(&h)), proposal.lookup_len())
+			{
+				if preimage_len != proposal_len {
+					return Err(Error::<T, I>::PreimageStoredWithDifferentLength.into())
+				}
+			}
+
 			let track =
 				T::Tracks::track_for(&proposal_origin).map_err(|_| Error::<T, I>::NoTrack)?;
 			let submission_deposit = Self::take_deposit(who, T::SubmissionDeposit::get())?;
diff --git a/substrate/frame/referenda/src/tests.rs b/substrate/frame/referenda/src/tests.rs
index 8f51136de0bfd..52251fcbdbeed 100644
--- a/substrate/frame/referenda/src/tests.rs
+++ b/substrate/frame/referenda/src/tests.rs
@@ -666,3 +666,19 @@ fn clear_metadata_works() {
 		}));
 	});
 }
+
+#[test]
+fn detects_incorrect_len() {
+	ExtBuilder::default().build_and_execute(|| {
+		let hash = note_preimage(1);
+		assert_noop!(
+			Referenda::submit(
+				RuntimeOrigin::signed(1),
+				Box::new(RawOrigin::Root.into()),
+				frame_support::traits::Bounded::Lookup { hash, len: 3 },
+				DispatchTime::At(1),
+			),
+			Error::<Test>::PreimageStoredWithDifferentLength
+		);
+	});
+}
diff --git a/substrate/frame/scheduler/src/lib.rs b/substrate/frame/scheduler/src/lib.rs
index 62417b8d2cc28..d19a1e0001dd3 100644
--- a/substrate/frame/scheduler/src/lib.rs
+++ b/substrate/frame/scheduler/src/lib.rs
@@ -1267,6 +1267,17 @@ impl<T: Config> Pallet<T> {
 					id: task.maybe_id,
 				});
 
+				// It was not available when we needed it, so we don't need to have requested it
+				// anymore.
+				T::Preimages::drop(&task.call);
+
+				// We don't know why `peek` failed, thus we most account here for the "full weight".
+				let _ = weight.try_consume(T::WeightInfo::service_task(
+					task.call.lookup_len().map(|x| x as usize),
+					task.maybe_id.is_some(),
+					task.maybe_periodic.is_some(),
+				));
+
 				return Err((Unavailable, Some(task)))
 			},
 		};
@@ -1435,6 +1446,7 @@ impl<T: Config> Pallet<T> {
 	}
 }
 
+#[allow(deprecated)]
 impl<T: Config> schedule::v2::Anon<BlockNumberFor<T>, <T as Config>::RuntimeCall, T::PalletsOrigin>
 	for Pallet<T>
 {
@@ -1469,6 +1481,8 @@ impl<T: Config> schedule::v2::Anon<BlockNumberFor<T>, <T as Config>::RuntimeCall
 	}
 }
 
+// TODO: migrate `schedule::v2::Anon` to `v3`
+#[allow(deprecated)]
 impl<T: Config> schedule::v2::Named<BlockNumberFor<T>, <T as Config>::RuntimeCall, T::PalletsOrigin>
 	for Pallet<T>
 {
diff --git a/substrate/frame/scheduler/src/tests.rs b/substrate/frame/scheduler/src/tests.rs
index bb02320ad751e..440355336396e 100644
--- a/substrate/frame/scheduler/src/tests.rs
+++ b/substrate/frame/scheduler/src/tests.rs
@@ -3008,6 +3008,8 @@ fn unavailable_call_is_detected() {
 
 		// Ensure the preimage isn't available
 		assert!(!Preimage::have(&bound));
+		// But we have requested it
+		assert!(Preimage::is_requested(&hash));
 
 		// Executes in block 4.
 		run_to_block(4);
@@ -3016,5 +3018,7 @@ fn unavailable_call_is_detected() {
 			System::events().last().unwrap().event,
 			crate::Event::CallUnavailable { task: (4, 0), id: Some(name) }.into()
 		);
+		// It should not be requested anymore.
+		assert!(!Preimage::is_requested(&hash));
 	});
 }
diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml
index d2a46146931b8..15c4bf9e290e7 100644
--- a/substrate/frame/staking/Cargo.toml
+++ b/substrate/frame/staking/Cargo.toml
@@ -40,10 +40,10 @@ frame-benchmarking = { path = "../benchmarking", default-features = false, optio
 rand_chacha = { version = "0.2", default-features = false, optional = true }
 
 [dev-dependencies]
+pallet-balances = { path = "../balances" }
 sp-tracing = { path = "../../primitives/tracing" }
 sp-core = { path = "../../primitives/core" }
 sp-npos-elections = { path = "../../primitives/npos-elections" }
-pallet-balances = { path = "../balances" }
 pallet-timestamp = { path = "../timestamp" }
 pallet-staking-reward-curve = { path = "reward-curve" }
 pallet-bags-list = { path = "../bags-list" }
diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs
index a83060873973c..0b67cd4603951 100644
--- a/substrate/frame/staking/src/benchmarking.rs
+++ b/substrate/frame/staking/src/benchmarking.rs
@@ -953,6 +953,15 @@ benchmarks! {
 		assert_eq!(MinCommission::<T>::get(), Perbill::from_percent(100));
 	}
 
+	restore_ledger {
+		let (stash, controller) = create_stash_controller::<T>(0, 100, RewardDestination::Staked)?;
+		// corrupt ledger.
+		Ledger::<T>::remove(controller);
+	}: _(RawOrigin::Root, stash.clone(), None, None, None)
+	verify {
+		assert_eq!(Staking::<T>::inspect_bond_state(&stash), Ok(LedgerIntegrityState::Ok));
+	}
+
 	impl_benchmark_test_suite!(
 		Staking,
 		crate::mock::ExtBuilder::default().has_stakers(true),
diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs
index b91b1bd28f35a..9a4386086aa6c 100644
--- a/substrate/frame/staking/src/lib.rs
+++ b/substrate/frame/staking/src/lib.rs
@@ -506,6 +506,20 @@ pub struct StakingLedger<T: Config> {
 	controller: Option<T::AccountId>,
 }
 
+/// State of a ledger with regards with its data and metadata integrity.
+#[derive(PartialEq, Debug)]
+enum LedgerIntegrityState {
+	/// Ledger, bond and corresponding staking lock is OK.
+	Ok,
+	/// Ledger and/or bond is corrupted. This means that the bond has a ledger with a different
+	/// stash than the bonded stash.
+	Corrupted,
+	/// Ledger was corrupted and it has been killed.
+	CorruptedKilled,
+	/// Ledger and bond are OK, however the ledger's stash lock is out of sync.
+	LockCorrupted,
+}
+
 impl<T: Config> StakingLedger<T> {
 	/// Remove entries from `unlocking` that are sufficiently old and optionally upto a given limit.
 	/// Reduce the total by the unlocked amount.
diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs
index 58a80994a62c1..ae55b2afabbb2 100644
--- a/substrate/frame/staking/src/mock.rs
+++ b/substrate/frame/staking/src/mock.rs
@@ -25,8 +25,8 @@ use frame_election_provider_support::{
 use frame_support::{
 	assert_ok, derive_impl, ord_parameter_types, parameter_types,
 	traits::{
-		ConstU64, Currency, EitherOfDiverse, FindAuthor, Get, Hooks, Imbalance, OnUnbalanced,
-		OneSessionHandler,
+		ConstU64, Currency, EitherOfDiverse, FindAuthor, Get, Hooks, Imbalance, LockableCurrency,
+		OnUnbalanced, OneSessionHandler, WithdrawReasons,
 	},
 	weights::constants::RocksDbWeight,
 };
@@ -787,55 +787,86 @@ pub(crate) fn bond_controller_stash(controller: AccountId, stash: AccountId) ->
 	Ok(())
 }
 
+// simulates `set_controller` without corrupted ledger checks for testing purposes.
+pub(crate) fn set_controller_no_checks(stash: &AccountId) {
+	let controller = Bonded::<Test>::get(stash).expect("testing stash should be bonded");
+	let ledger = Ledger::<Test>::get(&controller).expect("testing ledger should exist");
+
+	Ledger::<Test>::remove(&controller);
+	Ledger::<Test>::insert(stash, ledger);
+	Bonded::<Test>::insert(stash, stash);
+}
+
+// simulates `bond_extra` without corrupted ledger checks for testing purposes.
+pub(crate) fn bond_extra_no_checks(stash: &AccountId, amount: Balance) {
+	let controller = Bonded::<Test>::get(stash).expect("bond must exist to bond_extra");
+	let mut ledger = Ledger::<Test>::get(&controller).expect("ledger must exist to bond_extra");
+
+	let new_total = ledger.total + amount;
+	Balances::set_lock(crate::STAKING_ID, stash, new_total, WithdrawReasons::all());
+	ledger.total = new_total;
+	ledger.active = new_total;
+	Ledger::<Test>::insert(controller, ledger);
+}
+
 pub(crate) fn setup_double_bonded_ledgers() {
-	assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 10, RewardDestination::Staked));
-	assert_ok!(Staking::bond(RuntimeOrigin::signed(2), 20, RewardDestination::Staked));
-	assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 20, RewardDestination::Staked));
+	let init_ledgers = Ledger::<Test>::iter().count();
+
+	let _ = Balances::make_free_balance_be(&333, 2000);
+	let _ = Balances::make_free_balance_be(&444, 2000);
+	let _ = Balances::make_free_balance_be(&555, 2000);
+	let _ = Balances::make_free_balance_be(&777, 2000);
+
+	assert_ok!(Staking::bond(RuntimeOrigin::signed(333), 10, RewardDestination::Staked));
+	assert_ok!(Staking::bond(RuntimeOrigin::signed(444), 20, RewardDestination::Staked));
+	assert_ok!(Staking::bond(RuntimeOrigin::signed(555), 20, RewardDestination::Staked));
 	// not relevant to the test case, but ensures try-runtime checks pass.
-	[1, 2, 3]
+	[333, 444, 555]
 		.iter()
 		.for_each(|s| Payee::<Test>::insert(s, RewardDestination::Staked));
 
 	// we want to test the case where a controller can also be a stash of another ledger.
 	// for that, we change the controller/stash bonding so that:
-	// * 2 becomes controller of 1.
-	// * 3 becomes controller of 2.
-	// * 4 becomes controller of 3.
-	let ledger_1 = Ledger::<Test>::get(1).unwrap();
-	let ledger_2 = Ledger::<Test>::get(2).unwrap();
-	let ledger_3 = Ledger::<Test>::get(3).unwrap();
-
-	// 4 becomes controller of 3.
-	Bonded::<Test>::mutate(3, |controller| *controller = Some(4));
-	Ledger::<Test>::insert(4, ledger_3);
-
-	// 3 becomes controller of 2.
-	Bonded::<Test>::mutate(2, |controller| *controller = Some(3));
-	Ledger::<Test>::insert(3, ledger_2);
-
-	// 2 becomes controller of 1
-	Bonded::<Test>::mutate(1, |controller| *controller = Some(2));
-	Ledger::<Test>::insert(2, ledger_1);
-	// 1 is not controller anymore.
-	Ledger::<Test>::remove(1);
+	// * 444 becomes controller of 333.
+	// * 555 becomes controller of 444.
+	// * 777 becomes controller of 555.
+	let ledger_333 = Ledger::<Test>::get(333).unwrap();
+	let ledger_444 = Ledger::<Test>::get(444).unwrap();
+	let ledger_555 = Ledger::<Test>::get(555).unwrap();
+
+	// 777 becomes controller of 555.
+	Bonded::<Test>::mutate(555, |controller| *controller = Some(777));
+	Ledger::<Test>::insert(777, ledger_555);
+
+	// 555 becomes controller of 444.
+	Bonded::<Test>::mutate(444, |controller| *controller = Some(555));
+	Ledger::<Test>::insert(555, ledger_444);
+
+	// 444 becomes controller of 333.
+	Bonded::<Test>::mutate(333, |controller| *controller = Some(444));
+	Ledger::<Test>::insert(444, ledger_333);
+
+	// 333 is not controller anymore.
+	Ledger::<Test>::remove(333);
 
 	// checks. now we have:
-	// * 3 ledgers
-	assert_eq!(Ledger::<Test>::iter().count(), 3);
-	// * stash 1 has controller 2.
-	assert_eq!(Bonded::<Test>::get(1), Some(2));
-	assert_eq!(StakingLedger::<Test>::paired_account(StakingAccount::Stash(1)), Some(2));
-	assert_eq!(Ledger::<Test>::get(2).unwrap().stash, 1);
-
-	// * stash 2 has controller 3.
-	assert_eq!(Bonded::<Test>::get(2), Some(3));
-	assert_eq!(StakingLedger::<Test>::paired_account(StakingAccount::Stash(2)), Some(3));
-	assert_eq!(Ledger::<Test>::get(3).unwrap().stash, 2);
-
-	// * stash 3 has controller 4.
-	assert_eq!(Bonded::<Test>::get(3), Some(4));
-	assert_eq!(StakingLedger::<Test>::paired_account(StakingAccount::Stash(3)), Some(4));
-	assert_eq!(Ledger::<Test>::get(4).unwrap().stash, 3);
+	// * +3 ledgers
+	assert_eq!(Ledger::<Test>::iter().count(), 3 + init_ledgers);
+
+	// * stash 333 has controller 444.
+	assert_eq!(Bonded::<Test>::get(333), Some(444));
+	assert_eq!(StakingLedger::<Test>::paired_account(StakingAccount::Stash(333)), Some(444));
+	assert_eq!(Ledger::<Test>::get(444).unwrap().stash, 333);
+
+	// * stash 444 has controller 555.
+	assert_eq!(Bonded::<Test>::get(444), Some(555));
+	assert_eq!(StakingLedger::<Test>::paired_account(StakingAccount::Stash(444)), Some(555));
+	assert_eq!(Ledger::<Test>::get(555).unwrap().stash, 444);
+
+	// * stash 555 has controller 777.
+	assert_eq!(Bonded::<Test>::get(555), Some(777));
+	assert_eq!(StakingLedger::<Test>::paired_account(StakingAccount::Stash(555)), Some(777));
+	assert_eq!(Ledger::<Test>::get(777).unwrap().stash, 555);
 }
 
 #[macro_export]
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 5c49270449d39..887af37ae638f 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -27,8 +27,8 @@ use frame_support::{
 	dispatch::WithPostDispatchInfo,
 	pallet_prelude::*,
 	traits::{
-		Currency, Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance, Len,
-		LockableCurrency, OnUnbalanced, TryCollect, UnixTime,
+		Currency, Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance,
+		InspectLockableCurrency, Len, LockableCurrency, OnUnbalanced, TryCollect, UnixTime,
 	},
 	weights::Weight,
 };
@@ -51,8 +51,8 @@ use sp_std::prelude::*;
 use crate::{
 	election_size_tracker::StaticTracker, log, slashing, weights::WeightInfo, ActiveEraInfo,
 	BalanceOf, EraInfo, EraPayout, Exposure, ExposureOf, Forcing, IndividualExposure,
-	MaxNominationsOf, MaxWinnersOf, Nominations, NominationsQuota, PositiveImbalanceOf,
-	RewardDestination, SessionInterface, StakingLedger, ValidatorPrefs,
+	LedgerIntegrityState, MaxNominationsOf, MaxWinnersOf, Nominations, NominationsQuota,
+	PositiveImbalanceOf, RewardDestination, SessionInterface, StakingLedger, ValidatorPrefs,
 };
 
 use super::pallet::*;
@@ -86,6 +86,38 @@ impl<T: Config> Pallet<T> {
 		StakingLedger::<T>::paired_account(Stash(stash.clone()))
 	}
 
+	/// Inspects and returns the corruption state of a ledger and bond, if any.
+	///
+	/// Note: all operations in this method access directly the `Bonded` and `Ledger` storage maps
+	/// instead of using the [`StakingLedger`] API since the bond and/or ledger may be corrupted.
+	pub(crate) fn inspect_bond_state(
+		stash: &T::AccountId,
+	) -> Result<LedgerIntegrityState, Error<T>> {
+		let lock = T::Currency::balance_locked(crate::STAKING_ID, &stash);
+
+		let controller = <Bonded<T>>::get(stash).ok_or_else(|| {
+			if lock == Zero::zero() {
+				Error::<T>::NotStash
+			} else {
+				Error::<T>::BadState
+			}
+		})?;
+
+		match Ledger::<T>::get(controller) {
+			Some(ledger) =>
+				if ledger.stash != *stash {
+					Ok(LedgerIntegrityState::Corrupted)
+				} else {
+					if lock != ledger.total {
+						Ok(LedgerIntegrityState::LockCorrupted)
+					} else {
+						Ok(LedgerIntegrityState::Ok)
+					}
+				},
+			None => Ok(LedgerIntegrityState::CorruptedKilled),
+		}
+	}
+
 	/// The total balance that can be slashed from a stash account as of right now.
 	pub fn slashable_balance_of(stash: &T::AccountId) -> BalanceOf<T> {
 		// Weight note: consider making the stake accessible through stash.
@@ -1900,12 +1932,12 @@ impl<T: Config> Pallet<T> {
 			"VoterList contains non-staker"
 		);
 
+		Self::check_ledgers()?;
 		Self::check_bonded_consistency()?;
 		Self::check_payees()?;
 		Self::check_nominators()?;
 		Self::check_exposures()?;
 		Self::check_paged_exposures()?;
-		Self::check_ledgers()?;
 		Self::check_count()
 	}
 
@@ -1914,6 +1946,7 @@ impl<T: Config> Pallet<T> {
 	/// * A bonded (stash, controller) pair should have only one associated ledger. I.e. if the
 	///   ledger is bonded by stash, the controller account must not bond a different ledger.
 	/// * A bonded (stash, controller) pair must have an associated ledger.
+	///
 	/// NOTE: these checks result in warnings only. Once
 	/// <https://github.com/paritytech/polkadot-sdk/issues/3245> is resolved, turn warns into check
 	/// failures.
@@ -2008,19 +2041,18 @@ impl<T: Config> Pallet<T> {
 	}
 
 	/// Invariants:
-	/// * `ledger.controller` is not stored in the storage (but populated at retrieval).
 	/// * Stake consistency: ledger.total == ledger.active + sum(ledger.unlocking).
-	/// * The controller keying the ledger and the ledger stash matches the state of the `Bonded`
-	/// storage.
+	/// * The ledger's controller and stash matches the associated `Bonded` tuple.
+	/// * Staking locked funds for every bonded stash should be the same as its ledger's total.
+	/// * Staking ledger and bond are not corrupted.
 	fn check_ledgers() -> Result<(), TryRuntimeError> {
 		Bonded::<T>::iter()
 			.map(|(stash, ctrl)| {
-				// `ledger.controller` is never stored in raw storage.
-				let raw = Ledger::<T>::get(stash).unwrap_or_else(|| {
-					Ledger::<T>::get(ctrl.clone())
-						.expect("try_check: bonded stash/ctrl does not have an associated ledger")
-				});
-				ensure!(raw.controller.is_none(), "raw storage controller should be None");
+				// ensure locks consistency.
+				ensure!(
+					Self::inspect_bond_state(&stash) == Ok(LedgerIntegrityState::Ok),
+					"bond, ledger and/or staking lock inconsistent for a bonded stash."
+				);
 
 				// ensure ledger consistency.
 				Self::ensure_ledger_consistent(ctrl)
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index eab0a773f5209..6b0df8ffcb913 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -25,7 +25,7 @@ use frame_support::{
 	pallet_prelude::*,
 	traits::{
 		Currency, Defensive, DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get,
-		LockableCurrency, OnUnbalanced, UnixTime,
+		InspectLockableCurrency, LockableCurrency, OnUnbalanced, UnixTime, WithdrawReasons,
 	},
 	weights::Weight,
 	BoundedVec,
@@ -49,9 +49,9 @@ pub use impls::*;
 
 use crate::{
 	slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, EraPayout,
-	EraRewardPoints, Exposure, ExposurePage, Forcing, MaxNominationsOf, NegativeImbalanceOf,
-	Nominations, NominationsQuota, PositiveImbalanceOf, RewardDestination, SessionInterface,
-	StakingLedger, UnappliedSlash, UnlockChunk, ValidatorPrefs,
+	EraRewardPoints, Exposure, ExposurePage, Forcing, LedgerIntegrityState, MaxNominationsOf,
+	NegativeImbalanceOf, Nominations, NominationsQuota, PositiveImbalanceOf, RewardDestination,
+	SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, ValidatorPrefs,
 };
 
 // The speculative number of spans are used as an input of the weight annotation of
@@ -89,10 +89,10 @@ pub mod pallet {
 	pub trait Config: frame_system::Config {
 		/// The staking balance.
 		type Currency: LockableCurrency<
-			Self::AccountId,
-			Moment = BlockNumberFor<Self>,
-			Balance = Self::CurrencyBalance,
-		>;
+				Self::AccountId,
+				Moment = BlockNumberFor<Self>,
+				Balance = Self::CurrencyBalance,
+			> + InspectLockableCurrency<Self::AccountId>;
 		/// Just the `Currency::Balance` type; we have this item to allow us to constrain it to
 		/// `From<u64>`.
 		type CurrencyBalance: sp_runtime::traits::AtLeast32BitUnsigned
@@ -804,6 +804,7 @@ pub mod pallet {
 	}
 
 	#[pallet::error]
+	#[derive(PartialEq)]
 	pub enum Error<T> {
 		/// Not a controller account.
 		NotController,
@@ -867,6 +868,8 @@ pub mod pallet {
 		RewardDestinationRestricted,
 		/// Not enough funds available to withdraw
 		NotEnoughFunds,
+		/// Cannot reset a ledger.
+		CannotRestoreLedger,
 	}
 
 	#[pallet::hooks]
@@ -1992,6 +1995,108 @@ pub mod pallet {
 
 			Ok(Some(T::WeightInfo::deprecate_controller_batch(controllers.len() as u32)).into())
 		}
+
+		/// Restores the state of a ledger which is in an inconsistent state.
+		///
+		/// The requirements to restore a ledger are the following:
+		/// * The stash is bonded; or
+		/// * The stash is not bonded but it has a staking lock left behind; or
+		/// * If the stash has an associated ledger and its state is inconsistent; or
+		/// * If the ledger is not corrupted *but* its staking lock is out of sync.
+		///
+		/// The `maybe_*` input parameters will overwrite the corresponding data and metadata of the
+		/// ledger associated with the stash. If the input parameters are not set, the ledger will
+		/// be reset values from on-chain state.
+		#[pallet::call_index(29)]
+		#[pallet::weight(T::WeightInfo::restore_ledger())]
+		pub fn restore_ledger(
+			origin: OriginFor<T>,
+			stash: T::AccountId,
+			maybe_controller: Option<T::AccountId>,
+			maybe_total: Option<BalanceOf<T>>,
+			maybe_unlocking: Option<BoundedVec<UnlockChunk<BalanceOf<T>>, T::MaxUnlockingChunks>>,
+		) -> DispatchResult {
+			T::AdminOrigin::ensure_origin(origin)?;
+
+			let current_lock = T::Currency::balance_locked(crate::STAKING_ID, &stash);
+			let stash_balance = T::Currency::free_balance(&stash);
+
+			let (new_controller, new_total) = match Self::inspect_bond_state(&stash) {
+				Ok(LedgerIntegrityState::Corrupted) => {
+					let new_controller = maybe_controller.unwrap_or(stash.clone());
+
+					let new_total = if let Some(total) = maybe_total {
+						let new_total = total.min(stash_balance);
+						// enforce lock == ledger.amount.
+						T::Currency::set_lock(
+							crate::STAKING_ID,
+							&stash,
+							new_total,
+							WithdrawReasons::all(),
+						);
+						new_total
+					} else {
+						current_lock
+					};
+
+					Ok((new_controller, new_total))
+				},
+				Ok(LedgerIntegrityState::CorruptedKilled) => {
+					if current_lock == Zero::zero() {
+						// this case needs to restore both lock and ledger, so the new total needs
+						// to be given by the called since there's no way to restore the total
+						// on-chain.
+						ensure!(maybe_total.is_some(), Error::<T>::CannotRestoreLedger);
+						Ok((
+							stash.clone(),
+							maybe_total.expect("total exists as per the check above; qed."),
+						))
+					} else {
+						Ok((stash.clone(), current_lock))
+					}
+				},
+				Ok(LedgerIntegrityState::LockCorrupted) => {
+					// ledger is not corrupted but its locks are out of sync. In this case, we need
+					// to enforce a new ledger.total and staking lock for this stash.
+					let new_total =
+						maybe_total.ok_or(Error::<T>::CannotRestoreLedger)?.min(stash_balance);
+					T::Currency::set_lock(
+						crate::STAKING_ID,
+						&stash,
+						new_total,
+						WithdrawReasons::all(),
+					);
+
+					Ok((stash.clone(), new_total))
+				},
+				Err(Error::<T>::BadState) => {
+					// the stash and ledger do not exist but lock is lingering.
+					T::Currency::remove_lock(crate::STAKING_ID, &stash);
+					ensure!(
+						Self::inspect_bond_state(&stash) == Err(Error::<T>::NotStash),
+						Error::<T>::BadState
+					);
+
+					return Ok(());
+				},
+				Ok(LedgerIntegrityState::Ok) | Err(_) => Err(Error::<T>::CannotRestoreLedger),
+			}?;
+
+			// re-bond stash and controller tuple.
+			Bonded::<T>::insert(&stash, &new_controller);
+
+			// resoter ledger state.
+			let mut ledger = StakingLedger::<T>::new(stash.clone(), new_total);
+			ledger.controller = Some(new_controller);
+			ledger.unlocking = maybe_unlocking.unwrap_or_default();
+			ledger.update()?;
+
+			ensure!(
+				Self::inspect_bond_state(&stash) == Ok(LedgerIntegrityState::Ok),
+				Error::<T>::BadState
+			);
+			Ok(())
+		}
 	}
 }
 
diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs
index ef156e1955276..a5c9abe2f1762 100644
--- a/substrate/frame/staking/src/tests.rs
+++ b/substrate/frame/staking/src/tests.rs
@@ -6933,40 +6933,43 @@ mod ledger {
 			setup_double_bonded_ledgers();
 
 			// Case 1: double bonded but not corrupted:
-			// stash 2 has controller 3:
-			assert_eq!(Bonded::<Test>::get(2), Some(3));
-			assert_eq!(Ledger::<Test>::get(3).unwrap().stash, 2);
+			// stash 444 has controller 555:
+			assert_eq!(Bonded::<Test>::get(444), Some(555));
+			assert_eq!(Ledger::<Test>::get(555).unwrap().stash, 444);
 
-			// stash 2 is also a controller of 1:
-			assert_eq!(Bonded::<Test>::get(1), Some(2));
-			assert_eq!(StakingLedger::<Test>::paired_account(StakingAccount::Stash(1)), Some(2));
-			assert_eq!(Ledger::<Test>::get(2).unwrap().stash, 1);
+			// stash 444 is also a controller of 333:
+			assert_eq!(Bonded::<Test>::get(333), Some(444));
+			assert_eq!(
+				StakingLedger::<Test>::paired_account(StakingAccount::Stash(333)),
+				Some(444)
+			);
+			assert_eq!(Ledger::<Test>::get(444).unwrap().stash, 333);
 
-			// although 2 is double bonded (it is a controller and a stash of different ledgers),
+			// although 444 is double bonded (it is a controller and a stash of different ledgers),
 			// we can safely retrieve the ledger and mutate it since the correct ledger is
 			// returned.
-			let ledger_result = StakingLedger::<Test>::get(StakingAccount::Stash(2));
-			assert_eq!(ledger_result.unwrap().stash, 2); // correct ledger.
+			let ledger_result = StakingLedger::<Test>::get(StakingAccount::Stash(444));
+			assert_eq!(ledger_result.unwrap().stash, 444); // correct ledger.
 
-			let ledger_result = StakingLedger::<Test>::get(StakingAccount::Controller(2));
-			assert_eq!(ledger_result.unwrap().stash, 1); // correct ledger.
+			let ledger_result = StakingLedger::<Test>::get(StakingAccount::Controller(444));
+			assert_eq!(ledger_result.unwrap().stash, 333); // correct ledger.
 
-			// fetching ledger 1 by its stash works.
-			let ledger_result = StakingLedger::<Test>::get(StakingAccount::Stash(1));
-			assert_eq!(ledger_result.unwrap().stash, 1);
+			// fetching ledger 333 by its stash works.
+			let ledger_result = StakingLedger::<Test>::get(StakingAccount::Stash(333));
+			assert_eq!(ledger_result.unwrap().stash, 333);
 
 			// Case 2: corrupted ledger bonding.
 			// in this case, we simulate what happens when fetching a ledger by stash returns a
 			// ledger with a different stash. when this happens, we return an error instead of the
 			// ledger to prevent ledger mutations.
-			let mut ledger = Ledger::<Test>::get(2).unwrap();
-			assert_eq!(ledger.stash, 1);
-			ledger.stash = 2;
-			Ledger::<Test>::insert(2, ledger);
+			let mut ledger = Ledger::<Test>::get(444).unwrap();
+			assert_eq!(ledger.stash, 333);
+			ledger.stash = 444;
+			Ledger::<Test>::insert(444, ledger);
 
 			// now, we are prevented from fetching the ledger by stash from 1. It's associated
 			// controller (2) is now bonding a ledger with a different stash (2, not 1).
-			assert!(StakingLedger::<Test>::get(StakingAccount::Stash(1)).is_err());
+			assert!(StakingLedger::<Test>::get(StakingAccount::Stash(333)).is_err());
 		})
 	}
 
@@ -7069,7 +7072,7 @@ mod ledger {
 
 	#[test]
 	fn deprecate_controller_batch_works_full_weight() {
-		ExtBuilder::default().build_and_execute(|| {
+		ExtBuilder::default().try_state(false).build_and_execute(|| {
 			// Given:
 
 			let start = 1001;
@@ -7253,7 +7256,7 @@ mod ledger {
 			let bounded_controllers: BoundedVec<
 				_,
 				<Test as Config>::MaxControllersInDeprecationBatch,
-			> = BoundedVec::try_from(vec![1, 2, 3, 4]).unwrap();
+			> = BoundedVec::try_from(vec![333, 444, 555, 777]).unwrap();
 
 			assert_ok!(Staking::deprecate_controller_batch(
 				RuntimeOrigin::root(),
@@ -7276,7 +7279,7 @@ mod ledger {
 			let bounded_controllers: BoundedVec<
 				_,
 				<Test as Config>::MaxControllersInDeprecationBatch,
-			> = BoundedVec::try_from(vec![4, 3, 2, 1]).unwrap();
+			> = BoundedVec::try_from(vec![777, 555, 444, 333]).unwrap();
 
 			assert_ok!(Staking::deprecate_controller_batch(
 				RuntimeOrigin::root(),
@@ -7296,9 +7299,9 @@ mod ledger {
 			setup_double_bonded_ledgers();
 
 			// in this case, setting controller works due to the ordering of the calls.
-			assert_ok!(Staking::set_controller(RuntimeOrigin::signed(1)));
-			assert_ok!(Staking::set_controller(RuntimeOrigin::signed(2)));
-			assert_ok!(Staking::set_controller(RuntimeOrigin::signed(3)));
+			assert_ok!(Staking::set_controller(RuntimeOrigin::signed(333)));
+			assert_ok!(Staking::set_controller(RuntimeOrigin::signed(444)));
+			assert_ok!(Staking::set_controller(RuntimeOrigin::signed(555)));
 		})
 	}
 
@@ -7307,17 +7310,400 @@ mod ledger {
 		ExtBuilder::default().has_stakers(false).try_state(false).build_and_execute(|| {
 			setup_double_bonded_ledgers();
 
-			// setting the controller of ledger associated with stash 3 fails since its stash is a
+			// setting the controller of ledger associated with stash 555 fails since its stash is a
 			// controller of another ledger.
 			assert_noop!(
-				Staking::set_controller(RuntimeOrigin::signed(3)),
+				Staking::set_controller(RuntimeOrigin::signed(555)),
 				Error::<Test>::BadState
 			);
 			assert_noop!(
-				Staking::set_controller(RuntimeOrigin::signed(2)),
+				Staking::set_controller(RuntimeOrigin::signed(444)),
 				Error::<Test>::BadState
 			);
-			assert_ok!(Staking::set_controller(RuntimeOrigin::signed(1)));
+			assert_ok!(Staking::set_controller(RuntimeOrigin::signed(333)));
+		})
+	}
+}
+
+mod ledger_recovery {
+	use super::*;
+	use frame_support::traits::InspectLockableCurrency;
+
+	#[test]
+	fn inspect_recovery_ledger_simple_works() {
+		ExtBuilder::default().has_stakers(true).try_state(false).build_and_execute(|| {
+			setup_double_bonded_ledgers();
+
+			// non corrupted ledger.
+			assert_eq!(Staking::inspect_bond_state(&11).unwrap(), LedgerIntegrityState::Ok);
+
+			// non bonded stash.
+			assert!(Bonded::<Test>::get(&1111).is_none());
+			assert!(Staking::inspect_bond_state(&1111).is_err());
+
+			// double bonded but not corrupted.
+			assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok);
+		})
+	}
+
+	#[test]
+	fn inspect_recovery_ledger_corupted_killed_works() {
+		ExtBuilder::default().has_stakers(true).try_state(false).build_and_execute(|| {
+			setup_double_bonded_ledgers();
+
+			let lock_333_before = Balances::balance_locked(crate::STAKING_ID, &333);
+
+			// get into corrupted and killed ledger state by killing a corrupted ledger:
+			// init state:
+			//  (333, 444)
+			//  (444, 555)
+			// set_controller(444) to 444
+			//  (333, 444) -> corrupted
+			//  (444, 444)
+			// kill(333)
+			// (444, 444) -> corrupted and None.
+			assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok);
+			set_controller_no_checks(&444);
+
+			// now try-state fails.
+			assert!(Staking::do_try_state(System::block_number()).is_err());
+
+			// 333 is corrupted since it's controller is linking 444 ledger.
+			assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted);
+			// 444 however is OK.
+			assert_eq!(Staking::inspect_bond_state(&444).unwrap(), LedgerIntegrityState::Ok);
+
+			// kill the corrupted ledger that is associated with stash 333.
+			assert_ok!(StakingLedger::<Test>::kill(&333));
+
+			// 333 bond is no more but it returns `BadState` because the lock on this stash is
+			// still set (see checks below).
+			assert_eq!(Staking::inspect_bond_state(&333), Err(Error::<Test>::BadState));
+			// now the *other* ledger associated with 444 has been corrupted and killed (None).
+			assert_eq!(
+				Staking::inspect_bond_state(&444),
+				Ok(LedgerIntegrityState::CorruptedKilled)
+			);
+
+			// side effects on 333 - ledger, bonded, payee, lock should be completely empty.
+			// however, 333 lock remains.
+			assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), lock_333_before); // NOK
+			assert!(Bonded::<Test>::get(&333).is_none()); // OK
+			assert!(Payee::<Test>::get(&333).is_none()); // OK
+			assert!(Ledger::<Test>::get(&444).is_none()); // OK
+
+			// side effects on 444 - ledger, bonded, payee, lock should remain be intact.
+			// however, 444 lock was removed.
+			assert_eq!(Balances::balance_locked(crate::STAKING_ID, &444), 0); // NOK
+			assert!(Bonded::<Test>::get(&444).is_some()); // OK
+			assert!(Payee::<Test>::get(&444).is_some()); // OK
+			assert!(Ledger::<Test>::get(&555).is_none()); // NOK
+
+			assert!(Staking::do_try_state(System::block_number()).is_err());
+		})
+	}
+
+	#[test]
+	fn inspect_recovery_ledger_corupted_killed_other_works() {
+		ExtBuilder::default().has_stakers(true).try_state(false).build_and_execute(|| {
+			setup_double_bonded_ledgers();
+
+			let lock_333_before = Balances::balance_locked(crate::STAKING_ID, &333);
+
+			// get into corrupted and killed ledger state by killing a corrupted ledger:
+			// init state:
+			//  (333, 444)
+			//  (444, 555)
+			// set_controller(444) to 444
+			//  (333, 444) -> corrupted
+			//  (444, 444)
+			// kill(444)
+			// (333, 444) -> corrupted and None
+			assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok);
+			set_controller_no_checks(&444);
+
+			// now try-state fails.
+			assert!(Staking::do_try_state(System::block_number()).is_err());
+
+			// 333 is corrupted since it's controller is linking 444 ledger.
+			assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted);
+			// 444 however is OK.
+			assert_eq!(Staking::inspect_bond_state(&444).unwrap(), LedgerIntegrityState::Ok);
+
+			// kill the *other* ledger that is double bonded but not corrupted.
+			assert_ok!(StakingLedger::<Test>::kill(&444));
+
+			// now 333 is corrupted and None through the *other* ledger being killed.
+			assert_eq!(
+				Staking::inspect_bond_state(&333).unwrap(),
+				LedgerIntegrityState::CorruptedKilled,
+			);
+			// 444 is cleaned and not a stash anymore; no lock left behind.
+			assert_eq!(Ledger::<Test>::get(&444), None);
+			assert_eq!(Staking::inspect_bond_state(&444), Err(Error::<Test>::NotStash));
+
+			// side effects on 333 - ledger, bonded, payee, lock should be intact.
+			assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), lock_333_before); // OK
+			assert_eq!(Bonded::<Test>::get(&333), Some(444)); // OK
+			assert!(Payee::<Test>::get(&333).is_some()); // OK
+											 // however, ledger associated with its controller was killed.
+			assert!(Ledger::<Test>::get(&444).is_none()); // NOK
+
+			// side effects on 444 - ledger, bonded, payee, lock should be completely removed.
+			assert_eq!(Balances::balance_locked(crate::STAKING_ID, &444), 0); // OK
+			assert!(Bonded::<Test>::get(&444).is_none()); // OK
+			assert!(Payee::<Test>::get(&444).is_none()); // OK
+			assert!(Ledger::<Test>::get(&555).is_none()); // OK
+
+			assert!(Staking::do_try_state(System::block_number()).is_err());
+		})
+	}
+
+	#[test]
+	fn inspect_recovery_ledger_lock_corrupted_works() {
+		ExtBuilder::default().has_stakers(true).try_state(false).build_and_execute(|| {
+			setup_double_bonded_ledgers();
+
+			// get into lock corrupted ledger state by bond_extra on a ledger that is double bonded
+			// with a corrupted ledger.
+			// init state:
+			//  (333, 444)
+			//  (444, 555)
+			// set_controller(444) to 444
+			//  (333, 444) -> corrupted
+			//  (444, 444)
+			//  bond_extra(333, 10) -> lock corrupted on 444
+			assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok);
+			set_controller_no_checks(&444);
+			bond_extra_no_checks(&333, 10);
+
+			// now try-state fails.
+			assert!(Staking::do_try_state(System::block_number()).is_err());
+
+			// 333 is corrupted since it's controller is linking 444 ledger.
+			assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted);
+			// 444 ledger is not corrupted but locks got out of sync.
+			assert_eq!(
+				Staking::inspect_bond_state(&444).unwrap(),
+				LedgerIntegrityState::LockCorrupted
+			);
+		})
+	}
+
+	// Corrupted ledger restore.
+	//
+	// * Double bonded and corrupted ledger.
+	#[test]
+	fn restore_ledger_corrupted_works() {
+		ExtBuilder::default().has_stakers(true).build_and_execute(|| {
+			setup_double_bonded_ledgers();
+
+			// get into corrupted and killed ledger state.
+			// init state:
+			//  (333, 444)
+			//  (444, 555)
+			// set_controller(444) to 444
+			//  (333, 444) -> corrupted
+			//  (444, 444)
+			assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok);
+			set_controller_no_checks(&444);
+
+			assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted);
+
+			// now try-state fails.
+			assert!(Staking::do_try_state(System::block_number()).is_err());
+
+			// recover the ledger bonded by 333 stash.
+			assert_ok!(Staking::restore_ledger(RuntimeOrigin::root(), 333, None, None, None));
+
+			// try-state checks are ok now.
+			assert_ok!(Staking::do_try_state(System::block_number()));
+		})
+	}
+
+	// Corrupted and killed ledger restore.
+	//
+	// * Double bonded and corrupted ledger.
+	// * Ledger killed by own controller.
+	#[test]
+	fn restore_ledger_corrupted_killed_works() {
+		ExtBuilder::default().has_stakers(true).build_and_execute(|| {
+			setup_double_bonded_ledgers();
+
+			// ledger.total == lock
+			let total_444_before_corruption = Balances::balance_locked(crate::STAKING_ID, &444);
+
+			// get into corrupted and killed ledger state by killing a corrupted ledger:
+			// init state:
+			//  (333, 444)
+			//  (444, 555)
+			// set_controller(444) to 444
+			//  (333, 444) -> corrupted
+			//  (444, 444)
+			// kill(333)
+			// (444, 444) -> corrupted and None.
+			assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok);
+			set_controller_no_checks(&444);
+
+			// kill the corrupted ledger that is associated with stash 333.
+			assert_ok!(StakingLedger::<Test>::kill(&333));
+
+			// 333 bond is no more but it returns `BadState` because the lock on this stash is
+			// still set (see checks below).
+			assert_eq!(Staking::inspect_bond_state(&333), Err(Error::<Test>::BadState));
+			// now the *other* ledger associated with 444 has been corrupted and killed (None).
+			assert!(Staking::ledger(StakingAccount::Stash(444)).is_err());
+
+			// try-state should fail.
+			assert!(Staking::do_try_state(System::block_number()).is_err());
+
+			// recover the ledger bonded by 333 stash.
+			assert_ok!(Staking::restore_ledger(RuntimeOrigin::root(), 333, None, None, None));
+
+			// for the try-state checks to pass, we also need to recover the stash 444 which is
+			// corrupted too by proxy of kill(333). Currently, both the lock and the ledger of 444
+			// have been cleared so we need to provide the new amount to restore the ledger.
+			assert_noop!(
+				Staking::restore_ledger(RuntimeOrigin::root(), 444, None, None, None),
+				Error::<Test>::CannotRestoreLedger
+			);
+
+			assert_ok!(Staking::restore_ledger(
+				RuntimeOrigin::root(),
+				444,
+				None,
+				Some(total_444_before_corruption),
+				None,
+			));
+
+			// try-state checks are ok now.
+			assert_ok!(Staking::do_try_state(System::block_number()));
+		})
+	}
+
+	// Corrupted and killed by *other* ledger restore.
+	//
+	// * Double bonded and corrupted ledger.
+	// * Ledger killed by own controller.
+	#[test]
+	fn restore_ledger_corrupted_killed_other_works() {
+		ExtBuilder::default().has_stakers(true).build_and_execute(|| {
+			setup_double_bonded_ledgers();
+
+			// get into corrupted and killed ledger state by killing a corrupted ledger:
+			// init state:
+			//  (333, 444)
+			//  (444, 555)
+			// set_controller(444) to 444
+			//  (333, 444) -> corrupted
+			//  (444, 444)
+			// kill(444)
+			// (333, 444) -> corrupted and None
+			assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok);
+			set_controller_no_checks(&444);
+
+			// now try-state fails.
+			assert!(Staking::do_try_state(System::block_number()).is_err());
+
+			// 333 is corrupted since it's controller is linking 444 ledger.
+			assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted);
+			// 444 however is OK.
+			assert_eq!(Staking::inspect_bond_state(&444).unwrap(), LedgerIntegrityState::Ok);
+
+			// kill the *other* ledger that is double bonded but not corrupted.
+			assert_ok!(StakingLedger::<Test>::kill(&444));
+
+			// recover the ledger bonded by 333 stash.
+			assert_ok!(Staking::restore_ledger(RuntimeOrigin::root(), 333, None, None, None));
+
+			// 444 does not need recover in this case since it's been killed successfully.
+			assert_eq!(Staking::inspect_bond_state(&444), Err(Error::<Test>::NotStash));
+
+			// try-state checks are ok now.
+			assert_ok!(Staking::do_try_state(System::block_number()));
+		})
+	}
+
+	// Corrupted with bond_extra.
+	//
+	// * Double bonded and corrupted ledger.
+	// * Corrupted ledger calls `bond_extra`
+	#[test]
+	fn restore_ledger_corrupted_bond_extra_works() {
+		ExtBuilder::default().has_stakers(true).build_and_execute(|| {
+			setup_double_bonded_ledgers();
+
+			let lock_333_before = Balances::balance_locked(crate::STAKING_ID, &333);
+			let lock_444_before = Balances::balance_locked(crate::STAKING_ID, &444);
+
+			// get into corrupted and killed ledger state by killing a corrupted ledger:
+			// init state:
+			//  (333, 444)
+			//  (444, 555)
+			// set_controller(444) to 444
+			//  (333, 444) -> corrupted
+			//  (444, 444)
+			// bond_extra(444, 40) -> OK
+			// bond_extra(333, 30) -> locks out of sync
+
+			assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok);
+			set_controller_no_checks(&444);
+
+			// now try-state fails.
+			assert!(Staking::do_try_state(System::block_number()).is_err());
+
+			// if 444 bonds extra, the locks remain in sync.
+			bond_extra_no_checks(&444, 40);
+			assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), lock_333_before);
+			assert_eq!(Balances::balance_locked(crate::STAKING_ID, &444), lock_444_before + 40);
+
+			// however if 333 bonds extra, the wrong lock is updated.
+			bond_extra_no_checks(&333, 30);
+			assert_eq!(
+				Balances::balance_locked(crate::STAKING_ID, &333),
+				lock_444_before + 40 + 30
+			); //not OK
+			assert_eq!(Balances::balance_locked(crate::STAKING_ID, &444), lock_444_before + 40); // OK
+
+			// recover the ledger bonded by 333 stash. Note that the total/lock needs to be
+			// re-written since on-chain data lock has become out of sync.
+			assert_ok!(Staking::restore_ledger(
+				RuntimeOrigin::root(),
+				333,
+				None,
+				Some(lock_333_before + 30),
+				None
+			));
+
+			// now recover 444 that although it's not corrupted, its lock and ledger.total are out
+			// of sync. in which case, we need to explicitly set the ledger's lock and amount,
+			// otherwise the ledger recover will fail.
+			assert_noop!(
+				Staking::restore_ledger(RuntimeOrigin::root(), 444, None, None, None),
+				Error::<Test>::CannotRestoreLedger
+			);
+
+			//and enforcing a new ledger lock/total on this non-corrupted ledger will work.
+			assert_ok!(Staking::restore_ledger(
+				RuntimeOrigin::root(),
+				444,
+				None,
+				Some(lock_444_before + 40),
+				None
+			));
+
+			// double-check that ledgers got to expected state and bond_extra done during the
+			// corrupted state is part of the recovered ledgers.
+			let ledger_333 = Bonded::<Test>::get(&333).and_then(Ledger::<Test>::get).unwrap();
+			let ledger_444 = Bonded::<Test>::get(&444).and_then(Ledger::<Test>::get).unwrap();
+
+			assert_eq!(ledger_333.total, lock_333_before + 30);
+			assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), ledger_333.total);
+			assert_eq!(ledger_444.total, lock_444_before + 40);
+			assert_eq!(Balances::balance_locked(crate::STAKING_ID, &444), ledger_444.total);
+
+			// try-state checks are ok now.
+			assert_ok!(Staking::do_try_state(System::block_number()));
 		})
 	}
 }
diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs
index 6f729e08ba5c8..8a04a3dfb3f70 100644
--- a/substrate/frame/staking/src/weights.rs
+++ b/substrate/frame/staking/src/weights.rs
@@ -17,10 +17,10 @@
 
 //! Autogenerated weights for `pallet_staking`
 //!
-//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2024-01-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
+//! DATE: 2024-03-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-q7z7ruxr-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024`
 
 // Executed Command:
@@ -80,6 +80,7 @@ pub trait WeightInfo {
 	fn chill_other() -> Weight;
 	fn force_apply_min_commission() -> Weight;
 	fn set_min_commission() -> Weight;
+	fn restore_ledger() -> Weight;
 }
 
 /// Weights for `pallet_staking` using the Substrate node and recommended hardware.
@@ -87,21 +88,21 @@ pub struct SubstrateWeight<T>(PhantomData<T>);
 impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Storage: `Staking::Bonded` (r:1 w:1)
 	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Ledger` (r:1 w:1)
+	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Locks` (r:1 w:1)
 	/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Freezes` (r:1 w:0)
 	/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Ledger` (r:0 w:1)
-	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Payee` (r:0 w:1)
 	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
 	fn bond() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `927`
+		//  Measured:  `1042`
 		//  Estimated: `4764`
-		// Minimum execution time: 42_042_000 picoseconds.
-		Weight::from_parts(43_292_000, 4764)
-			.saturating_add(T::DbWeight::get().reads(3_u64))
+		// Minimum execution time: 48_753_000 picoseconds.
+		Weight::from_parts(50_539_000, 4764)
+			.saturating_add(T::DbWeight::get().reads(4_u64))
 			.saturating_add(T::DbWeight::get().writes(4_u64))
 	}
 	/// Storage: `Staking::Bonded` (r:1 w:0)
@@ -120,21 +121,21 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `1990`
 		//  Estimated: `8877`
-		// Minimum execution time: 85_050_000 picoseconds.
-		Weight::from_parts(87_567_000, 8877)
+		// Minimum execution time: 92_701_000 picoseconds.
+		Weight::from_parts(95_657_000, 8877)
 			.saturating_add(T::DbWeight::get().reads(9_u64))
 			.saturating_add(T::DbWeight::get().writes(7_u64))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:1)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:0)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Nominators` (r:1 w:0)
 	/// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::MinNominatorBond` (r:1 w:0)
 	/// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::CurrentEra` (r:1 w:0)
 	/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Bonded` (r:1 w:0)
-	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Locks` (r:1 w:1)
 	/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Freezes` (r:1 w:0)
@@ -147,41 +148,43 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `2195`
 		//  Estimated: `8877`
-		// Minimum execution time: 89_076_000 picoseconds.
-		Weight::from_parts(92_715_000, 8877)
+		// Minimum execution time: 101_049_000 picoseconds.
+		Weight::from_parts(103_729_000, 8877)
 			.saturating_add(T::DbWeight::get().reads(12_u64))
 			.saturating_add(T::DbWeight::get().writes(7_u64))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:1)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::CurrentEra` (r:1 w:0)
-	/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Bonded` (r:1 w:0)
 	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::CurrentEra` (r:1 w:0)
+	/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Locks` (r:1 w:1)
 	/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Freezes` (r:1 w:0)
 	/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`)
+	/// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0)
+	/// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`)
 	/// The range of component `s` is `[0, 100]`.
 	fn withdraw_unbonded_update(s: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1115`
+		//  Measured:  `1297`
 		//  Estimated: `4764`
-		// Minimum execution time: 42_067_000 picoseconds.
-		Weight::from_parts(43_239_807, 4764)
-			// Standard Error: 831
-			.saturating_add(Weight::from_parts(46_257, 0).saturating_mul(s.into()))
-			.saturating_add(T::DbWeight::get().reads(5_u64))
+		// Minimum execution time: 51_672_000 picoseconds.
+		Weight::from_parts(53_817_441, 4764)
+			// Standard Error: 1_124
+			.saturating_add(Weight::from_parts(49_168, 0).saturating_mul(s.into()))
+			.saturating_add(T::DbWeight::get().reads(6_u64))
 			.saturating_add(T::DbWeight::get().writes(2_u64))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:1)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:1)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::CurrentEra` (r:1 w:0)
 	/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::SlashingSpans` (r:1 w:1)
 	/// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`)
-	/// Storage: `Staking::Bonded` (r:1 w:1)
-	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Locks` (r:1 w:1)
 	/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Freezes` (r:1 w:0)
@@ -207,10 +210,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `2196 + s * (4 ±0)`
 		//  Estimated: `6248 + s * (4 ±0)`
-		// Minimum execution time: 86_490_000 picoseconds.
-		Weight::from_parts(95_358_751, 6248)
-			// Standard Error: 3_952
-			.saturating_add(Weight::from_parts(1_294_907, 0).saturating_mul(s.into()))
+		// Minimum execution time: 92_846_000 picoseconds.
+		Weight::from_parts(102_158_606, 6248)
+			// Standard Error: 4_187
+			.saturating_add(Weight::from_parts(1_436_364, 0).saturating_mul(s.into()))
 			.saturating_add(T::DbWeight::get().reads(13_u64))
 			.saturating_add(T::DbWeight::get().writes(11_u64))
 			.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into())))
@@ -218,6 +221,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:0)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:0)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::MinValidatorBond` (r:1 w:0)
 	/// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::MinCommission` (r:1 w:0)
@@ -228,8 +233,6 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Nominators` (r:1 w:0)
 	/// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Bonded` (r:1 w:0)
-	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListNodes` (r:1 w:1)
 	/// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListBags` (r:1 w:1)
@@ -242,31 +245,35 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `1372`
 		//  Estimated: `4556`
-		// Minimum execution time: 50_326_000 picoseconds.
-		Weight::from_parts(52_253_000, 4556)
+		// Minimum execution time: 58_162_000 picoseconds.
+		Weight::from_parts(60_124_000, 4556)
 			.saturating_add(T::DbWeight::get().reads(11_u64))
 			.saturating_add(T::DbWeight::get().writes(5_u64))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:0)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:0)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Nominators` (r:128 w:128)
 	/// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`)
 	/// The range of component `k` is `[1, 128]`.
 	fn kick(k: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1280 + k * (569 ±0)`
+		//  Measured:  `1815 + k * (572 ±0)`
 		//  Estimated: `4556 + k * (3033 ±0)`
-		// Minimum execution time: 29_305_000 picoseconds.
-		Weight::from_parts(32_199_604, 4556)
-			// Standard Error: 7_150
-			.saturating_add(Weight::from_parts(6_437_124, 0).saturating_mul(k.into()))
-			.saturating_add(T::DbWeight::get().reads(1_u64))
+		// Minimum execution time: 37_950_000 picoseconds.
+		Weight::from_parts(34_461_075, 4556)
+			// Standard Error: 8_013
+			.saturating_add(Weight::from_parts(6_696_510, 0).saturating_mul(k.into()))
+			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into())))
 			.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into())))
 			.saturating_add(Weight::from_parts(0, 3033).saturating_mul(k.into()))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:0)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:0)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::MinNominatorBond` (r:1 w:0)
 	/// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Nominators` (r:1 w:1)
@@ -277,8 +284,6 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::CurrentEra` (r:1 w:0)
 	/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Bonded` (r:1 w:0)
-	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListNodes` (r:2 w:2)
 	/// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListBags` (r:1 w:1)
@@ -292,10 +297,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `1866 + n * (102 ±0)`
 		//  Estimated: `6248 + n * (2520 ±0)`
-		// Minimum execution time: 63_267_000 picoseconds.
-		Weight::from_parts(61_741_404, 6248)
-			// Standard Error: 12_955
-			.saturating_add(Weight::from_parts(3_811_743, 0).saturating_mul(n.into()))
+		// Minimum execution time: 70_167_000 picoseconds.
+		Weight::from_parts(68_024_084, 6248)
+			// Standard Error: 14_256
+			.saturating_add(Weight::from_parts(4_195_757, 0).saturating_mul(n.into()))
 			.saturating_add(T::DbWeight::get().reads(12_u64))
 			.saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into())))
 			.saturating_add(T::DbWeight::get().writes(6_u64))
@@ -303,6 +308,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:0)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:0)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Validators` (r:1 w:0)
 	/// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Nominators` (r:1 w:1)
@@ -317,11 +324,11 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	fn chill() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1650`
+		//  Measured:  `1816`
 		//  Estimated: `6248`
-		// Minimum execution time: 52_862_000 picoseconds.
-		Weight::from_parts(54_108_000, 6248)
-			.saturating_add(T::DbWeight::get().reads(8_u64))
+		// Minimum execution time: 61_730_000 picoseconds.
+		Weight::from_parts(63_430_000, 6248)
+			.saturating_add(T::DbWeight::get().reads(9_u64))
 			.saturating_add(T::DbWeight::get().writes(6_u64))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:0)
@@ -334,37 +341,37 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `902`
 		//  Estimated: `4556`
-		// Minimum execution time: 16_350_000 picoseconds.
-		Weight::from_parts(16_802_000, 4556)
+		// Minimum execution time: 20_857_000 picoseconds.
+		Weight::from_parts(21_615_000, 4556)
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:0)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Payee` (r:1 w:1)
-	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Bonded` (r:1 w:0)
 	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Payee` (r:1 w:1)
+	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
 	fn update_payee() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `969`
 		//  Estimated: `4556`
-		// Minimum execution time: 19_981_000 picoseconds.
-		Weight::from_parts(20_539_000, 4556)
+		// Minimum execution time: 24_739_000 picoseconds.
+		Weight::from_parts(25_785_000, 4556)
 			.saturating_add(T::DbWeight::get().reads(3_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::Bonded` (r:1 w:1)
 	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Ledger` (r:1 w:2)
+	/// Storage: `Staking::Ledger` (r:2 w:2)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
 	fn set_controller() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `902`
-		//  Estimated: `4556`
-		// Minimum execution time: 19_304_000 picoseconds.
-		Weight::from_parts(20_000_000, 4556)
-			.saturating_add(T::DbWeight::get().reads(2_u64))
+		//  Estimated: `8122`
+		// Minimum execution time: 24_622_000 picoseconds.
+		Weight::from_parts(25_220_000, 8122)
+			.saturating_add(T::DbWeight::get().reads(3_u64))
 			.saturating_add(T::DbWeight::get().writes(3_u64))
 	}
 	/// Storage: `Staking::ValidatorCount` (r:0 w:1)
@@ -373,8 +380,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_568_000 picoseconds.
-		Weight::from_parts(2_708_000, 0)
+		// Minimum execution time: 2_634_000 picoseconds.
+		Weight::from_parts(2_842_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::ForceEra` (r:0 w:1)
@@ -383,8 +390,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 7_950_000 picoseconds.
-		Weight::from_parts(8_348_000, 0)
+		// Minimum execution time: 8_496_000 picoseconds.
+		Weight::from_parts(9_016_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::ForceEra` (r:0 w:1)
@@ -393,8 +400,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 7_967_000 picoseconds.
-		Weight::from_parts(8_222_000, 0)
+		// Minimum execution time: 8_510_000 picoseconds.
+		Weight::from_parts(8_893_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::ForceEra` (r:0 w:1)
@@ -403,8 +410,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 8_006_000 picoseconds.
-		Weight::from_parts(8_440_000, 0)
+		// Minimum execution time: 8_243_000 picoseconds.
+		Weight::from_parts(8_678_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::Invulnerables` (r:0 w:1)
@@ -414,30 +421,30 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_524_000 picoseconds.
-		Weight::from_parts(3_123_608, 0)
-			// Standard Error: 59
-			.saturating_add(Weight::from_parts(11_596, 0).saturating_mul(v.into()))
+		// Minimum execution time: 2_781_000 picoseconds.
+		Weight::from_parts(3_441_708, 0)
+			// Standard Error: 58
+			.saturating_add(Weight::from_parts(11_811, 0).saturating_mul(v.into()))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
-	/// Storage: `Staking::Ledger` (r:5900 w:11800)
+	/// Storage: `Staking::Ledger` (r:11800 w:11800)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:5900 w:5900)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Payee` (r:5900 w:0)
 	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Bonded` (r:0 w:5900)
-	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// The range of component `i` is `[0, 5900]`.
 	fn deprecate_controller_batch(i: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1356 + i * (151 ±0)`
-		//  Estimated: `990 + i * (3566 ±0)`
-		// Minimum execution time: 2_092_000 picoseconds.
-		Weight::from_parts(2_258_000, 990)
-			// Standard Error: 32_695
-			.saturating_add(Weight::from_parts(16_669_219, 0).saturating_mul(i.into()))
-			.saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(i.into())))
+		//  Measured:  `1746 + i * (229 ±0)`
+		//  Estimated: `990 + i * (7132 ±0)`
+		// Minimum execution time: 5_331_000 picoseconds.
+		Weight::from_parts(5_511_000, 990)
+			// Standard Error: 66_734
+			.saturating_add(Weight::from_parts(31_157_413, 0).saturating_mul(i.into()))
+			.saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(i.into())))
 			.saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(i.into())))
-			.saturating_add(Weight::from_parts(0, 3566).saturating_mul(i.into()))
+			.saturating_add(Weight::from_parts(0, 7132).saturating_mul(i.into()))
 	}
 	/// Storage: `Staking::SlashingSpans` (r:1 w:1)
 	/// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -472,10 +479,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `2196 + s * (4 ±0)`
 		//  Estimated: `6248 + s * (4 ±0)`
-		// Minimum execution time: 84_275_000 picoseconds.
-		Weight::from_parts(92_512_416, 6248)
-			// Standard Error: 3_633
-			.saturating_add(Weight::from_parts(1_315_923, 0).saturating_mul(s.into()))
+		// Minimum execution time: 89_473_000 picoseconds.
+		Weight::from_parts(98_055_990, 6248)
+			// Standard Error: 4_159
+			.saturating_add(Weight::from_parts(1_398_203, 0).saturating_mul(s.into()))
 			.saturating_add(T::DbWeight::get().reads(13_u64))
 			.saturating_add(T::DbWeight::get().writes(12_u64))
 			.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into())))
@@ -488,10 +495,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `66672`
 		//  Estimated: `70137`
-		// Minimum execution time: 101_707_000 picoseconds.
-		Weight::from_parts(912_819_462, 70137)
-			// Standard Error: 57_547
-			.saturating_add(Weight::from_parts(4_856_799, 0).saturating_mul(s.into()))
+		// Minimum execution time: 102_480_000 picoseconds.
+		Weight::from_parts(1_165_789_820, 70137)
+			// Standard Error: 77_157
+			.saturating_add(Weight::from_parts(6_489_253, 0).saturating_mul(s.into()))
 			.saturating_add(T::DbWeight::get().reads(1_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -528,10 +535,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `33297 + n * (377 ±0)`
 		//  Estimated: `30944 + n * (3774 ±0)`
-		// Minimum execution time: 138_657_000 picoseconds.
-		Weight::from_parts(167_173_445, 30944)
-			// Standard Error: 25_130
-			.saturating_add(Weight::from_parts(44_566_012, 0).saturating_mul(n.into()))
+		// Minimum execution time: 156_890_000 picoseconds.
+		Weight::from_parts(202_972_688, 30944)
+			// Standard Error: 29_972
+			.saturating_add(Weight::from_parts(48_226_698, 0).saturating_mul(n.into()))
 			.saturating_add(T::DbWeight::get().reads(14_u64))
 			.saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into())))
 			.saturating_add(T::DbWeight::get().writes(4_u64))
@@ -555,10 +562,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `1991 + l * (7 ±0)`
 		//  Estimated: `8877`
-		// Minimum execution time: 80_061_000 picoseconds.
-		Weight::from_parts(82_836_434, 8877)
-			// Standard Error: 4_348
-			.saturating_add(Weight::from_parts(75_744, 0).saturating_mul(l.into()))
+		// Minimum execution time: 88_482_000 picoseconds.
+		Weight::from_parts(92_616_600, 8877)
+			// Standard Error: 4_411
+			.saturating_add(Weight::from_parts(117_722, 0).saturating_mul(l.into()))
 			.saturating_add(T::DbWeight::get().reads(9_u64))
 			.saturating_add(T::DbWeight::get().writes(7_u64))
 	}
@@ -593,10 +600,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `2196 + s * (4 ±0)`
 		//  Estimated: `6248 + s * (4 ±0)`
-		// Minimum execution time: 92_560_000 picoseconds.
-		Weight::from_parts(97_684_741, 6248)
-			// Standard Error: 3_361
-			.saturating_add(Weight::from_parts(1_292_732, 0).saturating_mul(s.into()))
+		// Minimum execution time: 98_489_000 picoseconds.
+		Weight::from_parts(102_968_643, 6248)
+			// Standard Error: 4_823
+			.saturating_add(Weight::from_parts(1_420_838, 0).saturating_mul(s.into()))
 			.saturating_add(T::DbWeight::get().reads(12_u64))
 			.saturating_add(T::DbWeight::get().writes(11_u64))
 			.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into())))
@@ -642,12 +649,12 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0 + n * (720 ±0) + v * (3598 ±0)`
 		//  Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)`
-		// Minimum execution time: 564_963_000 picoseconds.
-		Weight::from_parts(569_206_000, 512390)
-			// Standard Error: 2_033_235
-			.saturating_add(Weight::from_parts(68_025_841, 0).saturating_mul(v.into()))
-			// Standard Error: 202_600
-			.saturating_add(Weight::from_parts(17_916_770, 0).saturating_mul(n.into()))
+		// Minimum execution time: 604_820_000 picoseconds.
+		Weight::from_parts(608_838_000, 512390)
+			// Standard Error: 2_300_345
+			.saturating_add(Weight::from_parts(72_980_573, 0).saturating_mul(v.into()))
+			// Standard Error: 229_216
+			.saturating_add(Weight::from_parts(20_739_416, 0).saturating_mul(n.into()))
 			.saturating_add(T::DbWeight::get().reads(206_u64))
 			.saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into())))
 			.saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into())))
@@ -678,12 +685,12 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `3175 + n * (911 ±0) + v * (395 ±0)`
 		//  Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)`
-		// Minimum execution time: 32_196_540_000 picoseconds.
-		Weight::from_parts(32_341_871_000, 512390)
-			// Standard Error: 354_657
-			.saturating_add(Weight::from_parts(5_143_440, 0).saturating_mul(v.into()))
-			// Standard Error: 354_657
-			.saturating_add(Weight::from_parts(3_328_189, 0).saturating_mul(n.into()))
+		// Minimum execution time: 37_380_439_000 picoseconds.
+		Weight::from_parts(38_187_734_000, 512390)
+			// Standard Error: 425_319
+			.saturating_add(Weight::from_parts(6_001_288, 0).saturating_mul(v.into()))
+			// Standard Error: 425_319
+			.saturating_add(Weight::from_parts(4_129_446, 0).saturating_mul(n.into()))
 			.saturating_add(T::DbWeight::get().reads(201_u64))
 			.saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into())))
 			.saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into())))
@@ -700,10 +707,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `979 + v * (50 ±0)`
 		//  Estimated: `3510 + v * (2520 ±0)`
-		// Minimum execution time: 2_381_903_000 picoseconds.
-		Weight::from_parts(32_693_059, 3510)
-			// Standard Error: 10_000
-			.saturating_add(Weight::from_parts(4_736_173, 0).saturating_mul(v.into()))
+		// Minimum execution time: 2_572_838_000 picoseconds.
+		Weight::from_parts(67_632_557, 3510)
+			// Standard Error: 12_028
+			.saturating_add(Weight::from_parts(5_117_459, 0).saturating_mul(v.into()))
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into())))
 			.saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into()))
@@ -714,6 +721,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::MaxValidatorsCount` (r:0 w:1)
 	/// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::MaxStakedRewards` (r:0 w:1)
+	/// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::ChillThreshold` (r:0 w:1)
 	/// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::MaxNominatorsCount` (r:0 w:1)
@@ -724,9 +733,9 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 5_434_000 picoseconds.
-		Weight::from_parts(5_742_000, 0)
-			.saturating_add(T::DbWeight::get().writes(6_u64))
+		// Minimum execution time: 5_962_000 picoseconds.
+		Weight::from_parts(6_497_000, 0)
+			.saturating_add(T::DbWeight::get().writes(7_u64))
 	}
 	/// Storage: `Staking::MinCommission` (r:0 w:1)
 	/// Proof: `Staking::MinCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -734,6 +743,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::MaxValidatorsCount` (r:0 w:1)
 	/// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::MaxStakedRewards` (r:0 w:1)
+	/// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::ChillThreshold` (r:0 w:1)
 	/// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::MaxNominatorsCount` (r:0 w:1)
@@ -744,9 +755,9 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 4_588_000 picoseconds.
-		Weight::from_parts(4_854_000, 0)
-			.saturating_add(T::DbWeight::get().writes(6_u64))
+		// Minimum execution time: 5_227_000 picoseconds.
+		Weight::from_parts(5_496_000, 0)
+			.saturating_add(T::DbWeight::get().writes(7_u64))
 	}
 	/// Storage: `Staking::Bonded` (r:1 w:0)
 	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
@@ -774,8 +785,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `1939`
 		//  Estimated: `6248`
-		// Minimum execution time: 68_780_000 picoseconds.
-		Weight::from_parts(71_479_000, 6248)
+		// Minimum execution time: 75_129_000 picoseconds.
+		Weight::from_parts(77_498_000, 6248)
 			.saturating_add(T::DbWeight::get().reads(12_u64))
 			.saturating_add(T::DbWeight::get().writes(6_u64))
 	}
@@ -787,8 +798,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `691`
 		//  Estimated: `3510`
-		// Minimum execution time: 12_268_000 picoseconds.
-		Weight::from_parts(12_661_000, 3510)
+		// Minimum execution time: 13_488_000 picoseconds.
+		Weight::from_parts(14_183_000, 3510)
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -798,31 +809,50 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 3_071_000 picoseconds.
-		Weight::from_parts(3_334_000, 0)
+		// Minimum execution time: 3_368_000 picoseconds.
+		Weight::from_parts(3_582_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
+	/// Storage: `Balances::Locks` (r:1 w:1)
+	/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
+	/// Storage: `System::Account` (r:1 w:1)
+	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:1)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Ledger` (r:1 w:1)
+	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Balances::Freezes` (r:1 w:0)
+	/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`)
+	fn restore_ledger() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `1047`
+		//  Estimated: `4764`
+		// Minimum execution time: 44_876_000 picoseconds.
+		Weight::from_parts(46_353_000, 4764)
+			.saturating_add(T::DbWeight::get().reads(5_u64))
+			.saturating_add(T::DbWeight::get().writes(4_u64))
+	}
 }
 
 // For backwards compatibility and tests.
 impl WeightInfo for () {
 	/// Storage: `Staking::Bonded` (r:1 w:1)
 	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Ledger` (r:1 w:1)
+	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Locks` (r:1 w:1)
 	/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Freezes` (r:1 w:0)
 	/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Ledger` (r:0 w:1)
-	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Payee` (r:0 w:1)
 	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
 	fn bond() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `927`
+		//  Measured:  `1042`
 		//  Estimated: `4764`
-		// Minimum execution time: 42_042_000 picoseconds.
-		Weight::from_parts(43_292_000, 4764)
-			.saturating_add(RocksDbWeight::get().reads(3_u64))
+		// Minimum execution time: 48_753_000 picoseconds.
+		Weight::from_parts(50_539_000, 4764)
+			.saturating_add(RocksDbWeight::get().reads(4_u64))
 			.saturating_add(RocksDbWeight::get().writes(4_u64))
 	}
 	/// Storage: `Staking::Bonded` (r:1 w:0)
@@ -841,21 +871,21 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `1990`
 		//  Estimated: `8877`
-		// Minimum execution time: 85_050_000 picoseconds.
-		Weight::from_parts(87_567_000, 8877)
+		// Minimum execution time: 92_701_000 picoseconds.
+		Weight::from_parts(95_657_000, 8877)
 			.saturating_add(RocksDbWeight::get().reads(9_u64))
 			.saturating_add(RocksDbWeight::get().writes(7_u64))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:1)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:0)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Nominators` (r:1 w:0)
 	/// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::MinNominatorBond` (r:1 w:0)
 	/// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::CurrentEra` (r:1 w:0)
 	/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Bonded` (r:1 w:0)
-	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Locks` (r:1 w:1)
 	/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Freezes` (r:1 w:0)
@@ -868,41 +898,43 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `2195`
 		//  Estimated: `8877`
-		// Minimum execution time: 89_076_000 picoseconds.
-		Weight::from_parts(92_715_000, 8877)
+		// Minimum execution time: 101_049_000 picoseconds.
+		Weight::from_parts(103_729_000, 8877)
 			.saturating_add(RocksDbWeight::get().reads(12_u64))
 			.saturating_add(RocksDbWeight::get().writes(7_u64))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:1)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::CurrentEra` (r:1 w:0)
-	/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Bonded` (r:1 w:0)
 	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::CurrentEra` (r:1 w:0)
+	/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Locks` (r:1 w:1)
 	/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Freezes` (r:1 w:0)
 	/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`)
+	/// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0)
+	/// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`)
 	/// The range of component `s` is `[0, 100]`.
 	fn withdraw_unbonded_update(s: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1115`
+		//  Measured:  `1297`
 		//  Estimated: `4764`
-		// Minimum execution time: 42_067_000 picoseconds.
-		Weight::from_parts(43_239_807, 4764)
-			// Standard Error: 831
-			.saturating_add(Weight::from_parts(46_257, 0).saturating_mul(s.into()))
-			.saturating_add(RocksDbWeight::get().reads(5_u64))
+		// Minimum execution time: 51_672_000 picoseconds.
+		Weight::from_parts(53_817_441, 4764)
+			// Standard Error: 1_124
+			.saturating_add(Weight::from_parts(49_168, 0).saturating_mul(s.into()))
+			.saturating_add(RocksDbWeight::get().reads(6_u64))
 			.saturating_add(RocksDbWeight::get().writes(2_u64))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:1)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:1)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::CurrentEra` (r:1 w:0)
 	/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::SlashingSpans` (r:1 w:1)
 	/// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`)
-	/// Storage: `Staking::Bonded` (r:1 w:1)
-	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Locks` (r:1 w:1)
 	/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Freezes` (r:1 w:0)
@@ -928,10 +960,10 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `2196 + s * (4 ±0)`
 		//  Estimated: `6248 + s * (4 ±0)`
-		// Minimum execution time: 86_490_000 picoseconds.
-		Weight::from_parts(95_358_751, 6248)
-			// Standard Error: 3_952
-			.saturating_add(Weight::from_parts(1_294_907, 0).saturating_mul(s.into()))
+		// Minimum execution time: 92_846_000 picoseconds.
+		Weight::from_parts(102_158_606, 6248)
+			// Standard Error: 4_187
+			.saturating_add(Weight::from_parts(1_436_364, 0).saturating_mul(s.into()))
 			.saturating_add(RocksDbWeight::get().reads(13_u64))
 			.saturating_add(RocksDbWeight::get().writes(11_u64))
 			.saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into())))
@@ -939,6 +971,8 @@ impl WeightInfo for () {
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:0)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:0)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::MinValidatorBond` (r:1 w:0)
 	/// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::MinCommission` (r:1 w:0)
@@ -949,8 +983,6 @@ impl WeightInfo for () {
 	/// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Nominators` (r:1 w:0)
 	/// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Bonded` (r:1 w:0)
-	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListNodes` (r:1 w:1)
 	/// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListBags` (r:1 w:1)
@@ -963,31 +995,35 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `1372`
 		//  Estimated: `4556`
-		// Minimum execution time: 50_326_000 picoseconds.
-		Weight::from_parts(52_253_000, 4556)
+		// Minimum execution time: 58_162_000 picoseconds.
+		Weight::from_parts(60_124_000, 4556)
 			.saturating_add(RocksDbWeight::get().reads(11_u64))
 			.saturating_add(RocksDbWeight::get().writes(5_u64))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:0)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:0)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Nominators` (r:128 w:128)
 	/// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`)
 	/// The range of component `k` is `[1, 128]`.
 	fn kick(k: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1280 + k * (569 ±0)`
+		//  Measured:  `1815 + k * (572 ±0)`
 		//  Estimated: `4556 + k * (3033 ±0)`
-		// Minimum execution time: 29_305_000 picoseconds.
-		Weight::from_parts(32_199_604, 4556)
-			// Standard Error: 7_150
-			.saturating_add(Weight::from_parts(6_437_124, 0).saturating_mul(k.into()))
-			.saturating_add(RocksDbWeight::get().reads(1_u64))
+		// Minimum execution time: 37_950_000 picoseconds.
+		Weight::from_parts(34_461_075, 4556)
+			// Standard Error: 8_013
+			.saturating_add(Weight::from_parts(6_696_510, 0).saturating_mul(k.into()))
+			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into())))
 			.saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into())))
 			.saturating_add(Weight::from_parts(0, 3033).saturating_mul(k.into()))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:0)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:0)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::MinNominatorBond` (r:1 w:0)
 	/// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Nominators` (r:1 w:1)
@@ -998,8 +1034,6 @@ impl WeightInfo for () {
 	/// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::CurrentEra` (r:1 w:0)
 	/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Bonded` (r:1 w:0)
-	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListNodes` (r:2 w:2)
 	/// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListBags` (r:1 w:1)
@@ -1013,10 +1047,10 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `1866 + n * (102 ±0)`
 		//  Estimated: `6248 + n * (2520 ±0)`
-		// Minimum execution time: 63_267_000 picoseconds.
-		Weight::from_parts(61_741_404, 6248)
-			// Standard Error: 12_955
-			.saturating_add(Weight::from_parts(3_811_743, 0).saturating_mul(n.into()))
+		// Minimum execution time: 70_167_000 picoseconds.
+		Weight::from_parts(68_024_084, 6248)
+			// Standard Error: 14_256
+			.saturating_add(Weight::from_parts(4_195_757, 0).saturating_mul(n.into()))
 			.saturating_add(RocksDbWeight::get().reads(12_u64))
 			.saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into())))
 			.saturating_add(RocksDbWeight::get().writes(6_u64))
@@ -1024,6 +1058,8 @@ impl WeightInfo for () {
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:0)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:0)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Validators` (r:1 w:0)
 	/// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Nominators` (r:1 w:1)
@@ -1038,11 +1074,11 @@ impl WeightInfo for () {
 	/// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	fn chill() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1650`
+		//  Measured:  `1816`
 		//  Estimated: `6248`
-		// Minimum execution time: 52_862_000 picoseconds.
-		Weight::from_parts(54_108_000, 6248)
-			.saturating_add(RocksDbWeight::get().reads(8_u64))
+		// Minimum execution time: 61_730_000 picoseconds.
+		Weight::from_parts(63_430_000, 6248)
+			.saturating_add(RocksDbWeight::get().reads(9_u64))
 			.saturating_add(RocksDbWeight::get().writes(6_u64))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:0)
@@ -1055,37 +1091,37 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `902`
 		//  Estimated: `4556`
-		// Minimum execution time: 16_350_000 picoseconds.
-		Weight::from_parts(16_802_000, 4556)
+		// Minimum execution time: 20_857_000 picoseconds.
+		Weight::from_parts(21_615_000, 4556)
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::Ledger` (r:1 w:0)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Payee` (r:1 w:1)
-	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Bonded` (r:1 w:0)
 	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Payee` (r:1 w:1)
+	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
 	fn update_payee() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `969`
 		//  Estimated: `4556`
-		// Minimum execution time: 19_981_000 picoseconds.
-		Weight::from_parts(20_539_000, 4556)
+		// Minimum execution time: 24_739_000 picoseconds.
+		Weight::from_parts(25_785_000, 4556)
 			.saturating_add(RocksDbWeight::get().reads(3_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::Bonded` (r:1 w:1)
 	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Ledger` (r:1 w:2)
+	/// Storage: `Staking::Ledger` (r:2 w:2)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
 	fn set_controller() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `902`
-		//  Estimated: `4556`
-		// Minimum execution time: 19_304_000 picoseconds.
-		Weight::from_parts(20_000_000, 4556)
-			.saturating_add(RocksDbWeight::get().reads(2_u64))
+		//  Estimated: `8122`
+		// Minimum execution time: 24_622_000 picoseconds.
+		Weight::from_parts(25_220_000, 8122)
+			.saturating_add(RocksDbWeight::get().reads(3_u64))
 			.saturating_add(RocksDbWeight::get().writes(3_u64))
 	}
 	/// Storage: `Staking::ValidatorCount` (r:0 w:1)
@@ -1094,8 +1130,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_568_000 picoseconds.
-		Weight::from_parts(2_708_000, 0)
+		// Minimum execution time: 2_634_000 picoseconds.
+		Weight::from_parts(2_842_000, 0)
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::ForceEra` (r:0 w:1)
@@ -1104,8 +1140,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 7_950_000 picoseconds.
-		Weight::from_parts(8_348_000, 0)
+		// Minimum execution time: 8_496_000 picoseconds.
+		Weight::from_parts(9_016_000, 0)
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::ForceEra` (r:0 w:1)
@@ -1114,8 +1150,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 7_967_000 picoseconds.
-		Weight::from_parts(8_222_000, 0)
+		// Minimum execution time: 8_510_000 picoseconds.
+		Weight::from_parts(8_893_000, 0)
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::ForceEra` (r:0 w:1)
@@ -1124,8 +1160,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 8_006_000 picoseconds.
-		Weight::from_parts(8_440_000, 0)
+		// Minimum execution time: 8_243_000 picoseconds.
+		Weight::from_parts(8_678_000, 0)
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::Invulnerables` (r:0 w:1)
@@ -1135,30 +1171,30 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_524_000 picoseconds.
-		Weight::from_parts(3_123_608, 0)
-			// Standard Error: 59
-			.saturating_add(Weight::from_parts(11_596, 0).saturating_mul(v.into()))
+		// Minimum execution time: 2_781_000 picoseconds.
+		Weight::from_parts(3_441_708, 0)
+			// Standard Error: 58
+			.saturating_add(Weight::from_parts(11_811, 0).saturating_mul(v.into()))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
-	/// Storage: `Staking::Ledger` (r:5900 w:11800)
+	/// Storage: `Staking::Ledger` (r:11800 w:11800)
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:5900 w:5900)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Payee` (r:5900 w:0)
 	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::Bonded` (r:0 w:5900)
-	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
 	/// The range of component `i` is `[0, 5900]`.
 	fn deprecate_controller_batch(i: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1356 + i * (151 ±0)`
-		//  Estimated: `990 + i * (3566 ±0)`
-		// Minimum execution time: 2_092_000 picoseconds.
-		Weight::from_parts(2_258_000, 990)
-			// Standard Error: 32_695
-			.saturating_add(Weight::from_parts(16_669_219, 0).saturating_mul(i.into()))
-			.saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(i.into())))
+		//  Measured:  `1746 + i * (229 ±0)`
+		//  Estimated: `990 + i * (7132 ±0)`
+		// Minimum execution time: 5_331_000 picoseconds.
+		Weight::from_parts(5_511_000, 990)
+			// Standard Error: 66_734
+			.saturating_add(Weight::from_parts(31_157_413, 0).saturating_mul(i.into()))
+			.saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(i.into())))
 			.saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(i.into())))
-			.saturating_add(Weight::from_parts(0, 3566).saturating_mul(i.into()))
+			.saturating_add(Weight::from_parts(0, 7132).saturating_mul(i.into()))
 	}
 	/// Storage: `Staking::SlashingSpans` (r:1 w:1)
 	/// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -1193,10 +1229,10 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `2196 + s * (4 ±0)`
 		//  Estimated: `6248 + s * (4 ±0)`
-		// Minimum execution time: 84_275_000 picoseconds.
-		Weight::from_parts(92_512_416, 6248)
-			// Standard Error: 3_633
-			.saturating_add(Weight::from_parts(1_315_923, 0).saturating_mul(s.into()))
+		// Minimum execution time: 89_473_000 picoseconds.
+		Weight::from_parts(98_055_990, 6248)
+			// Standard Error: 4_159
+			.saturating_add(Weight::from_parts(1_398_203, 0).saturating_mul(s.into()))
 			.saturating_add(RocksDbWeight::get().reads(13_u64))
 			.saturating_add(RocksDbWeight::get().writes(12_u64))
 			.saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into())))
@@ -1209,10 +1245,10 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `66672`
 		//  Estimated: `70137`
-		// Minimum execution time: 101_707_000 picoseconds.
-		Weight::from_parts(912_819_462, 70137)
-			// Standard Error: 57_547
-			.saturating_add(Weight::from_parts(4_856_799, 0).saturating_mul(s.into()))
+		// Minimum execution time: 102_480_000 picoseconds.
+		Weight::from_parts(1_165_789_820, 70137)
+			// Standard Error: 77_157
+			.saturating_add(Weight::from_parts(6_489_253, 0).saturating_mul(s.into()))
 			.saturating_add(RocksDbWeight::get().reads(1_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -1249,10 +1285,10 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `33297 + n * (377 ±0)`
 		//  Estimated: `30944 + n * (3774 ±0)`
-		// Minimum execution time: 138_657_000 picoseconds.
-		Weight::from_parts(167_173_445, 30944)
-			// Standard Error: 25_130
-			.saturating_add(Weight::from_parts(44_566_012, 0).saturating_mul(n.into()))
+		// Minimum execution time: 156_890_000 picoseconds.
+		Weight::from_parts(202_972_688, 30944)
+			// Standard Error: 29_972
+			.saturating_add(Weight::from_parts(48_226_698, 0).saturating_mul(n.into()))
 			.saturating_add(RocksDbWeight::get().reads(14_u64))
 			.saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(n.into())))
 			.saturating_add(RocksDbWeight::get().writes(4_u64))
@@ -1276,10 +1312,10 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `1991 + l * (7 ±0)`
 		//  Estimated: `8877`
-		// Minimum execution time: 80_061_000 picoseconds.
-		Weight::from_parts(82_836_434, 8877)
-			// Standard Error: 4_348
-			.saturating_add(Weight::from_parts(75_744, 0).saturating_mul(l.into()))
+		// Minimum execution time: 88_482_000 picoseconds.
+		Weight::from_parts(92_616_600, 8877)
+			// Standard Error: 4_411
+			.saturating_add(Weight::from_parts(117_722, 0).saturating_mul(l.into()))
 			.saturating_add(RocksDbWeight::get().reads(9_u64))
 			.saturating_add(RocksDbWeight::get().writes(7_u64))
 	}
@@ -1314,10 +1350,10 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `2196 + s * (4 ±0)`
 		//  Estimated: `6248 + s * (4 ±0)`
-		// Minimum execution time: 92_560_000 picoseconds.
-		Weight::from_parts(97_684_741, 6248)
-			// Standard Error: 3_361
-			.saturating_add(Weight::from_parts(1_292_732, 0).saturating_mul(s.into()))
+		// Minimum execution time: 98_489_000 picoseconds.
+		Weight::from_parts(102_968_643, 6248)
+			// Standard Error: 4_823
+			.saturating_add(Weight::from_parts(1_420_838, 0).saturating_mul(s.into()))
 			.saturating_add(RocksDbWeight::get().reads(12_u64))
 			.saturating_add(RocksDbWeight::get().writes(11_u64))
 			.saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into())))
@@ -1363,12 +1399,12 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `0 + n * (720 ±0) + v * (3598 ±0)`
 		//  Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)`
-		// Minimum execution time: 564_963_000 picoseconds.
-		Weight::from_parts(569_206_000, 512390)
-			// Standard Error: 2_033_235
-			.saturating_add(Weight::from_parts(68_025_841, 0).saturating_mul(v.into()))
-			// Standard Error: 202_600
-			.saturating_add(Weight::from_parts(17_916_770, 0).saturating_mul(n.into()))
+		// Minimum execution time: 604_820_000 picoseconds.
+		Weight::from_parts(608_838_000, 512390)
+			// Standard Error: 2_300_345
+			.saturating_add(Weight::from_parts(72_980_573, 0).saturating_mul(v.into()))
+			// Standard Error: 229_216
+			.saturating_add(Weight::from_parts(20_739_416, 0).saturating_mul(n.into()))
 			.saturating_add(RocksDbWeight::get().reads(206_u64))
 			.saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into())))
 			.saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into())))
@@ -1399,12 +1435,12 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `3175 + n * (911 ±0) + v * (395 ±0)`
 		//  Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)`
-		// Minimum execution time: 32_196_540_000 picoseconds.
-		Weight::from_parts(32_341_871_000, 512390)
-			// Standard Error: 354_657
-			.saturating_add(Weight::from_parts(5_143_440, 0).saturating_mul(v.into()))
-			// Standard Error: 354_657
-			.saturating_add(Weight::from_parts(3_328_189, 0).saturating_mul(n.into()))
+		// Minimum execution time: 37_380_439_000 picoseconds.
+		Weight::from_parts(38_187_734_000, 512390)
+			// Standard Error: 425_319
+			.saturating_add(Weight::from_parts(6_001_288, 0).saturating_mul(v.into()))
+			// Standard Error: 425_319
+			.saturating_add(Weight::from_parts(4_129_446, 0).saturating_mul(n.into()))
 			.saturating_add(RocksDbWeight::get().reads(201_u64))
 			.saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into())))
 			.saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into())))
@@ -1421,10 +1457,10 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `979 + v * (50 ±0)`
 		//  Estimated: `3510 + v * (2520 ±0)`
-		// Minimum execution time: 2_381_903_000 picoseconds.
-		Weight::from_parts(32_693_059, 3510)
-			// Standard Error: 10_000
-			.saturating_add(Weight::from_parts(4_736_173, 0).saturating_mul(v.into()))
+		// Minimum execution time: 2_572_838_000 picoseconds.
+		Weight::from_parts(67_632_557, 3510)
+			// Standard Error: 12_028
+			.saturating_add(Weight::from_parts(5_117_459, 0).saturating_mul(v.into()))
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into())))
 			.saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into()))
@@ -1435,6 +1471,8 @@ impl WeightInfo for () {
 	/// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::MaxValidatorsCount` (r:0 w:1)
 	/// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::MaxStakedRewards` (r:0 w:1)
+	/// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::ChillThreshold` (r:0 w:1)
 	/// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::MaxNominatorsCount` (r:0 w:1)
@@ -1445,9 +1483,9 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 5_434_000 picoseconds.
-		Weight::from_parts(5_742_000, 0)
-			.saturating_add(RocksDbWeight::get().writes(6_u64))
+		// Minimum execution time: 5_962_000 picoseconds.
+		Weight::from_parts(6_497_000, 0)
+			.saturating_add(RocksDbWeight::get().writes(7_u64))
 	}
 	/// Storage: `Staking::MinCommission` (r:0 w:1)
 	/// Proof: `Staking::MinCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -1455,6 +1493,8 @@ impl WeightInfo for () {
 	/// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::MaxValidatorsCount` (r:0 w:1)
 	/// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::MaxStakedRewards` (r:0 w:1)
+	/// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::ChillThreshold` (r:0 w:1)
 	/// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::MaxNominatorsCount` (r:0 w:1)
@@ -1465,9 +1505,9 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 4_588_000 picoseconds.
-		Weight::from_parts(4_854_000, 0)
-			.saturating_add(RocksDbWeight::get().writes(6_u64))
+		// Minimum execution time: 5_227_000 picoseconds.
+		Weight::from_parts(5_496_000, 0)
+			.saturating_add(RocksDbWeight::get().writes(7_u64))
 	}
 	/// Storage: `Staking::Bonded` (r:1 w:0)
 	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
@@ -1495,8 +1535,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `1939`
 		//  Estimated: `6248`
-		// Minimum execution time: 68_780_000 picoseconds.
-		Weight::from_parts(71_479_000, 6248)
+		// Minimum execution time: 75_129_000 picoseconds.
+		Weight::from_parts(77_498_000, 6248)
 			.saturating_add(RocksDbWeight::get().reads(12_u64))
 			.saturating_add(RocksDbWeight::get().writes(6_u64))
 	}
@@ -1508,8 +1548,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `691`
 		//  Estimated: `3510`
-		// Minimum execution time: 12_268_000 picoseconds.
-		Weight::from_parts(12_661_000, 3510)
+		// Minimum execution time: 13_488_000 picoseconds.
+		Weight::from_parts(14_183_000, 3510)
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -1519,8 +1559,27 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 3_071_000 picoseconds.
-		Weight::from_parts(3_334_000, 0)
+		// Minimum execution time: 3_368_000 picoseconds.
+		Weight::from_parts(3_582_000, 0)
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
+	/// Storage: `Balances::Locks` (r:1 w:1)
+	/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
+	/// Storage: `System::Account` (r:1 w:1)
+	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Bonded` (r:1 w:1)
+	/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
+	/// Storage: `Staking::Ledger` (r:1 w:1)
+	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
+	/// Storage: `Balances::Freezes` (r:1 w:0)
+	/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`)
+	fn restore_ledger() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `1047`
+		//  Estimated: `4764`
+		// Minimum execution time: 44_876_000 picoseconds.
+		Weight::from_parts(46_353_000, 4764)
+			.saturating_add(RocksDbWeight::get().reads(5_u64))
+			.saturating_add(RocksDbWeight::get().writes(4_u64))
+	}
 }
diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs
index 1997d8fc223ef..24e7e1c8a65c2 100644
--- a/substrate/frame/support/src/traits.rs
+++ b/substrate/frame/support/src/traits.rs
@@ -22,8 +22,8 @@
 pub mod tokens;
 pub use tokens::{
 	currency::{
-		ActiveIssuanceOf, Currency, LockIdentifier, LockableCurrency, NamedReservableCurrency,
-		ReservableCurrency, TotalIssuanceOf, VestingSchedule,
+		ActiveIssuanceOf, Currency, InspectLockableCurrency, LockIdentifier, LockableCurrency,
+		NamedReservableCurrency, ReservableCurrency, TotalIssuanceOf, VestingSchedule,
 	},
 	fungible, fungibles,
 	imbalance::{Imbalance, OnUnbalanced, SignedImbalance},
diff --git a/substrate/frame/support/src/traits/schedule.rs b/substrate/frame/support/src/traits/schedule.rs
index 7a7d1357da1e7..f41c73fe69a88 100644
--- a/substrate/frame/support/src/traits/schedule.rs
+++ b/substrate/frame/support/src/traits/schedule.rs
@@ -130,7 +130,7 @@ impl<T: Decode, H> MaybeHashed<T, H> {
 	}
 }
 
-// TODO: deprecate
+#[deprecated(note = "Use `v3` instead. Will be removed after September 2024.")]
 pub mod v1 {
 	use super::*;
 
@@ -218,10 +218,12 @@ pub mod v1 {
 		fn next_dispatch_time(id: Vec<u8>) -> Result<BlockNumber, ()>;
 	}
 
+	#[allow(deprecated)]
 	impl<T, BlockNumber, Call, RuntimeOrigin> Anon<BlockNumber, Call, RuntimeOrigin> for T
 	where
 		T: v2::Anon<BlockNumber, Call, RuntimeOrigin>,
 	{
+		#[allow(deprecated)]
 		type Address = T::Address;
 
 		fn schedule(
@@ -232,10 +234,13 @@ pub mod v1 {
 			call: Call,
 		) -> Result<Self::Address, DispatchError> {
 			let c = MaybeHashed::<Call, T::Hash>::Value(call);
+
+			#[allow(deprecated)]
 			T::schedule(when, maybe_periodic, priority, origin, c)
 		}
 
 		fn cancel(address: Self::Address) -> Result<(), ()> {
+			#[allow(deprecated)]
 			T::cancel(address)
 		}
 
@@ -243,18 +248,22 @@ pub mod v1 {
 			address: Self::Address,
 			when: DispatchTime<BlockNumber>,
 		) -> Result<Self::Address, DispatchError> {
+			#[allow(deprecated)]
 			T::reschedule(address, when)
 		}
 
 		fn next_dispatch_time(address: Self::Address) -> Result<BlockNumber, ()> {
+			#[allow(deprecated)]
 			T::next_dispatch_time(address)
 		}
 	}
 
+	#[allow(deprecated)]
 	impl<T, BlockNumber, Call, RuntimeOrigin> Named<BlockNumber, Call, RuntimeOrigin> for T
 	where
 		T: v2::Named<BlockNumber, Call, RuntimeOrigin>,
 	{
+		#[allow(deprecated)]
 		type Address = T::Address;
 
 		fn schedule_named(
@@ -266,10 +275,12 @@ pub mod v1 {
 			call: Call,
 		) -> Result<Self::Address, ()> {
 			let c = MaybeHashed::<Call, T::Hash>::Value(call);
+			#[allow(deprecated)]
 			T::schedule_named(id, when, maybe_periodic, priority, origin, c)
 		}
 
 		fn cancel_named(id: Vec<u8>) -> Result<(), ()> {
+			#[allow(deprecated)]
 			T::cancel_named(id)
 		}
 
@@ -277,16 +288,18 @@ pub mod v1 {
 			id: Vec<u8>,
 			when: DispatchTime<BlockNumber>,
 		) -> Result<Self::Address, DispatchError> {
+			#[allow(deprecated)]
 			T::reschedule_named(id, when)
 		}
 
 		fn next_dispatch_time(id: Vec<u8>) -> Result<BlockNumber, ()> {
+			#[allow(deprecated)]
 			T::next_dispatch_time(id)
 		}
 	}
 }
 
-// TODO: deprecate
+#[deprecated(note = "Use `v3` instead. Will be removed after September 2024.")]
 pub mod v2 {
 	use super::*;
 
@@ -478,4 +491,5 @@ pub mod v3 {
 	}
 }
 
+#[allow(deprecated)]
 pub use v1::*;
diff --git a/substrate/frame/support/src/traits/tokens/currency.rs b/substrate/frame/support/src/traits/tokens/currency.rs
index 8b773115011de..282e7f6447330 100644
--- a/substrate/frame/support/src/traits/tokens/currency.rs
+++ b/substrate/frame/support/src/traits/tokens/currency.rs
@@ -27,7 +27,7 @@ use sp_runtime::{traits::MaybeSerializeDeserialize, DispatchError};
 mod reservable;
 pub use reservable::{NamedReservableCurrency, ReservableCurrency};
 mod lockable;
-pub use lockable::{LockIdentifier, LockableCurrency, VestingSchedule};
+pub use lockable::{InspectLockableCurrency, LockIdentifier, LockableCurrency, VestingSchedule};
 
 /// Abstraction over a fungible assets system.
 pub trait Currency<AccountId> {
diff --git a/substrate/frame/support/src/traits/tokens/currency/lockable.rs b/substrate/frame/support/src/traits/tokens/currency/lockable.rs
index 955814f5aa9de..51a48dd15ce85 100644
--- a/substrate/frame/support/src/traits/tokens/currency/lockable.rs
+++ b/substrate/frame/support/src/traits/tokens/currency/lockable.rs
@@ -64,6 +64,12 @@ pub trait LockableCurrency<AccountId>: Currency<AccountId> {
 	fn remove_lock(id: LockIdentifier, who: &AccountId);
 }
 
+/// A inspect interface for a currency whose accounts can have liquidity restrictions.
+pub trait InspectLockableCurrency<AccountId>: LockableCurrency<AccountId> {
+	/// Amount of funds locked for `who` associated with `id`.
+	fn balance_locked(id: LockIdentifier, who: &AccountId) -> Self::Balance;
+}
+
 /// A vesting schedule over a currency. This allows a particular currency to have vesting limits
 /// applied to it.
 pub trait VestingSchedule<AccountId> {
diff --git a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs
index b7e5600a017a9..87a381fd7bf92 100644
--- a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs
+++ b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs
@@ -797,7 +797,7 @@ fn generate_runtime_api_versions(impls: &[ItemImpl]) -> Result<TokenStream> {
 	}
 
 	Ok(quote!(
-		const RUNTIME_API_VERSIONS: #c::ApisVec = #c::create_apis_vec!([ #( #result ),* ]);
+		pub const RUNTIME_API_VERSIONS: #c::ApisVec = #c::create_apis_vec!([ #( #result ),* ]);
 
 		#( #sections )*
 	))
diff --git a/templates/parachain/node/src/service.rs b/templates/parachain/node/src/service.rs
index 4dd24803e9b12..bb4a539495870 100644
--- a/templates/parachain/node/src/service.rs
+++ b/templates/parachain/node/src/service.rs
@@ -6,8 +6,8 @@ use std::{sync::Arc, time::Duration};
 use cumulus_client_cli::CollatorOptions;
 // Local Runtime Types
 use parachain_template_runtime::{
+	apis::RuntimeApi,
 	opaque::{Block, Hash},
-	RuntimeApi,
 };
 
 // Cumulus Imports
@@ -46,7 +46,7 @@ impl sc_executor::NativeExecutionDispatch for ParachainNativeExecutor {
 	);
 
 	fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
-		parachain_template_runtime::api::dispatch(method, data)
+		parachain_template_runtime::apis::api::dispatch(method, data)
 	}
 
 	fn native_version() -> sc_executor::NativeVersion {
diff --git a/templates/parachain/runtime/src/apis.rs b/templates/parachain/runtime/src/apis.rs
new file mode 100644
index 0000000000000..aa0cae843c378
--- /dev/null
+++ b/templates/parachain/runtime/src/apis.rs
@@ -0,0 +1,275 @@
+// This is free and unencumbered software released into the public domain.
+//
+// Anyone is free to copy, modify, publish, use, compile, sell, or
+// distribute this software, either in source code form or as a compiled
+// binary, for any purpose, commercial or non-commercial, and by any
+// means.
+//
+// In jurisdictions that recognize copyright laws, the author or authors
+// of this software dedicate any and all copyright interest in the
+// software to the public domain. We make this dedication for the benefit
+// of the public at large and to the detriment of our heirs and
+// successors. We intend this dedication to be an overt act of
+// relinquishment in perpetuity of all present and future rights to this
+// software under copyright law.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+// For more information, please refer to <http://unlicense.org>
+
+// External crates imports
+use frame_support::{
+	genesis_builder_helper::{build_config, create_default_config},
+	weights::Weight,
+};
+use pallet_aura::Authorities;
+use sp_api::impl_runtime_apis;
+use sp_consensus_aura::sr25519::AuthorityId as AuraId;
+use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
+use sp_runtime::{
+	traits::Block as BlockT,
+	transaction_validity::{TransactionSource, TransactionValidity},
+	ApplyExtrinsicResult,
+};
+use sp_std::prelude::Vec;
+use sp_version::RuntimeVersion;
+
+// Local module imports
+use super::{
+	AccountId, Aura, Balance, Block, Executive, InherentDataExt, Nonce, ParachainSystem, Runtime,
+	RuntimeCall, RuntimeGenesisConfig, SessionKeys, System, TransactionPayment, VERSION,
+};
+
+impl_runtime_apis! {
+	impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
+		fn slot_duration() -> sp_consensus_aura::SlotDuration {
+			sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration())
+		}
+
+		fn authorities() -> Vec<AuraId> {
+			Authorities::<Runtime>::get().into_inner()
+		}
+	}
+
+	impl sp_api::Core<Block> for Runtime {
+		fn version() -> RuntimeVersion {
+			VERSION
+		}
+
+		fn execute_block(block: Block) {
+			Executive::execute_block(block)
+		}
+
+		fn initialize_block(header: &<Block as BlockT>::Header) -> sp_runtime::ExtrinsicInclusionMode {
+			Executive::initialize_block(header)
+		}
+	}
+
+	impl sp_api::Metadata<Block> for Runtime {
+		fn metadata() -> OpaqueMetadata {
+			OpaqueMetadata::new(Runtime::metadata().into())
+		}
+
+		fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
+			Runtime::metadata_at_version(version)
+		}
+
+		fn metadata_versions() -> sp_std::vec::Vec<u32> {
+			Runtime::metadata_versions()
+		}
+	}
+
+	impl sp_block_builder::BlockBuilder<Block> for Runtime {
+		fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
+			Executive::apply_extrinsic(extrinsic)
+		}
+
+		fn finalize_block() -> <Block as BlockT>::Header {
+			Executive::finalize_block()
+		}
+
+		fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
+			data.create_extrinsics()
+		}
+
+		fn check_inherents(
+			block: Block,
+			data: sp_inherents::InherentData,
+		) -> sp_inherents::CheckInherentsResult {
+			data.check_extrinsics(&block)
+		}
+	}
+
+	impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
+		fn validate_transaction(
+			source: TransactionSource,
+			tx: <Block as BlockT>::Extrinsic,
+			block_hash: <Block as BlockT>::Hash,
+		) -> TransactionValidity {
+			Executive::validate_transaction(source, tx, block_hash)
+		}
+	}
+
+	impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
+		fn offchain_worker(header: &<Block as BlockT>::Header) {
+			Executive::offchain_worker(header)
+		}
+	}
+
+	impl sp_session::SessionKeys<Block> for Runtime {
+		fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
+			SessionKeys::generate(seed)
+		}
+
+		fn decode_session_keys(
+			encoded: Vec<u8>,
+		) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
+			SessionKeys::decode_into_raw_public_keys(&encoded)
+		}
+	}
+
+	impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce> for Runtime {
+		fn account_nonce(account: AccountId) -> Nonce {
+			System::account_nonce(account)
+		}
+	}
+
+	impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime {
+		fn query_info(
+			uxt: <Block as BlockT>::Extrinsic,
+			len: u32,
+		) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
+			TransactionPayment::query_info(uxt, len)
+		}
+		fn query_fee_details(
+			uxt: <Block as BlockT>::Extrinsic,
+			len: u32,
+		) -> pallet_transaction_payment::FeeDetails<Balance> {
+			TransactionPayment::query_fee_details(uxt, len)
+		}
+		fn query_weight_to_fee(weight: Weight) -> Balance {
+			TransactionPayment::weight_to_fee(weight)
+		}
+		fn query_length_to_fee(length: u32) -> Balance {
+			TransactionPayment::length_to_fee(length)
+		}
+	}
+
+	impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi<Block, Balance, RuntimeCall>
+		for Runtime
+	{
+		fn query_call_info(
+			call: RuntimeCall,
+			len: u32,
+		) -> pallet_transaction_payment::RuntimeDispatchInfo<Balance> {
+			TransactionPayment::query_call_info(call, len)
+		}
+		fn query_call_fee_details(
+			call: RuntimeCall,
+			len: u32,
+		) -> pallet_transaction_payment::FeeDetails<Balance> {
+			TransactionPayment::query_call_fee_details(call, len)
+		}
+		fn query_weight_to_fee(weight: Weight) -> Balance {
+			TransactionPayment::weight_to_fee(weight)
+		}
+		fn query_length_to_fee(length: u32) -> Balance {
+			TransactionPayment::length_to_fee(length)
+		}
+	}
+
+	impl cumulus_primitives_core::CollectCollationInfo<Block> for Runtime {
+		fn collect_collation_info(header: &<Block as BlockT>::Header) -> cumulus_primitives_core::CollationInfo {
+			ParachainSystem::collect_collation_info(header)
+		}
+	}
+
+	#[cfg(feature = "try-runtime")]
+	impl frame_try_runtime::TryRuntime<Block> for Runtime {
+		fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) {
+			use super::RuntimeBlockWeights;
+
+			let weight = Executive::try_runtime_upgrade(checks).unwrap();
+			(weight, RuntimeBlockWeights::get().max_block)
+		}
+
+		fn execute_block(
+			block: Block,
+			state_root_check: bool,
+			signature_check: bool,
+			select: frame_try_runtime::TryStateSelect,
+		) -> Weight {
+			// NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to
+			// have a backtrace here.
+			Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap()
+		}
+	}
+
+	#[cfg(feature = "runtime-benchmarks")]
+	impl frame_benchmarking::Benchmark<Block> for Runtime {
+		fn benchmark_metadata(extra: bool) -> (
+			Vec<frame_benchmarking::BenchmarkList>,
+			Vec<frame_support::traits::StorageInfo>,
+		) {
+			use frame_benchmarking::{Benchmarking, BenchmarkList};
+			use frame_support::traits::StorageInfoTrait;
+			use frame_system_benchmarking::Pallet as SystemBench;
+			use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
+			use super::*;
+
+			let mut list = Vec::<BenchmarkList>::new();
+			list_benchmarks!(list, extra);
+
+			let storage_info = AllPalletsWithSystem::storage_info();
+			(list, storage_info)
+		}
+
+		fn dispatch_benchmark(
+			config: frame_benchmarking::BenchmarkConfig
+		) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, sp_runtime::RuntimeString> {
+			use frame_benchmarking::{BenchmarkError, Benchmarking, BenchmarkBatch};
+			use super::*;
+
+			use frame_system_benchmarking::Pallet as SystemBench;
+			impl frame_system_benchmarking::Config for Runtime {
+				fn setup_set_code_requirements(code: &sp_std::vec::Vec<u8>) -> Result<(), BenchmarkError> {
+					ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32);
+					Ok(())
+				}
+
+				fn verify_set_code() {
+					System::assert_last_event(cumulus_pallet_parachain_system::Event::<Runtime>::ValidationFunctionStored.into());
+				}
+			}
+
+			use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
+			impl cumulus_pallet_session_benchmarking::Config for Runtime {}
+
+			use frame_support::traits::WhitelistedStorageKeys;
+			let whitelist = AllPalletsWithSystem::whitelisted_storage_keys();
+
+			let mut batches = Vec::<BenchmarkBatch>::new();
+			let params = (&config, &whitelist);
+			add_benchmarks!(params, batches);
+
+			if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
+			Ok(batches)
+		}
+	}
+
+	impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
+		fn create_default_config() -> Vec<u8> {
+			create_default_config::<RuntimeGenesisConfig>()
+		}
+
+		fn build_config(config: Vec<u8>) -> sp_genesis_builder::Result {
+			build_config::<RuntimeGenesisConfig>(config)
+		}
+	}
+}
diff --git a/templates/parachain/runtime/src/lib.rs b/templates/parachain/runtime/src/lib.rs
index ad21b79a5b1ba..5cfee123b01b4 100644
--- a/templates/parachain/runtime/src/lib.rs
+++ b/templates/parachain/runtime/src/lib.rs
@@ -6,19 +6,17 @@
 #[cfg(feature = "std")]
 include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
 
+pub mod apis;
 mod weights;
 pub mod xcm_config;
 
 use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases;
 use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery;
 use smallvec::smallvec;
-use sp_api::impl_runtime_apis;
-use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
 use sp_runtime::{
 	create_runtime_str, generic, impl_opaque_keys,
-	traits::{BlakeTwo256, Block as BlockT, IdentifyAccount, Verify},
-	transaction_validity::{TransactionSource, TransactionValidity},
-	ApplyExtrinsicResult, MultiSignature,
+	traits::{BlakeTwo256, IdentifyAccount, Verify},
+	MultiSignature,
 };
 
 use sp_std::prelude::*;
@@ -30,7 +28,6 @@ use cumulus_primitives_core::{AggregateMessageOrigin, ParaId};
 use frame_support::{
 	construct_runtime, derive_impl,
 	dispatch::DispatchClass,
-	genesis_builder_helper::{build_config, create_default_config},
 	parameter_types,
 	traits::{ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, TransformOrigin},
 	weights::{
@@ -57,8 +54,6 @@ use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate};
 
 use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight};
 
-use pallet_aura::Authorities;
-
 // XCM Imports
 use xcm::latest::prelude::BodyId;
 
@@ -187,7 +182,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
 	authoring_version: 1,
 	spec_version: 1,
 	impl_version: 0,
-	apis: RUNTIME_API_VERSIONS,
+	apis: apis::RUNTIME_API_VERSIONS,
 	transaction_version: 1,
 	state_version: 1,
 };
@@ -414,6 +409,7 @@ impl pallet_message_queue::Config for Runtime {
 	type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
 	type MaxStale = sp_core::ConstU32<8>;
 	type ServiceWeight = MessageQueueServiceWeight;
+	type IdleMaxServiceWeight = ();
 }
 
 impl cumulus_pallet_aura_ext::Config for Runtime {}
@@ -542,230 +538,6 @@ mod benches {
 	);
 }
 
-impl_runtime_apis! {
-	impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
-		fn slot_duration() -> sp_consensus_aura::SlotDuration {
-			sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration())
-		}
-
-		fn authorities() -> Vec<AuraId> {
-			Authorities::<Runtime>::get().into_inner()
-		}
-	}
-
-	impl sp_api::Core<Block> for Runtime {
-		fn version() -> RuntimeVersion {
-			VERSION
-		}
-
-		fn execute_block(block: Block) {
-			Executive::execute_block(block)
-		}
-
-		fn initialize_block(header: &<Block as BlockT>::Header) -> sp_runtime::ExtrinsicInclusionMode {
-			Executive::initialize_block(header)
-		}
-	}
-
-	impl sp_api::Metadata<Block> for Runtime {
-		fn metadata() -> OpaqueMetadata {
-			OpaqueMetadata::new(Runtime::metadata().into())
-		}
-
-		fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
-			Runtime::metadata_at_version(version)
-		}
-
-		fn metadata_versions() -> sp_std::vec::Vec<u32> {
-			Runtime::metadata_versions()
-		}
-	}
-
-	impl sp_block_builder::BlockBuilder<Block> for Runtime {
-		fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
-			Executive::apply_extrinsic(extrinsic)
-		}
-
-		fn finalize_block() -> <Block as BlockT>::Header {
-			Executive::finalize_block()
-		}
-
-		fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
-			data.create_extrinsics()
-		}
-
-		fn check_inherents(
-			block: Block,
-			data: sp_inherents::InherentData,
-		) -> sp_inherents::CheckInherentsResult {
-			data.check_extrinsics(&block)
-		}
-	}
-
-	impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
-		fn validate_transaction(
-			source: TransactionSource,
-			tx: <Block as BlockT>::Extrinsic,
-			block_hash: <Block as BlockT>::Hash,
-		) -> TransactionValidity {
-			Executive::validate_transaction(source, tx, block_hash)
-		}
-	}
-
-	impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
-		fn offchain_worker(header: &<Block as BlockT>::Header) {
-			Executive::offchain_worker(header)
-		}
-	}
-
-	impl sp_session::SessionKeys<Block> for Runtime {
-		fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
-			SessionKeys::generate(seed)
-		}
-
-		fn decode_session_keys(
-			encoded: Vec<u8>,
-		) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
-			SessionKeys::decode_into_raw_public_keys(&encoded)
-		}
-	}
-
-	impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce> for Runtime {
-		fn account_nonce(account: AccountId) -> Nonce {
-			System::account_nonce(account)
-		}
-	}
-
-	impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime {
-		fn query_info(
-			uxt: <Block as BlockT>::Extrinsic,
-			len: u32,
-		) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
-			TransactionPayment::query_info(uxt, len)
-		}
-		fn query_fee_details(
-			uxt: <Block as BlockT>::Extrinsic,
-			len: u32,
-		) -> pallet_transaction_payment::FeeDetails<Balance> {
-			TransactionPayment::query_fee_details(uxt, len)
-		}
-		fn query_weight_to_fee(weight: Weight) -> Balance {
-			TransactionPayment::weight_to_fee(weight)
-		}
-		fn query_length_to_fee(length: u32) -> Balance {
-			TransactionPayment::length_to_fee(length)
-		}
-	}
-
-	impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi<Block, Balance, RuntimeCall>
-		for Runtime
-	{
-		fn query_call_info(
-			call: RuntimeCall,
-			len: u32,
-		) -> pallet_transaction_payment::RuntimeDispatchInfo<Balance> {
-			TransactionPayment::query_call_info(call, len)
-		}
-		fn query_call_fee_details(
-			call: RuntimeCall,
-			len: u32,
-		) -> pallet_transaction_payment::FeeDetails<Balance> {
-			TransactionPayment::query_call_fee_details(call, len)
-		}
-		fn query_weight_to_fee(weight: Weight) -> Balance {
-			TransactionPayment::weight_to_fee(weight)
-		}
-		fn query_length_to_fee(length: u32) -> Balance {
-			TransactionPayment::length_to_fee(length)
-		}
-	}
-
-	impl cumulus_primitives_core::CollectCollationInfo<Block> for Runtime {
-		fn collect_collation_info(header: &<Block as BlockT>::Header) -> cumulus_primitives_core::CollationInfo {
-			ParachainSystem::collect_collation_info(header)
-		}
-	}
-
-	#[cfg(feature = "try-runtime")]
-	impl frame_try_runtime::TryRuntime<Block> for Runtime {
-		fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) {
-			let weight = Executive::try_runtime_upgrade(checks).unwrap();
-			(weight, RuntimeBlockWeights::get().max_block)
-		}
-
-		fn execute_block(
-			block: Block,
-			state_root_check: bool,
-			signature_check: bool,
-			select: frame_try_runtime::TryStateSelect,
-		) -> Weight {
-			// NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to
-			// have a backtrace here.
-			Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap()
-		}
-	}
-
-	#[cfg(feature = "runtime-benchmarks")]
-	impl frame_benchmarking::Benchmark<Block> for Runtime {
-		fn benchmark_metadata(extra: bool) -> (
-			Vec<frame_benchmarking::BenchmarkList>,
-			Vec<frame_support::traits::StorageInfo>,
-		) {
-			use frame_benchmarking::{Benchmarking, BenchmarkList};
-			use frame_support::traits::StorageInfoTrait;
-			use frame_system_benchmarking::Pallet as SystemBench;
-			use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
-
-			let mut list = Vec::<BenchmarkList>::new();
-			list_benchmarks!(list, extra);
-
-			let storage_info = AllPalletsWithSystem::storage_info();
-			(list, storage_info)
-		}
-
-		fn dispatch_benchmark(
-			config: frame_benchmarking::BenchmarkConfig
-		) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, sp_runtime::RuntimeString> {
-			use frame_benchmarking::{BenchmarkError, Benchmarking, BenchmarkBatch};
-
-			use frame_system_benchmarking::Pallet as SystemBench;
-			impl frame_system_benchmarking::Config for Runtime {
-				fn setup_set_code_requirements(code: &sp_std::vec::Vec<u8>) -> Result<(), BenchmarkError> {
-					ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32);
-					Ok(())
-				}
-
-				fn verify_set_code() {
-					System::assert_last_event(cumulus_pallet_parachain_system::Event::<Runtime>::ValidationFunctionStored.into());
-				}
-			}
-
-			use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
-			impl cumulus_pallet_session_benchmarking::Config for Runtime {}
-
-			use frame_support::traits::WhitelistedStorageKeys;
-			let whitelist = AllPalletsWithSystem::whitelisted_storage_keys();
-
-			let mut batches = Vec::<BenchmarkBatch>::new();
-			let params = (&config, &whitelist);
-			add_benchmarks!(params, batches);
-
-			if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
-			Ok(batches)
-		}
-	}
-
-	impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
-		fn create_default_config() -> Vec<u8> {
-			create_default_config::<RuntimeGenesisConfig>()
-		}
-
-		fn build_config(config: Vec<u8>) -> sp_genesis_builder::Result {
-			build_config::<RuntimeGenesisConfig>(config)
-		}
-	}
-}
-
 cumulus_pallet_parachain_system::register_validate_block! {
 	Runtime = Runtime,
 	BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,

From c7855fbffb8c60901ab8ed3f846dc38df660b18a Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Thu, 28 Mar 2024 13:16:37 +0100
Subject: [PATCH 195/202] add virtual nominator storage

---
 substrate/frame/staking/src/pallet/mod.rs | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index 6b0df8ffcb913..3b7279673d50e 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -387,6 +387,16 @@ pub mod pallet {
 	pub type Nominators<T: Config> =
 		CountedStorageMap<_, Twox64Concat, T::AccountId, Nominations<T>>;
 
+	/// Nominators whose funds are managed by other pallets.
+	///
+	/// This pallet does not apply any locks on them, hence they are only virtually bonded. These
+	/// nominators should not be allowed to mutate their ledger directly via application code and
+	/// can only be accessed via low level functions made available by this pallet.
+	// TODO(ank4n): Can we keep this entry in `Ledger`?
+	#[pallet::storage]
+	pub type VirtualNominators<T: Config> =
+	CountedStorageMap<_, Twox64Concat, T::AccountId, ()>;
+
 	/// The maximum nominator count before we stop allowing new validators to join.
 	///
 	/// When this value is not set, no limits are enforced.

From 71e7947a5a9862f0291d4f9e27b4af4e1be5889a Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 29 Mar 2024 04:42:34 +0100
Subject: [PATCH 196/202] add StakingUnsafe

---
 .../frame/delegated-staking/src/impls.rs      |  4 ----
 substrate/frame/delegated-staking/src/lib.rs  |  8 ++++---
 substrate/frame/nomination-pools/src/mock.rs  |  4 ----
 substrate/frame/staking/src/ledger.rs         |  4 ++--
 substrate/frame/staking/src/pallet/impls.rs   | 14 +++++++++--
 substrate/frame/staking/src/pallet/mod.rs     |  3 +--
 substrate/primitives/staking/src/lib.rs       | 23 +++++++++++++++----
 7 files changed, 38 insertions(+), 22 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index caf6b9aa4281e..3350e8b1aa3e7 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -165,10 +165,6 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		T::CoreStaking::slash_reward_fraction()
 	}
 
-	fn unsafe_release_all(_who: &Self::AccountId) {
-		defensive_assert!(false, "unsafe_release_all is not supported");
-	}
-
 	#[cfg(feature = "runtime-benchmarks")]
 	fn max_exposure_page_size() -> sp_staking::Page {
 		T::CoreStaking::max_exposure_page_size()
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 60eabb005c995..dcc5ca3e86167 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -179,7 +179,9 @@ use sp_runtime::{
 	traits::{AccountIdConversion, CheckedAdd, CheckedSub, Zero},
 	ArithmeticError, DispatchResult, Perbill, RuntimeDebug, Saturating,
 };
-use sp_staking::{delegation::DelegateeSupport, EraIndex, Stake, StakerStatus, StakingInterface};
+use sp_staking::{
+	delegation::DelegateeSupport, EraIndex, Stake, StakerStatus, StakingInterface, StakingUnsafe,
+};
 use sp_std::{convert::TryInto, prelude::*};
 
 pub type BalanceOf<T> =
@@ -215,7 +217,7 @@ pub mod pallet {
 		type RuntimeHoldReason: From<HoldReason>;
 
 		/// Core staking implementation.
-		type CoreStaking: StakingInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
+		type CoreStaking: StakingUnsafe<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
 	}
 
 	#[pallet::error]
@@ -519,7 +521,7 @@ impl<T: Config> Pallet<T> {
 		let stake = T::CoreStaking::stake(who)?;
 
 		// release funds from core staking.
-		T::CoreStaking::unsafe_release_all(who);
+		T::CoreStaking::force_release(who);
 
 		// transferring just released staked amount. This should never fail but if it does, it
 		// indicates bad state and we abort.
diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs
index 697a067cf4de9..5e2303284bfda 100644
--- a/substrate/frame/nomination-pools/src/mock.rs
+++ b/substrate/frame/nomination-pools/src/mock.rs
@@ -224,10 +224,6 @@ impl sp_staking::StakingInterface for StakingMock {
 	fn slash_reward_fraction() -> Perbill {
 		unimplemented!("method currently not used in testing")
 	}
-
-	fn unsafe_release_all(_who: &Self::AccountId) {
-		unimplemented!("method currently not used in testing")
-	}
 }
 
 #[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs
index e91a398819ebd..abbc5d4440ac2 100644
--- a/substrate/frame/staking/src/ledger.rs
+++ b/substrate/frame/staking/src/ledger.rs
@@ -32,7 +32,7 @@
 //! state consistency.
 
 use frame_support::{defensive, ensure, traits::Defensive};
-use sp_staking::{StakingAccount, StakingInterface};
+use sp_staking::{StakingAccount, StakingUnsafe};
 use sp_std::prelude::*;
 
 use crate::{
@@ -252,7 +252,7 @@ impl<T: Config> StakingLedger<T> {
 		let controller = <Bonded<T>>::get(stash).ok_or(Error::<T>::NotStash)?;
 
 		<Ledger<T>>::get(&controller).ok_or(Error::<T>::NotController).map(|ledger| {
-			Pallet::<T>::unsafe_release_all(&ledger.stash);
+			Pallet::<T>::force_release(&ledger.stash);
 			Ledger::<T>::remove(controller);
 
 			<Bonded<T>>::remove(&stash);
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 887af37ae638f..ad852b20445e3 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -44,7 +44,7 @@ use sp_staking::{
 	offence::{DisableStrategy, OffenceDetails, OnOffenceHandler},
 	EraIndex, OnStakingUpdate, Page, SessionIndex, Stake,
 	StakingAccount::{self, Controller, Stash},
-	StakingInterface,
+	StakingInterface, StakingUnsafe,
 };
 use sp_std::prelude::*;
 
@@ -1899,10 +1899,20 @@ impl<T: Config> StakingInterface for Pallet<T> {
 	fn slash_reward_fraction() -> Perbill {
 		SlashRewardFraction::<T>::get()
 	}
+}
 
-	fn unsafe_release_all(who: &Self::AccountId) {
+impl<T: Config> StakingUnsafe for Pallet<T> {
+	fn force_release(who: &Self::AccountId) {
 		T::Currency::remove_lock(crate::STAKING_ID, who)
 	}
+
+	fn virtual_bond(
+		who: &Self::AccountId,
+		value: Self::Balance,
+		payee: &Self::AccountId,
+	) -> DispatchResult {
+		unimplemented!()
+	}
 }
 
 /// Standard implementation of `DelegateeSupport` that supports only direct staking and no
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index 3b7279673d50e..743febd408b82 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -394,8 +394,7 @@ pub mod pallet {
 	/// can only be accessed via low level functions made available by this pallet.
 	// TODO(ank4n): Can we keep this entry in `Ledger`?
 	#[pallet::storage]
-	pub type VirtualNominators<T: Config> =
-	CountedStorageMap<_, Twox64Concat, T::AccountId, ()>;
+	pub type VirtualNominators<T: Config> = CountedStorageMap<_, Twox64Concat, T::AccountId, ()>;
 
 	/// The maximum nominator count before we stop allowing new validators to join.
 	///
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 65326b7e36a95..6ea45e2f3e643 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -295,11 +295,6 @@ pub trait StakingInterface {
 	/// Returns the fraction of the slash to be rewarded to reporter.
 	fn slash_reward_fraction() -> Perbill;
 
-	/// Release all funds bonded for stake.
-	///
-	/// Unsafe, only used for migration of `delegatee` accounts.
-	fn unsafe_release_all(who: &Self::AccountId);
-
 	#[cfg(feature = "runtime-benchmarks")]
 	fn max_exposure_page_size() -> Page;
 
@@ -314,6 +309,24 @@ pub trait StakingInterface {
 	fn set_current_era(era: EraIndex);
 }
 
+/// Set of low level apis to manipulate staking ledger.
+///
+/// This is a low level api and should be used if you know what you are doing.
+pub trait StakingUnsafe: StakingInterface {
+	/// Release all funds bonded for stake without unbonding the ledger.
+	///
+	/// Unsafe, only used for migration of `nominator` to `virtual_nominator`.
+	fn force_release(who: &Self::AccountId);
+
+	/// Book-keep a new bond for `who` without applying any locks (hence virtual).
+	///
+	/// Caller is responsible for ensuring the passed amount is locked and valid.
+	fn virtual_bond(
+		who: &Self::AccountId,
+		value: Self::Balance,
+		payee: &Self::AccountId,
+	) -> DispatchResult;
+}
 /// The amount of exposure for an era that an individual nominator has (susceptible to slashing).
 #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
 pub struct IndividualExposure<AccountId, Balance: HasCompact> {

From 9ad65b37f39f033e9cfdf7e74e794a07a40e17cb Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 29 Mar 2024 05:53:07 +0100
Subject: [PATCH 197/202] impl bond_extra

---
 .../frame/delegated-staking/src/impls.rs      |  2 +-
 substrate/frame/delegated-staking/src/lib.rs  |  2 +-
 substrate/frame/staking/src/ledger.rs         |  6 +-
 substrate/frame/staking/src/lib.rs            | 15 ----
 substrate/frame/staking/src/pallet/impls.rs   | 85 ++++++++++++++++---
 substrate/frame/staking/src/pallet/mod.rs     | 25 +-----
 substrate/frame/staking/src/slashing.rs       |  2 +-
 substrate/primitives/staking/src/lib.rs       |  3 +-
 8 files changed, 81 insertions(+), 59 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 3350e8b1aa3e7..610a0a33142db 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -94,7 +94,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		ensure!(delegatee.available_to_bond() >= value, Error::<T>::NotEnoughFunds);
 		ensure!(delegatee.ledger.payee == *payee, Error::<T>::InvalidRewardDestination);
 
-		T::CoreStaking::bond(who, value, payee)
+		T::CoreStaking::virtual_bond(who, value, payee)
 	}
 
 	fn nominate(who: &Self::AccountId, validators: Vec<Self::AccountId>) -> DispatchResult {
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index dcc5ca3e86167..618c20c2f976a 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -544,7 +544,7 @@ impl<T: Config> Pallet<T> {
 		if delegatee.is_bonded() {
 			T::CoreStaking::bond_extra(&delegatee.key, amount)
 		} else {
-			T::CoreStaking::bond(&delegatee.key, amount, &delegatee.reward_account())
+			T::CoreStaking::virtual_bond(&delegatee.key, amount, &delegatee.reward_account())
 		}
 	}
 
diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs
index abbc5d4440ac2..a0907f77e014a 100644
--- a/substrate/frame/staking/src/ledger.rs
+++ b/substrate/frame/staking/src/ledger.rs
@@ -178,7 +178,7 @@ impl<T: Config> StakingLedger<T> {
 			return Err(Error::<T>::NotStash)
 		}
 
-		Pallet::<T>::update_hold(&self.stash, self.total).map_err(|_| Error::<T>::BadState)?;
+		Pallet::<T>::update_lock(&self.stash, self.total).map_err(|_| Error::<T>::BadState)?;
 
 		Ledger::<T>::insert(
 			&self.controller().ok_or_else(|| {
@@ -199,7 +199,7 @@ impl<T: Config> StakingLedger<T> {
 			return Err(Error::<T>::AlreadyBonded);
 		}
 
-		if Pallet::<T>::restrict_reward_destination(&self.stash, payee.clone().from(&self.stash)) {
+		if Pallet::<T>::restrict_reward_destination(&self.stash, payee.clone()) {
 			return Err(Error::<T>::RewardDestinationRestricted);
 		}
 
@@ -214,7 +214,7 @@ impl<T: Config> StakingLedger<T> {
 			return Err(Error::<T>::NotStash);
 		}
 
-		if Pallet::<T>::restrict_reward_destination(&self.stash, payee.clone().from(&self.stash)) {
+		if Pallet::<T>::restrict_reward_destination(&self.stash, payee.clone()) {
 			return Err(Error::<T>::RewardDestinationRestricted);
 		}
 
diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs
index 9a4386086aa6c..2e69881dbee70 100644
--- a/substrate/frame/staking/src/lib.rs
+++ b/substrate/frame/staking/src/lib.rs
@@ -413,21 +413,6 @@ pub enum RewardDestination<AccountId> {
 	None,
 }
 
-impl<AccountId: Clone> RewardDestination<AccountId> {
-	fn from(self, stash: &AccountId) -> Option<AccountId> {
-		match self {
-			// FIXME(ank4n): Figure out later how to handle Controller
-			RewardDestination::Staked | RewardDestination::Stash => Some(stash.clone()),
-			RewardDestination::Account(a) => Some(a),
-			#[allow(deprecated)]
-			_ => {
-				defensive!("reward destination not set or set as deprecated controller");
-				None
-			},
-		}
-	}
-}
-
 /// Preference of what happens regarding validation.
 #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, Default, MaxEncodedLen)]
 pub struct ValidatorPrefs {
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index ad852b20445e3..1c1ad3820b733 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -35,7 +35,9 @@ use frame_support::{
 use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin};
 use pallet_session::historical;
 use sp_runtime::{
-	traits::{Bounded, Convert, One, SaturatedConversion, Saturating, StaticLookup, Zero},
+	traits::{
+		Bounded, CheckedSub, Convert, One, SaturatedConversion, Saturating, StaticLookup, Zero,
+	},
 	Perbill, Percent,
 };
 use sp_staking::{
@@ -151,6 +153,37 @@ impl<T: Config> Pallet<T> {
 		Self::slashable_balance_of_vote_weight(who, issuance)
 	}
 
+	pub(super) fn do_bond_extra(stash: &T::AccountId, additional: BalanceOf<T>) -> DispatchResult {
+		let mut ledger = Self::ledger(StakingAccount::Stash(stash.clone()))?;
+
+		let extra = if Self::is_virtual_nominator(stash) {
+			additional
+		} else {
+			// additional amount or actual balance of stash whichever is lower.
+			additional.min(
+				Self::stakeable_balance(stash)
+					.checked_sub(&ledger.total)
+					.ok_or(sp_runtime::ArithmeticError::Overflow)?,
+			)
+		};
+
+		ledger.total += extra;
+		ledger.active += extra;
+		// Last check: the new active amount of ledger must be more than ED.
+		ensure!(ledger.active >= T::Currency::minimum_balance(), Error::<T>::InsufficientBond);
+
+		// NOTE: ledger must be updated prior to calling `Self::weight_of`.
+		ledger.update()?;
+		// update this staker in the sorted list, if they exist in it.
+		if T::VoterList::contains(stash) {
+			let _ = T::VoterList::on_update(&stash, Self::weight_of(stash)).defensive();
+		}
+
+		Self::deposit_event(Event::<T>::Bonded { stash: stash.clone(), amount: extra });
+
+		Ok(())
+	}
+
 	pub(super) fn do_withdraw_unbonded(
 		controller: &T::AccountId,
 		num_slashing_spans: u32,
@@ -1139,31 +1172,39 @@ impl<T: Config> Pallet<T> {
 		EraInfo::<T>::get_full_exposure(era, account)
 	}
 
+	/// Balance that can be staked in the pallet. Includes already staked balance.
 	pub(crate) fn stakeable_balance(who: &T::AccountId) -> BalanceOf<T> {
-		if T::DelegateeSupport::is_delegatee(who) {
-			return T::DelegateeSupport::stakeable_balance(who);
-		}
-
 		T::Currency::free_balance(who)
 	}
 
+	/// Whether the passed reward destination is restricted for the given account.
+	///
+	/// Virtual nominators are not allowed to compound their rewards as this pallet does not manage
+	/// locks for them. For external pallets that manage the virtual bond, it is their
+	/// responsibility to distribute the reward and re-bond them.
+	///
+	/// Conservatively, we expect them to always set the reward destination to a non stash account.
 	pub(crate) fn restrict_reward_destination(
 		who: &T::AccountId,
-		reward_destination: Option<T::AccountId>,
+		reward_destination: RewardDestination<T::AccountId>,
 	) -> bool {
-		if T::DelegateeSupport::is_delegatee(who) {
-			return T::DelegateeSupport::restrict_reward_destination(who, reward_destination);
-		}
+		Self::is_virtual_nominator(who) &&
+			match reward_destination {
+				RewardDestination::Account(payee) => payee == *who,
+				_ => true,
+			}
+	}
 
-		false
+	pub(crate) fn is_virtual_nominator(who: &T::AccountId) -> bool {
+		VirtualNominators::<T>::contains_key(who)
 	}
 
-	pub(crate) fn update_hold(
+	pub(crate) fn update_lock(
 		who: &T::AccountId,
 		amount: BalanceOf<T>,
 	) -> sp_runtime::DispatchResult {
-		// only apply lock if it is not a delegatee. delegatee accounts are already locked/held.
-		if !T::DelegateeSupport::is_delegatee(who) {
+		// Skip locking virtual nominators. They are handled by external pallets.
+		if !Self::is_virtual_nominator(who) {
 			T::Currency::set_lock(crate::STAKING_ID, who, amount, WithdrawReasons::all());
 		}
 
@@ -1911,7 +1952,23 @@ impl<T: Config> StakingUnsafe for Pallet<T> {
 		value: Self::Balance,
 		payee: &Self::AccountId,
 	) -> DispatchResult {
-		unimplemented!()
+		if StakingLedger::<T>::is_bonded(StakingAccount::Stash(who.clone())) {
+			return Err(Error::<T>::AlreadyBonded.into())
+		}
+
+		frame_system::Pallet::<T>::inc_consumers(&who).map_err(|_| Error::<T>::BadState)?;
+
+		// mark who as a virtual nominator
+		VirtualNominators::<T>::insert(who, ());
+
+		Self::deposit_event(Event::<T>::Bonded { stash: who.clone(), amount: value });
+		let ledger = StakingLedger::<T>::new(who.clone(), value);
+
+		// You're auto-bonded forever, here. We might improve this by only bonding when
+		// you actually validate/nominate and remove once you unbond __everything__.
+		ledger.bond(RewardDestination::Account(payee.clone()))?;
+
+		Ok(())
 	}
 }
 
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index 743febd408b82..b51ed34065e9a 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -32,7 +32,7 @@ use frame_support::{
 };
 use frame_system::{ensure_root, ensure_signed, pallet_prelude::*};
 use sp_runtime::{
-	traits::{CheckedSub, SaturatedConversion, StaticLookup, Zero},
+	traits::{SaturatedConversion, StaticLookup, Zero},
 	ArithmeticError, Perbill, Percent,
 };
 
@@ -1005,29 +1005,8 @@ pub mod pallet {
 			#[pallet::compact] max_additional: BalanceOf<T>,
 		) -> DispatchResult {
 			let stash = ensure_signed(origin)?;
-			let mut ledger = Self::ledger(StakingAccount::Stash(stash.clone()))?;
 
-			let stash_balance = Self::stakeable_balance(&stash);
-			if let Some(extra) = stash_balance.checked_sub(&ledger.total) {
-				let extra = extra.min(max_additional);
-				ledger.total += extra;
-				ledger.active += extra;
-				// Last check: the new active amount of ledger must be more than ED.
-				ensure!(
-					ledger.active >= T::Currency::minimum_balance(),
-					Error::<T>::InsufficientBond
-				);
-
-				// NOTE: ledger must be updated prior to calling `Self::weight_of`.
-				ledger.update()?;
-				// update this staker in the sorted list, if they exist in it.
-				if T::VoterList::contains(&stash) {
-					let _ = T::VoterList::on_update(&stash, Self::weight_of(&stash)).defensive();
-				}
-
-				Self::deposit_event(Event::<T>::Bonded { stash, amount: extra });
-			}
-			Ok(())
+			Self::do_bond_extra(&stash, max_additional)
 		}
 
 		/// Schedule a portion of the stash to be unlocked ready for transfer out after the bond
diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs
index 364dc4215dfcd..e42165299b4f9 100644
--- a/substrate/frame/staking/src/slashing.rs
+++ b/substrate/frame/staking/src/slashing.rs
@@ -608,7 +608,7 @@ pub fn do_slash<T: Config>(
 			Err(_) => return, // nothing to do.
 		};
 
-	let lazy_slash = T::DelegateeSupport::is_delegatee(stash);
+	let lazy_slash = Pallet::<T>::is_virtual_nominator(stash);
 	let value = ledger.slash(value, T::Currency::minimum_balance(), slash_era);
 
 	if value.is_zero() {
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 6ea45e2f3e643..b5188717f8ce8 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -311,7 +311,7 @@ pub trait StakingInterface {
 
 /// Set of low level apis to manipulate staking ledger.
 ///
-/// This is a low level api and should be used if you know what you are doing.
+/// These apis bypass safety checks and should only be used if you know what you are doing.
 pub trait StakingUnsafe: StakingInterface {
 	/// Release all funds bonded for stake without unbonding the ledger.
 	///
@@ -327,6 +327,7 @@ pub trait StakingUnsafe: StakingInterface {
 		payee: &Self::AccountId,
 	) -> DispatchResult;
 }
+
 /// The amount of exposure for an era that an individual nominator has (susceptible to slashing).
 #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
 pub struct IndividualExposure<AccountId, Balance: HasCompact> {

From d884c47b446962068ee3bc3058a80e18dc64f693 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 29 Mar 2024 06:04:29 +0100
Subject: [PATCH 198/202] report slash via event listener

---
 substrate/frame/delegated-staking/src/impls.rs | 16 ++++++++++++++--
 substrate/frame/delegated-staking/src/mock.rs  |  2 +-
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 610a0a33142db..d0e5fb5da4975 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -305,10 +305,22 @@ impl<T: Config> DelegateeSupport for Pallet<T> {
 	}
 
 	fn report_slash(who: &Self::AccountId, slash: Self::Balance) {
+
+	}
+}
+
+impl<T: Config> sp_staking::OnStakingUpdate<T::AccountId, BalanceOf<T>> for Pallet<T> {
+	fn on_slash(
+		who: &T::AccountId,
+		_slashed_active: BalanceOf<T>,
+		_slashed_unlocking: &sp_std::collections::btree_map::BTreeMap<EraIndex, BalanceOf<T>>,
+		slashed_total: BalanceOf<T>,
+	) {
 		<Delegatees<T>>::mutate(who, |maybe_register| match maybe_register {
-			Some(register) => register.pending_slash.saturating_accrue(slash),
+			// if delegatee, register the slashed amount as pending slash.
+			Some(register) => register.pending_slash.saturating_accrue(slashed_total),
 			None => {
-				defensive!("should not be called on non-delegate");
+				// nothing to do
 			},
 		});
 	}
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 892b69b624e44..09f12dd243f2c 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -133,7 +133,7 @@ impl pallet_staking::Config for Runtime {
 	type NominationsQuota = pallet_staking::FixedNominationsQuota<16>;
 	type MaxUnlockingChunks = ConstU32<32>;
 	type MaxControllersInDeprecationBatch = ConstU32<100>;
-	type EventListeners = Pools;
+	type EventListeners = (Pools, DelegatedStaking);
 	type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
 	type WeightInfo = ();
 }

From 500ac8fb99173b9dcba1f094db2c05ab6c7338d7 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 29 Mar 2024 06:15:00 +0100
Subject: [PATCH 199/202] get rid of delegatee support

---
 .../frame/delegated-staking/src/impls.rs      | 51 ++-----------------
 substrate/frame/delegated-staking/src/lib.rs  | 16 +++---
 substrate/frame/delegated-staking/src/mock.rs |  3 +-
 .../frame/delegated-staking/src/tests.rs      |  1 -
 .../nomination-pools/test-staking/src/mock.rs |  1 -
 substrate/frame/staking/src/lib.rs            |  2 +-
 substrate/frame/staking/src/mock.rs           |  1 -
 substrate/frame/staking/src/pallet/impls.rs   | 19 -------
 substrate/frame/staking/src/pallet/mod.rs     |  7 ---
 substrate/frame/staking/src/slashing.rs       |  9 ++--
 .../primitives/staking/src/delegation.rs      | 49 ------------------
 11 files changed, 18 insertions(+), 141 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index d0e5fb5da4975..834bba4f29d6b 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -16,10 +16,11 @@
 // You should have received a copy of the GNU General Public License
 // along with this program. If not, see <https://www.gnu.org/licenses/>.
 
-//! Implementations of public traits, namely [StakingInterface], and [DelegateeSupport].
+//! Implementations of public traits, namely [StakingInterface], [DelegatedStakeInterface] and
+//! [OnStakingUpdate].
 
 use super::*;
-use sp_staking::delegation::DelegatedStakeInterface;
+use sp_staking::{delegation::DelegatedStakeInterface, OnStakingUpdate};
 
 /// StakingInterface implementation with delegation support.
 ///
@@ -265,51 +266,7 @@ impl<T: Config> DelegatedStakeInterface for Pallet<T> {
 	}
 }
 
-impl<T: Config> DelegateeSupport for Pallet<T> {
-	type Balance = BalanceOf<T>;
-	type AccountId = T::AccountId;
-
-	/// this balance is total delegator that can be staked, and importantly not extra balance that
-	/// is delegated but not bonded yet.
-	fn stakeable_balance(who: &Self::AccountId) -> Self::Balance {
-		Delegatee::<T>::from(who)
-			.map(|delegatee| delegatee.ledger.stakeable_balance())
-			.unwrap_or_default()
-	}
-
-	fn restrict_reward_destination(
-		who: &Self::AccountId,
-		reward_destination: Option<Self::AccountId>,
-	) -> bool {
-		let maybe_register = <Delegatees<T>>::get(who);
-
-		if maybe_register.is_none() {
-			// no restrictions for non delegates.
-			return false;
-		}
-
-		// restrict if reward destination is not set
-		if reward_destination.is_none() {
-			return true;
-		}
-
-		let register = maybe_register.expect("checked above; qed");
-		let reward_acc = reward_destination.expect("checked above; qed");
-
-		// restrict if reward account is not what delegate registered.
-		register.payee != reward_acc
-	}
-
-	fn is_delegatee(who: &Self::AccountId) -> bool {
-		Self::is_delegatee(who)
-	}
-
-	fn report_slash(who: &Self::AccountId, slash: Self::Balance) {
-
-	}
-}
-
-impl<T: Config> sp_staking::OnStakingUpdate<T::AccountId, BalanceOf<T>> for Pallet<T> {
+impl<T: Config> OnStakingUpdate<T::AccountId, BalanceOf<T>> for Pallet<T> {
 	fn on_slash(
 		who: &T::AccountId,
 		_slashed_active: BalanceOf<T>,
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 618c20c2f976a..dd0a29cd7830f 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -83,10 +83,6 @@
 //! [Config::CoreStaking] to provide delegation based staking. NominationPool can use this pallet as
 //! its Staking provider to support delegation based staking from pool accounts.
 //!
-//! #### [Delegatee Support](DelegateeSupport)
-//! Implements `DelegateeSupport` trait which an implementation of [StakingInterface] (such as
-//! pallet-staking) can use to back-support `delegatee` accounts.
-//!
 //! ## Lazy Slashing
 //! One of the reasons why direct nominators on staking pallet cannot scale well is because all
 //! nominators are slashed at the same time. This is expensive and needs to be bounded operation.
@@ -179,9 +175,7 @@ use sp_runtime::{
 	traits::{AccountIdConversion, CheckedAdd, CheckedSub, Zero},
 	ArithmeticError, DispatchResult, Perbill, RuntimeDebug, Saturating,
 };
-use sp_staking::{
-	delegation::DelegateeSupport, EraIndex, Stake, StakerStatus, StakingInterface, StakingUnsafe,
-};
+use sp_staking::{EraIndex, Stake, StakerStatus, StakingInterface, StakingUnsafe};
 use sp_std::{convert::TryInto, prelude::*};
 
 pub type BalanceOf<T> =
@@ -762,6 +756,14 @@ impl<T: Config> Pallet<T> {
 
 		Ok(())
 	}
+
+	/// Total balance that is available for stake. Includes already staked amount.
+	#[cfg(test)]
+	pub(crate) fn stakeable_balance(who: &T::AccountId) -> BalanceOf<T> {
+		Delegatee::<T>::from(who)
+			.map(|delegatee| delegatee.ledger.stakeable_balance())
+			.unwrap_or_default()
+	}
 }
 
 #[cfg(any(test, feature = "try-runtime"))]
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 09f12dd243f2c..ae1b84acdecbc 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -34,7 +34,7 @@ use frame_support::dispatch::RawOrigin;
 use pallet_staking::CurrentEra;
 use sp_core::U256;
 use sp_runtime::traits::Convert;
-use sp_staking::{delegation::DelegateeSupport, Stake, StakingInterface};
+use sp_staking::{Stake, StakingInterface};
 
 pub type T = Runtime;
 type Block = frame_system::mocking::MockBlock<Runtime>;
@@ -109,7 +109,6 @@ impl onchain::Config for OnChainSeqPhragmen {
 impl pallet_staking::Config for Runtime {
 	type Currency = Balances;
 	type CurrencyBalance = Balance;
-	type DelegateeSupport = DelegatedStaking;
 	type UnixTime = pallet_timestamp::Pallet<Self>;
 	type CurrencyToVote = ();
 	type RewardRemainder = ();
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index a278fd8850ad9..6e6fa6fb91692 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -22,7 +22,6 @@ use crate::mock::*;
 use frame_support::{assert_noop, assert_ok, traits::fungible::InspectHold};
 use pallet_nomination_pools::{Error as PoolsError, Event as PoolsEvent};
 use pallet_staking::Error as StakingError;
-use sp_staking::delegation::DelegateeSupport;
 
 #[test]
 fn create_a_delegatee_with_first_delegator() {
diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs
index 36d936de31a95..227f5ef5d5965 100644
--- a/substrate/frame/nomination-pools/test-staking/src/mock.rs
+++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs
@@ -111,7 +111,6 @@ parameter_types! {
 impl pallet_staking::Config for Runtime {
 	type Currency = Balances;
 	type CurrencyBalance = Balance;
-	type DelegateeSupport = pallet_staking::NoDelegation<Self>;
 	type UnixTime = pallet_timestamp::Pallet<Self>;
 	type CurrencyToVote = ();
 	type RewardRemainder = ();
diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs
index 2e69881dbee70..aeae8e80fb836 100644
--- a/substrate/frame/staking/src/lib.rs
+++ b/substrate/frame/staking/src/lib.rs
@@ -328,7 +328,7 @@ pub use sp_staking::{Exposure, IndividualExposure, StakerStatus};
 use sp_std::{collections::btree_map::BTreeMap, prelude::*};
 pub use weights::WeightInfo;
 
-pub use pallet::{pallet::*, NoDelegation, UseNominatorsAndValidatorsMap, UseValidatorsMap};
+pub use pallet::{pallet::*, UseNominatorsAndValidatorsMap, UseValidatorsMap};
 
 pub(crate) const STAKING_ID: LockIdentifier = *b"staking ";
 pub(crate) const LOG_TARGET: &str = "runtime::staking";
diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs
index ae55b2afabbb2..6db462c1a70fb 100644
--- a/substrate/frame/staking/src/mock.rs
+++ b/substrate/frame/staking/src/mock.rs
@@ -266,7 +266,6 @@ impl OnStakingUpdate<AccountId, Balance> for EventListenerMock {
 impl crate::pallet::pallet::Config for Test {
 	type Currency = Balances;
 	type CurrencyBalance = <Self as pallet_balances::Config>::Balance;
-	type DelegateeSupport = pallet_staking::NoDelegation<Self>;
 	type UnixTime = Timestamp;
 	type CurrencyToVote = ();
 	type RewardRemainder = RewardRemainderMock;
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 1c1ad3820b733..d67d8cc24e9df 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -42,7 +42,6 @@ use sp_runtime::{
 };
 use sp_staking::{
 	currency_to_vote::CurrencyToVote,
-	delegation::DelegateeSupport,
 	offence::{DisableStrategy, OffenceDetails, OnOffenceHandler},
 	EraIndex, OnStakingUpdate, Page, SessionIndex, Stake,
 	StakingAccount::{self, Controller, Stash},
@@ -1972,24 +1971,6 @@ impl<T: Config> StakingUnsafe for Pallet<T> {
 	}
 }
 
-/// Standard implementation of `DelegateeSupport` that supports only direct staking and no
-/// delegated staking.
-pub struct NoDelegation<T>(PhantomData<T>);
-impl<T: Config> DelegateeSupport for NoDelegation<T> {
-	type Balance = BalanceOf<T>;
-	type AccountId = T::AccountId;
-	fn stakeable_balance(_who: &Self::AccountId) -> Self::Balance {
-		defensive!("stakeable balance should not have been called for NoDelegation");
-		BalanceOf::<T>::zero()
-	}
-	fn is_delegatee(_who: &Self::AccountId) -> bool {
-		false
-	}
-	fn report_slash(_who: &Self::AccountId, _slash: Self::Balance) {
-		defensive!("delegation report_slash should not be have been called for NoDelegation");
-	}
-}
-
 #[cfg(any(test, feature = "try-runtime"))]
 impl<T: Config> Pallet<T> {
 	pub(crate) fn do_try_state(_: BlockNumberFor<T>) -> Result<(), TryRuntimeError> {
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index b51ed34065e9a..6d5b64f47360a 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -37,7 +37,6 @@ use sp_runtime::{
 };
 
 use sp_staking::{
-	delegation::DelegateeSupport,
 	EraIndex, Page, SessionIndex,
 	StakingAccount::{self, Controller, Stash},
 };
@@ -105,12 +104,6 @@ pub mod pallet {
 			+ TypeInfo
 			+ MaxEncodedLen;
 
-		/// Something that provides delegation support to staking pallet.
-		type DelegateeSupport: DelegateeSupport<
-			Balance = Self::CurrencyBalance,
-			AccountId = Self::AccountId,
-		>;
-
 		/// Time used for computing era duration.
 		///
 		/// It is guaranteed to start being called from the first `on_finalize`. Thus value at
diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs
index e42165299b4f9..3345031a36cae 100644
--- a/substrate/frame/staking/src/slashing.rs
+++ b/substrate/frame/staking/src/slashing.rs
@@ -64,7 +64,7 @@ use sp_runtime::{
 	traits::{Saturating, Zero},
 	DispatchResult, RuntimeDebug,
 };
-use sp_staking::{delegation::DelegateeSupport, offence::DisableStrategy, EraIndex};
+use sp_staking::{offence::DisableStrategy, EraIndex};
 use sp_std::vec::Vec;
 
 /// The proportion of the slashing reward to be paid out on the first slashing detection.
@@ -608,7 +608,6 @@ pub fn do_slash<T: Config>(
 			Err(_) => return, // nothing to do.
 		};
 
-	let lazy_slash = Pallet::<T>::is_virtual_nominator(stash);
 	let value = ledger.slash(value, T::Currency::minimum_balance(), slash_era);
 
 	if value.is_zero() {
@@ -616,10 +615,8 @@ pub fn do_slash<T: Config>(
 		return
 	}
 
-	if lazy_slash {
-		// If delegated staking, report slash and move on.
-		T::DelegateeSupport::report_slash(stash, value);
-	} else {
+	// Skip slashing for virtual nominators. The pallets managing them should handle the slashing.
+	if !Pallet::<T>::is_virtual_nominator(stash) {
 		let (imbalance, missing) = T::Currency::slash(stash, value);
 		slashed_imbalance.subsume(imbalance);
 
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index e51a48fddf3a3..ba30cb58fcba2 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -21,55 +21,6 @@ use scale_info::TypeInfo;
 use sp_runtime::{DispatchResult, Saturating};
 use sp_std::ops::Sub;
 
-/// Support plugin for `delegatee` accounts.
-///
-/// A `delegatee` account is an account that can receive delegations from other accounts. Their
-/// balance is made up of multiple child delegators. This trait allows a pallet such as
-/// `pallet-staking` to support these special accounts.
-pub trait DelegateeSupport {
-	/// Balance type used by the staking system.
-	type Balance: Sub<Output = Self::Balance>
-		+ Ord
-		+ PartialEq
-		+ Default
-		+ Copy
-		+ MaxEncodedLen
-		+ FullCodec
-		+ TypeInfo
-		+ Saturating;
-
-	/// AccountId type used by the staking system.
-	type AccountId: Clone + sp_std::fmt::Debug;
-
-	/// Balance of `delegatee` which can be staked.
-	///
-	/// Similar to free balance for a normal account.
-	fn stakeable_balance(delegatee: &Self::AccountId) -> Self::Balance;
-
-	/// Returns true if `delegatee` is restricted to update which account they can receive their
-	/// staking rewards.
-	///
-	/// For `delegatee` accounts we restrict the reward destination to be the same as the
-	/// `delegatee` account itself. This is since the actual `delegatee` balances is not considered
-	/// while staking. Instead, their balance is made up of multiple child delegators.
-	fn restrict_reward_destination(
-		_who: &Self::AccountId,
-		_reward_destination: Option<Self::AccountId>,
-	) -> bool {
-		// never restrict by default
-		false
-	}
-
-	/// Returns true if `who` is a `delegatee` and accepts delegations from other accounts.
-	fn is_delegatee(who: &Self::AccountId) -> bool;
-
-	/// Reports an ongoing slash to the `delegatee` account that would be applied lazily.
-	///
-	/// Slashing a delegatee account is not immediate since the balance is made up of multiple child
-	/// delegators. This function should bookkeep the slash to be applied later.
-	fn report_slash(who: &Self::AccountId, slash: Self::Balance);
-}
-
 /// Trait that extends on [`StakingInterface`] to provide additional capability to delegate funds to
 /// an account.
 pub trait DelegatedStakeInterface: StakingInterface {

From a8fc38505ea51f210e6629090696bdc9f4ea3e28 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 29 Mar 2024 07:38:20 +0100
Subject: [PATCH 200/202] fix tests

---
 substrate/frame/delegated-staking/src/lib.rs   | 6 ------
 substrate/frame/delegated-staking/src/tests.rs | 8 +-------
 substrate/frame/staking/src/pallet/mod.rs      | 7 ++++---
 substrate/primitives/staking/src/delegation.rs | 5 +----
 substrate/primitives/staking/src/lib.rs        | 5 +++--
 5 files changed, 9 insertions(+), 22 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index dd0a29cd7830f..b50769f88ffcd 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -100,12 +100,6 @@
 //! ## Migration from Nominator to Delegatee
 //! More details [here](https://hackmd.io/@ak0n/np-delegated-staking-migration).
 //!
-//! ## Reward Destination Restrictions
-//! This pallets set an important restriction of rewards account to be separate from `delegatee`
-//! account. This is because, `delegatee` balance is not what is directly exposed but the funds that
-//! are delegated to it. For `delegatee` accounts, we have also no way to auto-compound rewards. The
-//! rewards need to be paid out to delegators and then delegated again to the `delegatee` account.
-//!
 //! ## Nomination Pool vs Delegation Staking
 //! This pallet is not a replacement for Nomination Pool but adds a new primitive over staking
 //! pallet that can be used by Nomination Pool to support delegation based staking. It can be
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 6e6fa6fb91692..1fa873f9ecae7 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -403,13 +403,7 @@ mod staking_integration {
 				Staking::set_payee(RuntimeOrigin::signed(200), RewardDestination::Stash),
 				StakingError::<T>::RewardDestinationRestricted
 			);
-
-			// non stash account different than one passed to DelegatedStaking also does not work..
-			assert_noop!(
-				Staking::set_payee(RuntimeOrigin::signed(200), RewardDestination::Account(202)),
-				StakingError::<T>::RewardDestinationRestricted
-			);
-
+			
 			// passing correct reward destination works
 			assert_ok!(Staking::set_payee(
 				RuntimeOrigin::signed(200),
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index 6d5b64f47360a..5bb7efe31acbe 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -382,9 +382,10 @@ pub mod pallet {
 
 	/// Nominators whose funds are managed by other pallets.
 	///
-	/// This pallet does not apply any locks on them, hence they are only virtually bonded. These
-	/// nominators should not be allowed to mutate their ledger directly via application code and
-	/// can only be accessed via low level functions made available by this pallet.
+	/// This pallet does not apply any locks on them, therefore they are only virtually bonded. They
+	/// are expected to be keyless accounts and hence should not be allowed to mutate their ledger
+	/// directly via this pallet. Instead, these accounts are managed by other pallets and accessed
+	/// via low level apis. We keep track of them to do minimal integrity checks.
 	// TODO(ank4n): Can we keep this entry in `Ledger`?
 	#[pallet::storage]
 	pub type VirtualNominators<T: Config> = CountedStorageMap<_, Twox64Concat, T::AccountId, ()>;
diff --git a/substrate/primitives/staking/src/delegation.rs b/substrate/primitives/staking/src/delegation.rs
index ba30cb58fcba2..e7cad230b2703 100644
--- a/substrate/primitives/staking/src/delegation.rs
+++ b/substrate/primitives/staking/src/delegation.rs
@@ -16,10 +16,7 @@
 // limitations under the License.
 
 use crate::StakingInterface;
-use codec::{FullCodec, MaxEncodedLen};
-use scale_info::TypeInfo;
-use sp_runtime::{DispatchResult, Saturating};
-use sp_std::ops::Sub;
+use sp_runtime::{DispatchResult};
 
 /// Trait that extends on [`StakingInterface`] to provide additional capability to delegate funds to
 /// an account.
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index b5188717f8ce8..f6101f81c45cf 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -320,9 +320,10 @@ pub trait StakingUnsafe: StakingInterface {
 
 	/// Book-keep a new bond for `who` without applying any locks (hence virtual).
 	///
-	/// Caller is responsible for ensuring the passed amount is locked and valid.
+	/// It is important that who is a keyless account and therefore cannot interact with staking
+	/// pallet directly. Caller is responsible for ensuring the passed amount is locked and valid.
 	fn virtual_bond(
-		who: &Self::AccountId,
+		keyless_who: &Self::AccountId,
 		value: Self::Balance,
 		payee: &Self::AccountId,
 	) -> DispatchResult;

From 81c0c78780262cc41c59c6d693fbcf7f667fda4a Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 29 Mar 2024 07:59:14 +0100
Subject: [PATCH 201/202] add update payee to Staking Interface

---
 substrate/frame/delegated-staking/src/impls.rs | 4 ++++
 substrate/frame/delegated-staking/src/lib.rs   | 3 +--
 substrate/frame/delegated-staking/src/tests.rs | 2 +-
 substrate/frame/nomination-pools/src/mock.rs   | 4 ++++
 substrate/frame/staking/src/pallet/impls.rs    | 6 ++++++
 substrate/primitives/staking/src/lib.rs        | 3 +++
 6 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs
index 834bba4f29d6b..e256b917a94bd 100644
--- a/substrate/frame/delegated-staking/src/impls.rs
+++ b/substrate/frame/delegated-staking/src/impls.rs
@@ -122,6 +122,10 @@ impl<T: Config> StakingInterface for Pallet<T> {
 		T::CoreStaking::unbond(stash, value)
 	}
 
+	fn update_payee(stash: &Self::AccountId, reward_acc: &Self::AccountId) -> DispatchResult {
+		T::CoreStaking::update_payee(stash, reward_acc)
+	}
+
 	/// Withdraw unbonding funds until current era.
 	///
 	/// Funds are moved to unclaimed_withdrawals register of the `DelegateeLedger`.
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index b50769f88ffcd..65058c927e86f 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -517,8 +517,7 @@ impl<T: Config> Pallet<T> {
 			.map_err(|_| Error::<T>::BadState)?;
 
 		Self::do_register_delegatee(who, reward_account);
-		// FIXME(ank4n) expose set payee in staking interface.
-		// T::CoreStaking::set_payee(who, reward_account)
+		T::CoreStaking::update_payee(who, reward_account)?;
 
 		Self::do_delegate(&proxy_delegator, who, stake.total)
 	}
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index 1fa873f9ecae7..34f8399f340dc 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -403,7 +403,7 @@ mod staking_integration {
 				Staking::set_payee(RuntimeOrigin::signed(200), RewardDestination::Stash),
 				StakingError::<T>::RewardDestinationRestricted
 			);
-			
+
 			// passing correct reward destination works
 			assert_ok!(Staking::set_payee(
 				RuntimeOrigin::signed(200),
diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs
index 5e2303284bfda..6bac1d6c14284 100644
--- a/substrate/frame/nomination-pools/src/mock.rs
+++ b/substrate/frame/nomination-pools/src/mock.rs
@@ -190,6 +190,10 @@ impl sp_staking::StakingInterface for StakingMock {
 		}
 	}
 
+	fn update_payee(_: &Self::AccountId, _: &Self::AccountId) {
+		unimplemented!("method currently not used in testing")
+	}
+
 	fn election_ongoing() -> bool {
 		unimplemented!("method currently not used in testing")
 	}
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index d67d8cc24e9df..027bfa6e66dc2 100644
--- a/substrate/frame/staking/src/pallet/impls.rs
+++ b/substrate/frame/staking/src/pallet/impls.rs
@@ -1825,6 +1825,12 @@ impl<T: Config> StakingInterface for Pallet<T> {
 			.map(|_| ())
 	}
 
+	fn update_payee(stash: &Self::AccountId, reward_acc: &Self::AccountId) -> DispatchResult {
+		// since controller is deprecated and this function is never used for old ledgers with
+		// distinct controllers, we can safely assume that stash is the controller.
+		Self::set_payee(RawOrigin::Signed(stash.clone()).into(), RewardDestination::Account(reward_acc.clone()))
+	}
+
 	fn chill(who: &Self::AccountId) -> DispatchResult {
 		// defensive-only: any account bonded via this interface has the stash set as the
 		// controller, but we have to be sure. Same comment anywhere else that we read this.
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index f6101f81c45cf..2300ab062b379 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -256,6 +256,9 @@ pub trait StakingInterface {
 	/// schedules have reached their unlocking era should allow more calls to this function.
 	fn unbond(stash: &Self::AccountId, value: Self::Balance) -> DispatchResult;
 
+	/// Update the reward destination for the ledger associated with the stash.
+	fn update_payee(stash: &Self::AccountId, reward_acc: &Self::AccountId) -> DispatchResult;
+
 	/// Unlock any funds schedule to unlock before or at the current era.
 	///
 	/// Returns whether the stash was killed because of this withdraw or not.

From 5ebc35a0d21da6a82198c5a4d25e3af5aee4f966 Mon Sep 17 00:00:00 2001
From: Ankan <ankan.anurag@gmail.com>
Date: Fri, 29 Mar 2024 08:02:03 +0100
Subject: [PATCH 202/202] get rid of fixme

---
 substrate/frame/delegated-staking/src/lib.rs | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 65058c927e86f..3b49ff477f277 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -676,10 +676,6 @@ impl<T: Config> Pallet<T> {
 			.defensive_ok_or(Error::<T>::BadState)?
 			.save_or_kill(source_delegator);
 
-		// FIXME(ank4n): If all funds are migrated from source, it can be cleaned up and ED returned
-		// to delegate or alternatively whoever cleans it up. This could be a permission-less
-		// extrinsic.
-
 		// release funds from source
 		let released = T::Currency::release(
 			&HoldReason::Delegating.into(),