diff --git a/Cargo.lock b/Cargo.lock
index 397d0c7fe823af0f01e541dc8f2bde49ec43fd74..b71c1890ef291c08df4e9660e2b18e75e62aab79 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -13400,7 +13400,6 @@ dependencies = [
  "log",
  "pallet-bags-list 27.0.0",
  "pallet-balances 28.0.0",
- "pallet-delegated-staking 1.0.0",
  "pallet-election-provider-multi-phase 27.0.0",
  "pallet-nomination-pools 25.0.0",
  "pallet-session 28.0.0",
@@ -14485,6 +14484,29 @@ dependencies = [
  "sp-tracing 16.0.0",
 ]
 
+[[package]]
+name = "pallet-nomination-pools-test-transfer-stake"
+version = "1.0.0"
+dependencies = [
+ "frame-election-provider-support 28.0.0",
+ "frame-support 28.0.0",
+ "frame-system 28.0.0",
+ "log",
+ "pallet-bags-list 27.0.0",
+ "pallet-balances 28.0.0",
+ "pallet-nomination-pools 25.0.0",
+ "pallet-staking 28.0.0",
+ "pallet-staking-reward-curve",
+ "pallet-timestamp 27.0.0",
+ "parity-scale-codec",
+ "scale-info",
+ "sp-core 28.0.0",
+ "sp-io 30.0.0",
+ "sp-runtime 31.0.1",
+ "sp-staking 26.0.0",
+ "sp-tracing 16.0.0",
+]
+
 [[package]]
 name = "pallet-offences"
 version = "27.0.0"
diff --git a/Cargo.toml b/Cargo.toml
index 18c1dd2c68d2f09fec08aec3cc5961be8ecf2959..e57c648120a9069df53b89102c32e9b4c57140f9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -389,6 +389,7 @@ members = [
 	"substrate/frame/nomination-pools/fuzzer",
 	"substrate/frame/nomination-pools/runtime-api",
 	"substrate/frame/nomination-pools/test-delegate-stake",
+	"substrate/frame/nomination-pools/test-transfer-stake",
 	"substrate/frame/offences",
 	"substrate/frame/offences/benchmarking",
 	"substrate/frame/paged-list",
diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs
index cdf6fa92da2f5d5f09c6f48b21e2e4f13035d4ef..4f9ba8d8508cdecc904efefcde280e386fddc1d3 100644
--- a/polkadot/runtime/test-runtime/src/lib.rs
+++ b/polkadot/runtime/test-runtime/src/lib.rs
@@ -366,13 +366,11 @@ impl onchain::Config for OnChainSeqPhragmen {
 const MAX_QUOTA_NOMINATIONS: u32 = 16;
 
 impl pallet_staking::Config for Runtime {
-	type OldCurrency = Balances;
 	type Currency = Balances;
 	type CurrencyBalance = Balance;
 	type UnixTime = Timestamp;
 	type CurrencyToVote = polkadot_runtime_common::CurrencyToVote;
 	type RewardRemainder = ();
-	type RuntimeHoldReason = RuntimeHoldReason;
 	type RuntimeEvent = RuntimeEvent;
 	type Slash = ();
 	type Reward = ();
diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs
index a9ba0778fe0eff7b4801df2b045f038752390113..c85fc59c590ef2a215a857deba56ac31bc9ab7f6 100644
--- a/polkadot/runtime/westend/src/lib.rs
+++ b/polkadot/runtime/westend/src/lib.rs
@@ -728,10 +728,8 @@ parameter_types! {
 }
 
 impl pallet_staking::Config for Runtime {
-	type OldCurrency = Balances;
 	type Currency = Balances;
 	type CurrencyBalance = Balance;
-	type RuntimeHoldReason = RuntimeHoldReason;
 	type UnixTime = Timestamp;
 	type CurrencyToVote = CurrencyToVote;
 	type RewardRemainder = ();
diff --git a/polkadot/runtime/westend/src/tests.rs b/polkadot/runtime/westend/src/tests.rs
index 65b81cc00f06975e7be235cb7d7700824b356853..fcdaf7ff2de6d3c95207291bd6b2f47043877860 100644
--- a/polkadot/runtime/westend/src/tests.rs
+++ b/polkadot/runtime/westend/src/tests.rs
@@ -155,27 +155,25 @@ mod remote_tests {
 
 		let transport: Transport = var("WS").unwrap_or("ws://127.0.0.1:9900".to_string()).into();
 		let maybe_state_snapshot: Option<SnapshotConfig> = var("SNAP").map(|s| s.into()).ok();
-		let online_config = OnlineConfig {
-			transport,
-			state_snapshot: maybe_state_snapshot.clone(),
-			child_trie: false,
-			pallets: vec![
-				"Staking".into(),
-				"System".into(),
-				"Balances".into(),
-				"NominationPools".into(),
-				"DelegatedStaking".into(),
-			],
-			..Default::default()
-		};
 		let mut ext = Builder::<Block>::default()
 			.mode(if let Some(state_snapshot) = maybe_state_snapshot {
 				Mode::OfflineOrElseOnline(
 					OfflineConfig { state_snapshot: state_snapshot.clone() },
-					online_config,
+					OnlineConfig {
+						transport,
+						state_snapshot: Some(state_snapshot),
+						pallets: vec![
+							"staking".into(),
+							"system".into(),
+							"balances".into(),
+							"nomination-pools".into(),
+							"delegated-staking".into(),
+						],
+						..Default::default()
+					},
 				)
 			} else {
-				Mode::Online(online_config)
+				Mode::Online(OnlineConfig { transport, ..Default::default() })
 			})
 			.build()
 			.await
@@ -243,77 +241,6 @@ mod remote_tests {
 			);
 		});
 	}
-
-	#[tokio::test]
-	async fn staking_curr_fun_migrate() {
-		// Intended to be run only manually.
-		if var("RUN_MIGRATION_TESTS").is_err() {
-			return;
-		}
-		sp_tracing::try_init_simple();
-
-		let transport: Transport = var("WS").unwrap_or("ws://127.0.0.1:9944".to_string()).into();
-		let maybe_state_snapshot: Option<SnapshotConfig> = var("SNAP").map(|s| s.into()).ok();
-		let online_config = OnlineConfig {
-			transport,
-			state_snapshot: maybe_state_snapshot.clone(),
-			child_trie: false,
-			pallets: vec!["Staking".into(), "System".into(), "Balances".into()],
-			..Default::default()
-		};
-		let mut ext = Builder::<Block>::default()
-			.mode(if let Some(state_snapshot) = maybe_state_snapshot {
-				Mode::OfflineOrElseOnline(
-					OfflineConfig { state_snapshot: state_snapshot.clone() },
-					online_config,
-				)
-			} else {
-				Mode::Online(online_config)
-			})
-			.build()
-			.await
-			.unwrap();
-		ext.execute_with(|| {
-			// create an account with some balance
-			let alice = AccountId::from([1u8; 32]);
-			use frame_support::traits::Currency;
-			let _ = Balances::deposit_creating(&alice, 100_000 * UNITS);
-
-			let mut success = 0;
-			let mut err = 0;
-			let mut force_withdraw_acc = 0;
-			// iterate over all pools
-			pallet_staking::Ledger::<Runtime>::iter().for_each(|(ctrl, ledger)| {
-				match pallet_staking::Pallet::<Runtime>::migrate_currency(
-					RuntimeOrigin::signed(alice.clone()).into(),
-					ledger.stash.clone(),
-				) {
-					Ok(_) => {
-						let updated_ledger =
-							pallet_staking::Ledger::<Runtime>::get(&ctrl).expect("ledger exists");
-						let force_withdraw = ledger.total - updated_ledger.total;
-						if force_withdraw > 0 {
-							force_withdraw_acc += force_withdraw;
-							log::info!(target: "remote_test", "Force withdraw from stash {:?}: value {:?}", ledger.stash, force_withdraw);
-						}
-						success += 1;
-					},
-					Err(e) => {
-						log::error!(target: "remote_test", "Error migrating {:?}: {:?}", ledger.stash, e);
-						err += 1;
-					},
-				}
-			});
-
-			log::info!(
-				target: "remote_test",
-				"Migration stats: success: {}, err: {}, total force withdrawn stake: {}",
-				success,
-				err,
-				force_withdraw_acc
-			);
-		});
-	}
 }
 
 #[test]
diff --git a/polkadot/runtime/westend/src/weights/pallet_staking.rs b/polkadot/runtime/westend/src/weights/pallet_staking.rs
index f1e7f5ba1576eafbd768f51cf98faa41cbe02b5c..393fa0b37176a0ca5ce8160eec7e8e3ac56c3458 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-09-17, 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-obbyq9g6-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:
@@ -52,19 +52,19 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// 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::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, 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::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:  `1035`
-		//  Estimated: `4556`
-		// Minimum execution time: 70_147_000 picoseconds.
-		Weight::from_parts(71_795_000, 0)
-			.saturating_add(Weight::from_parts(0, 4556))
+		//  Measured:  `1009`
+		//  Estimated: `4764`
+		// 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(4))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -72,20 +72,20 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// 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: `Staking::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, 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: `VoterList::ListNodes` (r:3 w:3)
 	/// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListBags` (r:2 w:2)
 	/// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`)
 	fn bond_extra() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1947`
+		//  Measured:  `1921`
 		//  Estimated: `8877`
-		// Minimum execution time: 125_203_000 picoseconds.
-		Weight::from_parts(128_088_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))
@@ -100,23 +100,23 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// 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::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:0)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, 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: `VoterList::ListNodes` (r:3 w:3)
 	/// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListBags` (r:2 w:2)
 	/// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`)
 	fn unbond() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `2051`
+		//  Measured:  `2128`
 		//  Estimated: `8877`
-		// Minimum execution time: 101_991_000 picoseconds.
-		Weight::from_parts(104_567_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(6))
+			.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`)
@@ -124,25 +124,23 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// 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::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, 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`)
-	/// Storage: `DelegatedStaking::Agents` (r:1 w:0)
-	/// Proof: `DelegatedStaking::Agents` (`max_values`: None, `max_size`: Some(120), added: 2595, mode: `MaxEncodedLen`)
 	/// The range of component `s` is `[0, 100]`.
 	fn withdraw_unbonded_update(s: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1253`
-		//  Estimated: `4556`
-		// Minimum execution time: 76_450_000 picoseconds.
-		Weight::from_parts(78_836_594, 0)
-			.saturating_add(Weight::from_parts(0, 4556))
-			// Standard Error: 1_529
-			.saturating_add(Weight::from_parts(66_662, 0).saturating_mul(s.into()))
-			.saturating_add(T::DbWeight::get().reads(7))
+		//  Measured:  `1223`
+		//  Estimated: `4764`
+		// Minimum execution time: 45_152_000 picoseconds.
+		Weight::from_parts(46_460_819, 0)
+			.saturating_add(Weight::from_parts(0, 4764))
+			// 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)
@@ -153,10 +151,10 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// 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::VirtualStakers` (r:1 w:1)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, 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::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)
@@ -176,15 +174,15 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// The range of component `s` is `[0, 100]`.
 	fn withdraw_unbonded_kill(s: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `2153 + s * (4 ±0)`
+		//  Measured:  `2127 + s * (4 ±0)`
 		//  Estimated: `6248 + s * (4 ±0)`
-		// Minimum execution time: 121_962_000 picoseconds.
-		Weight::from_parts(131_000_151, 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_846
-			.saturating_add(Weight::from_parts(1_277_843, 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(12))
+			.saturating_add(T::DbWeight::get().writes(11))
 			.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into())))
 			.saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into()))
 	}
@@ -212,10 +210,10 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	fn validate() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1334`
+		//  Measured:  `1301`
 		//  Estimated: `4556`
-		// Minimum execution time: 66_450_000 picoseconds.
-		Weight::from_parts(68_302_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))
@@ -229,13 +227,13 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// The range of component `k` is `[1, 128]`.
 	fn kick(k: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1811 + k * (572 ±0)`
+		//  Measured:  `1778 + k * (572 ±0)`
 		//  Estimated: `4556 + k * (3033 ±0)`
-		// Minimum execution time: 43_875_000 picoseconds.
-		Weight::from_parts(47_332_240, 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_530
-			.saturating_add(Weight::from_parts(7_398_001, 0).saturating_mul(k.into()))
+			// 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())))
@@ -266,13 +264,13 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// The range of component `n` is `[1, 16]`.
 	fn nominate(n: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1830 + n * (102 ±0)`
+		//  Measured:  `1797 + n * (102 ±0)`
 		//  Estimated: `6248 + n * (2520 ±0)`
-		// Minimum execution time: 80_640_000 picoseconds.
-		Weight::from_parts(78_801_092, 0)
+		// Minimum execution time: 62_098_000 picoseconds.
+		Weight::from_parts(60_154_061, 0)
 			.saturating_add(Weight::from_parts(0, 6248))
-			// Standard Error: 22_249
-			.saturating_add(Weight::from_parts(4_996_344, 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))
@@ -296,10 +294,10 @@ 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:  `1780`
+		//  Measured:  `1747`
 		//  Estimated: `6248`
-		// Minimum execution time: 71_494_000 picoseconds.
-		Weight::from_parts(73_487_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(9))
 			.saturating_add(T::DbWeight::get().writes(6))
@@ -312,10 +310,10 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
 	fn set_payee() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `898`
+		//  Measured:  `865`
 		//  Estimated: `4556`
-		// Minimum execution time: 24_310_000 picoseconds.
-		Weight::from_parts(24_676_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))
@@ -328,10 +326,10 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
 	fn update_payee() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `965`
+		//  Measured:  `932`
 		//  Estimated: `4556`
-		// Minimum execution time: 31_348_000 picoseconds.
-		Weight::from_parts(32_384_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))
@@ -342,10 +340,10 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
 	fn set_controller() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `898`
+		//  Measured:  `865`
 		//  Estimated: `8122`
-		// Minimum execution time: 27_537_000 picoseconds.
-		Weight::from_parts(28_714_000, 0)
+		// 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))
@@ -356,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: 2_362_000 picoseconds.
-		Weight::from_parts(2_518_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))
 	}
@@ -367,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: 7_752_000 picoseconds.
-		Weight::from_parts(8_105_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))
 	}
@@ -378,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: 7_868_000 picoseconds.
-		Weight::from_parts(8_175_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))
 	}
@@ -389,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: 7_945_000 picoseconds.
-		Weight::from_parts(8_203_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))
 	}
@@ -401,11 +399,11 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_458_000 picoseconds.
-		Weight::from_parts(2_815_664, 0)
+		// Minimum execution time: 2_025_000 picoseconds.
+		Weight::from_parts(2_229_953, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 			// Standard Error: 67
-			.saturating_add(Weight::from_parts(12_287, 0).saturating_mul(v.into()))
+			.saturating_add(Weight::from_parts(11_785, 0).saturating_mul(v.into()))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
 	/// Storage: `Staking::Ledger` (r:1502 w:1502)
@@ -417,13 +415,13 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// The range of component `i` is `[0, 751]`.
 	fn deprecate_controller_batch(i: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `713 + i * (227 ±0)`
+		//  Measured:  `680 + i * (227 ±0)`
 		//  Estimated: `990 + i * (7132 ±0)`
-		// Minimum execution time: 4_976_000 picoseconds.
-		Weight::from_parts(5_102_000, 0)
+		// Minimum execution time: 4_321_000 picoseconds.
+		Weight::from_parts(4_407_000, 0)
 			.saturating_add(Weight::from_parts(0, 990))
-			// Standard Error: 36_458
-			.saturating_add(Weight::from_parts(25_359_275, 0).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, 7132).saturating_mul(i.into()))
@@ -434,10 +432,10 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// 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: `Staking::VirtualStakers` (r:1 w:1)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, 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: `System::Account` (r:1 w:1)
 	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Validators` (r:1 w:0)
@@ -459,15 +457,15 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// The range of component `s` is `[0, 100]`.
 	fn force_unstake(s: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `2153 + s * (4 ±0)`
+		//  Measured:  `2127 + s * (4 ±0)`
 		//  Estimated: `6248 + s * (4 ±0)`
-		// Minimum execution time: 116_776_000 picoseconds.
-		Weight::from_parts(125_460_389, 0)
+		// Minimum execution time: 78_908_000 picoseconds.
+		Weight::from_parts(84_886_373, 0)
 			.saturating_add(Weight::from_parts(0, 6248))
-			// Standard Error: 3_095
-			.saturating_add(Weight::from_parts(1_300_502, 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(13))
+			.saturating_add(T::DbWeight::get().writes(12))
 			.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into())))
 			.saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into()))
 	}
@@ -476,13 +474,13 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// The range of component `s` is `[1, 1000]`.
 	fn cancel_deferred_slash(s: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `66672`
-		//  Estimated: `70137`
-		// Minimum execution time: 135_135_000 picoseconds.
-		Weight::from_parts(937_565_332, 0)
-			.saturating_add(Weight::from_parts(0, 70137))
-			// Standard Error: 57_675
-			.saturating_add(Weight::from_parts(4_828_080, 0).saturating_mul(s.into()))
+		//  Measured:  `66639`
+		//  Estimated: `70104`
+		// Minimum execution time: 136_389_000 picoseconds.
+		Weight::from_parts(1_207_241_524, 0)
+			.saturating_add(Weight::from_parts(0, 70104))
+			// 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))
 	}
@@ -500,10 +498,12 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::ErasValidatorReward` (r:1 w:0)
 	/// Proof: `Staking::ErasValidatorReward` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::VirtualStakers` (r:65 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:65 w:65)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`)
+	/// Storage: `Balances::Locks` (r:65 w:65)
+	/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
+	/// Storage: `Balances::Freezes` (r:65 w:0)
+	/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`)
+	/// Storage: `System::Account` (r:65 w:65)
+	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::ErasStakersPaged` (r:1 w:0)
 	/// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	/// Storage: `Staking::ErasRewardPoints` (r:1 w:0)
@@ -512,32 +512,30 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// Proof: `Staking::ErasValidatorPrefs` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Payee` (r:65 w:0)
 	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
-	/// Storage: `System::Account` (r:65 w:65)
-	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
 	/// The range of component `n` is `[0, 64]`.
 	fn payout_stakers_alive_staked(n: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `8275 + n * (389 ±0)`
-		//  Estimated: `10805 + n * (3566 ±0)`
-		// Minimum execution time: 180_144_000 picoseconds.
-		Weight::from_parts(237_134_733, 0)
-			.saturating_add(Weight::from_parts(0, 10805))
-			// Standard Error: 52_498
-			.saturating_add(Weight::from_parts(73_633_326, 0).saturating_mul(n.into()))
+		//  Measured:  `8249 + n * (396 ±0)`
+		//  Estimated: `10779 + n * (3774 ±0)`
+		// Minimum execution time: 130_222_000 picoseconds.
+		Weight::from_parts(167_236_150, 0)
+			.saturating_add(Weight::from_parts(0, 10779))
+			// 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))
 			.saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into())))
-			.saturating_add(Weight::from_parts(0, 3566).saturating_mul(n.into()))
+			.saturating_add(Weight::from_parts(0, 3774).saturating_mul(n.into()))
 	}
 	/// 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::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:0)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, 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: `VoterList::ListNodes` (r:3 w:3)
 	/// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListBags` (r:2 w:2)
@@ -545,26 +543,26 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// The range of component `l` is `[1, 32]`.
 	fn rebond(l: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1845 + l * (5 ±0)`
+		//  Measured:  `1922 + l * (5 ±0)`
 		//  Estimated: `8877`
-		// Minimum execution time: 89_307_000 picoseconds.
-		Weight::from_parts(92_902_634, 0)
+		// Minimum execution time: 79_136_000 picoseconds.
+		Weight::from_parts(82_129_497, 0)
 			.saturating_add(Weight::from_parts(0, 8877))
-			// Standard Error: 4_446
-			.saturating_add(Weight::from_parts(73_546, 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(6))
+			.saturating_add(T::DbWeight::get().writes(7))
 	}
-	/// Storage: `Staking::VirtualStakers` (r:1 w:1)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, 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: `Staking::SlashingSpans` (r:1 w:1)
 	/// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`)
-	/// Storage: `Balances::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, 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::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)
@@ -584,15 +582,15 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// The range of component `s` is `[1, 100]`.
 	fn reap_stash(s: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `2153 + s * (4 ±0)`
+		//  Measured:  `2127 + s * (4 ±0)`
 		//  Estimated: `6248 + s * (4 ±0)`
-		// Minimum execution time: 130_544_000 picoseconds.
-		Weight::from_parts(133_260_598, 0)
+		// Minimum execution time: 89_375_000 picoseconds.
+		Weight::from_parts(91_224_907, 0)
 			.saturating_add(Weight::from_parts(0, 6248))
-			// Standard Error: 3_545
-			.saturating_add(Weight::from_parts(1_313_348, 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(12))
+			.saturating_add(T::DbWeight::get().writes(11))
 			.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into())))
 			.saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into()))
 	}
@@ -635,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 ±4) + v * (3566 ±40)`
-		// Minimum execution time: 654_756_000 picoseconds.
-		Weight::from_parts(658_861_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_078_102
-			.saturating_add(Weight::from_parts(67_775_668, 0).saturating_mul(v.into()))
-			// Standard Error: 207_071
-			.saturating_add(Weight::from_parts(22_624_711, 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())))
@@ -671,15 +669,15 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// The range of component `n` is `[500, 1000]`.
 	fn get_npos_voters(v: u32, n: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `3141 + n * (907 ±0) + v * (391 ±0)`
+		//  Measured:  `3108 + n * (907 ±0) + v * (391 ±0)`
 		//  Estimated: `456136 + n * (3566 ±0) + v * (3566 ±0)`
-		// Minimum execution time: 42_790_195_000 picoseconds.
-		Weight::from_parts(42_954_437_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: 478_107
-			.saturating_add(Weight::from_parts(6_744_044, 0).saturating_mul(v.into()))
-			// Standard Error: 478_107
-			.saturating_add(Weight::from_parts(4_837_739, 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())))
@@ -694,13 +692,13 @@ impl<T: frame_system::Config> pallet_staking::WeightInfo for WeightInfo<T> {
 	/// The range of component `v` is `[500, 1000]`.
 	fn get_npos_targets(v: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `979 + v * (50 ±0)`
+		//  Measured:  `946 + v * (50 ±0)`
 		//  Estimated: `3510 + v * (2520 ±0)`
-		// Minimum execution time: 2_851_801_000 picoseconds.
-		Weight::from_parts(4_477_533, 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_644
-			.saturating_add(Weight::from_parts(5_811_682, 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()))
@@ -723,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: 4_250_000 picoseconds.
-		Weight::from_parts(4_472_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))
 	}
@@ -746,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_986_000 picoseconds.
-		Weight::from_parts(4_144_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))
 	}
@@ -775,10 +773,10 @@ 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_other() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1903`
+		//  Measured:  `1870`
 		//  Estimated: `6248`
-		// Minimum execution time: 87_291_000 picoseconds.
-		Weight::from_parts(89_344_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))
@@ -789,10 +787,10 @@ 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`)
 	fn force_apply_min_commission() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `691`
+		//  Measured:  `658`
 		//  Estimated: `3510`
-		// Minimum execution time: 16_113_000 picoseconds.
-		Weight::from_parts(16_593_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))
@@ -803,53 +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: 2_433_000 picoseconds.
-		Weight::from_parts(2_561_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: `Staking::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:0)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`)
-	/// Storage: `System::Account` (r:1 w:0)
-	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Locks` (r:1 w:0)
+	/// 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`)
-	fn restore_ledger() -> Weight {
-		// Proof Size summary in bytes:
-		//  Measured:  `1040`
-		//  Estimated: `4764`
-		// Minimum execution time: 50_167_000 picoseconds.
-		Weight::from_parts(51_108_000, 0)
-			.saturating_add(Weight::from_parts(0, 4764))
-			.saturating_add(T::DbWeight::get().reads(6))
-			.saturating_add(T::DbWeight::get().writes(2))
-	}
-	/// Storage: `Staking::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, 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::Ledger` (r:1 w:0)
-	/// 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::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Freezes` (r:1 w:0)
 	/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`)
-	fn migrate_currency() -> Weight {
+	fn restore_ledger() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1209`
+		//  Measured:  `1014`
 		//  Estimated: `4764`
-		// Minimum execution time: 91_790_000 picoseconds.
-		Weight::from_parts(92_991_000, 0)
+		// 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(6))
-			.saturating_add(T::DbWeight::get().writes(2))
+			.saturating_add(T::DbWeight::get().reads(5))
+			.saturating_add(T::DbWeight::get().writes(4))
 	}
 }
diff --git a/prdoc/pr_5501.prdoc b/prdoc/pr_5501.prdoc
deleted file mode 100644
index f2a5aa9a4667980452d4ac4dc728752da3591634..0000000000000000000000000000000000000000
--- a/prdoc/pr_5501.prdoc
+++ /dev/null
@@ -1,47 +0,0 @@
-# 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: Currency to Fungible migration for pallet-staking
-
-doc:
-  - audience: Runtime User
-    description: |
-      Lazy migration of staking balance from `Currency::locks` to `Fungible::holds`. New extrinsic
-      `staking::migrate_currency` removes the old lock along with other housekeeping. Additionally, any ledger mutation
-      creates hold if it does not exist.
-
-      The pallet-staking configuration item `Currency` is updated to use `fungible::hold::Mutate` type while still
-      requiring `LockableCurrency` type to be passed as `OldCurrency` for migration purposes.
-
-
-crates:
-  - name: westend-runtime
-    bump: major
-  - name: kitchensink-runtime
-    bump: minor
-  - name: pallet-delegated-staking
-    bump: patch
-  - name: pallet-nomination-pools
-    bump: minor
-  - name: pallet-nomination-pools-runtime-api
-    bump: patch
-  - name: sp-staking
-    bump: patch
-  - name: pallet-beefy
-    bump: patch
-  - name: pallet-fast-unstake
-    bump: patch
-  - name: pallet-staking
-    bump: major
-  - name: pallet-grandpa
-    bump: patch
-  - name: pallet-babe
-    bump: patch
-  - name: pallet-nomination-pools-benchmarking
-    bump: patch
-  - name: pallet-session-benchmarking
-    bump: patch
-  - name: pallet-root-offences
-    bump: patch
-  - name: pallet-offences-benchmarking
-    bump: patch
diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs
index 26f4dacf9a1e3039d3cd8e8d0f79415e4727be07..0d9c2df95a82ffd3aa2a8bd50f8e423b2ade41f9 100644
--- a/substrate/bin/node/runtime/src/lib.rs
+++ b/substrate/bin/node/runtime/src/lib.rs
@@ -53,9 +53,7 @@ use frame_support::{
 			Balanced, Credit, HoldConsideration, ItemOf, NativeFromLeft, NativeOrWithId, UnionOf,
 		},
 		tokens::{
-			imbalance::{ResolveAssetTo, ResolveTo},
-			nonfungibles_v2::Inspect,
-			pay::PayAssetFromAccount,
+			imbalance::ResolveAssetTo, nonfungibles_v2::Inspect, pay::PayAssetFromAccount,
 			GetSalary, PayFromAccount,
 		},
 		AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, ConstU32, ConstU64,
@@ -721,15 +719,13 @@ impl pallet_staking::BenchmarkingConfig for StakingBenchmarkingConfig {
 }
 
 impl pallet_staking::Config for Runtime {
-	type OldCurrency = Balances;
 	type Currency = Balances;
 	type CurrencyBalance = Balance;
 	type UnixTime = Timestamp;
 	type CurrencyToVote = sp_staking::currency_to_vote::U128CurrencyToVote;
-	type RewardRemainder = ResolveTo<TreasuryAccount, Balances>;
+	type RewardRemainder = Treasury;
 	type RuntimeEvent = RuntimeEvent;
-	type RuntimeHoldReason = RuntimeHoldReason;
-	type Slash = ResolveTo<TreasuryAccount, Balances>; // send the slashed funds to the treasury.
+	type Slash = Treasury; // send the slashed funds to the treasury.
 	type Reward = (); // rewards are minted from the void
 	type SessionsPerEra = SessionsPerEra;
 	type BondingDuration = BondingDuration;
@@ -752,7 +748,7 @@ impl pallet_staking::Config for Runtime {
 	type MaxUnlockingChunks = ConstU32<32>;
 	type MaxControllersInDeprecationBatch = MaxControllersInDeprecationBatch;
 	type HistoryDepth = HistoryDepth;
-	type EventListeners = (NominationPools, DelegatedStaking);
+	type EventListeners = NominationPools;
 	type WeightInfo = pallet_staking::weights::SubstrateWeight<Runtime>;
 	type BenchmarkingConfig = StakingBenchmarkingConfig;
 	type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy;
@@ -936,21 +932,6 @@ impl pallet_bags_list::Config<VoterBagsListInstance> for Runtime {
 	type WeightInfo = pallet_bags_list::weights::SubstrateWeight<Runtime>;
 }
 
-parameter_types! {
-	pub const DelegatedStakingPalletId: PalletId = PalletId(*b"py/dlstk");
-	pub const SlashRewardFraction: Perbill = Perbill::from_percent(1);
-}
-
-impl pallet_delegated_staking::Config for Runtime {
-	type RuntimeEvent = RuntimeEvent;
-	type PalletId = DelegatedStakingPalletId;
-	type Currency = Balances;
-	type OnSlash = ();
-	type SlashRewardFraction = SlashRewardFraction;
-	type RuntimeHoldReason = RuntimeHoldReason;
-	type CoreStaking = Staking;
-}
-
 parameter_types! {
 	pub const PostUnbondPoolsWindow: u32 = 4;
 	pub const NominationPoolsPalletId: PalletId = PalletId(*b"py/nopls");
@@ -979,8 +960,7 @@ impl pallet_nomination_pools::Config for Runtime {
 	type RewardCounter = FixedU128;
 	type BalanceToU256 = BalanceToU256;
 	type U256ToBalance = U256ToBalance;
-	type StakeAdapter =
-		pallet_nomination_pools::adapter::DelegateStake<Self, Staking, DelegatedStaking>;
+	type StakeAdapter = pallet_nomination_pools::adapter::TransferStake<Self, Staking>;
 	type PostUnbondingPoolsWindow = PostUnbondPoolsWindow;
 	type MaxMetadataLen = ConstU32<256>;
 	type MaxUnbonding = ConstU32<8>;
@@ -2710,9 +2690,6 @@ mod runtime {
 	#[runtime::pallet_index(81)]
 	pub type VerifySignature = pallet_verify_signature::Pallet<Runtime>;
 
-	#[runtime::pallet_index(82)]
-	pub type DelegatedStaking = pallet_delegated_staking::Pallet<Runtime>;
-
 	#[runtime::pallet_index(83)]
 	pub type AssetRewards = pallet_asset_rewards::Pallet<Runtime>;
 
diff --git a/substrate/bin/node/testing/src/genesis.rs b/substrate/bin/node/testing/src/genesis.rs
index 0394f6cd7394d3715c268229ba254053d6de5f53..7f5364744c667f711a5e2c32e20636e904ee02c2 100644
--- a/substrate/bin/node/testing/src/genesis.rs
+++ b/substrate/bin/node/testing/src/genesis.rs
@@ -38,9 +38,9 @@ pub fn config_endowed(extra_endowed: Vec<AccountId>) -> RuntimeGenesisConfig {
 		(alice(), 111 * DOLLARS),
 		(bob(), 100 * DOLLARS),
 		(charlie(), 100_000_000 * DOLLARS),
-		(dave(), 112 * DOLLARS),
+		(dave(), 111 * DOLLARS),
 		(eve(), 101 * DOLLARS),
-		(ferdie(), 101 * DOLLARS),
+		(ferdie(), 100 * DOLLARS),
 	];
 
 	endowed.extend(extra_endowed.into_iter().map(|endowed| (endowed, 100 * DOLLARS)));
diff --git a/substrate/frame/babe/src/mock.rs b/substrate/frame/babe/src/mock.rs
index 8d00509e800b6368696bdea8ca686ef51f6bc71a..23857470adc4a5c751ef276a4c2d72b34f078490 100644
--- a/substrate/frame/babe/src/mock.rs
+++ b/substrate/frame/babe/src/mock.rs
@@ -157,7 +157,6 @@ impl onchain::Config for OnChainSeqPhragmen {
 
 #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)]
 impl pallet_staking::Config for Test {
-	type OldCurrency = Balances;
 	type Currency = Balances;
 	type SessionsPerEra = SessionsPerEra;
 	type BondingDuration = BondingDuration;
diff --git a/substrate/frame/beefy/src/mock.rs b/substrate/frame/beefy/src/mock.rs
index 38e0cc4cfc26641063af61a33b93cd8e996a2a84..7ae41c609180e4741c668372c2c2392bbb140808 100644
--- a/substrate/frame/beefy/src/mock.rs
+++ b/substrate/frame/beefy/src/mock.rs
@@ -235,7 +235,6 @@ impl onchain::Config for OnChainSeqPhragmen {
 #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)]
 impl pallet_staking::Config for Test {
 	type RuntimeEvent = RuntimeEvent;
-	type OldCurrency = Balances;
 	type Currency = Balances;
 	type AdminOrigin = frame_system::EnsureRoot<Self::AccountId>;
 	type SessionInterface = Self;
diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs
index 0dacfe9c55792f53e07fe708323ed6e0f8d5c784..1d181eb29cab7321d94b083149a8e58a17ecd924 100644
--- a/substrate/frame/delegated-staking/src/lib.rs
+++ b/substrate/frame/delegated-staking/src/lib.rs
@@ -520,7 +520,7 @@ impl<T: Config> Pallet<T> {
 		let stake = T::CoreStaking::stake(who)?;
 
 		// release funds from core staking.
-		T::CoreStaking::migrate_to_virtual_staker(who)?;
+		T::CoreStaking::migrate_to_virtual_staker(who);
 
 		// transfer just released staked amount plus any free amount.
 		let amount_to_transfer =
diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs
index 875279864f7ab3794777b1f8bf1756a4c15b703b..811d5739f4e98f24c30c7514455dac049fbbc421 100644
--- a/substrate/frame/delegated-staking/src/mock.rs
+++ b/substrate/frame/delegated-staking/src/mock.rs
@@ -102,7 +102,6 @@ impl onchain::Config for OnChainSeqPhragmen {
 
 #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)]
 impl pallet_staking::Config for Runtime {
-	type OldCurrency = Balances;
 	type Currency = Balances;
 	type UnixTime = pallet_timestamp::Pallet<Self>;
 	type AdminOrigin = frame_system::EnsureRoot<Self::AccountId>;
diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs
index c764e2741a2a4a0149853f2279bd8b556ba4b20b..b7b82a43771eb388ee1a5e0e11145e614f56930f 100644
--- a/substrate/frame/delegated-staking/src/tests.rs
+++ b/substrate/frame/delegated-staking/src/tests.rs
@@ -671,14 +671,12 @@ mod staking_integration {
 			));
 			assert_ok!(Staking::nominate(RuntimeOrigin::signed(agent), vec![GENESIS_VALIDATOR],));
 			let init_stake = Staking::stake(&agent).unwrap();
-			// no extra provider added.
-			assert_eq!(System::providers(&agent), 1);
 
 			// 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 delegate based stake.
 
 			// all balance currently is in 200
-			assert_eq!(pallet_staking::asset::total_balance::<T>(&agent), agent_amount);
+			assert_eq!(pallet_staking::asset::stakeable_balance::<T>(&agent), agent_amount);
 
 			// 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
@@ -687,9 +685,8 @@ mod staking_integration {
 				DelegatedStaking::generate_proxy_delegator(Agent::from(agent)).get();
 
 			assert_ok!(DelegatedStaking::migrate_to_agent(RawOrigin::Signed(agent).into(), 201));
-			// after migration, no provider left since free balance is 0 and staking pallet released
-			// all funds.
-			assert_eq!(System::providers(&agent), 0);
+			// after migration, funds are moved to proxy delegator, still a provider exists.
+			assert_eq!(System::providers(&agent), 1);
 			assert_eq!(Balances::free_balance(agent), 0);
 			// proxy delegator has one provider as well with no free balance.
 			assert_eq!(System::providers(&proxy_delegator), 1);
@@ -801,6 +798,8 @@ mod staking_integration {
 				RawOrigin::Signed(agent).into(),
 				reward_acc
 			));
+			// becoming an agent adds another provider.
+			assert_eq!(System::providers(&agent), 2);
 
 			// delegate to this account
 			fund(&delegator, 1000);
diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs
index 14f49466f0e2867fec4da4a360a53fe816d72d22..a78aa3f559060080344b84002d099ca8cb18caaa 100644
--- a/substrate/frame/delegated-staking/src/types.rs
+++ b/substrate/frame/delegated-staking/src/types.rs
@@ -131,6 +131,10 @@ impl<T: Config> AgentLedger<T> {
 	///
 	/// Increments provider count if this is a new agent.
 	pub(crate) fn update(self, key: &T::AccountId) {
+		if !<Agents<T>>::contains_key(key) {
+			// This is a new agent. Provide for this account.
+			frame_system::Pallet::<T>::inc_providers(key);
+		}
 		<Agents<T>>::insert(key, self)
 	}
 
@@ -138,6 +142,8 @@ impl<T: Config> AgentLedger<T> {
 	pub(crate) fn remove(key: &T::AccountId) {
 		debug_assert!(<Agents<T>>::contains_key(key), "Agent should exist in storage");
 		<Agents<T>>::remove(key);
+		// Remove provider reference.
+		let _ = frame_system::Pallet::<T>::dec_providers(key).defensive();
 	}
 
 	/// Effective total balance of the `Agent`.
diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml
index f11f9c04dbf4a6b5da7a04ebb17a1af89826df36..7a48ae868a5a2e63d6b0467753cf5ca5f8b56f2c 100644
--- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml
+++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml
@@ -34,7 +34,6 @@ frame-system = { workspace = true, default-features = true }
 
 pallet-bags-list = { workspace = true, default-features = true }
 pallet-balances = { workspace = true, default-features = true }
-pallet-delegated-staking = { workspace = true, default-features = true }
 pallet-election-provider-multi-phase = { workspace = true, default-features = true }
 pallet-nomination-pools = { workspace = true, default-features = true }
 pallet-session = { workspace = true, default-features = true }
@@ -48,7 +47,6 @@ try-runtime = [
 	"frame-system/try-runtime",
 	"pallet-bags-list/try-runtime",
 	"pallet-balances/try-runtime",
-	"pallet-delegated-staking/try-runtime",
 	"pallet-election-provider-multi-phase/try-runtime",
 	"pallet-nomination-pools/try-runtime",
 	"pallet-session/try-runtime",
diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs
index b1029e89fe85f65650fb5406314241c220cd2b28..26a6345e145ff1050581e32534d8b6fa09ba450d 100644
--- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs
+++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs
@@ -327,8 +327,8 @@ fn automatic_unbonding_pools() {
 		assert_eq!(<Runtime as pallet_nomination_pools::Config>::MaxUnbonding::get(), 1);
 
 		// init state of pool members.
-		let init_free_balance_2 = Balances::free_balance(2);
-		let init_free_balance_3 = Balances::free_balance(3);
+		let init_stakeable_balance_2 = pallet_staking::asset::stakeable_balance::<Runtime>(&2);
+		let init_stakeable_balance_3 = pallet_staking::asset::stakeable_balance::<Runtime>(&3);
 
 		let pool_bonded_account = Pools::generate_bonded_account(1);
 
@@ -378,7 +378,7 @@ fn automatic_unbonding_pools() {
 		System::reset_events();
 
 		let staked_before_withdraw_pool = staked_amount_for(pool_bonded_account);
-		assert_eq!(delegated_balance_for(pool_bonded_account), 5 + 10 + 10);
+		assert_eq!(pallet_staking::asset::stakeable_balance::<Runtime>(&pool_bonded_account), 26);
 
 		// now unbonding 3 will work, although the pool's ledger still has the unlocking chunks
 		// filled up.
@@ -390,13 +390,13 @@ fn automatic_unbonding_pools() {
 			[
 				// auto-withdraw happened as expected to release 2's unbonding funds, but the funds
 				// were not transferred to 2 and stay in the pool's transferrable balance instead.
-				pallet_staking::Event::Withdrawn { stash: pool_bonded_account, amount: 10 },
-				pallet_staking::Event::Unbonded { stash: pool_bonded_account, amount: 10 }
+				pallet_staking::Event::Withdrawn { stash: 7939698191839293293, amount: 10 },
+				pallet_staking::Event::Unbonded { stash: 7939698191839293293, amount: 10 }
 			]
 		);
 
 		// balance of the pool remains the same, it hasn't withdraw explicitly from the pool yet.
-		assert_eq!(delegated_balance_for(pool_bonded_account), 25);
+		assert_eq!(pallet_staking::asset::stakeable_balance::<Runtime>(&pool_bonded_account), 26);
 		// but the locked amount in the pool's account decreases due to the auto-withdraw:
 		assert_eq!(staked_before_withdraw_pool - 10, staked_amount_for(pool_bonded_account));
 
@@ -405,12 +405,12 @@ fn automatic_unbonding_pools() {
 
 		// however, note that the withdrawing from the pool still works for 2, the funds are taken
 		// from the pool's non staked balance.
-		assert_eq!(delegated_balance_for(pool_bonded_account), 25);
-		assert_eq!(staked_amount_for(pool_bonded_account), 15);
+		assert_eq!(pallet_staking::asset::stakeable_balance::<Runtime>(&pool_bonded_account), 26);
+		assert_eq!(pallet_staking::asset::staked::<Runtime>(&pool_bonded_account), 15);
 		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(2), 2, 10));
-		assert_eq!(delegated_balance_for(pool_bonded_account), 15);
+		assert_eq!(pallet_staking::asset::stakeable_balance::<Runtime>(&pool_bonded_account), 16);
 
-		assert_eq!(Balances::free_balance(2), 20);
+		assert_eq!(pallet_staking::asset::stakeable_balance::<Runtime>(&2), 20);
 		assert_eq!(TotalValueLocked::<Runtime>::get(), 15);
 
 		// 3 cannot withdraw yet.
@@ -429,9 +429,15 @@ fn automatic_unbonding_pools() {
 		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(3), 3, 10));
 
 		// final conditions are the expected.
-		assert_eq!(delegated_balance_for(pool_bonded_account), 5); // 5 init bonded
-		assert_eq!(Balances::free_balance(2), init_free_balance_2);
-		assert_eq!(Balances::free_balance(3), init_free_balance_3);
+		assert_eq!(pallet_staking::asset::stakeable_balance::<Runtime>(&pool_bonded_account), 6); // 5 init bonded + ED
+		assert_eq!(
+			pallet_staking::asset::stakeable_balance::<Runtime>(&2),
+			init_stakeable_balance_2
+		);
+		assert_eq!(
+			pallet_staking::asset::stakeable_balance::<Runtime>(&3),
+			init_stakeable_balance_3
+		);
 
 		assert_eq!(TotalValueLocked::<Runtime>::get(), init_tvl);
 	});
diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs
index bcb25f8287b35e07dd7a690362df7d0aca75677b..eaab848c1694485c47e4274ea83f223be53cd183 100644
--- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs
+++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs
@@ -21,7 +21,6 @@ use frame_support::{
 	assert_ok, parameter_types, traits,
 	traits::{Hooks, UnfilteredDispatchable, VariantCountOf},
 	weights::constants,
-	PalletId,
 };
 use frame_system::EnsureRoot;
 use sp_core::{ConstU32, Get};
@@ -37,7 +36,7 @@ use sp_runtime::{
 };
 use sp_staking::{
 	offence::{OffenceDetails, OnOffenceHandler},
-	Agent, DelegationInterface, EraIndex, SessionIndex, StakingInterface,
+	EraIndex, SessionIndex,
 };
 use std::collections::BTreeMap;
 
@@ -69,7 +68,6 @@ frame_support::construct_runtime!(
 		System: frame_system,
 		ElectionProviderMultiPhase: pallet_election_provider_multi_phase,
 		Staking: pallet_staking,
-		DelegatedStaking: pallet_delegated_staking,
 		Pools: pallet_nomination_pools,
 		Balances: pallet_balances,
 		BagsList: pallet_bags_list,
@@ -79,7 +77,7 @@ frame_support::construct_runtime!(
 	}
 );
 
-pub(crate) type AccountId = u128;
+pub(crate) type AccountId = u64;
 pub(crate) type AccountIndex = u32;
 pub(crate) type BlockNumber = u32;
 pub(crate) type Balance = u64;
@@ -89,10 +87,8 @@ pub(crate) type Moment = u32;
 
 #[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
 impl frame_system::Config for Runtime {
-	type AccountId = AccountId;
 	type Block = Block;
 	type AccountData = pallet_balances::AccountData<Balance>;
-	type Lookup = sp_runtime::traits::IdentityLookup<Self::AccountId>;
 }
 
 const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
@@ -269,8 +265,7 @@ impl pallet_nomination_pools::Config for Runtime {
 	type RewardCounter = sp_runtime::FixedU128;
 	type BalanceToU256 = BalanceToU256;
 	type U256ToBalance = U256ToBalance;
-	type StakeAdapter =
-		pallet_nomination_pools::adapter::DelegateStake<Self, Staking, DelegatedStaking>;
+	type StakeAdapter = pallet_nomination_pools::adapter::TransferStake<Self, Staking>;
 	type PostUnbondingPoolsWindow = ConstU32<2>;
 	type PalletId = PoolsPalletId;
 	type MaxMetadataLen = ConstU32<256>;
@@ -279,21 +274,6 @@ impl pallet_nomination_pools::Config for Runtime {
 	type AdminOrigin = frame_system::EnsureRoot<Self::AccountId>;
 }
 
-parameter_types! {
-	pub const DelegatedStakingPalletId: PalletId = PalletId(*b"py/dlstk");
-	pub const SlashRewardFraction: Perbill = Perbill::from_percent(1);
-}
-
-impl pallet_delegated_staking::Config for Runtime {
-	type RuntimeEvent = RuntimeEvent;
-	type PalletId = DelegatedStakingPalletId;
-	type Currency = Balances;
-	type OnSlash = ();
-	type SlashRewardFraction = SlashRewardFraction;
-	type RuntimeHoldReason = RuntimeHoldReason;
-	type CoreStaking = Staking;
-}
-
 parameter_types! {
 	pub static MaxUnlockingChunks: u32 = 32;
 }
@@ -305,7 +285,6 @@ pub(crate) const SLASHING_DISABLING_FACTOR: usize = 3;
 
 #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)]
 impl pallet_staking::Config for Runtime {
-	type OldCurrency = Balances;
 	type Currency = Balances;
 	type CurrencyBalance = Balance;
 	type UnixTime = Timestamp;
@@ -323,7 +302,7 @@ impl pallet_staking::Config for Runtime {
 	type NominationsQuota = pallet_staking::FixedNominationsQuota<MAX_QUOTA_NOMINATIONS>;
 	type TargetList = pallet_staking::UseValidatorsMap<Self>;
 	type MaxUnlockingChunks = MaxUnlockingChunks;
-	type EventListeners = (Pools, DelegatedStaking);
+	type EventListeners = Pools;
 	type WeightInfo = pallet_staking::weights::SubstrateWeight<Runtime>;
 	type DisablingStrategy =
 		pallet_staking::UpToLimitWithReEnablingDisablingStrategy<SLASHING_DISABLING_FACTOR>;
@@ -523,7 +502,7 @@ impl Default for BalancesExtBuilder {
 			(100, 100),
 			(200, 100),
 			// stashes
-			(11, 1100),
+			(11, 1000),
 			(21, 2000),
 			(31, 3000),
 			(41, 4000),
@@ -602,7 +581,7 @@ impl ExtBuilder {
 			// set the keys for the first session.
 			keys: stakers
 				.into_iter()
-				.map(|(id, ..)| (id, id, SessionKeys { other: (id as AccountId as u64).into() }))
+				.map(|(id, ..)| (id, id, SessionKeys { other: (id as u64).into() }))
 				.collect(),
 			..Default::default()
 		}
@@ -947,11 +926,7 @@ pub(crate) fn set_minimum_election_score(
 }
 
 pub(crate) fn staked_amount_for(account_id: AccountId) -> Balance {
-	Staking::total_stake(&account_id).expect("account must be staker")
-}
-
-pub(crate) fn delegated_balance_for(account_id: AccountId) -> Balance {
-	DelegatedStaking::agent_balance(Agent::from(account_id)).unwrap_or_default()
+	pallet_staking::asset::staked::<Runtime>(&account_id)
 }
 
 pub(crate) fn staking_events() -> Vec<pallet_staking::Event<Runtime>> {
diff --git a/substrate/frame/fast-unstake/src/mock.rs b/substrate/frame/fast-unstake/src/mock.rs
index cf4f5f49240e98eaf42a944687b3fd4df81fe431..f044fc610187578afd9276d48fb0ad5f2c6569ad 100644
--- a/substrate/frame/fast-unstake/src/mock.rs
+++ b/substrate/frame/fast-unstake/src/mock.rs
@@ -105,7 +105,6 @@ impl frame_election_provider_support::ElectionProvider for MockElection {
 
 #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)]
 impl pallet_staking::Config for Runtime {
-	type OldCurrency = Balances;
 	type Currency = Balances;
 	type UnixTime = pallet_timestamp::Pallet<Self>;
 	type AdminOrigin = frame_system::EnsureRoot<Self::AccountId>;
@@ -224,9 +223,8 @@ impl ExtBuilder {
 				.clone()
 				.into_iter()
 				.map(|(stash, _, balance)| (stash, balance * 2))
-				// give stakers enough balance for stake, ed and fast unstake deposit.
-				.chain(validators_range.clone().map(|x| (x, 7 + 1 + 100)))
-				.chain(nominators_range.clone().map(|x| (x, 7 + 1 + 100)))
+				.chain(validators_range.clone().map(|x| (x, 7 + 100)))
+				.chain(nominators_range.clone().map(|x| (x, 7 + 100)))
 				.collect::<Vec<_>>(),
 		}
 		.assimilate_storage(&mut storage);
diff --git a/substrate/frame/fast-unstake/src/tests.rs b/substrate/frame/fast-unstake/src/tests.rs
index 0fddb88e02b7bef231d5f9bb3961318c8656dc24..7c11f381ca102927e10a3b8241d87dfa28a07d5b 100644
--- a/substrate/frame/fast-unstake/src/tests.rs
+++ b/substrate/frame/fast-unstake/src/tests.rs
@@ -19,15 +19,7 @@
 
 use super::*;
 use crate::{mock::*, types::*, Event};
-use frame_support::{
-	pallet_prelude::*,
-	testing_prelude::*,
-	traits::{
-		fungible::Inspect,
-		tokens::{Fortitude::Polite, Preservation::Expendable},
-		Currency,
-	},
-};
+use frame_support::{pallet_prelude::*, testing_prelude::*, traits::Currency};
 use pallet_staking::{CurrentEra, RewardDestination};
 
 use sp_runtime::traits::BadOrigin;
@@ -154,7 +146,7 @@ fn deregister_works() {
 
 		// Controller then changes mind and deregisters.
 		assert_ok!(FastUnstake::deregister(RuntimeOrigin::signed(1)));
-		assert_eq!(<T as Config>::Currency::reserved_balance(&1), pre_reserved);
+		assert_eq!(<T as Config>::Currency::reserved_balance(&1) - pre_reserved, 0);
 
 		// Ensure stash no longer exists in the queue.
 		assert_eq!(Queue::<T>::get(1), None);
@@ -305,7 +297,7 @@ mod on_idle {
 			);
 			assert_eq!(Queue::<T>::count(), 3);
 
-			assert_eq!(<T as Config>::Currency::reserved_balance(&1), pre_reserved);
+			assert_eq!(<T as Config>::Currency::reserved_balance(&1) - pre_reserved, 0);
 
 			assert_eq!(
 				fast_unstake_events_since_last_call(),
@@ -801,8 +793,6 @@ mod on_idle {
 				RuntimeOrigin::signed(VALIDATOR_PREFIX),
 				vec![VALIDATOR_PREFIX]
 			));
-
-			assert_eq!(Balances::reducible_balance(&VALIDATOR_PREFIX, Expendable, Polite), 7);
 			assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(VALIDATOR_PREFIX)));
 
 			// but they indeed are exposed!
diff --git a/substrate/frame/grandpa/src/mock.rs b/substrate/frame/grandpa/src/mock.rs
index 0a85d9ffd2b08c4668b874685d9547a8a20785ee..87369c23948ca0993fc986f555782c48397549b2 100644
--- a/substrate/frame/grandpa/src/mock.rs
+++ b/substrate/frame/grandpa/src/mock.rs
@@ -161,7 +161,6 @@ impl onchain::Config for OnChainSeqPhragmen {
 
 #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)]
 impl pallet_staking::Config for Test {
-	type OldCurrency = Balances;
 	type Currency = Balances;
 	type CurrencyBalance = <Self as pallet_balances::Config>::Balance;
 	type SessionsPerEra = SessionsPerEra;
diff --git a/substrate/frame/nomination-pools/benchmarking/src/inner.rs b/substrate/frame/nomination-pools/benchmarking/src/inner.rs
index 20c5eafbcfc59dee4d2460224e83a70458804d6d..7ddb78cca3f9b8d78293f37c2e894ed805b84ed3 100644
--- a/substrate/frame/nomination-pools/benchmarking/src/inner.rs
+++ b/substrate/frame/nomination-pools/benchmarking/src/inner.rs
@@ -132,10 +132,6 @@ fn migrate_to_transfer_stake<T: Config>(pool_id: PoolId) {
 			.expect("member should have enough balance to transfer");
 		});
 
-	// Pool needs to have ED balance free to stake so give it some.
-	// Note: we didn't require ED until pallet-staking migrated from locks to holds.
-	let _ = CurrencyOf::<T>::mint_into(&pool_acc, CurrencyOf::<T>::minimum_balance());
-
 	pallet_staking::Pallet::<T>::migrate_to_direct_staker(&pool_acc);
 }
 
@@ -145,6 +141,14 @@ fn vote_to_balance<T: pallet_nomination_pools::Config>(
 	vote.try_into().map_err(|_| "could not convert u64 to Balance")
 }
 
+/// `assertion` should strictly be true if the adapter is using `Delegate` strategy and strictly
+/// false if the adapter is not using `Delegate` strategy.
+fn assert_if_delegate<T: pallet_nomination_pools::Config>(assertion: bool) {
+	let legacy_adapter_used = T::StakeAdapter::strategy_type() != StakeStrategyType::Delegate;
+	// one and only one of the two should be true.
+	assert!(assertion ^ legacy_adapter_used);
+}
+
 #[allow(unused)]
 struct ListScenario<T: pallet_nomination_pools::Config> {
 	/// Stash/Controller that is expected to be moved.
@@ -977,6 +981,9 @@ mod benchmarks {
 
 	#[benchmark]
 	fn apply_slash() {
+		// Note: With older `TransferStake` strategy, slashing is greedy and apply_slash should
+		// always fail.
+
 		// We want to fill member's unbonding pools. So let's bond with big enough amount.
 		let deposit_amount =
 			Pools::<T>::depositor_min_bond() * T::MaxUnbonding::get().into() * 4u32.into();
@@ -986,7 +993,7 @@ mod benchmarks {
 		// verify user balance in the pool.
 		assert_eq!(PoolMembers::<T>::get(&depositor).unwrap().total_balance(), deposit_amount);
 		// verify delegated balance.
-		assert!(
+		assert_if_delegate::<T>(
 			T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())) ==
 				Some(deposit_amount),
 		);
@@ -1010,7 +1017,7 @@ mod benchmarks {
 			deposit_amount / 2u32.into()
 		);
 		// verify delegated balance are not yet slashed.
-		assert!(
+		assert_if_delegate::<T>(
 			T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())) ==
 				Some(deposit_amount),
 		);
@@ -1034,11 +1041,13 @@ mod benchmarks {
 
 		#[block]
 		{
-			assert!(Pools::<T>::apply_slash(
-				RuntimeOrigin::Signed(slash_reporter.clone()).into(),
-				depositor_lookup.clone(),
-			)
-			.is_ok(),);
+			assert_if_delegate::<T>(
+				Pools::<T>::apply_slash(
+					RuntimeOrigin::Signed(slash_reporter.clone()).into(),
+					depositor_lookup.clone(),
+				)
+				.is_ok(),
+			);
 		}
 
 		// verify balances are correct and slash applied.
@@ -1046,7 +1055,7 @@ mod benchmarks {
 			PoolMembers::<T>::get(&depositor).unwrap().total_balance(),
 			deposit_amount / 2u32.into()
 		);
-		assert!(
+		assert_if_delegate::<T>(
 			T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())) ==
 				Some(deposit_amount / 2u32.into()),
 		);
@@ -1117,16 +1126,18 @@ mod benchmarks {
 		let _ = migrate_to_transfer_stake::<T>(1);
 		#[block]
 		{
-			assert!(Pools::<T>::migrate_pool_to_delegate_stake(
-				RuntimeOrigin::Signed(depositor.clone()).into(),
-				1u32.into(),
-			)
-			.is_ok(),);
+			assert_if_delegate::<T>(
+				Pools::<T>::migrate_pool_to_delegate_stake(
+					RuntimeOrigin::Signed(depositor.clone()).into(),
+					1u32.into(),
+				)
+				.is_ok(),
+			);
 		}
-		// this queries agent balance.
+		// this queries agent balance if `DelegateStake` strategy.
 		assert_eq!(
 			T::StakeAdapter::total_balance(Pool::from(pool_account.clone())),
-			Some(deposit_amount + CurrencyOf::<T>::minimum_balance())
+			Some(deposit_amount)
 		);
 	}
 
@@ -1141,11 +1152,13 @@ mod benchmarks {
 		let _ = migrate_to_transfer_stake::<T>(1);
 
 		// Now migrate pool to delegate stake keeping delegators unmigrated.
-		assert!(Pools::<T>::migrate_pool_to_delegate_stake(
-			RuntimeOrigin::Signed(depositor.clone()).into(),
-			1u32.into(),
-		)
-		.is_ok(),);
+		assert_if_delegate::<T>(
+			Pools::<T>::migrate_pool_to_delegate_stake(
+				RuntimeOrigin::Signed(depositor.clone()).into(),
+				1u32.into(),
+			)
+			.is_ok(),
+		);
 
 		// delegation does not exist.
 		assert!(
@@ -1158,14 +1171,16 @@ mod benchmarks {
 
 		#[block]
 		{
-			assert!(Pools::<T>::migrate_delegation(
-				RuntimeOrigin::Signed(depositor.clone()).into(),
-				depositor_lookup.clone(),
-			)
-			.is_ok(),);
+			assert_if_delegate::<T>(
+				Pools::<T>::migrate_delegation(
+					RuntimeOrigin::Signed(depositor.clone()).into(),
+					depositor_lookup.clone(),
+				)
+				.is_ok(),
+			);
 		}
 		// verify balances once more.
-		assert!(
+		assert_if_delegate::<T>(
 			T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())) ==
 				Some(deposit_amount),
 		);
diff --git a/substrate/frame/nomination-pools/benchmarking/src/mock.rs b/substrate/frame/nomination-pools/benchmarking/src/mock.rs
index 7c09cf22ad51e9575780525718d4fdd830bb6ecd..15d9e2c56031fe1e47b7b0cef3139ca177ddeb67 100644
--- a/substrate/frame/nomination-pools/benchmarking/src/mock.rs
+++ b/substrate/frame/nomination-pools/benchmarking/src/mock.rs
@@ -78,7 +78,6 @@ parameter_types! {
 }
 #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)]
 impl pallet_staking::Config for Runtime {
-	type OldCurrency = Balances;
 	type Currency = Balances;
 	type CurrencyBalance = Balance;
 	type UnixTime = pallet_timestamp::Pallet<Self>;
diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs
index f1c68af4ea6ad170bbd54af728cdfd68dcef3688..f125919dabfa6bce68dea67dd4fd60ed26ec0e3c 100644
--- a/substrate/frame/nomination-pools/src/adapter.rs
+++ b/substrate/frame/nomination-pools/src/adapter.rs
@@ -16,7 +16,6 @@
 // limitations under the License.
 
 use crate::*;
-use frame_support::traits::tokens::{Fortitude::Polite, Preservation::Expendable};
 use sp_staking::{Agent, DelegationInterface, DelegationMigrator, Delegator};
 
 /// Types of stake strategies.
@@ -246,10 +245,8 @@ pub trait StakeStrategy {
 /// strategy in an existing runtime, storage migration is required. See
 /// [`migration::unversioned::DelegationStakeMigration`]. For new runtimes, it is highly recommended
 /// to use the [`DelegateStake`] strategy.
-#[deprecated = "consider migrating to DelegateStake"]
 pub struct TransferStake<T: Config, Staking: StakingInterface>(PhantomData<(T, Staking)>);
 
-#[allow(deprecated)]
 impl<T: Config, Staking: StakingInterface<Balance = BalanceOf<T>, AccountId = T::AccountId>>
 	StakeStrategy for TransferStake<T, Staking>
 {
@@ -265,8 +262,7 @@ impl<T: Config, Staking: StakingInterface<Balance = BalanceOf<T>, AccountId = T:
 		pool_account: Pool<Self::AccountId>,
 		_: Member<Self::AccountId>,
 	) -> BalanceOf<T> {
-		// free/liquid balance of the pool account.
-		T::Currency::reducible_balance(&pool_account.get(), Expendable, Polite)
+		T::Currency::balance(&pool_account.0).saturating_sub(Self::active_stake(pool_account))
 	}
 
 	fn total_balance(pool_account: Pool<Self::AccountId>) -> Option<BalanceOf<T>> {
diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs
index f4552389a267abaacb459ed3b4fea0a82daa1a80..f544e79ec48192b77718c7ab2ef0b40d6cea3bd0 100644
--- a/substrate/frame/nomination-pools/src/mock.rs
+++ b/substrate/frame/nomination-pools/src/mock.rs
@@ -23,10 +23,8 @@ use frame_support::{
 	PalletId,
 };
 use frame_system::{EnsureSignedBy, RawOrigin};
-use sp_runtime::{BuildStorage, DispatchResult, FixedU128};
-use sp_staking::{
-	Agent, DelegationInterface, DelegationMigrator, Delegator, OnStakingUpdate, Stake,
-};
+use sp_runtime::{BuildStorage, FixedU128};
+use sp_staking::{OnStakingUpdate, Stake};
 
 pub type BlockNumber = u64;
 pub type AccountId = u128;
@@ -78,7 +76,6 @@ impl StakingMock {
 		let bonded = BondedBalanceMap::get();
 		let pre_total = bonded.get(&acc).unwrap();
 		Self::set_bonded_balance(acc, pre_total - amount);
-		DelegateMock::on_slash(acc, amount);
 		Pools::on_slash(&acc, pre_total - amount, &Default::default(), amount);
 	}
 }
@@ -115,8 +112,8 @@ impl sp_staking::StakingInterface for StakingMock {
 			.ok_or(DispatchError::Other("NotStash"))
 	}
 
-	fn is_virtual_staker(who: &Self::AccountId) -> bool {
-		AgentBalanceMap::get().contains_key(who)
+	fn is_virtual_staker(_who: &Self::AccountId) -> bool {
+		false
 	}
 
 	fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult {
@@ -165,9 +162,7 @@ impl sp_staking::StakingInterface for StakingMock {
 		staker_map.retain(|(unlocking_at, _amount)| *unlocking_at > current_era);
 
 		// if there was a withdrawal, notify the pallet.
-		let withdraw_amount = unlocking_before.saturating_sub(unlocking(&staker_map));
-		Pools::on_withdraw(&who, withdraw_amount);
-		DelegateMock::on_withdraw(who, withdraw_amount);
+		Pools::on_withdraw(&who, unlocking_before.saturating_sub(unlocking(&staker_map)));
 
 		UnbondingBalanceMap::set(&unbonding_map);
 		Ok(UnbondingBalanceMap::get().get(&who).unwrap().is_empty() &&
@@ -244,176 +239,6 @@ impl sp_staking::StakingInterface for StakingMock {
 	}
 }
 
-parameter_types! {
-	// Map of agent to their (delegated balance, unclaimed withdrawal, pending slash).
-	pub storage AgentBalanceMap: BTreeMap<AccountId, (Balance, Balance, Balance)> = Default::default();
-	pub storage DelegatorBalanceMap: BTreeMap<AccountId, Balance> = Default::default();
-}
-pub struct DelegateMock;
-impl DelegationInterface for DelegateMock {
-	type Balance = Balance;
-	type AccountId = AccountId;
-	fn agent_balance(agent: Agent<Self::AccountId>) -> Option<Self::Balance> {
-		AgentBalanceMap::get()
-			.get(&agent.get())
-			.copied()
-			.map(|(delegated, _, pending)| delegated - pending)
-	}
-
-	fn agent_transferable_balance(agent: Agent<Self::AccountId>) -> Option<Self::Balance> {
-		AgentBalanceMap::get()
-			.get(&agent.get())
-			.copied()
-			.map(|(_, unclaimed_withdrawals, _)| unclaimed_withdrawals)
-	}
-
-	fn delegator_balance(delegator: Delegator<Self::AccountId>) -> Option<Self::Balance> {
-		DelegatorBalanceMap::get().get(&delegator.get()).copied()
-	}
-
-	fn register_agent(
-		agent: Agent<Self::AccountId>,
-		_reward_account: &Self::AccountId,
-	) -> DispatchResult {
-		let mut agents = AgentBalanceMap::get();
-		agents.insert(agent.get(), (0, 0, 0));
-		AgentBalanceMap::set(&agents);
-		Ok(())
-	}
-
-	fn remove_agent(agent: Agent<Self::AccountId>) -> DispatchResult {
-		let mut agents = AgentBalanceMap::get();
-		let agent = agent.get();
-		assert!(agents.contains_key(&agent));
-		agents.remove(&agent);
-		AgentBalanceMap::set(&agents);
-		Ok(())
-	}
-
-	fn delegate(
-		delegator: Delegator<Self::AccountId>,
-		agent: Agent<Self::AccountId>,
-		amount: Self::Balance,
-	) -> DispatchResult {
-		let delegator = delegator.get();
-		let mut delegators = DelegatorBalanceMap::get();
-		delegators.entry(delegator).and_modify(|b| *b += amount).or_insert(amount);
-		DelegatorBalanceMap::set(&delegators);
-
-		let agent = agent.get();
-		let mut agents = AgentBalanceMap::get();
-		agents
-			.get_mut(&agent)
-			.map(|(d, _, _)| *d += amount)
-			.ok_or(DispatchError::Other("agent not registered"))?;
-		AgentBalanceMap::set(&agents);
-
-		if BondedBalanceMap::get().contains_key(&agent) {
-			StakingMock::bond_extra(&agent, amount)
-		} else {
-			// reward account does not matter in this context.
-			StakingMock::bond(&agent, amount, &999)
-		}
-	}
-
-	fn withdraw_delegation(
-		delegator: Delegator<Self::AccountId>,
-		agent: Agent<Self::AccountId>,
-		amount: Self::Balance,
-		_num_slashing_spans: u32,
-	) -> DispatchResult {
-		let mut delegators = DelegatorBalanceMap::get();
-		delegators.get_mut(&delegator.get()).map(|b| *b -= amount);
-		DelegatorBalanceMap::set(&delegators);
-
-		let mut agents = AgentBalanceMap::get();
-		agents.get_mut(&agent.get()).map(|(d, u, _)| {
-			*d -= amount;
-			*u -= amount;
-		});
-		AgentBalanceMap::set(&agents);
-
-		Ok(())
-	}
-
-	fn pending_slash(agent: Agent<Self::AccountId>) -> Option<Self::Balance> {
-		AgentBalanceMap::get()
-			.get(&agent.get())
-			.copied()
-			.map(|(_, _, pending_slash)| pending_slash)
-	}
-
-	fn delegator_slash(
-		agent: Agent<Self::AccountId>,
-		delegator: Delegator<Self::AccountId>,
-		value: Self::Balance,
-		_maybe_reporter: Option<Self::AccountId>,
-	) -> DispatchResult {
-		let mut delegators = DelegatorBalanceMap::get();
-		delegators.get_mut(&delegator.get()).map(|b| *b -= value);
-		DelegatorBalanceMap::set(&delegators);
-
-		let mut agents = AgentBalanceMap::get();
-		agents.get_mut(&agent.get()).map(|(_, _, p)| {
-			p.saturating_reduce(value);
-		});
-		AgentBalanceMap::set(&agents);
-
-		Ok(())
-	}
-}
-
-impl DelegateMock {
-	pub fn set_agent_balance(who: AccountId, delegated: Balance) {
-		let mut agents = AgentBalanceMap::get();
-		agents.insert(who, (delegated, 0, 0));
-		AgentBalanceMap::set(&agents);
-	}
-
-	pub fn set_delegator_balance(who: AccountId, amount: Balance) {
-		let mut delegators = DelegatorBalanceMap::get();
-		delegators.insert(who, amount);
-		DelegatorBalanceMap::set(&delegators);
-	}
-
-	pub fn on_slash(agent: AccountId, amount: Balance) {
-		let mut agents = AgentBalanceMap::get();
-		agents.get_mut(&agent).map(|(_, _, p)| *p += amount);
-		AgentBalanceMap::set(&agents);
-	}
-
-	fn on_withdraw(agent: AccountId, amount: Balance) {
-		let mut agents = AgentBalanceMap::get();
-		// if agent exists, add the amount to unclaimed withdrawals.
-		agents.get_mut(&agent).map(|(_, u, _)| *u += amount);
-		AgentBalanceMap::set(&agents);
-	}
-}
-
-impl DelegationMigrator for DelegateMock {
-	type Balance = Balance;
-	type AccountId = AccountId;
-	fn migrate_nominator_to_agent(
-		_agent: Agent<Self::AccountId>,
-		_reward_account: &Self::AccountId,
-	) -> DispatchResult {
-		unimplemented!("not used in current unit tests")
-	}
-
-	fn migrate_delegation(
-		_agent: Agent<Self::AccountId>,
-		_delegator: Delegator<Self::AccountId>,
-		_value: Self::Balance,
-	) -> DispatchResult {
-		unimplemented!("not used in current unit tests")
-	}
-
-	#[cfg(feature = "runtime-benchmarks")]
-	fn force_kill_agent(_agent: Agent<Self::AccountId>) {
-		unimplemented!("not used in current unit tests")
-	}
-}
-
 #[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
 impl frame_system::Config for Runtime {
 	type Nonce = u64;
@@ -470,7 +295,7 @@ impl pools::Config for Runtime {
 	type RewardCounter = RewardCounter;
 	type BalanceToU256 = BalanceToU256;
 	type U256ToBalance = U256ToBalance;
-	type StakeAdapter = adapter::DelegateStake<Self, StakingMock, DelegateMock>;
+	type StakeAdapter = adapter::TransferStake<Self, StakingMock>;
 	type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow;
 	type PalletId = PoolsPalletId;
 	type MaxMetadataLen = MaxMetadataLen;
@@ -697,21 +522,6 @@ pub fn reward_imbalance(pool: PoolId) -> RewardImbalance {
 	}
 }
 
-pub fn set_pool_balance(who: AccountId, amount: Balance) {
-	StakingMock::set_bonded_balance(who, amount);
-	DelegateMock::set_agent_balance(who, amount);
-}
-
-pub fn member_delegation(who: AccountId) -> Balance {
-	<T as Config>::StakeAdapter::member_delegation_balance(Member::from(who))
-		.expect("who must be a pool member")
-}
-
-pub fn pool_balance(id: PoolId) -> Balance {
-	<T as Config>::StakeAdapter::total_balance(Pool::from(Pools::generate_bonded_account(id)))
-		.expect("who must be a bonded pool account")
-}
-
 #[cfg(test)]
 mod test {
 	use super::*;
diff --git a/substrate/frame/nomination-pools/src/tests.rs b/substrate/frame/nomination-pools/src/tests.rs
index c46638d2f8f7bb474088b967e491c54d12bc3105..06261699a5b23ff58c227875b143a1eaba08e439 100644
--- a/substrate/frame/nomination-pools/src/tests.rs
+++ b/substrate/frame/nomination-pools/src/tests.rs
@@ -24,7 +24,6 @@ use sp_runtime::{
 	traits::{BadOrigin, Dispatchable},
 	FixedU128,
 };
-use sp_staking::{Agent, DelegationInterface};
 
 macro_rules! unbonding_pools_with_era {
 	($($k:expr => $v:expr),* $(,)?) => {{
@@ -128,41 +127,41 @@ mod bonded_pool {
 			};
 
 			// 1 points : 1 balance ratio
-			set_pool_balance(bonded_pool.bonded_account(), 100);
+			StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100);
 			assert_eq!(bonded_pool.balance_to_point(10), 10);
 			assert_eq!(bonded_pool.balance_to_point(0), 0);
 
 			// 2 points : 1 balance ratio
-			set_pool_balance(bonded_pool.bonded_account(), 50);
+			StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 50);
 			assert_eq!(bonded_pool.balance_to_point(10), 20);
 
 			// 1 points : 2 balance ratio
-			set_pool_balance(bonded_pool.bonded_account(), 100);
+			StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100);
 			bonded_pool.points = 50;
 			assert_eq!(bonded_pool.balance_to_point(10), 5);
 
 			// 100 points : 0 balance ratio
-			set_pool_balance(bonded_pool.bonded_account(), 0);
+			StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 0);
 			bonded_pool.points = 100;
 			assert_eq!(bonded_pool.balance_to_point(10), 100 * 10);
 
 			// 0 points : 100 balance
-			set_pool_balance(bonded_pool.bonded_account(), 100);
+			StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100);
 			bonded_pool.points = 0;
 			assert_eq!(bonded_pool.balance_to_point(10), 10);
 
 			// 10 points : 3 balance ratio
-			set_pool_balance(bonded_pool.bonded_account(), 30);
+			StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 30);
 			bonded_pool.points = 100;
 			assert_eq!(bonded_pool.balance_to_point(10), 33);
 
 			// 2 points : 3 balance ratio
-			set_pool_balance(bonded_pool.bonded_account(), 300);
+			StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 300);
 			bonded_pool.points = 200;
 			assert_eq!(bonded_pool.balance_to_point(10), 6);
 
 			// 4 points : 9 balance ratio
-			set_pool_balance(bonded_pool.bonded_account(), 900);
+			StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 900);
 			bonded_pool.points = 400;
 			assert_eq!(bonded_pool.balance_to_point(90), 40);
 		})
@@ -183,7 +182,7 @@ mod bonded_pool {
 				},
 			};
 
-			set_pool_balance(bonded_pool.bonded_account(), 100);
+			StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100);
 			assert_eq!(bonded_pool.points_to_balance(10), 10);
 			assert_eq!(bonded_pool.points_to_balance(0), 0);
 
@@ -192,27 +191,27 @@ mod bonded_pool {
 			assert_eq!(bonded_pool.points_to_balance(10), 20);
 
 			// 100 balance : 0 points ratio
-			set_pool_balance(bonded_pool.bonded_account(), 100);
+			StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100);
 			bonded_pool.points = 0;
 			assert_eq!(bonded_pool.points_to_balance(10), 0);
 
 			// 0 balance : 100 points ratio
-			set_pool_balance(bonded_pool.bonded_account(), 0);
+			StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 0);
 			bonded_pool.points = 100;
 			assert_eq!(bonded_pool.points_to_balance(10), 0);
 
 			// 10 balance : 3 points ratio
-			set_pool_balance(bonded_pool.bonded_account(), 100);
+			StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100);
 			bonded_pool.points = 30;
 			assert_eq!(bonded_pool.points_to_balance(10), 33);
 
 			// 2 balance : 3 points ratio
-			set_pool_balance(bonded_pool.bonded_account(), 200);
+			StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 200);
 			bonded_pool.points = 300;
 			assert_eq!(bonded_pool.points_to_balance(10), 6);
 
 			// 4 balance : 9 points ratio
-			set_pool_balance(bonded_pool.bonded_account(), 400);
+			StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 400);
 			bonded_pool.points = 900;
 			assert_eq!(bonded_pool.points_to_balance(90), 40);
 		})
@@ -270,21 +269,30 @@ mod bonded_pool {
 				<<Runtime as Config>::MaxPointsToBalance as Get<u8>>::get().into();
 
 			// Simulate a 100% slashed pool
-			set_pool_balance(pool.bonded_account(), 0);
+			StakingMock::set_bonded_balance(pool.bonded_account(), 0);
 			assert_noop!(pool.ok_to_join(), Error::<Runtime>::OverflowRisk);
 
 			// Simulate a slashed pool at `MaxPointsToBalance` + 1 slashed pool
-			set_pool_balance(pool.bonded_account(), max_points_to_balance.saturating_add(1));
+			StakingMock::set_bonded_balance(
+				pool.bonded_account(),
+				max_points_to_balance.saturating_add(1),
+			);
 			assert_ok!(pool.ok_to_join());
 
 			// Simulate a slashed pool at `MaxPointsToBalance`
-			set_pool_balance(pool.bonded_account(), max_points_to_balance);
+			StakingMock::set_bonded_balance(pool.bonded_account(), max_points_to_balance);
 			assert_noop!(pool.ok_to_join(), Error::<Runtime>::OverflowRisk);
 
-			set_pool_balance(pool.bonded_account(), Balance::MAX / max_points_to_balance);
+			StakingMock::set_bonded_balance(
+				pool.bonded_account(),
+				Balance::MAX / max_points_to_balance,
+			);
 
 			// and a sanity check
-			set_pool_balance(pool.bonded_account(), Balance::MAX / max_points_to_balance - 1);
+			StakingMock::set_bonded_balance(
+				pool.bonded_account(),
+				Balance::MAX / max_points_to_balance - 1,
+			);
 			assert_ok!(pool.ok_to_join());
 		});
 	}
@@ -302,7 +310,7 @@ mod bonded_pool {
 					state: PoolState::Open,
 				},
 			};
-			set_pool_balance(bonded_pool.bonded_account(), u128::MAX);
+			StakingMock::set_bonded_balance(bonded_pool.bonded_account(), u128::MAX);
 
 			// Max out the points and balance of the pool and make sure the conversion works as
 			// expected and does not overflow.
@@ -632,6 +640,8 @@ mod sub_pools {
 }
 
 mod join {
+	use sp_runtime::TokenError;
+
 	use super::*;
 
 	#[test]
@@ -718,7 +728,7 @@ mod join {
 			);
 
 			// Force the pools bonded balance to 0, simulating a 100% slash
-			set_pool_balance(Pools::generate_bonded_account(1), 0);
+			StakingMock::set_bonded_balance(Pools::generate_bonded_account(1), 0);
 			assert_noop!(
 				Pools::join(RuntimeOrigin::signed(11), 420, 1),
 				Error::<Runtime>::OverflowRisk
@@ -744,13 +754,29 @@ mod join {
 			let max_points_to_balance: u128 =
 				<<Runtime as Config>::MaxPointsToBalance as Get<u8>>::get().into();
 
-			set_pool_balance(Pools::generate_bonded_account(123), max_points_to_balance);
+			StakingMock::set_bonded_balance(
+				Pools::generate_bonded_account(123),
+				max_points_to_balance,
+			);
 			assert_noop!(
 				Pools::join(RuntimeOrigin::signed(11), 420, 123),
 				Error::<Runtime>::OverflowRisk
 			);
 
-			set_pool_balance(Pools::generate_bonded_account(1), max_points_to_balance);
+			StakingMock::set_bonded_balance(
+				Pools::generate_bonded_account(123),
+				Balance::MAX / max_points_to_balance,
+			);
+			// Balance needs to be gt Balance::MAX / `MaxPointsToBalance`
+			assert_noop!(
+				Pools::join(RuntimeOrigin::signed(11), 5, 123),
+				TokenError::FundsUnavailable,
+			);
+
+			StakingMock::set_bonded_balance(
+				Pools::generate_bonded_account(1),
+				max_points_to_balance,
+			);
 
 			// Cannot join a pool that isn't open
 			unsafe_set_state(123, PoolState::Blocked);
@@ -781,7 +807,7 @@ mod join {
 	#[cfg_attr(not(debug_assertions), should_panic)]
 	fn join_panics_when_reward_pool_not_found() {
 		ExtBuilder::default().build_and_execute(|| {
-			set_pool_balance(Pools::generate_bonded_account(123), 100);
+			StakingMock::set_bonded_balance(Pools::generate_bonded_account(123), 100);
 			BondedPool::<Runtime> {
 				id: 123,
 				inner: BondedPoolInner {
@@ -2295,8 +2321,8 @@ mod claim_payout {
 	fn rewards_are_rounded_down_depositor_collects_them() {
 		ExtBuilder::default().add_members(vec![(20, 20)]).build_and_execute(|| {
 			// initial balance of 10.
-			let init_balance_10 = Currency::free_balance(&10);
-			assert_eq!(member_delegation(10), 10);
+
+			assert_eq!(Currency::free_balance(&10), 35);
 			assert_eq!(
 				Currency::free_balance(&default_reward_account()),
 				Currency::minimum_balance()
@@ -2347,10 +2373,8 @@ mod claim_payout {
 			);
 
 			assert!(!Metadata::<T>::contains_key(1));
-			// original ed + ed put into reward account + reward + dust.
-			assert_eq!(Currency::free_balance(&10), init_balance_10 + 5 + 13 + 1);
-			// delegation reduced from 10 to 0.
-			assert_eq!(member_delegation(10), 0);
+			// original ed + ed put into reward account + reward + bond + dust.
+			assert_eq!(Currency::free_balance(&10), 35 + 5 + 13 + 10 + 1);
 		})
 	}
 
@@ -2420,10 +2444,9 @@ mod claim_payout {
 			let claimable_reward = 8 - ExistentialDeposit::get();
 			// NOTE: easier to read if we use 3, so let's use the number instead of variable.
 			assert_eq!(claimable_reward, 3, "test is correct if rewards are divisible by 3");
-			let init_balance = Currency::free_balance(&10);
 
 			// given
-			assert_eq!(member_delegation(10), 10);
+			assert_eq!(Currency::free_balance(&10), 35);
 
 			// when
 
@@ -2432,10 +2455,7 @@ mod claim_payout {
 			assert_ok!(Pools::claim_payout_other(RuntimeOrigin::signed(80), 10));
 
 			// then
-			// delegated balance does not change.
-			assert_eq!(member_delegation(10), 10);
-			// reward of 1 is paid out to 10.
-			assert_eq!(Currency::free_balance(&10), init_balance + 1);
+			assert_eq!(Currency::free_balance(&10), 36);
 			assert_eq!(Currency::free_balance(&default_reward_account()), 7);
 		})
 	}
@@ -2798,8 +2818,6 @@ mod unbond {
 		ExtBuilder::default()
 			.add_members(vec![(40, 40), (550, 550)])
 			.build_and_execute(|| {
-				let init_balance_40 = Currency::free_balance(&40);
-				let init_balance_550 = Currency::free_balance(&550);
 				let ed = Currency::minimum_balance();
 				// Given a slash from 600 -> 500
 				StakingMock::slash_by(1, 500);
@@ -2846,9 +2864,7 @@ mod unbond {
 					PoolMembers::<Runtime>::get(40).unwrap().unbonding_eras,
 					member_unbonding_eras!(3 => 6)
 				);
-				assert_eq!(member_delegation(40), 40);
-				// We claim rewards when unbonding
-				assert_eq!(Currency::free_balance(&40), init_balance_40 + 40);
+				assert_eq!(Currency::free_balance(&40), 40 + 40); // We claim rewards when unbonding
 
 				// When
 				unsafe_set_state(1, PoolState::Destroying);
@@ -2877,8 +2893,7 @@ mod unbond {
 					PoolMembers::<Runtime>::get(550).unwrap().unbonding_eras,
 					member_unbonding_eras!(3 => 92)
 				);
-				assert_eq!(member_delegation(550), 550);
-				assert_eq!(Currency::free_balance(&550), init_balance_550 + 550);
+				assert_eq!(Currency::free_balance(&550), 550 + 550);
 				assert_eq!(
 					pool_events_since_last_call(),
 					vec![
@@ -2919,8 +2934,7 @@ mod unbond {
 				);
 				assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 0);
 
-				// 550 is removed from pool.
-				assert_eq!(member_delegation(550), 0);
+				assert_eq!(Currency::free_balance(&550), 550 + 550 + 92);
 				assert_eq!(
 					pool_events_since_last_call(),
 					vec![
@@ -3518,7 +3532,7 @@ mod pool_withdraw_unbonded {
 
 			assert_eq!(StakingMock::active_stake(&default_bonded_account()), Ok(15));
 			assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(20));
-			assert_eq!(pool_balance(1), 20);
+			assert_eq!(Balances::free_balance(&default_bonded_account()), 20);
 
 			// When
 			CurrentEra::set(StakingMock::current_era() + StakingMock::bonding_duration() + 1);
@@ -3527,7 +3541,7 @@ mod pool_withdraw_unbonded {
 			// Then their unbonding balance is no longer locked
 			assert_eq!(StakingMock::active_stake(&default_bonded_account()), Ok(15));
 			assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(15));
-			assert_eq!(pool_balance(1), 20);
+			assert_eq!(Balances::free_balance(&default_bonded_account()), 20);
 		});
 	}
 	#[test]
@@ -3538,7 +3552,7 @@ mod pool_withdraw_unbonded {
 
 			assert_eq!(StakingMock::active_stake(&default_bonded_account()), Ok(15));
 			assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(20));
-			assert_eq!(pool_balance(1), 20);
+			assert_eq!(Balances::free_balance(&default_bonded_account()), 20);
 			assert_eq!(TotalValueLocked::<T>::get(), 20);
 
 			// When
@@ -3554,14 +3568,14 @@ mod pool_withdraw_unbonded {
 			// Then their unbonding balance is no longer locked
 			assert_eq!(StakingMock::active_stake(&default_bonded_account()), Ok(15));
 			assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(15));
-			assert_eq!(pool_balance(1), 20);
+			assert_eq!(Currency::free_balance(&default_bonded_account()), 20);
 
 			// The difference between TVL and member_balance is exactly the difference between
-			// `pool balance` (sum of all balance delegated to pool) and the `staked balance`.
-			// This is the withdrawn funds from the pool stake that has not yet been claimed by the
-			// respective members.
-			let non_locked_balance =
-				pool_balance(1) - StakingMock::total_stake(&default_bonded_account()).unwrap();
+			// `total_stake` and the `free_balance`.
+			// This relation is not guaranteed in the wild as arbitrary transfers towards
+			// `free_balance` can be made to the pool that are not accounted for.
+			let non_locked_balance = Balances::free_balance(&default_bonded_account()) -
+				StakingMock::total_stake(&default_bonded_account()).unwrap();
 			assert_eq!(member_balance, TotalValueLocked::<T>::get() + non_locked_balance);
 		});
 	}
@@ -3583,7 +3597,7 @@ mod withdraw_unbonded {
 				assert_eq!(StakingMock::bonding_duration(), 3);
 				assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(550), 550));
 				assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(40), 40));
-				assert_eq!(pool_balance(1), 600);
+				assert_eq!(Currency::free_balance(&default_bonded_account()), 600);
 
 				let mut current_era = 1;
 				CurrentEra::set(current_era);
@@ -3612,7 +3626,10 @@ mod withdraw_unbonded {
 						.1 /= 2;
 					UnbondingBalanceMap::set(&x);
 
-					set_pool_balance(1, pool_balance(1) / 2);
+					Currency::set_balance(
+						&default_bonded_account(),
+						Currency::free_balance(&default_bonded_account()) / 2, // 300
+					);
 					assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 10);
 					StakingMock::slash_by(1, 5);
 					assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 5);
@@ -3654,6 +3671,11 @@ mod withdraw_unbonded {
 						Event::PoolSlashed { pool_id: 1, balance: 5 }
 					]
 				);
+				assert_eq!(
+					balances_events_since_last_call(),
+					vec![BEvent::Burned { who: default_bonded_account(), amount: 300 }]
+				);
+
 				// When
 				assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(550), 550, 0));
 
@@ -3669,9 +3691,10 @@ mod withdraw_unbonded {
 						Event::MemberRemoved { pool_id: 1, member: 550, released_balance: 0 }
 					]
 				);
-
-				// member has 40 tokens in delegation, but only 20 can be withdrawan.
-				assert_eq!(member_delegation(40), 40);
+				assert_eq!(
+					balances_events_since_last_call(),
+					vec![BEvent::Transfer { from: default_bonded_account(), to: 550, amount: 275 }]
+				);
 
 				// When
 				assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(40), 40, 0));
@@ -3685,18 +3708,18 @@ mod withdraw_unbonded {
 				assert_eq!(
 					pool_events_since_last_call(),
 					vec![
-						// out of 40, 20 is withdrawn.
 						Event::Withdrawn { member: 40, pool_id: 1, balance: 20, points: 40 },
-						// member is removed and the dangling delegation of 20 tokens left in their
-						// account is released.
-						Event::MemberRemoved { pool_id: 1, member: 40, released_balance: 20 }
+						Event::MemberRemoved { pool_id: 1, member: 40, released_balance: 0 }
 					]
 				);
+				assert_eq!(
+					balances_events_since_last_call(),
+					vec![BEvent::Transfer { from: default_bonded_account(), to: 40, amount: 20 }]
+				);
 
 				// now, finally, the depositor can take out its share.
 				unsafe_set_state(1, PoolState::Destroying);
 				assert_ok!(fully_unbond_permissioned(10));
-				assert_eq!(member_delegation(10), 10);
 
 				current_era += 3;
 				CurrentEra::set(current_era);
@@ -3708,9 +3731,7 @@ mod withdraw_unbonded {
 					vec![
 						Event::Unbonded { member: 10, pool_id: 1, balance: 5, points: 5, era: 9 },
 						Event::Withdrawn { member: 10, pool_id: 1, balance: 5, points: 5 },
-						// when member is removed, any leftover delegation is released.
-						Event::MemberRemoved { pool_id: 1, member: 10, released_balance: 5 },
-						// when the last member leaves, the pool is destroyed.
+						Event::MemberRemoved { pool_id: 1, member: 10, released_balance: 0 },
 						Event::Destroyed { pool_id: 1 }
 					]
 				);
@@ -3718,6 +3739,7 @@ mod withdraw_unbonded {
 				assert_eq!(
 					balances_events_since_last_call(),
 					vec![
+						BEvent::Transfer { from: default_bonded_account(), to: 10, amount: 5 },
 						BEvent::Thawed { who: default_reward_account(), amount: 5 },
 						BEvent::Transfer { from: default_reward_account(), to: 10, amount: 5 }
 					]
@@ -3731,9 +3753,11 @@ mod withdraw_unbonded {
 			.add_members(vec![(40, 40), (550, 550)])
 			.build_and_execute(|| {
 				let _ = balances_events_since_last_call();
+
 				// Given
 				// current bond is 600, we slash it all to 300.
 				StakingMock::slash_by(1, 300);
+				Currency::set_balance(&default_bonded_account(), 300);
 				assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(300));
 
 				assert_ok!(fully_unbond_permissioned(40));
@@ -3763,6 +3787,10 @@ mod withdraw_unbonded {
 						}
 					]
 				);
+				assert_eq!(
+					balances_events_since_last_call(),
+					vec![BEvent::Burned { who: default_bonded_account(), amount: 300 },]
+				);
 
 				CurrentEra::set(StakingMock::bonding_duration());
 
@@ -3770,6 +3798,10 @@ mod withdraw_unbonded {
 				assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(40), 40, 0));
 
 				// Then
+				assert_eq!(
+					balances_events_since_last_call(),
+					vec![BEvent::Transfer { from: default_bonded_account(), to: 40, amount: 20 },]
+				);
 				assert_eq!(
 					pool_events_since_last_call(),
 					vec![
@@ -3787,6 +3819,10 @@ mod withdraw_unbonded {
 				assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(550), 550, 0));
 
 				// Then
+				assert_eq!(
+					balances_events_since_last_call(),
+					vec![BEvent::Transfer { from: default_bonded_account(), to: 550, amount: 275 },]
+				);
 				assert_eq!(
 					pool_events_since_last_call(),
 					vec![
@@ -3816,11 +3852,9 @@ mod withdraw_unbonded {
 				assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0));
 
 				// then
-				assert_eq!(
-					DelegateMock::agent_balance(Agent::from(default_bonded_account())),
-					None
-				);
-				assert_eq!(StakingMock::stake(&default_bonded_account()).unwrap().total, 0);
+				assert_eq!(Currency::free_balance(&10), 10 + 35);
+				assert_eq!(Currency::free_balance(&default_bonded_account()), 0);
+
 				// in this test 10 also gets a fair share of the slash, because the slash was
 				// applied to the bonded account.
 				assert_eq!(
@@ -3836,6 +3870,7 @@ mod withdraw_unbonded {
 				assert_eq!(
 					balances_events_since_last_call(),
 					vec![
+						BEvent::Transfer { from: default_bonded_account(), to: 10, amount: 5 },
 						BEvent::Thawed { who: default_reward_account(), amount: 5 },
 						BEvent::Transfer { from: default_reward_account(), to: 10, amount: 5 }
 					]
@@ -3843,6 +3878,35 @@ mod withdraw_unbonded {
 			});
 	}
 
+	#[test]
+	fn withdraw_unbonded_handles_faulty_sub_pool_accounting() {
+		ExtBuilder::default().build_and_execute(|| {
+			// Given
+			assert_eq!(Currency::minimum_balance(), 5);
+			assert_eq!(Currency::free_balance(&10), 35);
+			assert_eq!(Currency::free_balance(&default_bonded_account()), 10);
+			unsafe_set_state(1, PoolState::Destroying);
+			assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(10), 10));
+
+			// Simulate a slash that is not accounted for in the sub pools.
+			Currency::set_balance(&default_bonded_account(), 5);
+			assert_eq!(
+				SubPoolsStorage::<Runtime>::get(1).unwrap().with_era,
+				//------------------------------balance decrease is not account for
+				unbonding_pools_with_era! { 3 => UnbondPool { points: 10, balance: 10 } }
+			);
+
+			CurrentEra::set(3);
+
+			// When
+			assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0));
+
+			// Then
+			assert_eq!(Currency::free_balance(&10), 10 + 35);
+			assert_eq!(Currency::free_balance(&default_bonded_account()), 0);
+		});
+	}
+
 	#[test]
 	fn withdraw_unbonded_errors_correctly() {
 		ExtBuilder::default().with_check(0).build_and_execute(|| {
@@ -3861,10 +3925,6 @@ mod withdraw_unbonded {
 			let mut member = PoolMember { pool_id: 1, points: 10, ..Default::default() };
 			PoolMembers::<Runtime>::insert(11, member.clone());
 
-			// set agent and delegator balance
-			DelegateMock::set_agent_balance(Pools::generate_bonded_account(1), 10);
-			DelegateMock::set_delegator_balance(11, 10);
-
 			// Simulate calling `unbond`
 			member.unbonding_eras = member_unbonding_eras!(3 => 10);
 			PoolMembers::<Runtime>::insert(11, member.clone());
@@ -3985,7 +4045,7 @@ mod withdraw_unbonded {
 				}
 			);
 			CurrentEra::set(StakingMock::bonding_duration());
-			assert_eq!(member_delegation(100), 100);
+			assert_eq!(Currency::free_balance(&100), 100);
 
 			// Cannot permissionlessly withdraw
 			assert_noop!(
@@ -4001,7 +4061,6 @@ mod withdraw_unbonded {
 
 			assert_eq!(SubPoolsStorage::<Runtime>::get(1).unwrap(), Default::default(),);
 			assert_eq!(Currency::free_balance(&100), 100 + 100);
-			assert_eq!(member_delegation(100), 0);
 			assert!(!PoolMembers::<Runtime>::contains_key(100));
 			assert_eq!(
 				pool_events_since_last_call(),
@@ -4603,6 +4662,10 @@ mod withdraw_unbonded {
 
 			// move to era when unbonded funds can be withdrawn.
 			CurrentEra::set(4);
+
+			// increment consumer by 1 reproducing the erroneous consumer bug.
+			// refer https://github.com/paritytech/polkadot-sdk/issues/4440.
+			assert_ok!(frame_system::Pallet::<T>::inc_consumers(&pool_one));
 			assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0));
 
 			assert_eq!(
@@ -4649,7 +4712,7 @@ mod create {
 			));
 			assert_eq!(TotalValueLocked::<T>::get(), 10 + StakingMock::minimum_nominator_bond());
 
-			assert_eq!(member_delegation(11), StakingMock::minimum_nominator_bond());
+			assert_eq!(Currency::free_balance(&11), 0);
 			assert_eq!(
 				PoolMembers::<Runtime>::get(11).unwrap(),
 				PoolMember {
@@ -4788,7 +4851,7 @@ mod create {
 				789
 			));
 
-			assert_eq!(member_delegation(11), StakingMock::minimum_nominator_bond());
+			assert_eq!(Currency::free_balance(&11), 0);
 			// delete the initial pool created, then pool_Id `1` will be free
 
 			assert_noop!(
@@ -4951,9 +5014,16 @@ mod set_state {
 			// surpassed. Making this pool destroyable by anyone.
 			StakingMock::slash_by(1, 10);
 
-			// pending slash is correct.
-			assert_eq!(Pools::api_pool_pending_slash(1), 10);
-			assert_eq!(Pools::api_member_pending_slash(10), 10);
+			// in mock we are using transfer stake which implies slash is greedy. Extrinsic to
+			// apply pending slash should fail.
+			assert_noop!(
+				Pools::apply_slash(RuntimeOrigin::signed(11), 10),
+				Error::<Runtime>::NotSupported
+			);
+
+			// pending slash api should return zero as well.
+			assert_eq!(Pools::api_pool_pending_slash(1), 0);
+			assert_eq!(Pools::api_member_pending_slash(10), 0);
 
 			// When
 			assert_ok!(Pools::set_state(RuntimeOrigin::signed(11), 1, PoolState::Destroying));
@@ -5105,13 +5175,13 @@ mod bond_extra {
 			// given
 			assert_eq!(PoolMembers::<Runtime>::get(10).unwrap().points, 10);
 			assert_eq!(BondedPools::<Runtime>::get(1).unwrap().points, 10);
-			assert_eq!(member_delegation(10), 10);
+			assert_eq!(Currency::free_balance(&10), 100);
 
 			// when
 			assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10)));
 
 			// then
-			assert_eq!(member_delegation(10), 10 + 10);
+			assert_eq!(Currency::free_balance(&10), 90);
 			assert_eq!(PoolMembers::<Runtime>::get(10).unwrap().points, 20);
 			assert_eq!(BondedPools::<Runtime>::get(1).unwrap().points, 20);
 
@@ -5128,7 +5198,7 @@ mod bond_extra {
 			assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(20)));
 
 			// then
-			assert_eq!(member_delegation(10), 20 + 20);
+			assert_eq!(Currency::free_balance(&10), 70);
 			assert_eq!(PoolMembers::<Runtime>::get(10).unwrap().points, 40);
 			assert_eq!(BondedPools::<Runtime>::get(1).unwrap().points, 40);
 
@@ -5151,15 +5221,13 @@ mod bond_extra {
 			// given
 			assert_eq!(PoolMembers::<Runtime>::get(10).unwrap().points, 10);
 			assert_eq!(BondedPools::<Runtime>::get(1).unwrap().points, 10);
-			// 10 has delegated 10 tokens to the pool.
-			assert_eq!(member_delegation(10), 10);
+			assert_eq!(Currency::free_balance(&10), 35);
 
 			// when
 			assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::Rewards));
 
 			// then
-			// delegator balance is increased by the claimable reward.
-			assert_eq!(member_delegation(10), 10 + claimable_reward);
+			assert_eq!(Currency::free_balance(&10), 35);
 			assert_eq!(PoolMembers::<Runtime>::get(10).unwrap().points, 10 + claimable_reward);
 			assert_eq!(BondedPools::<Runtime>::get(1).unwrap().points, 10 + claimable_reward);
 
@@ -5196,8 +5264,8 @@ mod bond_extra {
 			assert_eq!(PoolMembers::<Runtime>::get(20).unwrap().points, 20);
 			assert_eq!(BondedPools::<Runtime>::get(1).unwrap().points, 30);
 
-			assert_eq!(member_delegation(10), 10);
-			assert_eq!(member_delegation(20), 20);
+			assert_eq!(Currency::free_balance(&10), 35);
+			assert_eq!(Currency::free_balance(&20), 20);
 			assert_eq!(TotalValueLocked::<T>::get(), 30);
 
 			// when
@@ -5205,7 +5273,7 @@ mod bond_extra {
 			assert_eq!(Currency::free_balance(&default_reward_account()), 7);
 
 			// then
-			assert_eq!(member_delegation(10), 10 + 1);
+			assert_eq!(Currency::free_balance(&10), 35);
 			assert_eq!(TotalValueLocked::<T>::get(), 31);
 
 			// 10's share of the reward is 1/3, since they gave 10/30 of the total shares.
@@ -5216,11 +5284,11 @@ mod bond_extra {
 			assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(20), BondExtra::Rewards));
 
 			// then
+			assert_eq!(Currency::free_balance(&20), 20);
 			assert_eq!(TotalValueLocked::<T>::get(), 33);
 
 			// 20's share of the rewards is the other 2/3 of the rewards, since they have 20/30 of
 			// the shares
-			assert_eq!(member_delegation(20), 20 + 2);
 			assert_eq!(PoolMembers::<Runtime>::get(20).unwrap().points, 20 + 2);
 			assert_eq!(BondedPools::<Runtime>::get(1).unwrap().points, 30 + 3);
 
@@ -5252,8 +5320,8 @@ mod bond_extra {
 			assert_eq!(PoolMembers::<Runtime>::get(10).unwrap().points, 10);
 			assert_eq!(PoolMembers::<Runtime>::get(20).unwrap().points, 20);
 			assert_eq!(BondedPools::<Runtime>::get(1).unwrap().points, 30);
-			assert_eq!(member_delegation(10), 10);
-			assert_eq!(member_delegation(20), 20);
+			assert_eq!(Currency::free_balance(&10), 35);
+			assert_eq!(Currency::free_balance(&20), 20);
 
 			// Permissioned by default
 			assert_noop!(
@@ -5269,7 +5337,7 @@ mod bond_extra {
 			assert_eq!(Currency::free_balance(&default_reward_account()), 7);
 
 			// then
-			assert_eq!(member_delegation(10), 10 + 1);
+			assert_eq!(Currency::free_balance(&10), 35);
 			assert_eq!(PoolMembers::<Runtime>::get(10).unwrap().points, 10 + 1);
 			assert_eq!(BondedPools::<Runtime>::get(1).unwrap().points, 30 + 1);
 
@@ -5287,7 +5355,7 @@ mod bond_extra {
 			));
 
 			// then
-			assert_eq!(member_delegation(20), 20 + 10);
+			assert_eq!(Currency::free_balance(&20), 12);
 			assert_eq!(Currency::free_balance(&default_reward_account()), 5);
 			assert_eq!(PoolMembers::<Runtime>::get(20).unwrap().points, 30);
 			assert_eq!(BondedPools::<Runtime>::get(1).unwrap().points, 41);
@@ -7419,3 +7487,63 @@ mod chill {
 		})
 	}
 }
+
+// the test mock is using `TransferStake` and so `DelegateStake` is not tested here. Extrinsics
+// meant for `DelegateStake` should be gated.
+//
+// `DelegateStake` tests are in `pallet-nomination-pools-test-delegate-stake`. Since we support both
+// strategies currently, we keep these tests as it is but in future we may remove `TransferStake`
+// completely.
+mod delegate_stake {
+	use super::*;
+	#[test]
+	fn delegation_specific_calls_are_gated() {
+		ExtBuilder::default().with_check(0).build_and_execute(|| {
+			// Given
+			Currency::set_balance(&11, ExistentialDeposit::get() + 2);
+			assert!(!PoolMembers::<Runtime>::contains_key(11));
+
+			// When
+			assert_ok!(Pools::join(RuntimeOrigin::signed(11), 2, 1));
+
+			// Then
+			assert_eq!(
+				pool_events_since_last_call(),
+				vec![
+					Event::Created { depositor: 10, pool_id: 1 },
+					Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true },
+					Event::Bonded { member: 11, pool_id: 1, bonded: 2, joined: true },
+				]
+			);
+
+			assert_eq!(
+				PoolMembers::<Runtime>::get(11).unwrap(),
+				PoolMember::<Runtime> { pool_id: 1, points: 2, ..Default::default() }
+			);
+
+			// ensure pool 1 cannot be migrated.
+			assert!(!Pools::api_pool_needs_delegate_migration(1));
+			assert_noop!(
+				Pools::migrate_pool_to_delegate_stake(RuntimeOrigin::signed(10), 1),
+				Error::<Runtime>::NotSupported
+			);
+
+			// members cannot be migrated either.
+			assert!(!Pools::api_member_needs_delegate_migration(10));
+			assert_noop!(
+				Pools::migrate_delegation(RuntimeOrigin::signed(10), 11),
+				Error::<Runtime>::NotSupported
+			);
+
+			// Given
+			// The bonded balance is slashed in half
+			StakingMock::slash_by(1, 6);
+
+			// since slash is greedy with `TransferStake`, `apply_slash` should not work either.
+			assert_noop!(
+				Pools::apply_slash(RuntimeOrigin::signed(10), 11),
+				Error::<Runtime>::NotSupported
+			);
+		});
+	}
+}
diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs
index 54783332aa3ef245bced9e737ed5c8a89265e7d8..cc6335959ab738115c88c4878bc3dc2d8bb6db81 100644
--- a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs
+++ b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs
@@ -21,10 +21,7 @@ mod mock;
 
 use frame_support::{
 	assert_noop, assert_ok, hypothetically,
-	traits::{
-		fungible::{InspectHold, Mutate},
-		Currency,
-	},
+	traits::{fungible::InspectHold, Currency},
 };
 use mock::*;
 use pallet_nomination_pools::{
@@ -945,12 +942,8 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() {
 fn pool_migration_e2e() {
 	new_test_ext().execute_with(|| {
 		LegacyAdapter::set(true);
-		assert_eq!(CurrentEra::<T>::get(), None);
-
-		// hack: mint ED to pool so that the deprecated `TransferStake` works correctly with
-		// staking.
 		assert_eq!(Balances::minimum_balance(), 5);
-		assert_ok!(Balances::mint_into(&POOL1_BONDED, 5));
+		assert_eq!(CurrentEra::<T>::get(), None);
 
 		// create the pool with TransferStake strategy.
 		assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10));
@@ -1057,11 +1050,10 @@ fn pool_migration_e2e() {
 
 		assert_eq!(
 			delegated_staking_events_since_last_call(),
-			// delegated also contains the extra ED that we minted when pool was `TransferStake` .
 			vec![DelegatedStakingEvent::Delegated {
 				agent: POOL1_BONDED,
 				delegator: proxy_delegator_1,
-				amount: 50 + 10 * 3 + 5
+				amount: 50 + 10 * 3
 			}]
 		);
 
@@ -1231,11 +1223,6 @@ fn disable_pool_operations_on_non_migrated() {
 		assert_eq!(Balances::minimum_balance(), 5);
 		assert_eq!(CurrentEra::<T>::get(), None);
 
-		// hack: mint ED to pool so that the deprecated `TransferStake` works correctly with
-		// staking.
-		assert_eq!(Balances::minimum_balance(), 5);
-		assert_ok!(Balances::mint_into(&POOL1_BONDED, 5));
-
 		// create the pool with TransferStake strategy.
 		assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10));
 		assert_eq!(LastPoolId::<Runtime>::get(), 1);
@@ -1344,12 +1331,11 @@ fn disable_pool_operations_on_non_migrated() {
 		assert_ok!(Pools::migrate_pool_to_delegate_stake(RuntimeOrigin::signed(10), 1));
 		assert_eq!(
 			delegated_staking_events_since_last_call(),
-			// delegated also contains the extra ED that we minted when pool was `TransferStake` .
 			vec![DelegatedStakingEvent::Delegated {
 				agent: POOL1_BONDED,
 				delegator: DelegatedStaking::generate_proxy_delegator(Agent::from(POOL1_BONDED))
 					.get(),
-				amount: 50 + 10 + 5
+				amount: 50 + 10
 			},]
 		);
 
diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs
index d943ba6f533330453b8961886005b4f20be0804b..d1bc4ef8ff281986532d069292b2fed7785e6ca4 100644
--- a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs
+++ b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs
@@ -15,9 +15,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// Disable warnings for `TransferStake` being deprecated.
-#![allow(deprecated)]
-
 use frame_election_provider_support::VoteWeight;
 use frame_support::{
 	assert_ok, derive_impl,
@@ -95,7 +92,6 @@ parameter_types! {
 
 #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)]
 impl pallet_staking::Config for Runtime {
-	type OldCurrency = Balances;
 	type Currency = Balances;
 	type UnixTime = pallet_timestamp::Pallet<Self>;
 	type AdminOrigin = frame_system::EnsureRoot<Self::AccountId>;
diff --git a/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml b/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..0b21d5f4e8cf1e3a98e3220a17bfe7eeb0b44cc0
--- /dev/null
+++ b/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml
@@ -0,0 +1,39 @@
+[package]
+name = "pallet-nomination-pools-test-transfer-stake"
+version = "1.0.0"
+authors.workspace = true
+edition.workspace = true
+license = "Apache-2.0"
+homepage.workspace = true
+repository.workspace = true
+description = "FRAME nomination pools pallet tests with the staking pallet"
+publish = false
+
+[lints]
+workspace = true
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
+
+[dev-dependencies]
+codec = { features = ["derive"], workspace = true, default-features = true }
+scale-info = { features = ["derive"], workspace = true, default-features = true }
+
+sp-core = { workspace = true, default-features = true }
+sp-io = { workspace = true, default-features = true }
+sp-runtime = { workspace = true, default-features = true }
+sp-staking = { workspace = true, default-features = true }
+
+frame-election-provider-support = { workspace = true, default-features = true }
+frame-support = { workspace = true, default-features = true }
+frame-system = { workspace = true, default-features = true }
+
+pallet-bags-list = { workspace = true, default-features = true }
+pallet-balances = { workspace = true, default-features = true }
+pallet-nomination-pools = { workspace = true, default-features = true }
+pallet-staking = { workspace = true, default-features = true }
+pallet-staking-reward-curve = { workspace = true, default-features = true }
+pallet-timestamp = { workspace = true, default-features = true }
+
+log = { workspace = true, default-features = true }
+sp-tracing = { workspace = true, default-features = true }
diff --git a/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..cc39cfee91c80d95db2b069023991f7647eb3b79
--- /dev/null
+++ b/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs
@@ -0,0 +1,912 @@
+// 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(test)]
+
+mod mock;
+
+use frame_support::{assert_noop, assert_ok, traits::Currency};
+use mock::*;
+use pallet_nomination_pools::{
+	BondExtra, BondedPools, Error as PoolsError, Event as PoolsEvent, LastPoolId, PoolMember,
+	PoolMembers, PoolState,
+};
+use pallet_staking::{
+	CurrentEra, Error as StakingError, Event as StakingEvent, Payee, RewardDestination,
+};
+use sp_runtime::{bounded_btree_map, traits::Zero};
+
+#[test]
+fn pool_lifecycle_e2e() {
+	new_test_ext().execute_with(|| {
+		assert_eq!(Balances::minimum_balance(), 5);
+		assert_eq!(CurrentEra::<T>::get(), 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, released_balance: 0 },
+				PoolsEvent::Withdrawn { member: 21, pool_id: 1, points: 10, balance: 10 },
+				PoolsEvent::MemberRemoved { pool_id: 1, member: 21, released_balance: 0 },
+			]
+		);
+
+		// 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, released_balance: 0 },
+				PoolsEvent::Destroyed { pool_id: 1 }
+			]
+		);
+	})
+}
+
+#[test]
+fn destroy_pool_with_erroneous_consumer() {
+	new_test_ext().execute_with(|| {
+		// 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);
+
+		// expect consumers on pool account to be 2 (staking lock and an explicit inc by staking).
+		assert_eq!(frame_system::Pallet::<T>::consumers(&POOL1_BONDED), 2);
+
+		// increment consumer by 1 reproducing the erroneous consumer bug.
+		// refer https://github.com/paritytech/polkadot-sdk/issues/4440.
+		assert_ok!(frame_system::Pallet::<T>::inc_consumers(&POOL1_BONDED));
+		assert_eq!(frame_system::Pallet::<T>::consumers(&POOL1_BONDED), 3);
+
+		// 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 },
+			]
+		);
+
+		// pool goes into destroying
+		assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying));
+
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying },]
+		);
+
+		// move to era 1
+		CurrentEra::<Runtime>::set(Some(1));
+
+		// depositor need to chill before unbonding
+		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: 1 + 3
+			}]
+		);
+
+		// waiting bonding duration:
+		CurrentEra::<Runtime>::set(Some(1 + 3));
+		// this should work even with an extra consumer count on pool account.
+		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, released_balance: 0 },
+				PoolsEvent::Destroyed { pool_id: 1 }
+			]
+		);
+	})
+}
+
+#[test]
+fn pool_chill_e2e() {
+	new_test_ext().execute_with(|| {
+		assert_eq!(Balances::minimum_balance(), 5);
+		assert_eq!(CurrentEra::<T>::get(), 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 },
+			]
+		);
+
+		// in case depositor does not have more than `MinNominatorBond` staked, we can end up in
+		// situation where a member unbonding would cause pool balance to drop below
+		// `MinNominatorBond` and hence not allowed. This can happen if the `MinNominatorBond` is
+		// increased after the pool is created.
+		assert_ok!(Staking::set_staking_configs(
+			RuntimeOrigin::root(),
+			pallet_staking::ConfigOp::Set(55), // minimum nominator bond
+			pallet_staking::ConfigOp::Noop,
+			pallet_staking::ConfigOp::Noop,
+			pallet_staking::ConfigOp::Noop,
+			pallet_staking::ConfigOp::Noop,
+			pallet_staking::ConfigOp::Noop,
+			pallet_staking::ConfigOp::Noop,
+		));
+
+		// members can unbond as long as total stake of the pool is above min nominator bond
+		assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10),);
+		assert_eq!(PoolMembers::<Runtime>::get(20).unwrap().unbonding_eras.len(), 1);
+		assert_eq!(PoolMembers::<Runtime>::get(20).unwrap().points, 0);
+
+		// this member cannot unbond since it will cause `pool stake < MinNominatorBond`
+		assert_noop!(
+			Pools::unbond(RuntimeOrigin::signed(21), 21, 10),
+			StakingError::<Runtime>::InsufficientBond,
+		);
+
+		// members can call `chill` permissionlessly now
+		assert_ok!(Pools::chill(RuntimeOrigin::signed(20), 1));
+
+		// now another member can unbond.
+		assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10));
+		assert_eq!(PoolMembers::<Runtime>::get(21).unwrap().unbonding_eras.len(), 1);
+		assert_eq!(PoolMembers::<Runtime>::get(21).unwrap().points, 0);
+
+		// nominator can not resume nomination until depositor have enough stake
+		assert_noop!(
+			Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]),
+			PoolsError::<Runtime>::MinimumBondNotMet,
+		);
+
+		// other members joining pool does not affect the depositor's ability to resume nomination
+		assert_ok!(Pools::join(RuntimeOrigin::signed(22), 10, 1));
+
+		assert_noop!(
+			Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]),
+			PoolsError::<Runtime>::MinimumBondNotMet,
+		);
+
+		// depositor can bond extra stake
+		assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10)));
+
+		// `chill` can not be called permissionlessly anymore
+		assert_noop!(
+			Pools::chill(RuntimeOrigin::signed(20), 1),
+			PoolsError::<Runtime>::NotNominator,
+		);
+
+		// now nominator can resume nomination
+		assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]));
+
+		// skip to make the unbonding period end.
+		CurrentEra::<Runtime>::set(Some(BondingDuration::get()));
+
+		// 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_eq!(
+			staking_events_since_last_call(),
+			vec![
+				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
+				StakingEvent::Chilled { stash: POOL1_BONDED },
+				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
+				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // other member bonding
+				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // depositor bond extra
+				StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 },
+			]
+		);
+	})
+}
+
+#[test]
+fn pool_slash_e2e() {
+	new_test_ext().execute_with(|| {
+		ExistentialDeposit::set(1);
+		assert_eq!(Balances::minimum_balance(), 1);
+		assert_eq!(CurrentEra::<T>::get(), None);
+
+		// create the pool, we know this has id 1.
+		assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10));
+		assert_eq!(LastPoolId::<Runtime>::get(), 1);
+
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![
+				PoolsEvent::Created { depositor: 10, pool_id: 1 },
+				PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true },
+			]
+		);
+
+		assert_eq!(
+			Payee::<Runtime>::get(POOL1_BONDED),
+			Some(RewardDestination::Account(POOL1_REWARD))
+		);
+
+		// have two members join
+		assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1));
+		assert_ok!(Pools::join(RuntimeOrigin::signed(21), 20, 1));
+
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![
+				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 20 },
+				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 20 }
+			]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![
+				PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true },
+				PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 20, joined: true },
+			]
+		);
+
+		// now let's progress a bit.
+		CurrentEra::<Runtime>::set(Some(1));
+
+		// 20 / 80 of the total funds are unlocked, and safe from any further slash.
+		assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 10));
+		assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10));
+
+		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::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10, era: 4 },
+				PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10, era: 4 }
+			]
+		);
+
+		CurrentEra::<Runtime>::set(Some(2));
+
+		// note: depositor cannot fully unbond at this point.
+		// these funds will still get slashed.
+		assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 10));
+		assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10));
+		assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10));
+
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![
+				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
+				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
+				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
+			]
+		);
+
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![
+				PoolsEvent::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10, era: 5 },
+				PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10, era: 5 },
+				PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 10, points: 10, era: 5 },
+			]
+		);
+
+		// At this point, 20 are safe from slash, 30 are unlocking but vulnerable to slash, and
+		// another 30 are active and vulnerable to slash. Let's slash half of them.
+		pallet_staking::slashing::do_slash::<Runtime>(
+			&POOL1_BONDED,
+			30,
+			&mut Default::default(),
+			&mut Default::default(),
+			2, // slash era 2, affects chunks at era 5 onwards.
+		);
+
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 30 }]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![
+				// 30 has been slashed to 15 (15 slash)
+				PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 5, balance: 15 },
+				// 30 has been slashed to 15 (15 slash)
+				PoolsEvent::PoolSlashed { pool_id: 1, balance: 15 }
+			]
+		);
+
+		CurrentEra::<Runtime>::set(Some(3));
+		assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10));
+
+		assert_eq!(
+			PoolMembers::<Runtime>::get(21).unwrap(),
+			PoolMember {
+				pool_id: 1,
+				points: 0,
+				last_recorded_reward_counter: Zero::zero(),
+				// the 10 points unlocked just now correspond to 5 points in the unbond pool.
+				unbonding_eras: bounded_btree_map!(5 => 10, 6 => 5)
+			}
+		);
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5 }]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 5, points: 5, era: 6 }]
+		);
+
+		// now we start withdrawing. we do it all at once, at era 6 where 20 and 21 are fully free.
+		CurrentEra::<Runtime>::set(Some(6));
+		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0));
+		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0));
+
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![
+				// 20 had unbonded 10 safely, and 10 got slashed by half.
+				PoolsEvent::Withdrawn { member: 20, pool_id: 1, balance: 10 + 5, points: 20 },
+				PoolsEvent::MemberRemoved { pool_id: 1, member: 20, released_balance: 0 },
+				// 21 unbonded all of it after the slash
+				PoolsEvent::Withdrawn { member: 21, pool_id: 1, balance: 5 + 5, points: 15 },
+				PoolsEvent::MemberRemoved { pool_id: 1, member: 21, released_balance: 0 }
+			]
+		);
+		assert_eq!(
+			staking_events_since_last_call(),
+			// a 10 (un-slashed) + 10/2 (slashed) balance from 10 has also been unlocked
+			vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 15 + 10 + 15 }]
+		);
+
+		// now, finally, we can unbond the depositor further than their current limit.
+		assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying));
+		assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 20));
+
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![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: 10, pool_id: 1, points: 10, balance: 10, era: 9 }
+			]
+		);
+
+		CurrentEra::<Runtime>::set(Some(9));
+		assert_eq!(
+			PoolMembers::<Runtime>::get(10).unwrap(),
+			PoolMember {
+				pool_id: 1,
+				points: 0,
+				last_recorded_reward_counter: Zero::zero(),
+				unbonding_eras: bounded_btree_map!(4 => 10, 5 => 10, 9 => 10)
+			}
+		);
+		// withdraw the depositor, they should lose 12 balance in total due to slash.
+		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0));
+
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 10 }]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![
+				PoolsEvent::Withdrawn { member: 10, pool_id: 1, balance: 10 + 15, points: 30 },
+				PoolsEvent::MemberRemoved { pool_id: 1, member: 10, released_balance: 0 },
+				PoolsEvent::Destroyed { pool_id: 1 }
+			]
+		);
+	});
+}
+
+#[test]
+fn pool_slash_proportional() {
+	// a typical example where 3 pool members unbond in era 99, 100, and 101, and a slash that
+	// happened in era 100 should only affect the latter two.
+	new_test_ext().execute_with(|| {
+		ExistentialDeposit::set(1);
+		BondingDuration::set(28);
+		assert_eq!(Balances::minimum_balance(), 1);
+		assert_eq!(CurrentEra::<T>::get(), None);
+
+		// create the pool, we know this has id 1.
+		assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10));
+		assert_eq!(LastPoolId::<T>::get(), 1);
+
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![
+				PoolsEvent::Created { depositor: 10, pool_id: 1 },
+				PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true },
+			]
+		);
+
+		// have two members join
+		let bond = 20;
+		assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1));
+		assert_ok!(Pools::join(RuntimeOrigin::signed(21), bond, 1));
+		assert_ok!(Pools::join(RuntimeOrigin::signed(22), bond, 1));
+
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![
+				StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond },
+				StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond },
+				StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond },
+			]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![
+				PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true },
+				PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: bond, joined: true },
+				PoolsEvent::Bonded { member: 22, pool_id: 1, bonded: bond, joined: true },
+			]
+		);
+
+		// now let's progress a lot.
+		CurrentEra::<T>::set(Some(99));
+
+		// and unbond
+		assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond));
+
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![PoolsEvent::Unbonded {
+				member: 20,
+				pool_id: 1,
+				balance: bond,
+				points: bond,
+				era: 127
+			}]
+		);
+
+		CurrentEra::<T>::set(Some(100));
+		assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, bond));
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![PoolsEvent::Unbonded {
+				member: 21,
+				pool_id: 1,
+				balance: bond,
+				points: bond,
+				era: 128
+			}]
+		);
+
+		CurrentEra::<T>::set(Some(101));
+		assert_ok!(Pools::unbond(RuntimeOrigin::signed(22), 22, bond));
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![PoolsEvent::Unbonded {
+				member: 22,
+				pool_id: 1,
+				balance: bond,
+				points: bond,
+				era: 129
+			}]
+		);
+
+		// Apply a slash that happened in era 100. This is typically applied with a delay.
+		// Of the total 100, 50 is slashed.
+		assert_eq!(BondedPools::<T>::get(1).unwrap().points, 40);
+		pallet_staking::slashing::do_slash::<Runtime>(
+			&POOL1_BONDED,
+			50,
+			&mut Default::default(),
+			&mut Default::default(),
+			100,
+		);
+
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 50 }]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![
+				// This era got slashed 12.5, which rounded up to 13.
+				PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 128, balance: 7 },
+				// This era got slashed 12 instead of 12.5 because an earlier chunk got 0.5 more
+				// slashed, and 12 is all the remaining slash
+				PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 129, balance: 8 },
+				// Bonded pool got slashed for 25, remaining 15 in it.
+				PoolsEvent::PoolSlashed { pool_id: 1, balance: 15 }
+			]
+		);
+	});
+}
+
+#[test]
+fn pool_slash_non_proportional_only_bonded_pool() {
+	// A typical example where a pool member unbonds in era 99, and they can get away with a slash
+	// that happened in era 100, as long as the pool has enough active bond to cover the slash. If
+	// everything else in the slashing/staking system works, this should always be the case.
+	// Nonetheless, `ledger.slash` has been written such that it will slash greedily from any chunk
+	// if it runs out of chunks that it thinks should be affected by the slash.
+	new_test_ext().execute_with(|| {
+		ExistentialDeposit::set(1);
+		BondingDuration::set(28);
+		assert_eq!(Balances::minimum_balance(), 1);
+		assert_eq!(CurrentEra::<T>::get(), None);
+
+		// create the pool, we know this has id 1.
+		assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10));
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![
+				PoolsEvent::Created { depositor: 10, pool_id: 1 },
+				PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true },
+			]
+		);
+
+		// have two members join
+		let bond = 20;
+		assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1));
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }]
+		);
+
+		// progress and unbond.
+		CurrentEra::<T>::set(Some(99));
+		assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond));
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond }]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![PoolsEvent::Unbonded {
+				member: 20,
+				pool_id: 1,
+				balance: bond,
+				points: bond,
+				era: 127
+			}]
+		);
+
+		// slash for 30. This will be deducted only from the bonded pool.
+		CurrentEra::<T>::set(Some(100));
+		assert_eq!(BondedPools::<T>::get(1).unwrap().points, 40);
+		pallet_staking::slashing::do_slash::<Runtime>(
+			&POOL1_BONDED,
+			30,
+			&mut Default::default(),
+			&mut Default::default(),
+			100,
+		);
+
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 30 }]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![PoolsEvent::PoolSlashed { pool_id: 1, balance: 10 }]
+		);
+	});
+}
+
+#[test]
+fn pool_slash_non_proportional_bonded_pool_and_chunks() {
+	// An uncommon example where even though some funds are unlocked such that they should not be
+	// affected by a slash, we still slash out of them. This should not happen at all. If a
+	// nomination has unbonded, from the next era onwards, their exposure will drop, so if an era
+	// happens in that era, then their share of that slash should naturally be less, such that only
+	// their active ledger stake is enough to compensate it.
+	new_test_ext().execute_with(|| {
+		ExistentialDeposit::set(1);
+		BondingDuration::set(28);
+		assert_eq!(Balances::minimum_balance(), 1);
+		assert_eq!(CurrentEra::<T>::get(), None);
+
+		// create the pool, we know this has id 1.
+		assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10));
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![
+				PoolsEvent::Created { depositor: 10, pool_id: 1 },
+				PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true },
+			]
+		);
+
+		// have two members join
+		let bond = 20;
+		assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1));
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }]
+		);
+
+		// progress and unbond.
+		CurrentEra::<T>::set(Some(99));
+		assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond));
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond }]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![PoolsEvent::Unbonded {
+				member: 20,
+				pool_id: 1,
+				balance: bond,
+				points: bond,
+				era: 127
+			}]
+		);
+
+		// slash 50. This will be deducted only from the bonded pool and one of the unbonding pools.
+		CurrentEra::<T>::set(Some(100));
+		assert_eq!(BondedPools::<T>::get(1).unwrap().points, 40);
+		pallet_staking::slashing::do_slash::<Runtime>(
+			&POOL1_BONDED,
+			50,
+			&mut Default::default(),
+			&mut Default::default(),
+			100,
+		);
+
+		assert_eq!(
+			staking_events_since_last_call(),
+			vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 50 }]
+		);
+		assert_eq!(
+			pool_events_since_last_call(),
+			vec![
+				// out of 20, 10 was taken.
+				PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 127, balance: 10 },
+				// out of 40, all was taken.
+				PoolsEvent::PoolSlashed { pool_id: 1, balance: 0 }
+			]
+		);
+	});
+}
diff --git a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d913c5fe6948cb5a0fae1d5ccf8e533e5ddb8cc7
--- /dev/null
+++ b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs
@@ -0,0 +1,231 @@
+// 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 frame_election_provider_support::VoteWeight;
+use frame_support::{
+	assert_ok, derive_impl,
+	pallet_prelude::*,
+	parameter_types,
+	traits::{ConstU64, ConstU8, VariantCountOf},
+	PalletId,
+};
+use sp_runtime::{
+	traits::{Convert, IdentityLookup},
+	BuildStorage, FixedU128, Perbill,
+};
+
+type AccountId = u128;
+type BlockNumber = u64;
+type Balance = u128;
+
+pub(crate) type T = Runtime;
+
+pub(crate) const POOL1_BONDED: AccountId = 20318131474730217858575332831085u128;
+pub(crate) const POOL1_REWARD: AccountId = 20397359637244482196168876781421u128;
+
+#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
+impl frame_system::Config for Runtime {
+	type AccountId = AccountId;
+	type Lookup = IdentityLookup<Self::AccountId>;
+	type Block = Block;
+	type AccountData = pallet_balances::AccountData<Balance>;
+}
+
+impl pallet_timestamp::Config for Runtime {
+	type Moment = u64;
+	type OnTimestampSet = ();
+	type MinimumPeriod = ConstU64<5>;
+	type WeightInfo = ();
+}
+
+parameter_types! {
+	pub static ExistentialDeposit: Balance = 5;
+}
+
+#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)]
+impl pallet_balances::Config for Runtime {
+	type Balance = Balance;
+	type ExistentialDeposit = ExistentialDeposit;
+	type AccountStore = System;
+	type FreezeIdentifier = RuntimeFreezeReason;
+	type MaxFreezes = VariantCountOf<RuntimeFreezeReason>;
+	type RuntimeFreezeReason = RuntimeFreezeReason;
+}
+
+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;
+}
+
+#[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)]
+impl pallet_staking::Config for Runtime {
+	type Currency = Balances;
+	type UnixTime = pallet_timestamp::Pallet<Self>;
+	type AdminOrigin = frame_system::EnsureRoot<Self::AccountId>;
+	type BondingDuration = BondingDuration;
+	type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
+	type ElectionProvider =
+		frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>;
+	type GenesisElectionProvider = Self::ElectionProvider;
+	type VoterList = VoterList;
+	type TargetList = pallet_staking::UseValidatorsMap<Self>;
+	type EventListeners = Pools;
+	type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
+}
+
+parameter_types! {
+	pub static BagThresholds: &'static [VoteWeight] = &[10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000];
+}
+
+type VoterBagsListInstance = pallet_bags_list::Instance1;
+impl pallet_bags_list::Config<VoterBagsListInstance> for Runtime {
+	type RuntimeEvent = RuntimeEvent;
+	type WeightInfo = ();
+	type BagThresholds = BagThresholds;
+	type ScoreProvider = Staking;
+	type Score = VoteWeight;
+}
+
+pub struct BalanceToU256;
+impl Convert<Balance, sp_core::U256> for BalanceToU256 {
+	fn convert(n: Balance) -> sp_core::U256 {
+		n.into()
+	}
+}
+
+pub struct U256ToBalance;
+impl Convert<sp_core::U256, Balance> for U256ToBalance {
+	fn convert(n: sp_core::U256) -> Balance {
+		n.try_into().unwrap()
+	}
+}
+
+parameter_types! {
+	pub const PostUnbondingPoolsWindow: u32 = 10;
+	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 = FixedU128;
+	type BalanceToU256 = BalanceToU256;
+	type U256ToBalance = U256ToBalance;
+	type StakeAdapter = pallet_nomination_pools::adapter::TransferStake<Self, Staking>;
+	type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow;
+	type MaxMetadataLen = ConstU32<256>;
+	type MaxUnbonding = ConstU32<8>;
+	type MaxPointsToBalance = ConstU8<10>;
+	type PalletId = PoolsPalletId;
+	type AdminOrigin = frame_system::EnsureRoot<Self::AccountId>;
+}
+
+type Block = frame_system::mocking::MockBlock<Runtime>;
+
+frame_support::construct_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,
+	}
+);
+
+pub fn new_test_ext() -> sp_io::TestExternalities {
+	sp_tracing::try_init_simple();
+	let mut storage = frame_system::GenesisConfig::<Runtime>::default().build_storage().unwrap();
+	let _ = pallet_nomination_pools::GenesisConfig::<Runtime> {
+		min_join_bond: 2,
+		min_create_bond: 2,
+		max_pools: Some(3),
+		max_members_per_pool: Some(5),
+		max_members: Some(3 * 5),
+		global_max_commission: Some(Perbill::from_percent(90)),
+	}
+	.assimilate_storage(&mut storage)
+	.unwrap();
+
+	let _ = pallet_balances::GenesisConfig::<Runtime> {
+		balances: vec![(10, 100), (20, 100), (21, 100), (22, 100)],
+	}
+	.assimilate_storage(&mut 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);
+
+		// set some limit for nominations.
+		assert_ok!(Staking::set_staking_configs(
+			RuntimeOrigin::root(),
+			pallet_staking::ConfigOp::Set(10), // minimum nominator bond
+			pallet_staking::ConfigOp::Noop,
+			pallet_staking::ConfigOp::Noop,
+			pallet_staking::ConfigOp::Noop,
+			pallet_staking::ConfigOp::Noop,
+			pallet_staking::ConfigOp::Noop,
+			pallet_staking::ConfigOp::Noop,
+		));
+	});
+
+	ext
+}
+
+parameter_types! {
+	static ObservedEventsPools: usize = 0;
+	static ObservedEventsStaking: usize = 0;
+	static ObservedEventsBalances: 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 staking_events_since_last_call() -> Vec<pallet_staking::Event<Runtime>> {
+	let events = System::events()
+		.into_iter()
+		.map(|r| r.event)
+		.filter_map(|e| if let RuntimeEvent::Staking(inner) = e { Some(inner) } else { None })
+		.collect::<Vec<_>>();
+	let already_seen = ObservedEventsStaking::get();
+	ObservedEventsStaking::set(events.len());
+	events.into_iter().skip(already_seen).collect()
+}
diff --git a/substrate/frame/offences/benchmarking/src/inner.rs b/substrate/frame/offences/benchmarking/src/inner.rs
index 3d3cd470bc24cc3fd63eaf09a52b99ee5eb7b33e..75f3e9931e34c3d8827049d76d0e5510086ccdba 100644
--- a/substrate/frame/offences/benchmarking/src/inner.rs
+++ b/substrate/frame/offences/benchmarking/src/inner.rs
@@ -180,12 +180,16 @@ where
 	<T as frame_system::Config>::RuntimeEvent: TryInto<frame_system::Event<T>>,
 {
 	// make sure that all slashes have been applied
-	// deposit to reporter + reporter account endowed.
-	assert_eq!(System::<T>::read_events_for_pallet::<pallet_balances::Event<T>>().len(), 2);
+	// (n nominators + one validator) * (slashed + unlocked) + deposit to reporter +
+	// reporter account endowed + some funds rescinded from issuance.
+	assert_eq!(
+		System::<T>::read_events_for_pallet::<pallet_balances::Event<T>>().len(),
+		2 * (offender_count + 1) + 3
+	);
 	// (n nominators + one validator) * slashed + Slash Reported
 	assert_eq!(
 		System::<T>::read_events_for_pallet::<pallet_staking::Event<T>>().len(),
-		1 * (offender_count + 1) as usize + 1
+		1 * (offender_count + 1) + 1
 	);
 	// offence
 	assert_eq!(System::<T>::read_events_for_pallet::<pallet_offences::Event>().len(), 1);
diff --git a/substrate/frame/offences/benchmarking/src/mock.rs b/substrate/frame/offences/benchmarking/src/mock.rs
index 3c81f2a664e32138f5fee5f43aab30e1f7ce6819..c5c178aa4443dbd44c38b56e212fcfa1599cbfb6 100644
--- a/substrate/frame/offences/benchmarking/src/mock.rs
+++ b/substrate/frame/offences/benchmarking/src/mock.rs
@@ -125,7 +125,6 @@ impl onchain::Config for OnChainSeqPhragmen {
 
 #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)]
 impl pallet_staking::Config for Test {
-	type OldCurrency = Balances;
 	type Currency = Balances;
 	type CurrencyBalance = <Self as pallet_balances::Config>::Balance;
 	type UnixTime = pallet_timestamp::Pallet<Self>;
diff --git a/substrate/frame/root-offences/src/mock.rs b/substrate/frame/root-offences/src/mock.rs
index 3f14dc00b56068f8be244d24e4cb011748c0aa7f..7a96b8eade4e13f290020ffc0f0a12fa5f72600d 100644
--- a/substrate/frame/root-offences/src/mock.rs
+++ b/substrate/frame/root-offences/src/mock.rs
@@ -126,7 +126,6 @@ parameter_types! {
 
 #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)]
 impl pallet_staking::Config for Test {
-	type OldCurrency = Balances;
 	type Currency = Balances;
 	type CurrencyBalance = <Self as pallet_balances::Config>::Balance;
 	type UnixTime = Timestamp;
@@ -207,10 +206,10 @@ impl ExtBuilder {
 				(30, self.balance_factor * 50),
 				(40, self.balance_factor * 50),
 				// stashes
-				(11, self.balance_factor * 1500),
-				(21, self.balance_factor * 1500),
-				(31, self.balance_factor * 1000),
-				(41, self.balance_factor * 2000),
+				(11, self.balance_factor * 1000),
+				(21, self.balance_factor * 1000),
+				(31, self.balance_factor * 500),
+				(41, self.balance_factor * 1000),
 			],
 		}
 		.assimilate_storage(&mut storage)
diff --git a/substrate/frame/session/benchmarking/src/mock.rs b/substrate/frame/session/benchmarking/src/mock.rs
index 74201da3d2f310f58593d8566eb650086245c76f..346cd04c0fa9eb5f917557aa050e759762f9a341 100644
--- a/substrate/frame/session/benchmarking/src/mock.rs
+++ b/substrate/frame/session/benchmarking/src/mock.rs
@@ -133,7 +133,6 @@ impl onchain::Config for OnChainSeqPhragmen {
 
 #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)]
 impl pallet_staking::Config for Test {
-	type OldCurrency = Balances;
 	type Currency = Balances;
 	type CurrencyBalance = <Self as pallet_balances::Config>::Balance;
 	type UnixTime = pallet_timestamp::Pallet<Self>;
diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml
index 74b1c78e9cbee9661978ee2111ec9d3410a7f56c..22176b6d720b201583905f59780c19aa7c33d2f4 100644
--- a/substrate/frame/staking/Cargo.toml
+++ b/substrate/frame/staking/Cargo.toml
@@ -41,7 +41,6 @@ rand_chacha = { optional = true, workspace = true }
 [dev-dependencies]
 frame-benchmarking = { workspace = true, default-features = true }
 frame-election-provider-support = { workspace = true, default-features = true }
-frame-support = { features = ["experimental"], workspace = true, default-features = true }
 pallet-bags-list = { workspace = true, default-features = true }
 pallet-balances = { workspace = true, default-features = true }
 pallet-staking-reward-curve = { workspace = true, default-features = true }
diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs
index a1140d317c204957e5f7cc9178f704cffe5965c1..23368b1f8fca713f78405165c00ec09d54a8d257 100644
--- a/substrate/frame/staking/src/asset.rs
+++ b/substrate/frame/staking/src/asset.rs
@@ -18,15 +18,9 @@
 //! Contains all the interactions with [`Config::Currency`] to manipulate the underlying staking
 //! asset.
 
-use crate::{BalanceOf, Config, HoldReason, NegativeImbalanceOf, PositiveImbalanceOf};
-use frame_support::traits::{
-	fungible::{
-		hold::{Balanced as FunHoldBalanced, Inspect as FunHoldInspect, Mutate as FunHoldMutate},
-		Balanced, Inspect as FunInspect,
-	},
-	tokens::{Fortitude, Precision, Preservation},
-};
-use sp_runtime::{DispatchResult, Saturating};
+use frame_support::traits::{Currency, InspectLockableCurrency, LockableCurrency};
+
+use crate::{BalanceOf, Config, NegativeImbalanceOf, PositiveImbalanceOf};
 
 /// Existential deposit for the chain.
 pub fn existential_deposit<T: Config>() -> BalanceOf<T> {
@@ -38,7 +32,7 @@ pub fn total_issuance<T: Config>() -> BalanceOf<T> {
 	T::Currency::total_issuance()
 }
 
-/// Total balance of `who`. Includes both free and staked.
+/// Total balance of `who`. Includes both, free and reserved.
 pub fn total_balance<T: Config>(who: &T::AccountId) -> BalanceOf<T> {
 	T::Currency::total_balance(who)
 }
@@ -47,65 +41,42 @@ pub fn total_balance<T: Config>(who: &T::AccountId) -> BalanceOf<T> {
 ///
 /// This includes balance free to stake along with any balance that is already staked.
 pub fn stakeable_balance<T: Config>(who: &T::AccountId) -> BalanceOf<T> {
-	free_to_stake::<T>(who).saturating_add(staked::<T>(who))
+	T::Currency::free_balance(who)
 }
 
 /// Balance of `who` that is currently at stake.
 ///
-/// The staked amount is on hold and cannot be transferred out of `who`s account.
+/// The staked amount is locked and cannot be transferred out of `who`s account.
 pub fn staked<T: Config>(who: &T::AccountId) -> BalanceOf<T> {
-	T::Currency::balance_on_hold(&HoldReason::Staking.into(), who)
-}
-
-/// Balance of who that can be staked additionally.
-///
-/// Does not include the current stake.
-pub fn free_to_stake<T: Config>(who: &T::AccountId) -> BalanceOf<T> {
-	// since we want to be able to use frozen funds for staking, we force the reduction.
-	T::Currency::reducible_balance(who, Preservation::Preserve, Fortitude::Force)
+	T::Currency::balance_locked(crate::STAKING_ID, who)
 }
 
 /// Set balance that can be staked for `who`.
 ///
-/// If `Value` is lower than the current staked balance, the difference is unlocked.
-///
-/// Should only be used with test.
+/// This includes any balance that is already staked.
 #[cfg(any(test, feature = "runtime-benchmarks"))]
 pub fn set_stakeable_balance<T: Config>(who: &T::AccountId, value: BalanceOf<T>) {
-	use frame_support::traits::fungible::Mutate;
-
-	// minimum free balance (non-staked) required to keep the account alive.
-	let ed = existential_deposit::<T>();
-	// currently on stake
-	let staked_balance = staked::<T>(who);
-
-	// if new value is greater than staked balance, mint some free balance.
-	if value > staked_balance {
-		let _ = T::Currency::set_balance(who, value - staked_balance + ed);
-	} else {
-		// else reduce the staked balance.
-		update_stake::<T>(who, value).expect("can remove from what is staked");
-		// burn all free, only leaving ED.
-		let _ = T::Currency::set_balance(who, ed);
-	}
-
-	// ensure new stakeable balance same as desired `value`.
-	assert_eq!(stakeable_balance::<T>(who), value);
+	T::Currency::make_free_balance_be(who, value);
 }
 
 /// Update `amount` at stake for `who`.
 ///
 /// Overwrites the existing stake amount. If passed amount is lower than the existing stake, the
 /// difference is unlocked.
-pub fn update_stake<T: Config>(who: &T::AccountId, amount: BalanceOf<T>) -> DispatchResult {
-	T::Currency::set_on_hold(&HoldReason::Staking.into(), who, amount)
+pub fn update_stake<T: Config>(who: &T::AccountId, amount: BalanceOf<T>) {
+	T::Currency::set_lock(
+		crate::STAKING_ID,
+		who,
+		amount,
+		frame_support::traits::WithdrawReasons::all(),
+	);
 }
 
-/// Release all staked amount to `who`.
+/// Kill the stake of `who`.
 ///
-/// Fails if there are consumers left on `who` that restricts it from being reaped.
-pub fn kill_stake<T: Config>(who: &T::AccountId) -> DispatchResult {
-	T::Currency::release_all(&HoldReason::Staking.into(), who, Precision::BestEffort).map(|_| ())
+/// All locked amount is unlocked.
+pub fn kill_stake<T: Config>(who: &T::AccountId) {
+	T::Currency::remove_lock(crate::STAKING_ID, who);
 }
 
 /// Slash the value from `who`.
@@ -115,32 +86,29 @@ pub fn slash<T: Config>(
 	who: &T::AccountId,
 	value: BalanceOf<T>,
 ) -> (NegativeImbalanceOf<T>, BalanceOf<T>) {
-	T::Currency::slash(&HoldReason::Staking.into(), who, value)
+	T::Currency::slash(who, value)
 }
 
 /// Mint `value` into an existing account `who`.
 ///
 /// This does not increase the total issuance.
-pub fn mint_into_existing<T: Config>(
+pub fn mint_existing<T: Config>(
 	who: &T::AccountId,
 	value: BalanceOf<T>,
 ) -> Option<PositiveImbalanceOf<T>> {
-	// since the account already exists, we mint exact value even if value is below ED.
-	T::Currency::deposit(who, value, Precision::Exact).ok()
+	T::Currency::deposit_into_existing(who, value).ok()
 }
 
-/// Mint `value` and create account for `who` if it does not exist.
-///
-/// If value is below existential deposit, the account is not created.
+/// Mint reward and create account for `who` if it does not exist.
 ///
-/// Note: This does not increase the total issuance.
+/// This does not increase the total issuance.
 pub fn mint_creating<T: Config>(who: &T::AccountId, value: BalanceOf<T>) -> PositiveImbalanceOf<T> {
-	T::Currency::deposit(who, value, Precision::BestEffort).unwrap_or_default()
+	T::Currency::deposit_creating(who, value)
 }
 
 /// Deposit newly issued or slashed `value` into `who`.
 pub fn deposit_slashed<T: Config>(who: &T::AccountId, value: NegativeImbalanceOf<T>) {
-	let _ = T::Currency::resolve(who, value);
+	T::Currency::resolve_creating(who, value)
 }
 
 /// Issue `value` increasing total issuance.
@@ -153,5 +121,5 @@ pub fn issue<T: Config>(value: BalanceOf<T>) -> NegativeImbalanceOf<T> {
 /// Burn the amount from the total issuance.
 #[cfg(feature = "runtime-benchmarks")]
 pub fn burn<T: Config>(amount: BalanceOf<T>) -> PositiveImbalanceOf<T> {
-	T::Currency::rescind(amount)
+	T::Currency::burn(amount)
 }
diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs
index 59d272168d68bc06f73e4e85ce7fc5a407ca3daf..79d8dd3fbc30365e4a81a2f708383754f67a49cc 100644
--- a/substrate/frame/staking/src/benchmarking.rs
+++ b/substrate/frame/staking/src/benchmarking.rs
@@ -257,11 +257,7 @@ mod benchmarks {
 			.map(|l| l.active)
 			.ok_or("ledger not created after")?;
 
-		let _ = asset::mint_into_existing::<T>(
-			&stash,
-			max_additional + asset::existential_deposit::<T>(),
-		)
-		.unwrap();
+		let _ = asset::mint_existing::<T>(&stash, max_additional).unwrap();
 
 		whitelist_account!(stash);
 
@@ -1137,23 +1133,6 @@ mod benchmarks {
 		Ok(())
 	}
 
-	#[benchmark]
-	fn migrate_currency() -> Result<(), BenchmarkError> {
-		let (stash, _ctrl) =
-			create_stash_controller::<T>(USER_SEED, 100, RewardDestination::Staked)?;
-		let stake = asset::staked::<T>(&stash);
-		migrate_to_old_currency::<T>(stash.clone());
-		// no holds
-		assert!(asset::staked::<T>(&stash).is_zero());
-		whitelist_account!(stash);
-
-		#[extrinsic_call]
-		_(RawOrigin::Signed(stash.clone()), stash.clone());
-
-		assert_eq!(asset::staked::<T>(&stash), stake);
-		Ok(())
-	}
-
 	impl_benchmark_test_suite!(
 		Staking,
 		crate::mock::ExtBuilder::default().has_stakers(true),
diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs
index 1d66ebd27e9f729e8a42a93960435ccf78b79769..ac3be04cf607176d6aee437a7b49bc3f4afffd55 100644
--- a/substrate/frame/staking/src/ledger.rs
+++ b/substrate/frame/staking/src/ledger.rs
@@ -32,7 +32,6 @@
 //! state consistency.
 
 use frame_support::{defensive, ensure, traits::Defensive};
-use sp_runtime::DispatchResult;
 use sp_staking::{StakingAccount, StakingInterface};
 
 use crate::{
@@ -188,8 +187,7 @@ impl<T: Config> StakingLedger<T> {
 		// We skip locking virtual stakers.
 		if !Pallet::<T>::is_virtual_staker(&self.stash) {
 			// for direct stakers, update lock on stash based on ledger.
-			asset::update_stake::<T>(&self.stash, self.total)
-				.map_err(|_| Error::<T>::NotEnoughFunds)?;
+			asset::update_stake::<T>(&self.stash, self.total);
 		}
 
 		Ledger::<T>::insert(
@@ -252,7 +250,7 @@ impl<T: Config> StakingLedger<T> {
 
 	/// Clears all data related to a staking ledger and its bond in both [`Ledger`] and [`Bonded`]
 	/// storage items and updates the stash staking lock.
-	pub(crate) fn kill(stash: &T::AccountId) -> DispatchResult {
+	pub(crate) fn kill(stash: &T::AccountId) -> Result<(), Error<T>> {
 		let controller = <Bonded<T>>::get(stash).ok_or(Error::<T>::NotStash)?;
 
 		<Ledger<T>>::get(&controller).ok_or(Error::<T>::NotController).map(|ledger| {
@@ -261,9 +259,9 @@ impl<T: Config> StakingLedger<T> {
 			<Payee<T>>::remove(&stash);
 
 			// kill virtual staker if it exists.
-			if <VirtualStakers<T>>::take(&ledger.stash).is_none() {
+			if <VirtualStakers<T>>::take(&stash).is_none() {
 				// if not virtual staker, clear locks.
-				asset::kill_stake::<T>(&ledger.stash)?;
+				asset::kill_stake::<T>(&ledger.stash);
 			}
 
 			Ok(())
diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs
index 42230cb27b756306446cf23cea536a054b11e119..6361663b2b1c05939ba24f572c171c00af2f77e9 100644
--- a/substrate/frame/staking/src/lib.rs
+++ b/substrate/frame/staking/src/lib.rs
@@ -312,8 +312,7 @@ use codec::{Decode, Encode, HasCompact, MaxEncodedLen};
 use frame_support::{
 	defensive, defensive_assert,
 	traits::{
-		tokens::fungible::{Credit, Debt},
-		ConstU32, Defensive, DefensiveMax, DefensiveSaturating, Get, LockIdentifier,
+		ConstU32, Currency, Defensive, DefensiveMax, DefensiveSaturating, Get, LockIdentifier,
 	},
 	weights::Weight,
 	BoundedVec, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound,
@@ -362,9 +361,12 @@ pub type RewardPoint = u32;
 /// The balance type of this pallet.
 pub type BalanceOf<T> = <T as Config>::CurrencyBalance;
 
-type PositiveImbalanceOf<T> = Debt<<T as frame_system::Config>::AccountId, <T as Config>::Currency>;
-pub type NegativeImbalanceOf<T> =
-	Credit<<T as frame_system::Config>::AccountId, <T as Config>::Currency>;
+type PositiveImbalanceOf<T> = <<T as Config>::Currency as Currency<
+	<T as frame_system::Config>::AccountId,
+>>::PositiveImbalance;
+pub type NegativeImbalanceOf<T> = <<T as Config>::Currency as Currency<
+	<T as frame_system::Config>::AccountId,
+>>::NegativeImbalance;
 
 type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup>::Source;
 
diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs
index 6346949576fa796726b136822737d6bd5c9fb3e4..769b84826b41613f27873fed650f47999806441f 100644
--- a/substrate/frame/staking/src/mock.rs
+++ b/substrate/frame/staking/src/mock.rs
@@ -25,7 +25,8 @@ use frame_election_provider_support::{
 use frame_support::{
 	assert_ok, derive_impl, ord_parameter_types, parameter_types,
 	traits::{
-		ConstU64, EitherOfDiverse, FindAuthor, Get, Imbalance, OnUnbalanced, OneSessionHandler,
+		ConstU64, Currency, EitherOfDiverse, FindAuthor, Get, Imbalance, LockableCurrency,
+		OnUnbalanced, OneSessionHandler, WithdrawReasons,
 	},
 	weights::constants::RocksDbWeight,
 };
@@ -263,7 +264,6 @@ pub(crate) const DISABLING_LIMIT_FACTOR: usize = 3;
 
 #[derive_impl(crate::config_preludes::TestDefaultConfig)]
 impl crate::pallet::pallet::Config for Test {
-	type OldCurrency = Balances;
 	type Currency = Balances;
 	type UnixTime = Timestamp;
 	type RewardRemainder = RewardRemainderMock;
@@ -432,7 +432,6 @@ impl ExtBuilder {
 	fn build(self) -> sp_io::TestExternalities {
 		sp_tracing::try_init_simple();
 		let mut storage = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap();
-		let ed = ExistentialDeposit::get();
 
 		let _ = pallet_balances::GenesisConfig::<Test> {
 			balances: vec![
@@ -447,23 +446,19 @@ impl ExtBuilder {
 				(40, self.balance_factor),
 				(50, self.balance_factor),
 				// stashes
-				// Note: Previously this pallet used locks and stakers could stake all their
-				// balance including ED. Now with holds, stakers are required to maintain
-				// (non-staked) ED in their accounts. Therefore, we drop an additional existential
-				// deposit to genesis stakers.
-				(11, self.balance_factor * 1000 + ed),
-				(21, self.balance_factor * 2000 + ed),
-				(31, self.balance_factor * 2000 + ed),
-				(41, self.balance_factor * 2000 + ed),
-				(51, self.balance_factor * 2000 + ed),
-				(201, self.balance_factor * 2000 + ed),
-				(202, self.balance_factor * 2000 + ed),
+				(11, self.balance_factor * 1000),
+				(21, self.balance_factor * 2000),
+				(31, self.balance_factor * 2000),
+				(41, self.balance_factor * 2000),
+				(51, self.balance_factor * 2000),
+				(201, self.balance_factor * 2000),
+				(202, self.balance_factor * 2000),
 				// optional nominator
-				(100, self.balance_factor * 2000 + ed),
-				(101, self.balance_factor * 2000 + ed),
+				(100, self.balance_factor * 2000),
+				(101, self.balance_factor * 2000),
 				// aux accounts
 				(60, self.balance_factor),
-				(61, self.balance_factor * 2000 + ed),
+				(61, self.balance_factor * 2000),
 				(70, self.balance_factor),
 				(71, self.balance_factor * 2000),
 				(80, self.balance_factor),
@@ -580,7 +575,7 @@ pub(crate) fn current_era() -> EraIndex {
 }
 
 pub(crate) fn bond(who: AccountId, val: Balance) {
-	let _ = asset::set_stakeable_balance::<Test>(&who, val);
+	let _ = Balances::make_free_balance_be(&who, val);
 	assert_ok!(Staking::bond(RuntimeOrigin::signed(who), val, RewardDestination::Stash));
 }
 
@@ -605,6 +600,10 @@ pub(crate) fn bond_virtual_nominator(
 	val: Balance,
 	target: Vec<AccountId>,
 ) {
+	// In a real scenario, `who` is a keyless account managed by another pallet which provides for
+	// it.
+	System::inc_providers(&who);
+
 	// Bond who virtually.
 	assert_ok!(<Staking as sp_staking::StakingUnchecked>::virtual_bond(&who, val, &payee));
 	assert_ok!(Staking::nominate(RuntimeOrigin::signed(who), target));
@@ -810,7 +809,7 @@ pub(crate) fn bond_extra_no_checks(stash: &AccountId, amount: Balance) {
 	let mut ledger = Ledger::<Test>::get(&controller).expect("ledger must exist to bond_extra");
 
 	let new_total = ledger.total + amount;
-	let _ = asset::update_stake::<Test>(stash, new_total);
+	Balances::set_lock(crate::STAKING_ID, stash, new_total, WithdrawReasons::all());
 	ledger.total = new_total;
 	ledger.active = new_total;
 	Ledger::<Test>::insert(controller, ledger);
@@ -819,10 +818,10 @@ pub(crate) fn bond_extra_no_checks(stash: &AccountId, amount: Balance) {
 pub(crate) fn setup_double_bonded_ledgers() {
 	let init_ledgers = Ledger::<Test>::iter().count();
 
-	let _ = asset::set_stakeable_balance::<Test>(&333, 2000);
-	let _ = asset::set_stakeable_balance::<Test>(&444, 2000);
-	let _ = asset::set_stakeable_balance::<Test>(&555, 2000);
-	let _ = asset::set_stakeable_balance::<Test>(&777, 2000);
+	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));
@@ -924,5 +923,5 @@ pub(crate) fn staking_events_since_last_call() -> Vec<crate::Event<Test>> {
 }
 
 pub(crate) fn balances(who: &AccountId) -> (Balance, Balance) {
-	(asset::stakeable_balance::<Test>(who), Balances::reserved_balance(who))
+	(Balances::free_balance(who), Balances::reserved_balance(who))
 }
diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs
index 8c3ff23315a42d94803f2324cebf4c4930951fe0..2ae925d036435976c2f58d49e27f81dad1bfc1d1 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::{
-		Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance,
-		InspectLockableCurrency, Len, LockableCurrency, OnUnbalanced, TryCollect, UnixTime,
+		Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance, Len, OnUnbalanced,
+		TryCollect, UnixTime,
 	},
 	weights::Weight,
 };
@@ -36,9 +36,10 @@ use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin};
 use pallet_session::historical;
 use sp_runtime::{
 	traits::{
-		Bounded, CheckedAdd, Convert, One, SaturatedConversion, Saturating, StaticLookup, Zero,
+		Bounded, CheckedAdd, CheckedSub, Convert, One, SaturatedConversion, Saturating,
+		StaticLookup, Zero,
 	},
-	ArithmeticError, DispatchResult, Perbill, Percent,
+	ArithmeticError, Perbill, Percent,
 };
 use sp_staking::{
 	currency_to_vote::CurrencyToVote,
@@ -53,7 +54,6 @@ use crate::{
 	BalanceOf, EraInfo, EraPayout, Exposure, ExposureOf, Forcing, IndividualExposure,
 	LedgerIntegrityState, MaxNominationsOf, MaxWinnersOf, Nominations, NominationsQuota,
 	PositiveImbalanceOf, RewardDestination, SessionInterface, StakingLedger, ValidatorPrefs,
-	STAKING_ID,
 };
 use alloc::{boxed::Box, vec, vec::Vec};
 
@@ -96,12 +96,10 @@ impl<T: Config> Pallet<T> {
 	pub(crate) fn inspect_bond_state(
 		stash: &T::AccountId,
 	) -> Result<LedgerIntegrityState, Error<T>> {
-		// look at any old unmigrated lock as well.
-		let hold_or_lock = asset::staked::<T>(&stash)
-			.max(T::OldCurrency::balance_locked(STAKING_ID, &stash).into());
+		let lock = asset::staked::<T>(&stash);
 
 		let controller = <Bonded<T>>::get(stash).ok_or_else(|| {
-			if hold_or_lock == Zero::zero() {
+			if lock == Zero::zero() {
 				Error::<T>::NotStash
 			} else {
 				Error::<T>::BadState
@@ -113,7 +111,7 @@ impl<T: Config> Pallet<T> {
 				if ledger.stash != *stash {
 					Ok(LedgerIntegrityState::Corrupted)
 				} else {
-					if hold_or_lock != ledger.total {
+					if lock != ledger.total {
 						Ok(LedgerIntegrityState::LockCorrupted)
 					} else {
 						Ok(LedgerIntegrityState::Ok)
@@ -165,7 +163,11 @@ impl<T: Config> Pallet<T> {
 			additional
 		} else {
 			// additional amount or actual balance of stash whichever is lower.
-			additional.min(asset::free_to_stake::<T>(stash))
+			additional.min(
+				asset::stakeable_balance::<T>(stash)
+					.checked_sub(&ledger.total)
+					.ok_or(ArithmeticError::Overflow)?,
+			)
 		};
 
 		ledger.total = ledger.total.checked_add(&extra).ok_or(ArithmeticError::Overflow)?;
@@ -414,12 +416,12 @@ impl<T: Config> Pallet<T> {
 		let dest = Self::payee(StakingAccount::Stash(stash.clone()))?;
 
 		let maybe_imbalance = match dest {
-			RewardDestination::Stash => asset::mint_into_existing::<T>(stash, amount),
+			RewardDestination::Stash => asset::mint_existing::<T>(stash, amount),
 			RewardDestination::Staked => Self::ledger(Stash(stash.clone()))
 				.and_then(|mut ledger| {
 					ledger.active += amount;
 					ledger.total += amount;
-					let r = asset::mint_into_existing::<T>(stash, amount);
+					let r = asset::mint_existing::<T>(stash, amount);
 
 					let _ = ledger
 						.update()
@@ -797,6 +799,8 @@ impl<T: Config> Pallet<T> {
 		Self::do_remove_validator(&stash);
 		Self::do_remove_nominator(&stash);
 
+		frame_system::Pallet::<T>::dec_consumers(&stash);
+
 		Ok(())
 	}
 
@@ -1159,81 +1163,6 @@ impl<T: Config> Pallet<T> {
 	) -> Exposure<T::AccountId, BalanceOf<T>> {
 		EraInfo::<T>::get_full_exposure(era, account)
 	}
-
-	pub(super) fn do_migrate_currency(stash: &T::AccountId) -> DispatchResult {
-		if Self::is_virtual_staker(stash) {
-			return Self::do_migrate_virtual_staker(stash);
-		}
-
-		let ledger = Self::ledger(Stash(stash.clone()))?;
-		let staked: BalanceOf<T> = T::OldCurrency::balance_locked(STAKING_ID, stash).into();
-		ensure!(!staked.is_zero(), Error::<T>::AlreadyMigrated);
-		ensure!(ledger.total == staked, Error::<T>::BadState);
-
-		// remove old staking lock
-		T::OldCurrency::remove_lock(STAKING_ID, &stash);
-
-		// check if we can hold all stake.
-		let max_hold = asset::free_to_stake::<T>(&stash);
-		let force_withdraw = if max_hold >= staked {
-			// this means we can hold all stake. yay!
-			asset::update_stake::<T>(&stash, staked)?;
-			Zero::zero()
-		} else {
-			// if we are here, it means we cannot hold all user stake. We will do a force withdraw
-			// from ledger, but that's okay since anyways user do not have funds for it.
-			let force_withdraw = staked.saturating_sub(max_hold);
-
-			// we ignore if active is 0. It implies the locked amount is not actively staked. The
-			// account can still get away from potential slash but we can't do much better here.
-			StakingLedger {
-				total: max_hold,
-				active: ledger.active.saturating_sub(force_withdraw),
-				// we are not changing the stash, so we can keep the stash.
-				..ledger
-			}
-			.update()?;
-			force_withdraw
-		};
-
-		// Get rid of the extra consumer we used to have with OldCurrency.
-		frame_system::Pallet::<T>::dec_consumers(&stash);
-
-		Self::deposit_event(Event::<T>::CurrencyMigrated { stash: stash.clone(), force_withdraw });
-		Ok(())
-	}
-
-	fn do_migrate_virtual_staker(stash: &T::AccountId) -> DispatchResult {
-		// Funds for virtual stakers not managed/held by this pallet. We only need to clear
-		// the extra consumer we used to have with OldCurrency.
-		frame_system::Pallet::<T>::dec_consumers(&stash);
-
-		// The delegation system that manages the virtual staker needed to increment provider
-		// previously because of the consumer needed by this pallet. In reality, this stash
-		// is just a key for managing the ledger and the account does not need to hold any
-		// balance or exist. We decrement this provider.
-		let actual_providers = frame_system::Pallet::<T>::providers(stash);
-
-		let expected_providers =
-			// provider is expected to be 1 but someone can always transfer some free funds to
-			// these accounts, increasing the provider.
-			if asset::free_to_stake::<T>(&stash) >= asset::existential_deposit::<T>() {
-				2
-			} else {
-				1
-			};
-
-		// We should never have more than expected providers.
-		ensure!(actual_providers <= expected_providers, Error::<T>::BadState);
-
-		// if actual provider is less than expected, it is already migrated.
-		ensure!(actual_providers == expected_providers, Error::<T>::AlreadyMigrated);
-
-		// dec provider
-		let _ = frame_system::Pallet::<T>::dec_providers(&stash)?;
-
-		return Ok(())
-	}
 }
 
 impl<T: Config> Pallet<T> {
@@ -1996,10 +1925,9 @@ impl<T: Config> StakingInterface for Pallet<T> {
 }
 
 impl<T: Config> sp_staking::StakingUnchecked for Pallet<T> {
-	fn migrate_to_virtual_staker(who: &Self::AccountId) -> DispatchResult {
-		asset::kill_stake::<T>(who)?;
+	fn migrate_to_virtual_staker(who: &Self::AccountId) {
+		asset::kill_stake::<T>(who);
 		VirtualStakers::<T>::insert(who, ());
-		Ok(())
 	}
 
 	/// Virtually bonds `keyless_who` to `payee` with `value`.
@@ -2017,6 +1945,9 @@ impl<T: Config> sp_staking::StakingUnchecked for Pallet<T> {
 		// check if payee not same as who.
 		ensure!(keyless_who != payee, Error::<T>::RewardDestinationRestricted);
 
+		// mark this pallet as consumer of `who`.
+		frame_system::Pallet::<T>::inc_consumers(&keyless_who).map_err(|_| Error::<T>::BadState)?;
+
 		// mark who as a virtual staker.
 		VirtualStakers::<T>::insert(keyless_who, ());
 
@@ -2028,13 +1959,11 @@ impl<T: Config> sp_staking::StakingUnchecked for Pallet<T> {
 		Ok(())
 	}
 
-	/// Only meant to be used in tests.
 	#[cfg(feature = "runtime-benchmarks")]
 	fn migrate_to_direct_staker(who: &Self::AccountId) {
 		assert!(VirtualStakers::<T>::contains_key(who));
 		let ledger = StakingLedger::<T>::get(Stash(who.clone())).unwrap();
-		let _ = asset::update_stake::<T>(who, ledger.total)
-			.expect("funds must be transferred to stash");
+		asset::update_stake::<T>(who, ledger.total);
 		VirtualStakers::<T>::remove(who);
 	}
 }
@@ -2171,7 +2100,7 @@ impl<T: Config> Pallet<T> {
 				if VirtualStakers::<T>::contains_key(stash.clone()) {
 					ensure!(
 						asset::staked::<T>(&stash) == Zero::zero(),
-						"virtual stakers should not have any staked balance"
+						"virtual stakers should not have any locked balance"
 					);
 					ensure!(
 						<Bonded<T>>::get(stash.clone()).unwrap() == stash.clone(),
@@ -2199,7 +2128,7 @@ impl<T: Config> Pallet<T> {
 				} else {
 					ensure!(
 						Self::inspect_bond_state(&stash) == Ok(LedgerIntegrityState::Ok),
-						"bond, ledger and/or staking hold inconsistent for a bonded stash."
+						"bond, ledger and/or staking lock inconsistent for a bonded stash."
 					);
 				}
 
diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs
index 7d5da9ea0c49753e0db14092b978d0c88b6dcd63..b3f8c18f704cd7e5158c89f0e432f50d7bcb8c04 100644
--- a/substrate/frame/staking/src/pallet/mod.rs
+++ b/substrate/frame/staking/src/pallet/mod.rs
@@ -25,12 +25,8 @@ use frame_election_provider_support::{
 use frame_support::{
 	pallet_prelude::*,
 	traits::{
-		fungible::{
-			hold::{Balanced as FunHoldBalanced, Mutate as FunHoldMutate},
-			Mutate as FunMutate,
-		},
 		Defensive, DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get,
-		InspectLockableCurrency, OnUnbalanced, UnixTime,
+		InspectLockableCurrency, LockableCurrency, OnUnbalanced, UnixTime,
 	},
 	weights::Weight,
 	BoundedVec,
@@ -93,27 +89,13 @@ pub mod pallet {
 
 	#[pallet::config(with_default)]
 	pub trait Config: frame_system::Config {
-		/// The old trait for staking balance. Deprecated and only used for migrating old ledgers.
-		#[pallet::no_default]
-		type OldCurrency: InspectLockableCurrency<
-			Self::AccountId,
-			Moment = BlockNumberFor<Self>,
-			Balance = Self::CurrencyBalance,
-		>;
-
 		/// The staking balance.
 		#[pallet::no_default]
-		type Currency: FunHoldMutate<
+		type Currency: LockableCurrency<
 				Self::AccountId,
-				Reason = Self::RuntimeHoldReason,
+				Moment = BlockNumberFor<Self>,
 				Balance = Self::CurrencyBalance,
-			> + FunMutate<Self::AccountId, Balance = Self::CurrencyBalance>
-			+ FunHoldBalanced<Self::AccountId, Balance = Self::CurrencyBalance>;
-
-		/// Overarching hold reason.
-		#[pallet::no_default_bounds]
-		type RuntimeHoldReason: From<HoldReason>;
-
+			> + 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
@@ -124,8 +106,6 @@ pub mod pallet {
 			+ Default
 			+ From<u64>
 			+ TypeInfo
-			+ Send
-			+ Sync
 			+ MaxEncodedLen;
 		/// Time used for computing era duration.
 		///
@@ -329,14 +309,6 @@ pub mod pallet {
 		type WeightInfo: WeightInfo;
 	}
 
-	/// A reason for placing a hold on funds.
-	#[pallet::composite_enum]
-	pub enum HoldReason {
-		/// Funds on stake by a nominator or a validator.
-		#[codec(index = 0)]
-		Staking,
-	}
-
 	/// Default implementations of [`DefaultConfig`], which can be used to implement [`Config`].
 	pub mod config_preludes {
 		use super::*;
@@ -355,8 +327,6 @@ pub mod pallet {
 		impl DefaultConfig for TestDefaultConfig {
 			#[inject_runtime_type]
 			type RuntimeEvent = ();
-			#[inject_runtime_type]
-			type RuntimeHoldReason = ();
 			type CurrencyBalance = u128;
 			type CurrencyToVote = ();
 			type NominationsQuota = crate::FixedNominationsQuota<16>;
@@ -795,7 +765,7 @@ pub mod pallet {
 					status
 				);
 				assert!(
-					asset::free_to_stake::<T>(stash) >= balance,
+					asset::stakeable_balance::<T>(stash) >= balance,
 					"Stash does not have enough balance to bond."
 				);
 				frame_support::assert_ok!(<Pallet<T>>::bond(
@@ -888,9 +858,6 @@ pub mod pallet {
 		ValidatorDisabled { stash: T::AccountId },
 		/// Validator has been re-enabled.
 		ValidatorReenabled { stash: T::AccountId },
-		/// Staking balance migrated from locks to holds, with any balance that could not be held
-		/// is force withdrawn.
-		CurrencyMigrated { stash: T::AccountId, force_withdraw: BalanceOf<T> },
 	}
 
 	#[pallet::error]
@@ -962,10 +929,6 @@ pub mod pallet {
 		NotEnoughFunds,
 		/// Operation not allowed for virtual stakers.
 		VirtualStakerNotAllowed,
-		/// Stash could not be reaped as other pallet might depend on it.
-		CannotReapStash,
-		/// The stake of this account is already migrated to `Fungible` holds.
-		AlreadyMigrated,
 	}
 
 	#[pallet::hooks]
@@ -1209,7 +1172,10 @@ pub mod pallet {
 				return Err(Error::<T>::InsufficientBond.into())
 			}
 
-			let stash_balance = asset::free_to_stake::<T>(&stash);
+			// Would fail if account has no provider.
+			frame_system::Pallet::<T>::inc_consumers(&stash)?;
+
+			let stash_balance = asset::stakeable_balance::<T>(&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);
@@ -2265,8 +2231,8 @@ pub mod pallet {
 
 					let new_total = if let Some(total) = maybe_total {
 						let new_total = total.min(stash_balance);
-						// enforce hold == ledger.amount.
-						asset::update_stake::<T>(&stash, new_total)?;
+						// enforce lock == ledger.amount.
+						asset::update_stake::<T>(&stash, new_total);
 						new_total
 					} else {
 						current_lock
@@ -2293,13 +2259,13 @@ pub mod pallet {
 					// 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);
-					asset::update_stake::<T>(&stash, new_total)?;
+					asset::update_stake::<T>(&stash, new_total);
 
 					Ok((stash.clone(), new_total))
 				},
 				Err(Error::<T>::BadState) => {
 					// the stash and ledger do not exist but lock is lingering.
-					asset::kill_stake::<T>(&stash)?;
+					asset::kill_stake::<T>(&stash);
 					ensure!(
 						Self::inspect_bond_state(&stash) == Err(Error::<T>::NotStash),
 						Error::<T>::BadState
@@ -2325,26 +2291,6 @@ pub mod pallet {
 			);
 			Ok(())
 		}
-
-		/// Migrates permissionlessly a stash from locks to holds.
-		///
-		/// This removes the old lock on the stake and creates a hold on it atomically. If all
-		/// stake cannot be held, the best effort is made to hold as much as possible. The remaining
-		/// stake is removed from the ledger.
-		///
-		/// The fee is waived if the migration is successful.
-		#[pallet::call_index(30)]
-		#[pallet::weight(T::WeightInfo::migrate_currency())]
-		pub fn migrate_currency(
-			origin: OriginFor<T>,
-			stash: T::AccountId,
-		) -> DispatchResultWithPostInfo {
-			let _ = ensure_signed(origin)?;
-			Self::do_migrate_currency(&stash)?;
-
-			// Refund the transaction fee if successful.
-			Ok(Pays::No.into())
-		}
 	}
 }
 
diff --git a/substrate/frame/staking/src/testing_utils.rs b/substrate/frame/staking/src/testing_utils.rs
index dfd5422106c081784c95985fa64477b596e93064..81337710aa9043bf975a95c3d5377b0dea0738f8 100644
--- a/substrate/frame/staking/src/testing_utils.rs
+++ b/substrate/frame/staking/src/testing_utils.rs
@@ -238,21 +238,3 @@ pub fn create_validators_with_nominators_for_era<T: Config>(
 pub fn current_era<T: Config>() -> EraIndex {
 	CurrentEra::<T>::get().unwrap_or(0)
 }
-
-pub fn migrate_to_old_currency<T: Config>(who: T::AccountId) {
-	use frame_support::traits::LockableCurrency;
-	let staked = asset::staked::<T>(&who);
-
-	// apply locks (this also adds a consumer).
-	T::OldCurrency::set_lock(
-		STAKING_ID,
-		&who,
-		staked,
-		frame_support::traits::WithdrawReasons::all(),
-	);
-	// remove holds.
-	asset::kill_stake::<T>(&who).expect("remove hold failed");
-
-	// replicate old behaviour of explicit increment of consumer.
-	frame_system::Pallet::<T>::inc_consumers(&who).expect("increment consumer failed");
-}
diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs
index 90841514399403301be4eb3a0d2ba87da543ddc2..6c2335e1aac8a0f32beba70ac6974729e70af441 100644
--- a/substrate/frame/staking/src/tests.rs
+++ b/substrate/frame/staking/src/tests.rs
@@ -26,12 +26,8 @@ use frame_election_provider_support::{
 use frame_support::{
 	assert_noop, assert_ok, assert_storage_noop,
 	dispatch::{extract_actual_weight, GetDispatchInfo, WithPostDispatchInfo},
-	hypothetically,
 	pallet_prelude::*,
-	traits::{
-		fungible::Inspect, Currency, Get, InspectLockableCurrency, LockableCurrency,
-		ReservableCurrency, WithdrawReasons,
-	},
+	traits::{Currency, Get, ReservableCurrency},
 };
 
 use mock::*;
@@ -112,7 +108,7 @@ fn force_unstake_works() {
 		// Cant transfer
 		assert_noop!(
 			Balances::transfer_allow_death(RuntimeOrigin::signed(11), 1, 10),
-			TokenError::FundsUnavailable,
+			TokenError::Frozen,
 		);
 		// Force unstake requires root.
 		assert_noop!(Staking::force_unstake(RuntimeOrigin::signed(11), 11, 2), BadOrigin);
@@ -233,7 +229,8 @@ fn basic_setup_works() {
 		assert_eq!(active_era(), 0);
 
 		// Account 10 has `balance_factor` free balance
-		assert_eq!(Balances::balance(&10), 1);
+		assert_eq!(asset::stakeable_balance::<Test>(&10), 1);
+		assert_eq!(asset::stakeable_balance::<Test>(&10), 1);
 
 		// New era is not being forced
 		assert_eq!(ForceEra::<Test>::get(), Forcing::NotForcing);
@@ -363,16 +360,8 @@ fn rewards_should_work() {
 				remainder: maximum_payout - total_payout_0
 			}
 		);
-
-		// make note of total issuance before rewards.
-		let total_issuance_0 = asset::total_issuance::<Test>();
-
 		mock::make_all_reward_payment(0);
 
-		// total issuance should have increased
-		let total_issuance_1 = asset::total_issuance::<Test>();
-		assert_eq!(total_issuance_1, total_issuance_0 + total_payout_0);
-
 		assert_eq_error_rate!(
 			asset::total_balance::<Test>(&11),
 			init_balance_11 + part_for_11 * total_payout_0 * 2 / 3,
@@ -412,7 +401,6 @@ fn rewards_should_work() {
 		);
 		mock::make_all_reward_payment(1);
 
-		assert_eq!(asset::total_issuance::<Test>(), total_issuance_1 + total_payout_1);
 		assert_eq_error_rate!(
 			asset::total_balance::<Test>(&11),
 			init_balance_11 + part_for_11 * (total_payout_0 * 2 / 3 + total_payout_1),
@@ -502,7 +490,7 @@ fn staking_should_work() {
 			}
 		);
 		// e.g. it cannot reserve more than 500 that it has free from the total 2000
-		assert_noop!(Balances::reserve(&3, 501), DispatchError::ConsumerRemaining);
+		assert_noop!(Balances::reserve(&3, 501), BalancesError::<Test, _>::LiquidityRestrictions);
 		assert_ok!(Balances::reserve(&3, 409));
 	});
 }
@@ -701,7 +689,7 @@ fn nominating_and_rewards_should_work() {
 			);
 			// Nominator 3: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 21]'s reward. ==>
 			// 2/9 + 3/11
-			assert_eq!(asset::stakeable_balance::<Test>(&3), initial_balance);
+			assert_eq!(asset::total_balance::<Test>(&3), initial_balance);
 			// 333 is the reward destination for 3.
 			assert_eq_error_rate!(
 				asset::total_balance::<Test>(&333),
@@ -1004,9 +992,9 @@ fn cannot_transfer_staked_balance() {
 	ExtBuilder::default().nominate(false).build_and_execute(|| {
 		// Confirm account 11 is stashed
 		assert_eq!(Staking::bonded(&11), Some(11));
-		// Confirm account 11 has some stakeable balance
+		// Confirm account 11 has some free balance
 		assert_eq!(asset::stakeable_balance::<Test>(&11), 1000);
-		// Confirm account 11 is totally staked
+		// Confirm account 11 (via controller) is totally staked
 		assert_eq!(Staking::eras_stakers(active_era(), &11).total, 1000);
 		// Confirm account 11 cannot transfer as a result
 		assert_noop!(
@@ -1033,12 +1021,11 @@ fn cannot_transfer_staked_balance_2() {
 		assert_eq!(asset::stakeable_balance::<Test>(&21), 2000);
 		// Confirm account 21 (via controller) is totally staked
 		assert_eq!(Staking::eras_stakers(active_era(), &21).total, 1000);
-		// Confirm account 21 cannot transfer more than 1000
+		// Confirm account 21 can transfer at most 1000
 		assert_noop!(
 			Balances::transfer_allow_death(RuntimeOrigin::signed(21), 21, 1001),
 			TokenError::Frozen,
 		);
-		// Confirm account 21 needs to leave at least ED in free balance to be able to transfer
 		assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(21), 21, 1000));
 	});
 }
@@ -1049,61 +1036,17 @@ fn cannot_reserve_staked_balance() {
 	ExtBuilder::default().build_and_execute(|| {
 		// Confirm account 11 is stashed
 		assert_eq!(Staking::bonded(&11), Some(11));
-		// Confirm account 11 is totally staked
-		assert_eq!(asset::staked::<Test>(&11), 1000);
-
+		// Confirm account 11 has some free balance
+		assert_eq!(asset::stakeable_balance::<Test>(&11), 1000);
+		// Confirm account 11 (via controller 10) is totally staked
+		assert_eq!(Staking::eras_stakers(active_era(), &11).own, 1000);
 		// Confirm account 11 cannot reserve as a result
-		assert_noop!(Balances::reserve(&11, 2), BalancesError::<Test, _>::InsufficientBalance);
-		assert_noop!(Balances::reserve(&11, 1), DispatchError::ConsumerRemaining);
+		assert_noop!(Balances::reserve(&11, 1), BalancesError::<Test, _>::LiquidityRestrictions);
 
 		// Give account 11 extra free balance
-		let _ = asset::set_stakeable_balance::<Test>(&11, 1000 + 1000);
-		assert_eq!(asset::free_to_stake::<Test>(&11), 1000);
-
+		let _ = asset::set_stakeable_balance::<Test>(&11, 10000);
 		// Confirm account 11 can now reserve balance
-		assert_ok!(Balances::reserve(&11, 500));
-
-		// free to stake balance has reduced
-		assert_eq!(asset::free_to_stake::<Test>(&11), 500);
-	});
-}
-
-#[test]
-fn locked_balance_can_be_staked() {
-	// Checks that a bonded account cannot reserve balance from free balance
-	ExtBuilder::default().build_and_execute(|| {
-		// Confirm account 11 is stashed
-		assert_eq!(Staking::bonded(&11), Some(11));
-		assert_eq!(asset::staked::<Test>(&11), 1000);
-		assert_eq!(asset::free_to_stake::<Test>(&11), 0);
-
-		// add some staking balance to 11
-		let _ = asset::set_stakeable_balance::<Test>(&11, 1000 + 1000);
-		// free to stake is 1000
-		assert_eq!(asset::free_to_stake::<Test>(&11), 1000);
-
-		// lock some balance
-		Balances::set_lock(*b"somelock", &11, 500, WithdrawReasons::all());
-
-		// locked balance still available for staking
-		assert_eq!(asset::free_to_stake::<Test>(&11), 1000);
-
-		// can stake free balance
-		assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(11), 500));
-		assert_eq!(asset::staked::<Test>(&11), 1500);
-
-		// Can stake the locked balance
-		assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(11), 500));
-		assert_eq!(asset::staked::<Test>(&11), 2000);
-		// no balance left to stake
-		assert_eq!(asset::free_to_stake::<Test>(&11), 0);
-
-		// this does not fail if someone tries to stake more than free balance but just stakes
-		// whatever is available. (not sure if that is the best way, but we keep it backward
-		// compatible)
-		assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(11), 10));
-		// no extra balance staked.
-		assert_eq!(asset::staked::<Test>(&11), 2000);
+		assert_ok!(Balances::reserve(&11, 1));
 	});
 }
 
@@ -1114,9 +1057,9 @@ fn reward_destination_works() {
 		// Check that account 11 is a validator
 		assert!(Session::validators().contains(&11));
 		// Check the balance of the validator account
-		assert_eq!(asset::total_balance::<Test>(&10), 1);
+		assert_eq!(asset::stakeable_balance::<Test>(&10), 1);
 		// Check the balance of the stash account
-		assert_eq!(asset::total_balance::<Test>(&11), 1001);
+		assert_eq!(asset::stakeable_balance::<Test>(&11), 1000);
 		// Check how much is at stake
 		assert_eq!(
 			Staking::ledger(11.into()).unwrap(),
@@ -1351,12 +1294,12 @@ fn bond_extra_and_withdraw_unbonded_works() {
 		// Give account 11 some large free balance greater than total
 		let _ = asset::set_stakeable_balance::<Test>(&11, 1000000);
 
-		// ensure it has the correct balance.
-		assert_eq!(asset::stakeable_balance::<Test>(&11), 1000000);
-
 		// Initial config should be correct
 		assert_eq!(active_era(), 0);
 
+		// check the balance of a validator accounts.
+		assert_eq!(asset::total_balance::<Test>(&11), 1000000);
+
 		// confirm that 10 is a normal validator and gets paid at the end of the era.
 		mock::start_active_era(1);
 
@@ -2134,7 +2077,7 @@ fn bond_with_no_staked_value() {
 			);
 			// bonded with absolute minimum value possible.
 			assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 5, RewardDestination::Account(1)));
-			assert_eq!(pallet_balances::Holds::<Test>::get(&1)[0].amount, 5);
+			assert_eq!(pallet_balances::Locks::<Test>::get(&1)[0].amount, 5);
 
 			// unbonding even 1 will cause all to be unbonded.
 			assert_ok!(Staking::unbond(RuntimeOrigin::signed(1), 1));
@@ -2155,14 +2098,14 @@ fn bond_with_no_staked_value() {
 			// not yet removed.
 			assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(1), 0));
 			assert!(Staking::ledger(1.into()).is_ok());
-			assert_eq!(pallet_balances::Holds::<Test>::get(&1)[0].amount, 5);
+			assert_eq!(pallet_balances::Locks::<Test>::get(&1)[0].amount, 5);
 
 			mock::start_active_era(3);
 
 			// poof. Account 1 is removed from the staking system.
 			assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(1), 0));
 			assert!(Staking::ledger(1.into()).is_err());
-			assert_eq!(pallet_balances::Holds::<Test>::get(&1).len(), 0);
+			assert_eq!(pallet_balances::Locks::<Test>::get(&1).len(), 0);
 		});
 }
 
@@ -2395,20 +2338,9 @@ fn reward_validator_slashing_validator_does_not_overflow() {
 		EraInfo::<Test>::set_exposure(0, &11, exposure);
 		ErasValidatorReward::<Test>::insert(0, stake);
 		assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 0, 0));
-		assert_eq!(asset::stakeable_balance::<Test>(&11), stake * 2);
+		assert_eq!(asset::total_balance::<Test>(&11), stake * 2);
 
-		// ensure ledger has `stake` and no more.
-		Ledger::<Test>::insert(
-			11,
-			StakingLedgerInspect {
-				stash: 11,
-				total: stake,
-				active: stake,
-				unlocking: Default::default(),
-				legacy_claimed_rewards: bounded_vec![1],
-			},
-		);
-		// Set staker (unsafe, can reduce balance below actual stake)
+		// Set staker
 		let _ = asset::set_stakeable_balance::<Test>(&11, stake);
 		let _ = asset::set_stakeable_balance::<Test>(&2, stake);
 
@@ -2434,8 +2366,8 @@ fn reward_validator_slashing_validator_does_not_overflow() {
 			&[Perbill::from_percent(100)],
 		);
 
-		assert_eq!(asset::stakeable_balance::<Test>(&11), stake - 1);
-		assert_eq!(asset::stakeable_balance::<Test>(&2), 1);
+		assert_eq!(asset::total_balance::<Test>(&11), stake - 1);
+		assert_eq!(asset::total_balance::<Test>(&2), 1);
 	})
 }
 
@@ -2695,8 +2627,8 @@ fn reporters_receive_their_slice() {
 		// 50% * (10% * initial_balance / 2)
 		let reward = (initial_balance / 20) / 2;
 		let reward_each = reward / 2; // split into two pieces.
-		assert_eq!(asset::total_balance::<Test>(&1), 10 + reward_each);
-		assert_eq!(asset::total_balance::<Test>(&2), 20 + reward_each);
+		assert_eq!(asset::stakeable_balance::<Test>(&1), 10 + reward_each);
+		assert_eq!(asset::stakeable_balance::<Test>(&2), 20 + reward_each);
 	});
 }
 
@@ -2721,7 +2653,7 @@ fn subsequent_reports_in_same_span_pay_out_less() {
 		// F1 * (reward_proportion * slash - 0)
 		// 50% * (10% * initial_balance * 20%)
 		let reward = (initial_balance / 5) / 20;
-		assert_eq!(asset::total_balance::<Test>(&1), 10 + reward);
+		assert_eq!(asset::stakeable_balance::<Test>(&1), 10 + reward);
 
 		on_offence_now(
 			&[OffenceDetails {
@@ -2736,7 +2668,7 @@ fn subsequent_reports_in_same_span_pay_out_less() {
 		// F1 * (reward_proportion * slash - prior_payout)
 		// 50% * (10% * (initial_balance / 2) - prior_payout)
 		let reward = ((initial_balance / 20) - prior_payout) / 2;
-		assert_eq!(asset::total_balance::<Test>(&1), 10 + prior_payout + reward);
+		assert_eq!(asset::stakeable_balance::<Test>(&1), 10 + prior_payout + reward);
 	});
 }
 
@@ -2880,9 +2812,8 @@ fn garbage_collection_after_slashing() {
 			// validator and nominator slash in era are garbage-collected by era change,
 			// so we don't test those here.
 
-			assert_eq!(asset::stakeable_balance::<Test>(&11), 0);
-			// Non staked balance is not touched.
-			assert_eq!(asset::total_balance::<Test>(&11), ExistentialDeposit::get());
+			assert_eq!(asset::stakeable_balance::<Test>(&11), 2);
+			assert_eq!(asset::total_balance::<Test>(&11), 2);
 
 			let slashing_spans = SlashingSpans::<Test>::get(&11).unwrap();
 			assert_eq!(slashing_spans.iter().count(), 2);
@@ -6161,7 +6092,7 @@ fn nomination_quota_max_changes_decoding() {
 		.add_staker(70, 71, 10, StakerStatus::Nominator(vec![1, 2, 3]))
 		.add_staker(30, 330, 10, StakerStatus::Nominator(vec![1, 2, 3, 4]))
 		.add_staker(50, 550, 10, StakerStatus::Nominator(vec![1, 2, 3, 4]))
-		.balance_factor(11)
+		.balance_factor(10)
 		.build_and_execute(|| {
 			// pre-condition.
 			assert_eq!(MaxNominationsOf::<Test>::get(), 16);
@@ -6277,248 +6208,240 @@ fn force_apply_min_commission_works() {
 
 #[test]
 fn proportional_slash_stop_slashing_if_remaining_zero() {
-	ExtBuilder::default().nominate(true).build_and_execute(|| {
-		let c = |era, value| UnlockChunk::<Balance> { era, value };
+	let c = |era, value| UnlockChunk::<Balance> { era, value };
 
-		// we have some chunks, but they are not affected.
-		let unlocking = bounded_vec![c(1, 10), c(2, 10)];
+	// we have some chunks, but they are not affected.
+	let unlocking = bounded_vec![c(1, 10), c(2, 10)];
 
-		// Given
-		let mut ledger = StakingLedger::<Test>::new(123, 20);
-		ledger.total = 40;
-		ledger.unlocking = unlocking;
+	// Given
+	let mut ledger = StakingLedger::<Test>::new(123, 20);
+	ledger.total = 40;
+	ledger.unlocking = unlocking;
 
-		assert_eq!(BondingDuration::get(), 3);
+	assert_eq!(BondingDuration::get(), 3);
 
-		// should not slash more than the amount requested, by accidentally slashing the first
-		// chunk.
-		assert_eq!(ledger.slash(18, 1, 0), 18);
-	});
+	// should not slash more than the amount requested, by accidentally slashing the first chunk.
+	assert_eq!(ledger.slash(18, 1, 0), 18);
 }
 
 #[test]
 fn proportional_ledger_slash_works() {
-	ExtBuilder::default().nominate(true).build_and_execute(|| {
-		let c = |era, value| UnlockChunk::<Balance> { era, value };
-		// Given
-		let mut ledger = StakingLedger::<Test>::new(123, 10);
-		assert_eq!(BondingDuration::get(), 3);
-
-		// When we slash a ledger with no unlocking chunks
-		assert_eq!(ledger.slash(5, 1, 0), 5);
-		// Then
-		assert_eq!(ledger.total, 5);
-		assert_eq!(ledger.active, 5);
-		assert_eq!(LedgerSlashPerEra::get().0, 5);
-		assert_eq!(LedgerSlashPerEra::get().1, Default::default());
-
-		// When we slash a ledger with no unlocking chunks and the slash amount is greater then the
-		// total
-		assert_eq!(ledger.slash(11, 1, 0), 5);
-		// Then
-		assert_eq!(ledger.total, 0);
-		assert_eq!(ledger.active, 0);
-		assert_eq!(LedgerSlashPerEra::get().0, 0);
-		assert_eq!(LedgerSlashPerEra::get().1, Default::default());
-
-		// Given
-		ledger.unlocking = bounded_vec![c(4, 10), c(5, 10)];
-		ledger.total = 2 * 10;
-		ledger.active = 0;
-		// When all the chunks overlap with the slash eras
-		assert_eq!(ledger.slash(20, 0, 0), 20);
-		// Then
-		assert_eq!(ledger.unlocking, vec![]);
-		assert_eq!(ledger.total, 0);
-		assert_eq!(LedgerSlashPerEra::get().0, 0);
-		assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(4, 0), (5, 0)]));
-
-		// Given
-		ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)];
-		ledger.total = 4 * 100;
-		ledger.active = 0;
-		// When the first 2 chunks don't overlap with the affected range of unlock eras.
-		assert_eq!(ledger.slash(140, 0, 3), 140);
-		// Then
-		assert_eq!(ledger.unlocking, vec![c(4, 100), c(5, 100), c(6, 30), c(7, 30)]);
-		assert_eq!(ledger.total, 4 * 100 - 140);
-		assert_eq!(LedgerSlashPerEra::get().0, 0);
-		assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(6, 30), (7, 30)]));
-
-		// Given
-		ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)];
-		ledger.total = 4 * 100;
-		ledger.active = 0;
-		// When the first 2 chunks don't overlap with the affected range of unlock eras.
-		assert_eq!(ledger.slash(15, 0, 3), 15);
-		// Then
-		assert_eq!(ledger.unlocking, vec![c(4, 100), c(5, 100), c(6, 100 - 8), c(7, 100 - 7)]);
-		assert_eq!(ledger.total, 4 * 100 - 15);
-		assert_eq!(LedgerSlashPerEra::get().0, 0);
-		assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(6, 92), (7, 93)]));
-
-		// Given
-		ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)];
-		ledger.active = 500;
-		// 900
-		ledger.total = 40 + 10 + 100 + 250 + 500;
-		// When we have a partial slash that touches all chunks
-		assert_eq!(ledger.slash(900 / 2, 0, 0), 450);
-		// Then
-		assert_eq!(ledger.active, 500 / 2);
-		assert_eq!(
-			ledger.unlocking,
-			vec![c(4, 40 / 2), c(5, 100 / 2), c(6, 10 / 2), c(7, 250 / 2)]
-		);
-		assert_eq!(ledger.total, 900 / 2);
-		assert_eq!(LedgerSlashPerEra::get().0, 500 / 2);
-		assert_eq!(
-			LedgerSlashPerEra::get().1,
-			BTreeMap::from([(4, 40 / 2), (5, 100 / 2), (6, 10 / 2), (7, 250 / 2)])
-		);
-
-		// slash 1/4th with not chunk.
-		ledger.unlocking = bounded_vec![];
-		ledger.active = 500;
-		ledger.total = 500;
-		// When we have a partial slash that touches all chunks
-		assert_eq!(ledger.slash(500 / 4, 0, 0), 500 / 4);
-		// Then
-		assert_eq!(ledger.active, 3 * 500 / 4);
-		assert_eq!(ledger.unlocking, vec![]);
-		assert_eq!(ledger.total, ledger.active);
-		assert_eq!(LedgerSlashPerEra::get().0, 3 * 500 / 4);
-		assert_eq!(LedgerSlashPerEra::get().1, Default::default());
-
-		// Given we have the same as above,
-		ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)];
-		ledger.active = 500;
-		ledger.total = 40 + 10 + 100 + 250 + 500; // 900
-		assert_eq!(ledger.total, 900);
-		// When we have a higher min balance
-		assert_eq!(
-			ledger.slash(
-				900 / 2,
-				25, /* min balance - chunks with era 0 & 2 will be slashed to <=25, causing it
-				     * to get swept */
-				0
-			),
-			450
-		);
-		assert_eq!(ledger.active, 500 / 2);
-		// the last chunk was not slashed 50% like all the rest, because some other earlier chunks
-		// got dusted.
-		assert_eq!(ledger.unlocking, vec![c(5, 100 / 2), c(7, 150)]);
-		assert_eq!(ledger.total, 900 / 2);
-		assert_eq!(LedgerSlashPerEra::get().0, 500 / 2);
-		assert_eq!(
-			LedgerSlashPerEra::get().1,
-			BTreeMap::from([(4, 0), (5, 100 / 2), (6, 0), (7, 150)])
-		);
-
-		// Given
-		// slash order --------------------NA--------2----------0----------1----
-		ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)];
-		ledger.active = 500;
-		ledger.total = 40 + 10 + 100 + 250 + 500; // 900
-		assert_eq!(
-			ledger.slash(
-				500 + 10 + 250 + 100 / 2, // active + era 6 + era 7 + era 5 / 2
-				0,
-				3 /* slash era 6 first, so the affected parts are era 6, era 7 and
-				   * ledge.active. This will cause the affected to go to zero, and then we will
-				   * start slashing older chunks */
-			),
-			500 + 250 + 10 + 100 / 2
-		);
-		// Then
-		assert_eq!(ledger.active, 0);
-		assert_eq!(ledger.unlocking, vec![c(4, 40), c(5, 100 / 2)]);
-		assert_eq!(ledger.total, 90);
-		assert_eq!(LedgerSlashPerEra::get().0, 0);
-		assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(5, 100 / 2), (6, 0), (7, 0)]));
-
-		// Given
-		// iteration order------------------NA---------2----------0----------1----
-		ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)];
-		ledger.active = 100;
-		ledger.total = 5 * 100;
-		// When
-		assert_eq!(
-			ledger.slash(
-				351, // active + era 6 + era 7 + era 5 / 2 + 1
-				50,  // min balance - everything slashed below 50 will get dusted
-				3    /* slash era 3+3 first, so the affected parts are era 6, era 7 and
-				      * ledge.active. This will cause the affected to go to zero, and then we
-				      * will start slashing older chunks */
-			),
-			400
-		);
-		// Then
-		assert_eq!(ledger.active, 0);
-		assert_eq!(ledger.unlocking, vec![c(4, 100)]);
-		assert_eq!(ledger.total, 100);
-		assert_eq!(LedgerSlashPerEra::get().0, 0);
-		assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(5, 0), (6, 0), (7, 0)]));
-
-		// Tests for saturating arithmetic
+	let c = |era, value| UnlockChunk::<Balance> { era, value };
+	// Given
+	let mut ledger = StakingLedger::<Test>::new(123, 10);
+	assert_eq!(BondingDuration::get(), 3);
+
+	// When we slash a ledger with no unlocking chunks
+	assert_eq!(ledger.slash(5, 1, 0), 5);
+	// Then
+	assert_eq!(ledger.total, 5);
+	assert_eq!(ledger.active, 5);
+	assert_eq!(LedgerSlashPerEra::get().0, 5);
+	assert_eq!(LedgerSlashPerEra::get().1, Default::default());
+
+	// When we slash a ledger with no unlocking chunks and the slash amount is greater then the
+	// total
+	assert_eq!(ledger.slash(11, 1, 0), 5);
+	// Then
+	assert_eq!(ledger.total, 0);
+	assert_eq!(ledger.active, 0);
+	assert_eq!(LedgerSlashPerEra::get().0, 0);
+	assert_eq!(LedgerSlashPerEra::get().1, Default::default());
+
+	// Given
+	ledger.unlocking = bounded_vec![c(4, 10), c(5, 10)];
+	ledger.total = 2 * 10;
+	ledger.active = 0;
+	// When all the chunks overlap with the slash eras
+	assert_eq!(ledger.slash(20, 0, 0), 20);
+	// Then
+	assert_eq!(ledger.unlocking, vec![]);
+	assert_eq!(ledger.total, 0);
+	assert_eq!(LedgerSlashPerEra::get().0, 0);
+	assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(4, 0), (5, 0)]));
+
+	// Given
+	ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)];
+	ledger.total = 4 * 100;
+	ledger.active = 0;
+	// When the first 2 chunks don't overlap with the affected range of unlock eras.
+	assert_eq!(ledger.slash(140, 0, 3), 140);
+	// Then
+	assert_eq!(ledger.unlocking, vec![c(4, 100), c(5, 100), c(6, 30), c(7, 30)]);
+	assert_eq!(ledger.total, 4 * 100 - 140);
+	assert_eq!(LedgerSlashPerEra::get().0, 0);
+	assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(6, 30), (7, 30)]));
+
+	// Given
+	ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)];
+	ledger.total = 4 * 100;
+	ledger.active = 0;
+	// When the first 2 chunks don't overlap with the affected range of unlock eras.
+	assert_eq!(ledger.slash(15, 0, 3), 15);
+	// Then
+	assert_eq!(ledger.unlocking, vec![c(4, 100), c(5, 100), c(6, 100 - 8), c(7, 100 - 7)]);
+	assert_eq!(ledger.total, 4 * 100 - 15);
+	assert_eq!(LedgerSlashPerEra::get().0, 0);
+	assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(6, 92), (7, 93)]));
+
+	// Given
+	ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)];
+	ledger.active = 500;
+	// 900
+	ledger.total = 40 + 10 + 100 + 250 + 500;
+	// When we have a partial slash that touches all chunks
+	assert_eq!(ledger.slash(900 / 2, 0, 0), 450);
+	// Then
+	assert_eq!(ledger.active, 500 / 2);
+	assert_eq!(ledger.unlocking, vec![c(4, 40 / 2), c(5, 100 / 2), c(6, 10 / 2), c(7, 250 / 2)]);
+	assert_eq!(ledger.total, 900 / 2);
+	assert_eq!(LedgerSlashPerEra::get().0, 500 / 2);
+	assert_eq!(
+		LedgerSlashPerEra::get().1,
+		BTreeMap::from([(4, 40 / 2), (5, 100 / 2), (6, 10 / 2), (7, 250 / 2)])
+	);
 
-		// Given
-		let slash = u64::MAX as Balance * 2;
-		// The value of the other parts of ledger that will get slashed
-		let value = slash - (10 * 4);
-
-		ledger.active = 10;
-		ledger.unlocking = bounded_vec![c(4, 10), c(5, 10), c(6, 10), c(7, value)];
-		ledger.total = value + 40;
-		// When
-		let slash_amount = ledger.slash(slash, 0, 0);
-		assert_eq_error_rate!(slash_amount, slash, 5);
-		// Then
-		assert_eq!(ledger.active, 0); // slash of 9
-		assert_eq!(ledger.unlocking, vec![]);
-		assert_eq!(ledger.total, 0);
-		assert_eq!(LedgerSlashPerEra::get().0, 0);
-		assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(4, 0), (5, 0), (6, 0), (7, 0)]));
+	// slash 1/4th with not chunk.
+	ledger.unlocking = bounded_vec![];
+	ledger.active = 500;
+	ledger.total = 500;
+	// When we have a partial slash that touches all chunks
+	assert_eq!(ledger.slash(500 / 4, 0, 0), 500 / 4);
+	// Then
+	assert_eq!(ledger.active, 3 * 500 / 4);
+	assert_eq!(ledger.unlocking, vec![]);
+	assert_eq!(ledger.total, ledger.active);
+	assert_eq!(LedgerSlashPerEra::get().0, 3 * 500 / 4);
+	assert_eq!(LedgerSlashPerEra::get().1, Default::default());
+
+	// Given we have the same as above,
+	ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)];
+	ledger.active = 500;
+	ledger.total = 40 + 10 + 100 + 250 + 500; // 900
+	assert_eq!(ledger.total, 900);
+	// When we have a higher min balance
+	assert_eq!(
+		ledger.slash(
+			900 / 2,
+			25, /* min balance - chunks with era 0 & 2 will be slashed to <=25, causing it to
+			     * get swept */
+			0
+		),
+		450
+	);
+	assert_eq!(ledger.active, 500 / 2);
+	// the last chunk was not slashed 50% like all the rest, because some other earlier chunks got
+	// dusted.
+	assert_eq!(ledger.unlocking, vec![c(5, 100 / 2), c(7, 150)]);
+	assert_eq!(ledger.total, 900 / 2);
+	assert_eq!(LedgerSlashPerEra::get().0, 500 / 2);
+	assert_eq!(
+		LedgerSlashPerEra::get().1,
+		BTreeMap::from([(4, 0), (5, 100 / 2), (6, 0), (7, 150)])
+	);
 
-		// Given
-		use sp_runtime::PerThing as _;
-		let slash = u64::MAX as Balance * 2;
-		let value = u64::MAX as Balance * 2;
-		let unit = 100;
-		// slash * value that will saturate
-		assert!(slash.checked_mul(value).is_none());
-		// but slash * unit won't.
-		assert!(slash.checked_mul(unit).is_some());
-		ledger.unlocking = bounded_vec![c(4, unit), c(5, value), c(6, unit), c(7, unit)];
-		//--------------------------------------note value^^^
-		ledger.active = unit;
-		ledger.total = unit * 4 + value;
-		// When
-		assert_eq!(ledger.slash(slash, 0, 0), slash);
-		// Then
-		// The amount slashed out of `unit`
-		let affected_balance = value + unit * 4;
-		let ratio = Perquintill::from_rational_with_rounding(slash, affected_balance, Rounding::Up)
-			.unwrap();
-		// `unit` after the slash is applied
-		let unit_slashed = {
-			let unit_slash = ratio.mul_ceil(unit);
-			unit - unit_slash
-		};
-		let value_slashed = {
-			let value_slash = ratio.mul_ceil(value);
-			value - value_slash
-		};
-		assert_eq!(ledger.active, unit_slashed);
-		assert_eq!(ledger.unlocking, vec![c(5, value_slashed), c(7, 32)]);
-		assert_eq!(ledger.total, value_slashed + 32);
-		assert_eq!(LedgerSlashPerEra::get().0, 0);
-		assert_eq!(
-			LedgerSlashPerEra::get().1,
-			BTreeMap::from([(4, 0), (5, value_slashed), (6, 0), (7, 32)])
-		);
-	});
+	// Given
+	// slash order --------------------NA--------2----------0----------1----
+	ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)];
+	ledger.active = 500;
+	ledger.total = 40 + 10 + 100 + 250 + 500; // 900
+	assert_eq!(
+		ledger.slash(
+			500 + 10 + 250 + 100 / 2, // active + era 6 + era 7 + era 5 / 2
+			0,
+			3 /* slash era 6 first, so the affected parts are era 6, era 7 and
+			   * ledge.active. This will cause the affected to go to zero, and then we will
+			   * start slashing older chunks */
+		),
+		500 + 250 + 10 + 100 / 2
+	);
+	// Then
+	assert_eq!(ledger.active, 0);
+	assert_eq!(ledger.unlocking, vec![c(4, 40), c(5, 100 / 2)]);
+	assert_eq!(ledger.total, 90);
+	assert_eq!(LedgerSlashPerEra::get().0, 0);
+	assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(5, 100 / 2), (6, 0), (7, 0)]));
+
+	// Given
+	// iteration order------------------NA---------2----------0----------1----
+	ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)];
+	ledger.active = 100;
+	ledger.total = 5 * 100;
+	// When
+	assert_eq!(
+		ledger.slash(
+			351, // active + era 6 + era 7 + era 5 / 2 + 1
+			50,  // min balance - everything slashed below 50 will get dusted
+			3    /* slash era 3+3 first, so the affected parts are era 6, era 7 and
+			      * ledge.active. This will cause the affected to go to zero, and then we will
+			      * start slashing older chunks */
+		),
+		400
+	);
+	// Then
+	assert_eq!(ledger.active, 0);
+	assert_eq!(ledger.unlocking, vec![c(4, 100)]);
+	assert_eq!(ledger.total, 100);
+	assert_eq!(LedgerSlashPerEra::get().0, 0);
+	assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(5, 0), (6, 0), (7, 0)]));
+
+	// Tests for saturating arithmetic
+
+	// Given
+	let slash = u64::MAX as Balance * 2;
+	// The value of the other parts of ledger that will get slashed
+	let value = slash - (10 * 4);
+
+	ledger.active = 10;
+	ledger.unlocking = bounded_vec![c(4, 10), c(5, 10), c(6, 10), c(7, value)];
+	ledger.total = value + 40;
+	// When
+	let slash_amount = ledger.slash(slash, 0, 0);
+	assert_eq_error_rate!(slash_amount, slash, 5);
+	// Then
+	assert_eq!(ledger.active, 0); // slash of 9
+	assert_eq!(ledger.unlocking, vec![]);
+	assert_eq!(ledger.total, 0);
+	assert_eq!(LedgerSlashPerEra::get().0, 0);
+	assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(4, 0), (5, 0), (6, 0), (7, 0)]));
+
+	// Given
+	use sp_runtime::PerThing as _;
+	let slash = u64::MAX as Balance * 2;
+	let value = u64::MAX as Balance * 2;
+	let unit = 100;
+	// slash * value that will saturate
+	assert!(slash.checked_mul(value).is_none());
+	// but slash * unit won't.
+	assert!(slash.checked_mul(unit).is_some());
+	ledger.unlocking = bounded_vec![c(4, unit), c(5, value), c(6, unit), c(7, unit)];
+	//--------------------------------------note value^^^
+	ledger.active = unit;
+	ledger.total = unit * 4 + value;
+	// When
+	assert_eq!(ledger.slash(slash, 0, 0), slash);
+	// Then
+	// The amount slashed out of `unit`
+	let affected_balance = value + unit * 4;
+	let ratio =
+		Perquintill::from_rational_with_rounding(slash, affected_balance, Rounding::Up).unwrap();
+	// `unit` after the slash is applied
+	let unit_slashed = {
+		let unit_slash = ratio.mul_ceil(unit);
+		unit - unit_slash
+	};
+	let value_slashed = {
+		let value_slash = ratio.mul_ceil(value);
+		value - value_slash
+	};
+	assert_eq!(ledger.active, unit_slashed);
+	assert_eq!(ledger.unlocking, vec![c(5, value_slashed), c(7, 32)]);
+	assert_eq!(ledger.total, value_slashed + 32);
+	assert_eq!(LedgerSlashPerEra::get().0, 0);
+	assert_eq!(
+		LedgerSlashPerEra::get().1,
+		BTreeMap::from([(4, 0), (5, value_slashed), (6, 0), (7, 32)])
+	);
 }
 
 #[test]
@@ -7203,7 +7126,7 @@ mod staking_unchecked {
 	fn virtual_bond_does_not_lock() {
 		ExtBuilder::default().build_and_execute(|| {
 			mock::start_active_era(1);
-			assert_eq!(asset::total_balance::<Test>(&10), 1);
+			assert_eq!(asset::stakeable_balance::<Test>(&10), 1);
 			// 10 can bond more than its balance amount since we do not require lock for virtual
 			// bonding.
 			assert_ok!(<Staking as StakingUnchecked>::virtual_bond(&10, 100, &15));
@@ -7342,7 +7265,7 @@ mod staking_unchecked {
 			assert_eq!(asset::staked::<Test>(&200), 1000);
 
 			// migrate them to virtual staker
-			assert_ok!(<Staking as StakingUnchecked>::migrate_to_virtual_staker(&200));
+			<Staking as StakingUnchecked>::migrate_to_virtual_staker(&200);
 			// payee needs to be updated to a non-stash account.
 			assert_ok!(<Staking as StakingInterface>::set_payee(&200, &201));
 
@@ -7369,7 +7292,7 @@ mod staking_unchecked {
 				// 101 is a nominator for 11
 				assert_eq!(initial_exposure.others.first().unwrap().who, 101);
 				// make 101 a virtual nominator
-				assert_ok!(<Staking as StakingUnchecked>::migrate_to_virtual_staker(&101));
+				<Staking as StakingUnchecked>::migrate_to_virtual_staker(&101);
 				// set payee different to self.
 				assert_ok!(<Staking as StakingInterface>::set_payee(&101, &102));
 
@@ -7444,7 +7367,7 @@ mod staking_unchecked {
 				// 101 is a nominator for 11
 				assert_eq!(initial_exposure.others.first().unwrap().who, 101);
 				// make 101 a virtual nominator
-				assert_ok!(<Staking as StakingUnchecked>::migrate_to_virtual_staker(&101));
+				<Staking as StakingUnchecked>::migrate_to_virtual_staker(&101);
 				// set payee different to self.
 				assert_ok!(<Staking as StakingInterface>::set_payee(&101, &102));
 
@@ -7500,7 +7423,7 @@ mod staking_unchecked {
 			// 333 is corrupted
 			assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted);
 			// migrate to virtual staker.
-			assert_ok!(<Staking as StakingUnchecked>::migrate_to_virtual_staker(&333));
+			<Staking as StakingUnchecked>::migrate_to_virtual_staker(&333);
 
 			// recover the ledger won't work for virtual staker
 			assert_noop!(
@@ -8111,7 +8034,8 @@ mod ledger_recovery {
 			// side effects on 333 - ledger, bonded, payee, lock should be intact.
 			assert_eq!(asset::staked::<Test>(&333), lock_333_before); // OK
 			assert_eq!(Bonded::<Test>::get(&333), Some(444)); // OK
-			assert!(Payee::<Test>::get(&333).is_some());
+			assert!(Payee::<Test>::get(&333).is_some()); // OK
+
 			// however, ledger associated with its controller was killed.
 			assert!(Ledger::<Test>::get(&444).is_none()); // NOK
 
@@ -9157,249 +9081,3 @@ mod getters {
 		});
 	}
 }
-
-mod hold_migration {
-	use super::*;
-	use sp_staking::{Stake, StakingInterface};
-
-	#[test]
-	fn ledger_update_creates_hold() {
-		ExtBuilder::default().has_stakers(true).build_and_execute(|| {
-			// GIVEN alice who is a nominator with old currency
-			let alice = 300;
-			bond_nominator(alice, 1000, vec![11]);
-			assert_eq!(asset::staked::<Test>(&alice), 1000);
-			assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 0);
-			// migrate alice currency to legacy locks
-			testing_utils::migrate_to_old_currency::<Test>(alice);
-			// no more holds
-			assert_eq!(asset::staked::<Test>(&alice), 0);
-			assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 1000);
-			assert_eq!(
-				<Staking as StakingInterface>::stake(&alice),
-				Ok(Stake { total: 1000, active: 1000 })
-			);
-
-			// any ledger mutation should create a hold
-			hypothetically!({
-				// give some extra balance to alice.
-				let _ = asset::mint_into_existing::<Test>(&alice, 100);
-
-				// WHEN new fund is bonded to ledger.
-				assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(alice), 100));
-
-				// THEN new hold is created
-				assert_eq!(asset::staked::<Test>(&alice), 1000 + 100);
-				assert_eq!(
-					<Staking as StakingInterface>::stake(&alice),
-					Ok(Stake { total: 1100, active: 1100 })
-				);
-
-				// old locked balance is untouched
-				assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 1000);
-			});
-
-			hypothetically!({
-				// WHEN new fund is unbonded from ledger.
-				assert_ok!(Staking::unbond(RuntimeOrigin::signed(alice), 100));
-
-				// THEN hold is updated.
-				assert_eq!(asset::staked::<Test>(&alice), 1000);
-				assert_eq!(
-					<Staking as StakingInterface>::stake(&alice),
-					Ok(Stake { total: 1000, active: 900 })
-				);
-
-				// old locked balance is untouched
-				assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 1000);
-			});
-
-			// WHEN alice currency is migrated.
-			assert_ok!(Staking::migrate_currency(RuntimeOrigin::signed(1), alice));
-
-			// THEN hold is updated.
-			assert_eq!(asset::staked::<Test>(&alice), 1000);
-			assert_eq!(
-				<Staking as StakingInterface>::stake(&alice),
-				Ok(Stake { total: 1000, active: 1000 })
-			);
-
-			// ensure cannot migrate again.
-			assert_noop!(
-				Staking::migrate_currency(RuntimeOrigin::signed(1), alice),
-				Error::<Test>::AlreadyMigrated
-			);
-
-			// locked balance is removed
-			assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 0);
-		});
-	}
-
-	#[test]
-	fn migrate_removes_old_lock() {
-		ExtBuilder::default().has_stakers(true).build_and_execute(|| {
-			// GIVEN alice who is a nominator with old currency
-			let alice = 300;
-			bond_nominator(alice, 1000, vec![11]);
-			testing_utils::migrate_to_old_currency::<Test>(alice);
-			assert_eq!(asset::staked::<Test>(&alice), 0);
-			assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 1000);
-			let pre_migrate_consumer = System::consumers(&alice);
-			System::reset_events();
-
-			// WHEN alice currency is migrated.
-			assert_ok!(Staking::migrate_currency(RuntimeOrigin::signed(1), alice));
-
-			// THEN
-			// the extra consumer from old code is removed.
-			assert_eq!(System::consumers(&alice), pre_migrate_consumer - 1);
-			// ensure no lock
-			assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 0);
-			// ensure stake and hold are same.
-			assert_eq!(
-				<Staking as StakingInterface>::stake(&alice),
-				Ok(Stake { total: 1000, active: 1000 })
-			);
-			assert_eq!(asset::staked::<Test>(&alice), 1000);
-			// ensure events are emitted.
-			assert_eq!(
-				staking_events_since_last_call(),
-				vec![Event::CurrencyMigrated { stash: alice, force_withdraw: 0 }]
-			);
-
-			// ensure cannot migrate again.
-			assert_noop!(
-				Staking::migrate_currency(RuntimeOrigin::signed(1), alice),
-				Error::<Test>::AlreadyMigrated
-			);
-		});
-	}
-	#[test]
-	fn cannot_hold_all_stake() {
-		// When there is not enough funds to hold all stake, part of the stake if force withdrawn.
-		// At end of the migration, the stake and hold should be same.
-		ExtBuilder::default().has_stakers(true).build_and_execute(|| {
-			// GIVEN alice who is a nominator with old currency.
-			let alice = 300;
-			let stake = 1000;
-			bond_nominator(alice, stake, vec![11]);
-			testing_utils::migrate_to_old_currency::<Test>(alice);
-			assert_eq!(asset::staked::<Test>(&alice), 0);
-			assert_eq!(Balances::balance_locked(STAKING_ID, &alice), stake);
-			// ledger has 1000 staked.
-			assert_eq!(
-				<Staking as StakingInterface>::stake(&alice),
-				Ok(Stake { total: stake, active: stake })
-			);
-
-			// Get rid of the extra ED to emulate all their balance including ED is staked.
-			assert_ok!(Balances::transfer_allow_death(
-				RuntimeOrigin::signed(alice),
-				10,
-				ExistentialDeposit::get()
-			));
-
-			let expected_force_withdraw = ExistentialDeposit::get();
-
-			// ledger mutation would fail in this case before migration because of failing hold.
-			assert_noop!(
-				Staking::unbond(RuntimeOrigin::signed(alice), 100),
-				Error::<Test>::NotEnoughFunds
-			);
-
-			// clear events
-			System::reset_events();
-
-			// WHEN alice currency is migrated.
-			assert_ok!(Staking::migrate_currency(RuntimeOrigin::signed(1), alice));
-
-			// THEN
-			let expected_hold = stake - expected_force_withdraw;
-			// ensure no lock
-			assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 0);
-			// ensure stake and hold are same.
-			assert_eq!(
-				<Staking as StakingInterface>::stake(&alice),
-				Ok(Stake { total: expected_hold, active: expected_hold })
-			);
-			assert_eq!(asset::staked::<Test>(&alice), expected_hold);
-			// ensure events are emitted.
-			assert_eq!(
-				staking_events_since_last_call(),
-				vec![Event::CurrencyMigrated {
-					stash: alice,
-					force_withdraw: expected_force_withdraw
-				}]
-			);
-
-			// ensure cannot migrate again.
-			assert_noop!(
-				Staking::migrate_currency(RuntimeOrigin::signed(1), alice),
-				Error::<Test>::AlreadyMigrated
-			);
-
-			// unbond works after migration.
-			assert_ok!(Staking::unbond(RuntimeOrigin::signed(alice), 100));
-		});
-	}
-
-	#[test]
-	fn virtual_staker_consumer_provider_dec() {
-		// Ensure virtual stakers consumer and provider count is decremented.
-		ExtBuilder::default().has_stakers(true).build_and_execute(|| {
-			// 200 virtual bonds
-			bond_virtual_nominator(200, 201, 500, vec![11, 21]);
-
-			// previously the virtual nominator had a provider inc by the delegation system as
-			// well as a consumer by this pallet.
-			System::inc_providers(&200);
-			System::inc_consumers(&200).expect("has provider, can consume");
-
-			hypothetically!({
-				// migrate 200
-				assert_ok!(Staking::migrate_currency(RuntimeOrigin::signed(1), 200));
-
-				// ensure account does not exist in system anymore.
-				assert_eq!(System::consumers(&200), 0);
-				assert_eq!(System::providers(&200), 0);
-				assert!(!System::account_exists(&200));
-
-				// ensure cannot migrate again.
-				assert_noop!(
-					Staking::migrate_currency(RuntimeOrigin::signed(1), 200),
-					Error::<Test>::AlreadyMigrated
-				);
-			});
-
-			hypothetically!({
-				// 200 has an erroneously extra provider
-				System::inc_providers(&200);
-
-				// causes migration to fail.
-				assert_noop!(
-					Staking::migrate_currency(RuntimeOrigin::signed(1), 200),
-					Error::<Test>::BadState
-				);
-			});
-
-			// 200 is funded for more than ED by a random account.
-			assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(999), 200, 10));
-
-			// it has an extra provider now.
-			assert_eq!(System::providers(&200), 2);
-
-			// migrate 200
-			assert_ok!(Staking::migrate_currency(RuntimeOrigin::signed(1), 200));
-
-			// 1 provider is left, consumers is 0.
-			assert_eq!(System::providers(&200), 1);
-			assert_eq!(System::consumers(&200), 0);
-
-			// ensure cannot migrate again.
-			assert_noop!(
-				Staking::migrate_currency(RuntimeOrigin::signed(1), 200),
-				Error::<Test>::AlreadyMigrated
-			);
-		});
-	}
-}
diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs
index 02ccdacb01c4295f29e4735cda32704e2438f828..56f561679cfc78aee1cca7f1a5b759e17b2f93d9 100644
--- a/substrate/frame/staking/src/weights.rs
+++ b/substrate/frame/staking/src/weights.rs
@@ -18,25 +18,27 @@
 //! Autogenerated weights for `pallet_staking`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-09-17, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-obbyq9g6-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024`
 
 // Executed Command:
-// target/production/substrate-node
+// ./target/production/substrate-node
 // benchmark
 // pallet
+// --chain=dev
 // --steps=50
 // --repeat=20
+// --pallet=pallet_staking
+// --no-storage-info
+// --no-median-slopes
+// --no-min-squares
 // --extrinsic=*
 // --wasm-execution=compiled
 // --heap-pages=4096
-// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json
-// --pallet=pallet_staking
-// --chain=dev
-// --header=./substrate/HEADER-APACHE2
 // --output=./substrate/frame/staking/src/weights.rs
+// --header=./substrate/HEADER-APACHE2
 // --template=./substrate/.maintain/frame-weight-template.hbs
 
 #![cfg_attr(rustfmt, rustfmt_skip)]
@@ -81,7 +83,6 @@ pub trait WeightInfo {
 	fn force_apply_min_commission() -> Weight;
 	fn set_min_commission() -> Weight;
 	fn restore_ledger() -> Weight;
-	fn migrate_currency() -> Weight;
 }
 
 /// Weights for `pallet_staking` using the Substrate node and recommended hardware.
@@ -91,18 +92,18 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// 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::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, 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::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:  `1068`
-		//  Estimated: `4556`
-		// Minimum execution time: 71_854_000 picoseconds.
-		Weight::from_parts(73_408_000, 4556)
+		//  Measured:  `1042`
+		//  Estimated: `4764`
+		// Minimum execution time: 46_504_000 picoseconds.
+		Weight::from_parts(48_459_000, 4764)
 			.saturating_add(T::DbWeight::get().reads(4_u64))
 			.saturating_add(T::DbWeight::get().writes(4_u64))
 	}
@@ -110,20 +111,20 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// 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: `Staking::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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: `VoterList::ListNodes` (r:3 w:3)
 	/// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListBags` (r:2 w:2)
 	/// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`)
 	fn bond_extra() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `2049`
+		//  Measured:  `1990`
 		//  Estimated: `8877`
-		// Minimum execution time: 127_442_000 picoseconds.
-		Weight::from_parts(130_845_000, 8877)
+		// Minimum execution time: 90_475_000 picoseconds.
+		Weight::from_parts(93_619_000, 8877)
 			.saturating_add(T::DbWeight::get().reads(9_u64))
 			.saturating_add(T::DbWeight::get().writes(7_u64))
 	}
@@ -137,22 +138,22 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// 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::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:0)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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: `VoterList::ListNodes` (r:3 w:3)
 	/// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListBags` (r:2 w:2)
 	/// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`)
 	fn unbond() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `2151`
+		//  Measured:  `2195`
 		//  Estimated: `8877`
-		// Minimum execution time: 105_259_000 picoseconds.
-		Weight::from_parts(107_112_000, 8877)
+		// Minimum execution time: 99_335_000 picoseconds.
+		Weight::from_parts(101_440_000, 8877)
 			.saturating_add(T::DbWeight::get().reads(12_u64))
-			.saturating_add(T::DbWeight::get().writes(6_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`)
@@ -160,21 +161,21 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// 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::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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:  `1393`
-		//  Estimated: `4556`
-		// Minimum execution time: 77_158_000 picoseconds.
-		Weight::from_parts(79_140_122, 4556)
-			// Standard Error: 1_688
-			.saturating_add(Weight::from_parts(62_663, 0).saturating_mul(s.into()))
+		//  Measured:  `1297`
+		//  Estimated: `4764`
+		// Minimum execution time: 50_067_000 picoseconds.
+		Weight::from_parts(52_396_327, 4764)
+			// Standard Error: 1_419
+			.saturating_add(Weight::from_parts(51_406, 0).saturating_mul(s.into()))
 			.saturating_add(T::DbWeight::get().reads(6_u64))
 			.saturating_add(T::DbWeight::get().writes(2_u64))
 	}
@@ -186,10 +187,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// 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::VirtualStakers` (r:1 w:1)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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::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)
@@ -209,14 +210,14 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// The range of component `s` is `[0, 100]`.
 	fn withdraw_unbonded_kill(s: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `2255 + s * (4 ±0)`
+		//  Measured:  `2196 + s * (4 ±0)`
 		//  Estimated: `6248 + s * (4 ±0)`
-		// Minimum execution time: 125_396_000 picoseconds.
-		Weight::from_parts(134_915_543, 6248)
-			// Standard Error: 3_660
-			.saturating_add(Weight::from_parts(1_324_736, 0).saturating_mul(s.into()))
+		// Minimum execution time: 92_931_000 picoseconds.
+		Weight::from_parts(101_398_156, 6248)
+			// Standard Error: 4_180
+			.saturating_add(Weight::from_parts(1_377_850, 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(11_u64))
 			.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into())))
 			.saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into()))
 	}
@@ -244,10 +245,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	fn validate() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1438`
+		//  Measured:  `1372`
 		//  Estimated: `4556`
-		// Minimum execution time: 68_826_000 picoseconds.
-		Weight::from_parts(71_261_000, 4556)
+		// Minimum execution time: 56_291_000 picoseconds.
+		Weight::from_parts(58_372_000, 4556)
 			.saturating_add(T::DbWeight::get().reads(11_u64))
 			.saturating_add(T::DbWeight::get().writes(5_u64))
 	}
@@ -260,12 +261,12 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// The range of component `k` is `[1, 128]`.
 	fn kick(k: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1848 + k * (572 ±0)`
+		//  Measured:  `1815 + k * (572 ±0)`
 		//  Estimated: `4556 + k * (3033 ±0)`
-		// Minimum execution time: 46_082_000 picoseconds.
-		Weight::from_parts(49_541_374, 4556)
-			// Standard Error: 7_218
-			.saturating_add(Weight::from_parts(7_281_079, 0).saturating_mul(k.into()))
+		// Minimum execution time: 36_218_000 picoseconds.
+		Weight::from_parts(38_811_308, 4556)
+			// Standard Error: 8_352
+			.saturating_add(Weight::from_parts(6_527_398, 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())))
@@ -296,12 +297,12 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// The range of component `n` is `[1, 16]`.
 	fn nominate(n: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1932 + n * (102 ±0)`
+		//  Measured:  `1866 + n * (102 ±0)`
 		//  Estimated: `6248 + n * (2520 ±0)`
-		// Minimum execution time: 83_854_000 picoseconds.
-		Weight::from_parts(81_387_241, 6248)
-			// Standard Error: 16_811
-			.saturating_add(Weight::from_parts(4_900_554, 0).saturating_mul(n.into()))
+		// Minimum execution time: 68_607_000 picoseconds.
+		Weight::from_parts(66_831_185, 6248)
+			// Standard Error: 14_014
+			.saturating_add(Weight::from_parts(4_031_635, 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))
@@ -325,10 +326,10 @@ 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:  `1882`
+		//  Measured:  `1816`
 		//  Estimated: `6248`
-		// Minimum execution time: 73_939_000 picoseconds.
-		Weight::from_parts(75_639_000, 6248)
+		// Minimum execution time: 60_088_000 picoseconds.
+		Weight::from_parts(62_471_000, 6248)
 			.saturating_add(T::DbWeight::get().reads(9_u64))
 			.saturating_add(T::DbWeight::get().writes(6_u64))
 	}
@@ -340,10 +341,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
 	fn set_payee() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `935`
+		//  Measured:  `902`
 		//  Estimated: `4556`
-		// Minimum execution time: 24_592_000 picoseconds.
-		Weight::from_parts(25_092_000, 4556)
+		// Minimum execution time: 19_777_000 picoseconds.
+		Weight::from_parts(20_690_000, 4556)
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -355,10 +356,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
 	fn update_payee() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1002`
+		//  Measured:  `969`
 		//  Estimated: `4556`
-		// Minimum execution time: 29_735_000 picoseconds.
-		Weight::from_parts(30_546_000, 4556)
+		// Minimum execution time: 23_705_000 picoseconds.
+		Weight::from_parts(24_409_000, 4556)
 			.saturating_add(T::DbWeight::get().reads(3_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -368,10 +369,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
 	fn set_controller() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `935`
+		//  Measured:  `902`
 		//  Estimated: `8122`
-		// Minimum execution time: 28_728_000 picoseconds.
-		Weight::from_parts(29_709_000, 8122)
+		// Minimum execution time: 23_479_000 picoseconds.
+		Weight::from_parts(24_502_000, 8122)
 			.saturating_add(T::DbWeight::get().reads(3_u64))
 			.saturating_add(T::DbWeight::get().writes(3_u64))
 	}
@@ -381,8 +382,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_519_000 picoseconds.
-		Weight::from_parts(2_673_000, 0)
+		// Minimum execution time: 2_675_000 picoseconds.
+		Weight::from_parts(2_802_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::ForceEra` (r:0 w:1)
@@ -391,8 +392,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 8_050_000 picoseconds.
-		Weight::from_parts(8_268_000, 0)
+		// Minimum execution time: 7_067_000 picoseconds.
+		Weight::from_parts(7_413_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::ForceEra` (r:0 w:1)
@@ -401,8 +402,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 8_131_000 picoseconds.
-		Weight::from_parts(8_349_000, 0)
+		// Minimum execution time: 6_977_000 picoseconds.
+		Weight::from_parts(7_353_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::ForceEra` (r:0 w:1)
@@ -411,8 +412,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 8_104_000 picoseconds.
-		Weight::from_parts(8_317_000, 0)
+		// Minimum execution time: 7_071_000 picoseconds.
+		Weight::from_parts(7_463_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::Invulnerables` (r:0 w:1)
@@ -422,10 +423,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_669_000 picoseconds.
-		Weight::from_parts(3_013_436, 0)
-			// Standard Error: 31
-			.saturating_add(Weight::from_parts(10_704, 0).saturating_mul(v.into()))
+		// Minimum execution time: 2_833_000 picoseconds.
+		Weight::from_parts(3_328_130, 0)
+			// Standard Error: 30
+			.saturating_add(Weight::from_parts(10_058, 0).saturating_mul(v.into()))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::Ledger` (r:11800 w:11800)
@@ -437,12 +438,12 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// The range of component `i` is `[0, 5900]`.
 	fn deprecate_controller_batch(i: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1779 + i * (229 ±0)`
+		//  Measured:  `1746 + i * (229 ±0)`
 		//  Estimated: `990 + i * (7132 ±0)`
-		// Minimum execution time: 5_101_000 picoseconds.
-		Weight::from_parts(5_368_000, 990)
-			// Standard Error: 75_180
-			.saturating_add(Weight::from_parts(33_781_643, 0).saturating_mul(i.into()))
+		// Minimum execution time: 5_300_000 picoseconds.
+		Weight::from_parts(5_437_000, 990)
+			// Standard Error: 66_261
+			.saturating_add(Weight::from_parts(30_172_457, 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, 7132).saturating_mul(i.into()))
@@ -453,10 +454,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// 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: `Staking::VirtualStakers` (r:1 w:1)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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: `System::Account` (r:1 w:1)
 	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Validators` (r:1 w:0)
@@ -478,14 +479,14 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// The range of component `s` is `[0, 100]`.
 	fn force_unstake(s: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `2255 + s * (4 ±0)`
+		//  Measured:  `2196 + s * (4 ±0)`
 		//  Estimated: `6248 + s * (4 ±0)`
-		// Minimum execution time: 119_955_000 picoseconds.
-		Weight::from_parts(128_392_032, 6248)
-			// Standard Error: 3_773
-			.saturating_add(Weight::from_parts(1_302_488, 0).saturating_mul(s.into()))
+		// Minimum execution time: 87_677_000 picoseconds.
+		Weight::from_parts(96_386_462, 6248)
+			// Standard Error: 3_717
+			.saturating_add(Weight::from_parts(1_370_585, 0).saturating_mul(s.into()))
 			.saturating_add(T::DbWeight::get().reads(13_u64))
-			.saturating_add(T::DbWeight::get().writes(13_u64))
+			.saturating_add(T::DbWeight::get().writes(12_u64))
 			.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into())))
 			.saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into()))
 	}
@@ -494,12 +495,12 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// The range of component `s` is `[1, 1000]`.
 	fn cancel_deferred_slash(s: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `66705`
-		//  Estimated: `70170`
-		// Minimum execution time: 139_290_000 picoseconds.
-		Weight::from_parts(959_667_494, 70170)
-			// Standard Error: 56_271
-			.saturating_add(Weight::from_parts(4_798_293, 0).saturating_mul(s.into()))
+		//  Measured:  `66672`
+		//  Estimated: `70137`
+		// Minimum execution time: 105_086_000 picoseconds.
+		Weight::from_parts(1_167_895_222, 70137)
+			// Standard Error: 77_022
+			.saturating_add(Weight::from_parts(6_487_305, 0).saturating_mul(s.into()))
 			.saturating_add(T::DbWeight::get().reads(1_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -517,10 +518,12 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::ErasValidatorReward` (r:1 w:0)
 	/// Proof: `Staking::ErasValidatorReward` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::VirtualStakers` (r:257 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:257 w:257)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`)
+	/// Storage: `Balances::Locks` (r:257 w:257)
+	/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
+	/// Storage: `Balances::Freezes` (r:257 w:0)
+	/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`)
+	/// Storage: `System::Account` (r:257 w:257)
+	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::ErasStakersPaged` (r:1 w:0)
 	/// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	/// Storage: `Staking::ErasRewardPoints` (r:1 w:0)
@@ -529,31 +532,29 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Proof: `Staking::ErasValidatorPrefs` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Payee` (r:257 w:0)
 	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
-	/// Storage: `System::Account` (r:257 w:257)
-	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
 	/// The range of component `n` is `[0, 256]`.
 	fn payout_stakers_alive_staked(n: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `33283 + n * (370 ±0)`
-		//  Estimated: `30958 + n * (3566 ±0)`
-		// Minimum execution time: 193_068_000 picoseconds.
-		Weight::from_parts(252_762_568, 30958)
-			// Standard Error: 22_743
-			.saturating_add(Weight::from_parts(81_185_306, 0).saturating_mul(n.into()))
+		//  Measured:  `33297 + n * (377 ±0)`
+		//  Estimated: `30944 + n * (3774 ±3)`
+		// Minimum execution time: 154_210_000 picoseconds.
+		Weight::from_parts(192_836_012, 30944)
+			// Standard Error: 40_441
+			.saturating_add(Weight::from_parts(47_646_642, 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))
 			.saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into())))
-			.saturating_add(Weight::from_parts(0, 3566).saturating_mul(n.into()))
+			.saturating_add(Weight::from_parts(0, 3774).saturating_mul(n.into()))
 	}
 	/// 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::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:0)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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: `VoterList::ListNodes` (r:3 w:3)
 	/// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListBags` (r:2 w:2)
@@ -561,25 +562,25 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// The range of component `l` is `[1, 32]`.
 	fn rebond(l: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1947 + l * (7 ±0)`
+		//  Measured:  `1991 + l * (7 ±0)`
 		//  Estimated: `8877`
-		// Minimum execution time: 91_151_000 picoseconds.
-		Weight::from_parts(93_596_096, 8877)
-			// Standard Error: 5_313
-			.saturating_add(Weight::from_parts(124_684, 0).saturating_mul(l.into()))
+		// Minimum execution time: 88_337_000 picoseconds.
+		Weight::from_parts(91_391_254, 8877)
+			// Standard Error: 4_485
+			.saturating_add(Weight::from_parts(103_443, 0).saturating_mul(l.into()))
 			.saturating_add(T::DbWeight::get().reads(9_u64))
-			.saturating_add(T::DbWeight::get().writes(6_u64))
+			.saturating_add(T::DbWeight::get().writes(7_u64))
 	}
-	/// Storage: `Staking::VirtualStakers` (r:1 w:1)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, 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: `Staking::SlashingSpans` (r:1 w:1)
 	/// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`)
-	/// Storage: `Balances::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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::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)
@@ -599,14 +600,14 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// The range of component `s` is `[1, 100]`.
 	fn reap_stash(s: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `2255 + s * (4 ±0)`
+		//  Measured:  `2196 + s * (4 ±0)`
 		//  Estimated: `6248 + s * (4 ±0)`
-		// Minimum execution time: 133_214_000 picoseconds.
-		Weight::from_parts(137_290_527, 6248)
-			// Standard Error: 4_153
-			.saturating_add(Weight::from_parts(1_291_007, 0).saturating_mul(s.into()))
+		// Minimum execution time: 98_014_000 picoseconds.
+		Weight::from_parts(102_537_670, 6248)
+			// Standard Error: 3_324
+			.saturating_add(Weight::from_parts(1_353_142, 0).saturating_mul(s.into()))
 			.saturating_add(T::DbWeight::get().reads(12_u64))
-			.saturating_add(T::DbWeight::get().writes(12_u64))
+			.saturating_add(T::DbWeight::get().writes(11_u64))
 			.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into())))
 			.saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into()))
 	}
@@ -650,12 +651,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: 692_301_000 picoseconds.
-		Weight::from_parts(708_732_000, 512390)
-			// Standard Error: 2_117_299
-			.saturating_add(Weight::from_parts(70_087_600, 0).saturating_mul(v.into()))
-			// Standard Error: 210_977
-			.saturating_add(Weight::from_parts(22_953_405, 0).saturating_mul(n.into()))
+		// Minimum execution time: 608_575_000 picoseconds.
+		Weight::from_parts(613_663_000, 512390)
+			// Standard Error: 2_286_521
+			.saturating_add(Weight::from_parts(72_108_001, 0).saturating_mul(v.into()))
+			// Standard Error: 227_839
+			.saturating_add(Weight::from_parts(20_314_085, 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())))
@@ -684,14 +685,14 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// The range of component `n` is `[500, 1000]`.
 	fn get_npos_voters(v: u32, n: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `3241 + n * (911 ±0) + v * (395 ±0)`
+		//  Measured:  `3175 + n * (911 ±0) + v * (395 ±0)`
 		//  Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)`
-		// Minimum execution time: 43_708_472_000 picoseconds.
-		Weight::from_parts(44_048_436_000, 512390)
-			// Standard Error: 493_244
-			.saturating_add(Weight::from_parts(6_697_278, 0).saturating_mul(v.into()))
-			// Standard Error: 493_244
-			.saturating_add(Weight::from_parts(4_559_779, 0).saturating_mul(n.into()))
+		// Minimum execution time: 37_173_756_000 picoseconds.
+		Weight::from_parts(37_488_937_000, 512390)
+			// Standard Error: 467_413
+			.saturating_add(Weight::from_parts(8_086_367, 0).saturating_mul(v.into()))
+			// Standard Error: 467_413
+			.saturating_add(Weight::from_parts(3_108_193, 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())))
@@ -706,12 +707,12 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// The range of component `v` is `[500, 1000]`.
 	fn get_npos_targets(v: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1012 + v * (50 ±0)`
+		//  Measured:  `979 + v * (50 ±0)`
 		//  Estimated: `3510 + v * (2520 ±0)`
-		// Minimum execution time: 2_917_165_000 picoseconds.
-		Weight::from_parts(2_948_999_000, 3510)
-			// Standard Error: 33_372
-			.saturating_add(Weight::from_parts(2_126_909, 0).saturating_mul(v.into()))
+		// Minimum execution time: 2_641_258_000 picoseconds.
+		Weight::from_parts(382_882_595, 3510)
+			// Standard Error: 11_991
+			.saturating_add(Weight::from_parts(4_695_820, 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()))
@@ -734,8 +735,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 4_748_000 picoseconds.
-		Weight::from_parts(5_052_000, 0)
+		// Minimum execution time: 5_753_000 picoseconds.
+		Weight::from_parts(6_529_000, 0)
 			.saturating_add(T::DbWeight::get().writes(7_u64))
 	}
 	/// Storage: `Staking::MinCommission` (r:0 w:1)
@@ -756,8 +757,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 4_316_000 picoseconds.
-		Weight::from_parts(4_526_000, 0)
+		// Minimum execution time: 5_212_000 picoseconds.
+		Weight::from_parts(5_451_000, 0)
 			.saturating_add(T::DbWeight::get().writes(7_u64))
 	}
 	/// Storage: `Staking::Bonded` (r:1 w:0)
@@ -784,10 +785,10 @@ 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_other() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `2005`
+		//  Measured:  `1939`
 		//  Estimated: `6248`
-		// Minimum execution time: 87_374_000 picoseconds.
-		Weight::from_parts(89_848_000, 6248)
+		// Minimum execution time: 73_000_000 picoseconds.
+		Weight::from_parts(75_184_000, 6248)
 			.saturating_add(T::DbWeight::get().reads(12_u64))
 			.saturating_add(T::DbWeight::get().writes(6_u64))
 	}
@@ -797,10 +798,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`)
 	fn force_apply_min_commission() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `724`
+		//  Measured:  `691`
 		//  Estimated: `3510`
-		// Minimum execution time: 15_529_000 picoseconds.
-		Weight::from_parts(16_094_000, 3510)
+		// Minimum execution time: 13_056_000 picoseconds.
+		Weight::from_parts(13_517_000, 3510)
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -810,51 +811,28 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_533_000 picoseconds.
-		Weight::from_parts(2_817_000, 0)
+		// Minimum execution time: 3_201_000 picoseconds.
+		Weight::from_parts(3_442_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
-	/// Storage: `Staking::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:0)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`)
-	/// Storage: `System::Account` (r:1 w:0)
-	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Locks` (r:1 w:0)
+	/// 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`)
-	fn restore_ledger() -> Weight {
-		// Proof Size summary in bytes:
-		//  Measured:  `1110`
-		//  Estimated: `4764`
-		// Minimum execution time: 50_105_000 picoseconds.
-		Weight::from_parts(50_966_000, 4764)
-			.saturating_add(T::DbWeight::get().reads(6_u64))
-			.saturating_add(T::DbWeight::get().writes(2_u64))
-	}
-	/// Storage: `Staking::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, 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::Ledger` (r:1 w:0)
-	/// 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::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Freezes` (r:1 w:0)
 	/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`)
-	fn migrate_currency() -> Weight {
+	fn restore_ledger() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1246`
+		//  Measured:  `1047`
 		//  Estimated: `4764`
-		// Minimum execution time: 94_054_000 picoseconds.
-		Weight::from_parts(96_272_000, 4764)
-			.saturating_add(T::DbWeight::get().reads(6_u64))
-			.saturating_add(T::DbWeight::get().writes(2_u64))
+		// Minimum execution time: 44_671_000 picoseconds.
+		Weight::from_parts(45_611_000, 4764)
+			.saturating_add(T::DbWeight::get().reads(5_u64))
+			.saturating_add(T::DbWeight::get().writes(4_u64))
 	}
 }
 
@@ -864,18 +842,18 @@ impl WeightInfo for () {
 	/// 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::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, 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::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:  `1068`
-		//  Estimated: `4556`
-		// Minimum execution time: 71_854_000 picoseconds.
-		Weight::from_parts(73_408_000, 4556)
+		//  Measured:  `1042`
+		//  Estimated: `4764`
+		// Minimum execution time: 46_504_000 picoseconds.
+		Weight::from_parts(48_459_000, 4764)
 			.saturating_add(RocksDbWeight::get().reads(4_u64))
 			.saturating_add(RocksDbWeight::get().writes(4_u64))
 	}
@@ -883,20 +861,20 @@ impl WeightInfo for () {
 	/// 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: `Staking::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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: `VoterList::ListNodes` (r:3 w:3)
 	/// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListBags` (r:2 w:2)
 	/// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`)
 	fn bond_extra() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `2049`
+		//  Measured:  `1990`
 		//  Estimated: `8877`
-		// Minimum execution time: 127_442_000 picoseconds.
-		Weight::from_parts(130_845_000, 8877)
+		// Minimum execution time: 90_475_000 picoseconds.
+		Weight::from_parts(93_619_000, 8877)
 			.saturating_add(RocksDbWeight::get().reads(9_u64))
 			.saturating_add(RocksDbWeight::get().writes(7_u64))
 	}
@@ -910,22 +888,22 @@ impl WeightInfo for () {
 	/// 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::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:0)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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: `VoterList::ListNodes` (r:3 w:3)
 	/// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListBags` (r:2 w:2)
 	/// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`)
 	fn unbond() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `2151`
+		//  Measured:  `2195`
 		//  Estimated: `8877`
-		// Minimum execution time: 105_259_000 picoseconds.
-		Weight::from_parts(107_112_000, 8877)
+		// Minimum execution time: 99_335_000 picoseconds.
+		Weight::from_parts(101_440_000, 8877)
 			.saturating_add(RocksDbWeight::get().reads(12_u64))
-			.saturating_add(RocksDbWeight::get().writes(6_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`)
@@ -933,21 +911,21 @@ impl WeightInfo for () {
 	/// 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::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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:  `1393`
-		//  Estimated: `4556`
-		// Minimum execution time: 77_158_000 picoseconds.
-		Weight::from_parts(79_140_122, 4556)
-			// Standard Error: 1_688
-			.saturating_add(Weight::from_parts(62_663, 0).saturating_mul(s.into()))
+		//  Measured:  `1297`
+		//  Estimated: `4764`
+		// Minimum execution time: 50_067_000 picoseconds.
+		Weight::from_parts(52_396_327, 4764)
+			// Standard Error: 1_419
+			.saturating_add(Weight::from_parts(51_406, 0).saturating_mul(s.into()))
 			.saturating_add(RocksDbWeight::get().reads(6_u64))
 			.saturating_add(RocksDbWeight::get().writes(2_u64))
 	}
@@ -959,10 +937,10 @@ impl WeightInfo for () {
 	/// 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::VirtualStakers` (r:1 w:1)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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::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)
@@ -982,14 +960,14 @@ impl WeightInfo for () {
 	/// The range of component `s` is `[0, 100]`.
 	fn withdraw_unbonded_kill(s: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `2255 + s * (4 ±0)`
+		//  Measured:  `2196 + s * (4 ±0)`
 		//  Estimated: `6248 + s * (4 ±0)`
-		// Minimum execution time: 125_396_000 picoseconds.
-		Weight::from_parts(134_915_543, 6248)
-			// Standard Error: 3_660
-			.saturating_add(Weight::from_parts(1_324_736, 0).saturating_mul(s.into()))
+		// Minimum execution time: 92_931_000 picoseconds.
+		Weight::from_parts(101_398_156, 6248)
+			// Standard Error: 4_180
+			.saturating_add(Weight::from_parts(1_377_850, 0).saturating_mul(s.into()))
 			.saturating_add(RocksDbWeight::get().reads(13_u64))
-			.saturating_add(RocksDbWeight::get().writes(12_u64))
+			.saturating_add(RocksDbWeight::get().writes(11_u64))
 			.saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into())))
 			.saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into()))
 	}
@@ -1017,10 +995,10 @@ impl WeightInfo for () {
 	/// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	fn validate() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1438`
+		//  Measured:  `1372`
 		//  Estimated: `4556`
-		// Minimum execution time: 68_826_000 picoseconds.
-		Weight::from_parts(71_261_000, 4556)
+		// Minimum execution time: 56_291_000 picoseconds.
+		Weight::from_parts(58_372_000, 4556)
 			.saturating_add(RocksDbWeight::get().reads(11_u64))
 			.saturating_add(RocksDbWeight::get().writes(5_u64))
 	}
@@ -1033,12 +1011,12 @@ impl WeightInfo for () {
 	/// The range of component `k` is `[1, 128]`.
 	fn kick(k: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1848 + k * (572 ±0)`
+		//  Measured:  `1815 + k * (572 ±0)`
 		//  Estimated: `4556 + k * (3033 ±0)`
-		// Minimum execution time: 46_082_000 picoseconds.
-		Weight::from_parts(49_541_374, 4556)
-			// Standard Error: 7_218
-			.saturating_add(Weight::from_parts(7_281_079, 0).saturating_mul(k.into()))
+		// Minimum execution time: 36_218_000 picoseconds.
+		Weight::from_parts(38_811_308, 4556)
+			// Standard Error: 8_352
+			.saturating_add(Weight::from_parts(6_527_398, 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())))
@@ -1069,12 +1047,12 @@ impl WeightInfo for () {
 	/// The range of component `n` is `[1, 16]`.
 	fn nominate(n: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1932 + n * (102 ±0)`
+		//  Measured:  `1866 + n * (102 ±0)`
 		//  Estimated: `6248 + n * (2520 ±0)`
-		// Minimum execution time: 83_854_000 picoseconds.
-		Weight::from_parts(81_387_241, 6248)
-			// Standard Error: 16_811
-			.saturating_add(Weight::from_parts(4_900_554, 0).saturating_mul(n.into()))
+		// Minimum execution time: 68_607_000 picoseconds.
+		Weight::from_parts(66_831_185, 6248)
+			// Standard Error: 14_014
+			.saturating_add(Weight::from_parts(4_031_635, 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))
@@ -1098,10 +1076,10 @@ 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:  `1882`
+		//  Measured:  `1816`
 		//  Estimated: `6248`
-		// Minimum execution time: 73_939_000 picoseconds.
-		Weight::from_parts(75_639_000, 6248)
+		// Minimum execution time: 60_088_000 picoseconds.
+		Weight::from_parts(62_471_000, 6248)
 			.saturating_add(RocksDbWeight::get().reads(9_u64))
 			.saturating_add(RocksDbWeight::get().writes(6_u64))
 	}
@@ -1113,10 +1091,10 @@ impl WeightInfo for () {
 	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
 	fn set_payee() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `935`
+		//  Measured:  `902`
 		//  Estimated: `4556`
-		// Minimum execution time: 24_592_000 picoseconds.
-		Weight::from_parts(25_092_000, 4556)
+		// Minimum execution time: 19_777_000 picoseconds.
+		Weight::from_parts(20_690_000, 4556)
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -1128,10 +1106,10 @@ impl WeightInfo for () {
 	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
 	fn update_payee() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1002`
+		//  Measured:  `969`
 		//  Estimated: `4556`
-		// Minimum execution time: 29_735_000 picoseconds.
-		Weight::from_parts(30_546_000, 4556)
+		// Minimum execution time: 23_705_000 picoseconds.
+		Weight::from_parts(24_409_000, 4556)
 			.saturating_add(RocksDbWeight::get().reads(3_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -1141,10 +1119,10 @@ impl WeightInfo for () {
 	/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
 	fn set_controller() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `935`
+		//  Measured:  `902`
 		//  Estimated: `8122`
-		// Minimum execution time: 28_728_000 picoseconds.
-		Weight::from_parts(29_709_000, 8122)
+		// Minimum execution time: 23_479_000 picoseconds.
+		Weight::from_parts(24_502_000, 8122)
 			.saturating_add(RocksDbWeight::get().reads(3_u64))
 			.saturating_add(RocksDbWeight::get().writes(3_u64))
 	}
@@ -1154,8 +1132,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_519_000 picoseconds.
-		Weight::from_parts(2_673_000, 0)
+		// Minimum execution time: 2_675_000 picoseconds.
+		Weight::from_parts(2_802_000, 0)
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::ForceEra` (r:0 w:1)
@@ -1164,8 +1142,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 8_050_000 picoseconds.
-		Weight::from_parts(8_268_000, 0)
+		// Minimum execution time: 7_067_000 picoseconds.
+		Weight::from_parts(7_413_000, 0)
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::ForceEra` (r:0 w:1)
@@ -1174,8 +1152,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 8_131_000 picoseconds.
-		Weight::from_parts(8_349_000, 0)
+		// Minimum execution time: 6_977_000 picoseconds.
+		Weight::from_parts(7_353_000, 0)
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::ForceEra` (r:0 w:1)
@@ -1184,8 +1162,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 8_104_000 picoseconds.
-		Weight::from_parts(8_317_000, 0)
+		// Minimum execution time: 7_071_000 picoseconds.
+		Weight::from_parts(7_463_000, 0)
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::Invulnerables` (r:0 w:1)
@@ -1195,10 +1173,10 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_669_000 picoseconds.
-		Weight::from_parts(3_013_436, 0)
-			// Standard Error: 31
-			.saturating_add(Weight::from_parts(10_704, 0).saturating_mul(v.into()))
+		// Minimum execution time: 2_833_000 picoseconds.
+		Weight::from_parts(3_328_130, 0)
+			// Standard Error: 30
+			.saturating_add(Weight::from_parts(10_058, 0).saturating_mul(v.into()))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
 	/// Storage: `Staking::Ledger` (r:11800 w:11800)
@@ -1210,12 +1188,12 @@ impl WeightInfo for () {
 	/// The range of component `i` is `[0, 5900]`.
 	fn deprecate_controller_batch(i: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1779 + i * (229 ±0)`
+		//  Measured:  `1746 + i * (229 ±0)`
 		//  Estimated: `990 + i * (7132 ±0)`
-		// Minimum execution time: 5_101_000 picoseconds.
-		Weight::from_parts(5_368_000, 990)
-			// Standard Error: 75_180
-			.saturating_add(Weight::from_parts(33_781_643, 0).saturating_mul(i.into()))
+		// Minimum execution time: 5_300_000 picoseconds.
+		Weight::from_parts(5_437_000, 990)
+			// Standard Error: 66_261
+			.saturating_add(Weight::from_parts(30_172_457, 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, 7132).saturating_mul(i.into()))
@@ -1226,10 +1204,10 @@ impl WeightInfo for () {
 	/// 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: `Staking::VirtualStakers` (r:1 w:1)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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: `System::Account` (r:1 w:1)
 	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Validators` (r:1 w:0)
@@ -1251,14 +1229,14 @@ impl WeightInfo for () {
 	/// The range of component `s` is `[0, 100]`.
 	fn force_unstake(s: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `2255 + s * (4 ±0)`
+		//  Measured:  `2196 + s * (4 ±0)`
 		//  Estimated: `6248 + s * (4 ±0)`
-		// Minimum execution time: 119_955_000 picoseconds.
-		Weight::from_parts(128_392_032, 6248)
-			// Standard Error: 3_773
-			.saturating_add(Weight::from_parts(1_302_488, 0).saturating_mul(s.into()))
+		// Minimum execution time: 87_677_000 picoseconds.
+		Weight::from_parts(96_386_462, 6248)
+			// Standard Error: 3_717
+			.saturating_add(Weight::from_parts(1_370_585, 0).saturating_mul(s.into()))
 			.saturating_add(RocksDbWeight::get().reads(13_u64))
-			.saturating_add(RocksDbWeight::get().writes(13_u64))
+			.saturating_add(RocksDbWeight::get().writes(12_u64))
 			.saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into())))
 			.saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into()))
 	}
@@ -1267,12 +1245,12 @@ impl WeightInfo for () {
 	/// The range of component `s` is `[1, 1000]`.
 	fn cancel_deferred_slash(s: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `66705`
-		//  Estimated: `70170`
-		// Minimum execution time: 139_290_000 picoseconds.
-		Weight::from_parts(959_667_494, 70170)
-			// Standard Error: 56_271
-			.saturating_add(Weight::from_parts(4_798_293, 0).saturating_mul(s.into()))
+		//  Measured:  `66672`
+		//  Estimated: `70137`
+		// Minimum execution time: 105_086_000 picoseconds.
+		Weight::from_parts(1_167_895_222, 70137)
+			// Standard Error: 77_022
+			.saturating_add(Weight::from_parts(6_487_305, 0).saturating_mul(s.into()))
 			.saturating_add(RocksDbWeight::get().reads(1_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -1290,10 +1268,12 @@ impl WeightInfo for () {
 	/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::ErasValidatorReward` (r:1 w:0)
 	/// Proof: `Staking::ErasValidatorReward` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`)
-	/// Storage: `Staking::VirtualStakers` (r:257 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:257 w:257)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`)
+	/// Storage: `Balances::Locks` (r:257 w:257)
+	/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
+	/// Storage: `Balances::Freezes` (r:257 w:0)
+	/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`)
+	/// Storage: `System::Account` (r:257 w:257)
+	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::ErasStakersPaged` (r:1 w:0)
 	/// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	/// Storage: `Staking::ErasRewardPoints` (r:1 w:0)
@@ -1302,31 +1282,29 @@ impl WeightInfo for () {
 	/// Proof: `Staking::ErasValidatorPrefs` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`)
 	/// Storage: `Staking::Payee` (r:257 w:0)
 	/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
-	/// Storage: `System::Account` (r:257 w:257)
-	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
 	/// The range of component `n` is `[0, 256]`.
 	fn payout_stakers_alive_staked(n: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `33283 + n * (370 ±0)`
-		//  Estimated: `30958 + n * (3566 ±0)`
-		// Minimum execution time: 193_068_000 picoseconds.
-		Weight::from_parts(252_762_568, 30958)
-			// Standard Error: 22_743
-			.saturating_add(Weight::from_parts(81_185_306, 0).saturating_mul(n.into()))
+		//  Measured:  `33297 + n * (377 ±0)`
+		//  Estimated: `30944 + n * (3774 ±3)`
+		// Minimum execution time: 154_210_000 picoseconds.
+		Weight::from_parts(192_836_012, 30944)
+			// Standard Error: 40_441
+			.saturating_add(Weight::from_parts(47_646_642, 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))
 			.saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into())))
-			.saturating_add(Weight::from_parts(0, 3566).saturating_mul(n.into()))
+			.saturating_add(Weight::from_parts(0, 3774).saturating_mul(n.into()))
 	}
 	/// 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::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:0)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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: `VoterList::ListNodes` (r:3 w:3)
 	/// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`)
 	/// Storage: `VoterList::ListBags` (r:2 w:2)
@@ -1334,25 +1312,25 @@ impl WeightInfo for () {
 	/// The range of component `l` is `[1, 32]`.
 	fn rebond(l: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1947 + l * (7 ±0)`
+		//  Measured:  `1991 + l * (7 ±0)`
 		//  Estimated: `8877`
-		// Minimum execution time: 91_151_000 picoseconds.
-		Weight::from_parts(93_596_096, 8877)
-			// Standard Error: 5_313
-			.saturating_add(Weight::from_parts(124_684, 0).saturating_mul(l.into()))
+		// Minimum execution time: 88_337_000 picoseconds.
+		Weight::from_parts(91_391_254, 8877)
+			// Standard Error: 4_485
+			.saturating_add(Weight::from_parts(103_443, 0).saturating_mul(l.into()))
 			.saturating_add(RocksDbWeight::get().reads(9_u64))
-			.saturating_add(RocksDbWeight::get().writes(6_u64))
+			.saturating_add(RocksDbWeight::get().writes(7_u64))
 	}
-	/// Storage: `Staking::VirtualStakers` (r:1 w:1)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, 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: `Staking::SlashingSpans` (r:1 w:1)
 	/// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`)
-	/// Storage: `Balances::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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::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)
@@ -1372,14 +1350,14 @@ impl WeightInfo for () {
 	/// The range of component `s` is `[1, 100]`.
 	fn reap_stash(s: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `2255 + s * (4 ±0)`
+		//  Measured:  `2196 + s * (4 ±0)`
 		//  Estimated: `6248 + s * (4 ±0)`
-		// Minimum execution time: 133_214_000 picoseconds.
-		Weight::from_parts(137_290_527, 6248)
-			// Standard Error: 4_153
-			.saturating_add(Weight::from_parts(1_291_007, 0).saturating_mul(s.into()))
+		// Minimum execution time: 98_014_000 picoseconds.
+		Weight::from_parts(102_537_670, 6248)
+			// Standard Error: 3_324
+			.saturating_add(Weight::from_parts(1_353_142, 0).saturating_mul(s.into()))
 			.saturating_add(RocksDbWeight::get().reads(12_u64))
-			.saturating_add(RocksDbWeight::get().writes(12_u64))
+			.saturating_add(RocksDbWeight::get().writes(11_u64))
 			.saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into())))
 			.saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into()))
 	}
@@ -1423,12 +1401,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: 692_301_000 picoseconds.
-		Weight::from_parts(708_732_000, 512390)
-			// Standard Error: 2_117_299
-			.saturating_add(Weight::from_parts(70_087_600, 0).saturating_mul(v.into()))
-			// Standard Error: 210_977
-			.saturating_add(Weight::from_parts(22_953_405, 0).saturating_mul(n.into()))
+		// Minimum execution time: 608_575_000 picoseconds.
+		Weight::from_parts(613_663_000, 512390)
+			// Standard Error: 2_286_521
+			.saturating_add(Weight::from_parts(72_108_001, 0).saturating_mul(v.into()))
+			// Standard Error: 227_839
+			.saturating_add(Weight::from_parts(20_314_085, 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())))
@@ -1457,14 +1435,14 @@ impl WeightInfo for () {
 	/// The range of component `n` is `[500, 1000]`.
 	fn get_npos_voters(v: u32, n: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `3241 + n * (911 ±0) + v * (395 ±0)`
+		//  Measured:  `3175 + n * (911 ±0) + v * (395 ±0)`
 		//  Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)`
-		// Minimum execution time: 43_708_472_000 picoseconds.
-		Weight::from_parts(44_048_436_000, 512390)
-			// Standard Error: 493_244
-			.saturating_add(Weight::from_parts(6_697_278, 0).saturating_mul(v.into()))
-			// Standard Error: 493_244
-			.saturating_add(Weight::from_parts(4_559_779, 0).saturating_mul(n.into()))
+		// Minimum execution time: 37_173_756_000 picoseconds.
+		Weight::from_parts(37_488_937_000, 512390)
+			// Standard Error: 467_413
+			.saturating_add(Weight::from_parts(8_086_367, 0).saturating_mul(v.into()))
+			// Standard Error: 467_413
+			.saturating_add(Weight::from_parts(3_108_193, 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())))
@@ -1479,12 +1457,12 @@ impl WeightInfo for () {
 	/// The range of component `v` is `[500, 1000]`.
 	fn get_npos_targets(v: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1012 + v * (50 ±0)`
+		//  Measured:  `979 + v * (50 ±0)`
 		//  Estimated: `3510 + v * (2520 ±0)`
-		// Minimum execution time: 2_917_165_000 picoseconds.
-		Weight::from_parts(2_948_999_000, 3510)
-			// Standard Error: 33_372
-			.saturating_add(Weight::from_parts(2_126_909, 0).saturating_mul(v.into()))
+		// Minimum execution time: 2_641_258_000 picoseconds.
+		Weight::from_parts(382_882_595, 3510)
+			// Standard Error: 11_991
+			.saturating_add(Weight::from_parts(4_695_820, 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()))
@@ -1507,8 +1485,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 4_748_000 picoseconds.
-		Weight::from_parts(5_052_000, 0)
+		// Minimum execution time: 5_753_000 picoseconds.
+		Weight::from_parts(6_529_000, 0)
 			.saturating_add(RocksDbWeight::get().writes(7_u64))
 	}
 	/// Storage: `Staking::MinCommission` (r:0 w:1)
@@ -1529,8 +1507,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 4_316_000 picoseconds.
-		Weight::from_parts(4_526_000, 0)
+		// Minimum execution time: 5_212_000 picoseconds.
+		Weight::from_parts(5_451_000, 0)
 			.saturating_add(RocksDbWeight::get().writes(7_u64))
 	}
 	/// Storage: `Staking::Bonded` (r:1 w:0)
@@ -1557,10 +1535,10 @@ impl WeightInfo for () {
 	/// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	fn chill_other() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `2005`
+		//  Measured:  `1939`
 		//  Estimated: `6248`
-		// Minimum execution time: 87_374_000 picoseconds.
-		Weight::from_parts(89_848_000, 6248)
+		// Minimum execution time: 73_000_000 picoseconds.
+		Weight::from_parts(75_184_000, 6248)
 			.saturating_add(RocksDbWeight::get().reads(12_u64))
 			.saturating_add(RocksDbWeight::get().writes(6_u64))
 	}
@@ -1570,10 +1548,10 @@ impl WeightInfo for () {
 	/// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`)
 	fn force_apply_min_commission() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `724`
+		//  Measured:  `691`
 		//  Estimated: `3510`
-		// Minimum execution time: 15_529_000 picoseconds.
-		Weight::from_parts(16_094_000, 3510)
+		// Minimum execution time: 13_056_000 picoseconds.
+		Weight::from_parts(13_517_000, 3510)
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -1583,50 +1561,27 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_533_000 picoseconds.
-		Weight::from_parts(2_817_000, 0)
+		// Minimum execution time: 3_201_000 picoseconds.
+		Weight::from_parts(3_442_000, 0)
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
-	/// Storage: `Staking::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Holds` (r:1 w:0)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`)
-	/// Storage: `System::Account` (r:1 w:0)
-	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
-	/// Storage: `Balances::Locks` (r:1 w:0)
+	/// 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`)
-	fn restore_ledger() -> Weight {
-		// Proof Size summary in bytes:
-		//  Measured:  `1110`
-		//  Estimated: `4764`
-		// Minimum execution time: 50_105_000 picoseconds.
-		Weight::from_parts(50_966_000, 4764)
-			.saturating_add(RocksDbWeight::get().reads(6_u64))
-			.saturating_add(RocksDbWeight::get().writes(2_u64))
-	}
-	/// Storage: `Staking::VirtualStakers` (r:1 w:0)
-	/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, 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::Ledger` (r:1 w:0)
-	/// 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::Holds` (r:1 w:1)
-	/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`)
 	/// Storage: `Balances::Freezes` (r:1 w:0)
 	/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`)
-	fn migrate_currency() -> Weight {
+	fn restore_ledger() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `1246`
+		//  Measured:  `1047`
 		//  Estimated: `4764`
-		// Minimum execution time: 94_054_000 picoseconds.
-		Weight::from_parts(96_272_000, 4764)
-			.saturating_add(RocksDbWeight::get().reads(6_u64))
-			.saturating_add(RocksDbWeight::get().writes(2_u64))
+		// Minimum execution time: 44_671_000 picoseconds.
+		Weight::from_parts(45_611_000, 4764)
+			.saturating_add(RocksDbWeight::get().reads(5_u64))
+			.saturating_add(RocksDbWeight::get().writes(4_u64))
 	}
 }
\ No newline at end of file
diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs
index 8e23c6800a9d53a240261b51a7f87dd20017b9e0..17010a8907fc23325d2726e59285313f5fea53a6 100644
--- a/substrate/primitives/staking/src/lib.rs
+++ b/substrate/primitives/staking/src/lib.rs
@@ -325,7 +325,7 @@ pub trait StakingUnchecked: StakingInterface {
 	/// Migrate an existing staker to a virtual staker.
 	///
 	/// It would release all funds held by the implementation pallet.
-	fn migrate_to_virtual_staker(who: &Self::AccountId) -> DispatchResult;
+	fn migrate_to_virtual_staker(who: &Self::AccountId);
 
 	/// Book-keep a new bond for `keyless_who` without applying any locks (hence virtual).
 	///