referrerpolicy=no-referrer-when-downgrade

pallet_nomination_pools_test_delegate_stake/
lib.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18#![cfg(test)]
19
20// We do not declare all features used by `construct_runtime`
21#[allow(unexpected_cfgs)]
22mod mock;
23
24use frame_support::{
25	assert_noop, assert_ok, hypothetically,
26	traits::{
27		fungible::{InspectHold, Mutate},
28		Currency,
29	},
30};
31use mock::*;
32use pallet_nomination_pools::{
33	BondExtra, BondedPools, CommissionChangeRate, ConfigOp, Error as PoolsError,
34	Event as PoolsEvent, LastPoolId, PoolMember, PoolMembers, PoolState,
35};
36use pallet_staking::{
37	CurrentEra, Error as StakingError, Event as StakingEvent, Payee, RewardDestination,
38};
39
40use pallet_delegated_staking::Event as DelegatedStakingEvent;
41
42use sp_runtime::{bounded_btree_map, traits::Zero, Perbill};
43use sp_staking::Agent;
44
45#[test]
46fn pool_lifecycle_e2e() {
47	new_test_ext().execute_with(|| {
48		assert_eq!(Balances::minimum_balance(), 5);
49		assert_eq!(CurrentEra::<T>::get(), None);
50
51		// create the pool, we know this has id 1.
52		assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10));
53		assert_eq!(LastPoolId::<Runtime>::get(), 1);
54
55		// have the pool nominate.
56		assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]));
57
58		assert_eq!(
59			staking_events_since_last_call(),
60			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }]
61		);
62		assert_eq!(
63			pool_events_since_last_call(),
64			vec![
65				PoolsEvent::Created { depositor: 10, pool_id: 1 },
66				PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true },
67				PoolsEvent::PoolNominationMade { pool_id: 1, caller: 10 },
68			]
69		);
70
71		// have two members join
72		assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1));
73		assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1));
74
75		assert_eq!(
76			staking_events_since_last_call(),
77			vec![
78				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 },
79				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 },
80			]
81		);
82		assert_eq!(
83			pool_events_since_last_call(),
84			vec![
85				PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true },
86				PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true },
87			]
88		);
89
90		// pool goes into destroying
91		assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying));
92
93		// depositor cannot unbond yet.
94		assert_noop!(
95			Pools::unbond(RuntimeOrigin::signed(10), 10, 50),
96			PoolsError::<Runtime>::MinimumBondNotMet,
97		);
98
99		// now the members want to unbond.
100		assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10));
101		assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10));
102
103		assert_eq!(PoolMembers::<Runtime>::get(20).unwrap().unbonding_eras.len(), 1);
104		assert_eq!(PoolMembers::<Runtime>::get(20).unwrap().points, 0);
105		assert_eq!(PoolMembers::<Runtime>::get(21).unwrap().unbonding_eras.len(), 1);
106		assert_eq!(PoolMembers::<Runtime>::get(21).unwrap().points, 0);
107
108		assert_eq!(
109			staking_events_since_last_call(),
110			vec![
111				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
112				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
113			]
114		);
115		assert_eq!(
116			pool_events_since_last_call(),
117			vec![
118				PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying },
119				PoolsEvent::Unbonded { member: 20, pool_id: 1, points: 10, balance: 10, era: 3 },
120				PoolsEvent::Unbonded { member: 21, pool_id: 1, points: 10, balance: 10, era: 3 },
121			]
122		);
123
124		// depositor cannot still unbond
125		assert_noop!(
126			Pools::unbond(RuntimeOrigin::signed(10), 10, 50),
127			PoolsError::<Runtime>::MinimumBondNotMet,
128		);
129
130		for e in 1..BondingDuration::get() {
131			CurrentEra::<Runtime>::set(Some(e));
132			assert_noop!(
133				Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0),
134				PoolsError::<Runtime>::CannotWithdrawAny
135			);
136		}
137
138		// members are now unlocked.
139		CurrentEra::<Runtime>::set(Some(BondingDuration::get()));
140
141		// depositor cannot still unbond
142		assert_noop!(
143			Pools::unbond(RuntimeOrigin::signed(10), 10, 50),
144			PoolsError::<Runtime>::MinimumBondNotMet,
145		);
146
147		// but members can now withdraw.
148		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0));
149		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0));
150		assert!(PoolMembers::<Runtime>::get(20).is_none());
151		assert!(PoolMembers::<Runtime>::get(21).is_none());
152
153		assert_eq!(
154			staking_events_since_last_call(),
155			vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 },]
156		);
157		assert_eq!(
158			pool_events_since_last_call(),
159			vec![
160				PoolsEvent::Withdrawn { member: 20, pool_id: 1, points: 10, balance: 10 },
161				PoolsEvent::MemberRemoved { pool_id: 1, member: 20, released_balance: 0 },
162				PoolsEvent::Withdrawn { member: 21, pool_id: 1, points: 10, balance: 10 },
163				PoolsEvent::MemberRemoved { pool_id: 1, member: 21, released_balance: 0 },
164			]
165		);
166
167		assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 50));
168
169		assert_eq!(
170			staking_events_since_last_call(),
171			vec![
172				StakingEvent::Chilled { stash: POOL1_BONDED },
173				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 50 },
174			]
175		);
176		assert_eq!(
177			pool_events_since_last_call(),
178			vec![PoolsEvent::Unbonded { member: 10, pool_id: 1, points: 50, balance: 50, era: 6 },]
179		);
180
181		// waiting another bonding duration:
182		CurrentEra::<Runtime>::set(Some(BondingDuration::get() * 2));
183		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 1));
184
185		// pools is fully destroyed now.
186		assert_eq!(
187			staking_events_since_last_call(),
188			vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 50 },]
189		);
190		assert_eq!(
191			pool_events_since_last_call(),
192			vec![
193				PoolsEvent::Withdrawn { member: 10, pool_id: 1, points: 50, balance: 50 },
194				PoolsEvent::MemberRemoved { pool_id: 1, member: 10, released_balance: 0 },
195				PoolsEvent::Destroyed { pool_id: 1 }
196			]
197		);
198	})
199}
200
201#[test]
202fn pool_chill_e2e() {
203	new_test_ext().execute_with(|| {
204		assert_eq!(Balances::minimum_balance(), 5);
205		assert_eq!(CurrentEra::<T>::get(), None);
206
207		// create the pool, we know this has id 1.
208		assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10));
209		assert_eq!(LastPoolId::<Runtime>::get(), 1);
210
211		// have the pool nominate.
212		assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]));
213
214		assert_eq!(
215			staking_events_since_last_call(),
216			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }]
217		);
218		assert_eq!(
219			pool_events_since_last_call(),
220			vec![
221				PoolsEvent::Created { depositor: 10, pool_id: 1 },
222				PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true },
223				PoolsEvent::PoolNominationMade { pool_id: 1, caller: 10 },
224			]
225		);
226
227		// have two members join
228		assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1));
229		assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1));
230
231		assert_eq!(
232			staking_events_since_last_call(),
233			vec![
234				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 },
235				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 },
236			]
237		);
238		assert_eq!(
239			pool_events_since_last_call(),
240			vec![
241				PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true },
242				PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true },
243			]
244		);
245
246		// in case depositor does not have more than `MinNominatorBond` staked, we can end up in
247		// situation where a member unbonding would cause pool balance to drop below
248		// `MinNominatorBond` and hence not allowed. This can happen if the `MinNominatorBond` is
249		// increased after the pool is created.
250		assert_ok!(Staking::set_staking_configs(
251			RuntimeOrigin::root(),
252			pallet_staking::ConfigOp::Set(55), // minimum nominator bond
253			pallet_staking::ConfigOp::Noop,
254			pallet_staking::ConfigOp::Noop,
255			pallet_staking::ConfigOp::Noop,
256			pallet_staking::ConfigOp::Noop,
257			pallet_staking::ConfigOp::Noop,
258			pallet_staking::ConfigOp::Noop,
259		));
260
261		// members can unbond as long as total stake of the pool is above min nominator bond
262		assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10),);
263		assert_eq!(PoolMembers::<Runtime>::get(20).unwrap().unbonding_eras.len(), 1);
264		assert_eq!(PoolMembers::<Runtime>::get(20).unwrap().points, 0);
265
266		// this member cannot unbond since it will cause `pool stake < MinNominatorBond`
267		assert_noop!(
268			Pools::unbond(RuntimeOrigin::signed(21), 21, 10),
269			StakingError::<Runtime>::InsufficientBond,
270		);
271
272		// members can call `chill` permissionlessly now
273		assert_ok!(Pools::chill(RuntimeOrigin::signed(20), 1));
274
275		// now another member can unbond.
276		assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10));
277		assert_eq!(PoolMembers::<Runtime>::get(21).unwrap().unbonding_eras.len(), 1);
278		assert_eq!(PoolMembers::<Runtime>::get(21).unwrap().points, 0);
279
280		// nominator can not resume nomination until depositor have enough stake
281		assert_noop!(
282			Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]),
283			PoolsError::<Runtime>::MinimumBondNotMet,
284		);
285
286		// other members joining pool does not affect the depositor's ability to resume nomination
287		assert_ok!(Pools::join(RuntimeOrigin::signed(22), 10, 1));
288
289		assert_noop!(
290			Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]),
291			PoolsError::<Runtime>::MinimumBondNotMet,
292		);
293
294		// depositor can bond extra stake
295		assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10)));
296
297		// `chill` can not be called permissionlessly anymore
298		assert_noop!(
299			Pools::chill(RuntimeOrigin::signed(20), 1),
300			PoolsError::<Runtime>::NotNominator,
301		);
302
303		// now nominator can resume nomination
304		assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]));
305
306		// skip to make the unbonding period end.
307		CurrentEra::<Runtime>::set(Some(BondingDuration::get()));
308
309		// members can now withdraw.
310		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0));
311		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0));
312
313		assert_eq!(
314			staking_events_since_last_call(),
315			vec![
316				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
317				StakingEvent::Chilled { stash: POOL1_BONDED },
318				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
319				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // other member bonding
320				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // depositor bond extra
321				StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 },
322			]
323		);
324	})
325}
326
327#[test]
328fn pool_slash_e2e() {
329	new_test_ext().execute_with(|| {
330		ExistentialDeposit::set(1);
331		assert_eq!(Balances::minimum_balance(), 1);
332		assert_eq!(CurrentEra::<T>::get(), None);
333
334		// create the pool, we know this has id 1.
335		assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10));
336		assert_eq!(LastPoolId::<Runtime>::get(), 1);
337
338		assert_eq!(
339			staking_events_since_last_call(),
340			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }]
341		);
342		assert_eq!(
343			pool_events_since_last_call(),
344			vec![
345				PoolsEvent::Created { depositor: 10, pool_id: 1 },
346				PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true },
347			]
348		);
349
350		assert_eq!(
351			Payee::<Runtime>::get(POOL1_BONDED),
352			Some(RewardDestination::Account(POOL1_REWARD))
353		);
354
355		// have two members join
356		assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1));
357		assert_ok!(Pools::join(RuntimeOrigin::signed(21), 20, 1));
358
359		assert_eq!(
360			staking_events_since_last_call(),
361			vec![
362				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 20 },
363				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 20 }
364			]
365		);
366		assert_eq!(
367			pool_events_since_last_call(),
368			vec![
369				PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true },
370				PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 20, joined: true },
371			]
372		);
373
374		// now let's progress a bit.
375		CurrentEra::<Runtime>::set(Some(1));
376
377		// 20 / 80 of the total funds are unlocked, and safe from any further slash.
378		assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 10));
379		assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10));
380
381		assert_eq!(
382			staking_events_since_last_call(),
383			vec![
384				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
385				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }
386			]
387		);
388		assert_eq!(
389			pool_events_since_last_call(),
390			vec![
391				PoolsEvent::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10, era: 4 },
392				PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10, era: 4 }
393			]
394		);
395
396		CurrentEra::<Runtime>::set(Some(2));
397
398		// note: depositor cannot fully unbond at this point.
399		// these funds will still get slashed.
400		assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 10));
401		assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10));
402		assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10));
403
404		assert_eq!(
405			staking_events_since_last_call(),
406			vec![
407				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
408				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
409				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
410			]
411		);
412
413		assert_eq!(
414			pool_events_since_last_call(),
415			vec![
416				PoolsEvent::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10, era: 5 },
417				PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10, era: 5 },
418				PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 10, points: 10, era: 5 },
419			]
420		);
421
422		// At this point, 20 are safe from slash, 30 are unlocking but vulnerable to slash, and and
423		// another 30 are active and vulnerable to slash. Let's slash half of them.
424		pallet_staking::slashing::do_slash::<Runtime>(
425			&POOL1_BONDED,
426			30,
427			&mut Default::default(),
428			&mut Default::default(),
429			2, // slash era 2, affects chunks at era 5 onwards.
430		);
431
432		assert_eq!(
433			staking_events_since_last_call(),
434			vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 30 }]
435		);
436		assert_eq!(
437			pool_events_since_last_call(),
438			vec![
439				// 30 has been slashed to 15 (15 slash)
440				PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 5, balance: 15 },
441				// 30 has been slashed to 15 (15 slash)
442				PoolsEvent::PoolSlashed { pool_id: 1, balance: 15 }
443			]
444		);
445
446		CurrentEra::<Runtime>::set(Some(3));
447		assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10));
448
449		assert_eq!(
450			PoolMembers::<Runtime>::get(21).unwrap(),
451			PoolMember {
452				pool_id: 1,
453				points: 0,
454				last_recorded_reward_counter: Zero::zero(),
455				// the 10 points unlocked just now correspond to 5 points in the unbond pool.
456				unbonding_eras: bounded_btree_map!(5 => 10, 6 => 5)
457			}
458		);
459		assert_eq!(
460			staking_events_since_last_call(),
461			vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5 }]
462		);
463		assert_eq!(
464			pool_events_since_last_call(),
465			vec![PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 5, points: 5, era: 6 }]
466		);
467
468		// now we start withdrawing. we do it all at once, at era 6 where 20 and 21 are fully free.
469		CurrentEra::<Runtime>::set(Some(6));
470		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0));
471		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0));
472
473		assert_eq!(
474			pool_events_since_last_call(),
475			vec![
476				// 20 had unbonded 10 safely, and 10 got slashed by half.
477				PoolsEvent::Withdrawn { member: 20, pool_id: 1, balance: 10 + 5, points: 20 },
478				PoolsEvent::MemberRemoved { pool_id: 1, member: 20, released_balance: 0 },
479				// 21 unbonded all of it after the slash
480				PoolsEvent::Withdrawn { member: 21, pool_id: 1, balance: 5 + 5, points: 15 },
481				PoolsEvent::MemberRemoved { pool_id: 1, member: 21, released_balance: 0 }
482			]
483		);
484		assert_eq!(
485			staking_events_since_last_call(),
486			// a 10 (un-slashed) + 10/2 (slashed) balance from 10 has also been unlocked
487			vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 15 + 10 + 15 }]
488		);
489
490		// now, finally, we can unbond the depositor further than their current limit.
491		assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying));
492		assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 20));
493
494		assert_eq!(
495			staking_events_since_last_call(),
496			vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }]
497		);
498		assert_eq!(
499			pool_events_since_last_call(),
500			vec![
501				PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying },
502				PoolsEvent::Unbonded { member: 10, pool_id: 1, points: 10, balance: 10, era: 9 }
503			]
504		);
505
506		CurrentEra::<Runtime>::set(Some(9));
507		assert_eq!(
508			PoolMembers::<Runtime>::get(10).unwrap(),
509			PoolMember {
510				pool_id: 1,
511				points: 0,
512				last_recorded_reward_counter: Zero::zero(),
513				unbonding_eras: bounded_btree_map!(4 => 10, 5 => 10, 9 => 10)
514			}
515		);
516		// withdraw the depositor, they should lose 12 balance in total due to slash.
517		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0));
518
519		assert_eq!(
520			staking_events_since_last_call(),
521			vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 10 }]
522		);
523		assert_eq!(
524			pool_events_since_last_call(),
525			vec![
526				PoolsEvent::Withdrawn { member: 10, pool_id: 1, balance: 10 + 15, points: 30 },
527				PoolsEvent::MemberRemoved { pool_id: 1, member: 10, released_balance: 0 },
528				PoolsEvent::Destroyed { pool_id: 1 }
529			]
530		);
531	});
532}
533
534#[test]
535fn pool_slash_proportional() {
536	// a typical example where 3 pool members unbond in era 99, 100, and 101, and a slash that
537	// happened in era 100 should only affect the latter two.
538	new_test_ext().execute_with(|| {
539		ExistentialDeposit::set(2);
540		BondingDuration::set(28);
541		assert_eq!(Balances::minimum_balance(), 2);
542		assert_eq!(Staking::current_era(), None);
543
544		// create the pool, we know this has id 1.
545		assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10));
546		assert_eq!(LastPoolId::<T>::get(), 1);
547
548		assert_eq!(
549			staking_events_since_last_call(),
550			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }]
551		);
552		assert_eq!(
553			delegated_staking_events_since_last_call(),
554			vec![DelegatedStakingEvent::Delegated {
555				agent: POOL1_BONDED,
556				delegator: 10,
557				amount: 40
558			}]
559		);
560		assert_eq!(
561			pool_events_since_last_call(),
562			vec![
563				PoolsEvent::Created { depositor: 10, pool_id: 1 },
564				PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true },
565			]
566		);
567
568		// have two members join
569		let bond = 20;
570		assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1));
571		assert_ok!(Pools::join(RuntimeOrigin::signed(21), bond, 1));
572		assert_ok!(Pools::join(RuntimeOrigin::signed(22), bond, 1));
573
574		assert_eq!(
575			staking_events_since_last_call(),
576			vec![
577				StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond },
578				StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond },
579				StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond },
580			]
581		);
582		assert_eq!(
583			delegated_staking_events_since_last_call(),
584			vec![
585				DelegatedStakingEvent::Delegated {
586					agent: POOL1_BONDED,
587					delegator: 20,
588					amount: bond
589				},
590				DelegatedStakingEvent::Delegated {
591					agent: POOL1_BONDED,
592					delegator: 21,
593					amount: bond
594				},
595				DelegatedStakingEvent::Delegated {
596					agent: POOL1_BONDED,
597					delegator: 22,
598					amount: bond
599				}
600			]
601		);
602		assert_eq!(
603			pool_events_since_last_call(),
604			vec![
605				PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true },
606				PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: bond, joined: true },
607				PoolsEvent::Bonded { member: 22, pool_id: 1, bonded: bond, joined: true },
608			]
609		);
610
611		// now let's progress a lot.
612		CurrentEra::<T>::set(Some(99));
613
614		// and unbond
615		assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond));
616
617		assert_eq!(
618			staking_events_since_last_call(),
619			vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },]
620		);
621		assert_eq!(
622			pool_events_since_last_call(),
623			vec![PoolsEvent::Unbonded {
624				member: 20,
625				pool_id: 1,
626				balance: bond,
627				points: bond,
628				era: 127
629			}]
630		);
631
632		CurrentEra::<T>::set(Some(100));
633		assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, bond));
634		assert_eq!(
635			staking_events_since_last_call(),
636			vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },]
637		);
638		assert_eq!(
639			pool_events_since_last_call(),
640			vec![PoolsEvent::Unbonded {
641				member: 21,
642				pool_id: 1,
643				balance: bond,
644				points: bond,
645				era: 128
646			}]
647		);
648
649		CurrentEra::<T>::set(Some(101));
650		assert_ok!(Pools::unbond(RuntimeOrigin::signed(22), 22, bond));
651		assert_eq!(
652			staking_events_since_last_call(),
653			vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },]
654		);
655		assert_eq!(
656			pool_events_since_last_call(),
657			vec![PoolsEvent::Unbonded {
658				member: 22,
659				pool_id: 1,
660				balance: bond,
661				points: bond,
662				era: 129
663			}]
664		);
665
666		// Apply a slash that happened in era 100. This is typically applied with a delay.
667		// Of the total 100, 50 is slashed.
668		assert_eq!(BondedPools::<T>::get(1).unwrap().points, 40);
669
670		// no pending slash yet.
671		assert_eq!(Pools::api_pool_pending_slash(1), 0);
672		// and therefore applying slash fails
673		assert_noop!(
674			Pools::apply_slash(RuntimeOrigin::signed(10), 21),
675			PoolsError::<Runtime>::NothingToSlash
676		);
677
678		hypothetically!({
679			// a very small amount is slashed
680			pallet_staking::slashing::do_slash::<Runtime>(
681				&POOL1_BONDED,
682				3,
683				&mut Default::default(),
684				&mut Default::default(),
685				100,
686			);
687
688			// ensure correct amount is pending to be slashed
689			assert_eq!(Pools::api_pool_pending_slash(1), 3);
690
691			// 21 has pending slash lower than ED (2)
692			assert_eq!(Pools::api_member_pending_slash(21), 1);
693
694			// slash fails as minimum pending slash amount not met.
695			assert_noop!(
696				Pools::apply_slash(RuntimeOrigin::signed(10), 21),
697				PoolsError::<Runtime>::SlashTooLow
698			);
699		});
700
701		pallet_staking::slashing::do_slash::<Runtime>(
702			&POOL1_BONDED,
703			50,
704			&mut Default::default(),
705			&mut Default::default(),
706			100,
707		);
708
709		// Pools api returns correct slash amount.
710		assert_eq!(Pools::api_pool_pending_slash(1), 50);
711
712		assert_eq!(
713			staking_events_since_last_call(),
714			vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 50 }]
715		);
716		assert_eq!(
717			pool_events_since_last_call(),
718			vec![
719				// This era got slashed 12.5, which rounded up to 13.
720				PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 128, balance: 7 },
721				// This era got slashed 12 instead of 12.5 because an earlier chunk got 0.5 more
722				// slashed, and 12 is all the remaining slash
723				PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 129, balance: 8 },
724				// Bonded pool got slashed for 25, remaining 15 in it.
725				PoolsEvent::PoolSlashed { pool_id: 1, balance: 15 }
726			]
727		);
728
729		// 21's balance in the pool is slashed.
730		assert_eq!(PoolMembers::<Runtime>::get(21).unwrap().total_balance(), 7);
731		// But their actual balance is still unslashed.
732		assert_eq!(Balances::total_balance_on_hold(&21), bond);
733		// 21 has pending slash
734		assert_eq!(Pools::api_member_pending_slash(21), bond - 7);
735		// apply slash permissionlessly.
736		assert_ok!(Pools::apply_slash(RuntimeOrigin::signed(10), 21));
737		// member balance is slashed.
738		assert_eq!(Balances::total_balance_on_hold(&21), 7);
739		// 21 has no pending slash anymore
740		assert_eq!(Pools::api_member_pending_slash(21), 0);
741
742		assert_eq!(
743			delegated_staking_events_since_last_call(),
744			vec![DelegatedStakingEvent::Slashed {
745				agent: POOL1_BONDED,
746				delegator: 21,
747				amount: bond - 7
748			}]
749		);
750
751		// 22 balance isn't slashed yet as well.
752		assert_eq!(PoolMembers::<Runtime>::get(22).unwrap().total_balance(), 8);
753		assert_eq!(Balances::total_balance_on_hold(&22), bond);
754
755		// they try to withdraw. This should slash them.
756		CurrentEra::<T>::set(Some(129));
757		let pre_balance = Balances::free_balance(&22);
758		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(22), 22, 0));
759		// all balance should be released.
760		assert_eq!(Balances::total_balance_on_hold(&22), 0);
761		assert_eq!(Balances::free_balance(&22), pre_balance + 8);
762
763		assert_eq!(
764			delegated_staking_events_since_last_call(),
765			vec![
766				DelegatedStakingEvent::Slashed {
767					agent: POOL1_BONDED,
768					delegator: 22,
769					amount: bond - 8
770				},
771				DelegatedStakingEvent::Released { agent: POOL1_BONDED, delegator: 22, amount: 8 },
772			]
773		);
774	});
775}
776
777#[test]
778fn pool_slash_non_proportional_only_bonded_pool() {
779	// A typical example where a pool member unbonds in era 99, and they can get away with a slash
780	// that happened in era 100, as long as the pool has enough active bond to cover the slash. If
781	// everything else in the slashing/staking system works, this should always be the case.
782	// Nonetheless, `ledger.slash` has been written such that it will slash greedily from any chunk
783	// if it runs out of chunks that it thinks should be affected by the slash.
784	new_test_ext().execute_with(|| {
785		ExistentialDeposit::set(1);
786		BondingDuration::set(28);
787		assert_eq!(Balances::minimum_balance(), 1);
788		assert_eq!(CurrentEra::<T>::get(), None);
789
790		// create the pool, we know this has id 1.
791		assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10));
792		assert_eq!(
793			staking_events_since_last_call(),
794			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }]
795		);
796		assert_eq!(
797			pool_events_since_last_call(),
798			vec![
799				PoolsEvent::Created { depositor: 10, pool_id: 1 },
800				PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true },
801			]
802		);
803
804		// have two members join
805		let bond = 20;
806		assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1));
807		assert_eq!(
808			staking_events_since_last_call(),
809			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }]
810		);
811		assert_eq!(
812			pool_events_since_last_call(),
813			vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }]
814		);
815
816		// progress and unbond.
817		CurrentEra::<T>::set(Some(99));
818		assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond));
819		assert_eq!(
820			staking_events_since_last_call(),
821			vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond }]
822		);
823		assert_eq!(
824			pool_events_since_last_call(),
825			vec![PoolsEvent::Unbonded {
826				member: 20,
827				pool_id: 1,
828				balance: bond,
829				points: bond,
830				era: 127
831			}]
832		);
833
834		// slash for 30. This will be deducted only from the bonded pool.
835		CurrentEra::<T>::set(Some(100));
836		assert_eq!(BondedPools::<T>::get(1).unwrap().points, 40);
837		pallet_staking::slashing::do_slash::<Runtime>(
838			&POOL1_BONDED,
839			30,
840			&mut Default::default(),
841			&mut Default::default(),
842			100,
843		);
844
845		assert_eq!(
846			staking_events_since_last_call(),
847			vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 30 }]
848		);
849		assert_eq!(
850			pool_events_since_last_call(),
851			vec![PoolsEvent::PoolSlashed { pool_id: 1, balance: 10 }]
852		);
853	});
854}
855
856#[test]
857fn pool_slash_non_proportional_bonded_pool_and_chunks() {
858	// An uncommon example where even though some funds are unlocked such that they should not be
859	// affected by a slash, we still slash out of them. This should not happen at all. If a
860	// nomination has unbonded, from the next era onwards, their exposure will drop, so if an era
861	// happens in that era, then their share of that slash should naturally be less, such that only
862	// their active ledger stake is enough to compensate it.
863	new_test_ext().execute_with(|| {
864		ExistentialDeposit::set(1);
865		BondingDuration::set(28);
866		assert_eq!(Balances::minimum_balance(), 1);
867		assert_eq!(CurrentEra::<T>::get(), None);
868
869		// create the pool, we know this has id 1.
870		assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10));
871		assert_eq!(
872			staking_events_since_last_call(),
873			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }]
874		);
875		assert_eq!(
876			pool_events_since_last_call(),
877			vec![
878				PoolsEvent::Created { depositor: 10, pool_id: 1 },
879				PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true },
880			]
881		);
882
883		// have two members join
884		let bond = 20;
885		assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1));
886		assert_eq!(
887			staking_events_since_last_call(),
888			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }]
889		);
890		assert_eq!(
891			pool_events_since_last_call(),
892			vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }]
893		);
894
895		// progress and unbond.
896		CurrentEra::<T>::set(Some(99));
897		assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond));
898		assert_eq!(
899			staking_events_since_last_call(),
900			vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond }]
901		);
902		assert_eq!(
903			pool_events_since_last_call(),
904			vec![PoolsEvent::Unbonded {
905				member: 20,
906				pool_id: 1,
907				balance: bond,
908				points: bond,
909				era: 127
910			}]
911		);
912
913		// slash 50. This will be deducted only from the bonded pool and one of the unbonding pools.
914		CurrentEra::<T>::set(Some(100));
915		assert_eq!(BondedPools::<T>::get(1).unwrap().points, 40);
916		pallet_staking::slashing::do_slash::<Runtime>(
917			&POOL1_BONDED,
918			50,
919			&mut Default::default(),
920			&mut Default::default(),
921			100,
922		);
923
924		assert_eq!(
925			staking_events_since_last_call(),
926			vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 50 }]
927		);
928		assert_eq!(
929			pool_events_since_last_call(),
930			vec![
931				// out of 20, 10 was taken.
932				PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 127, balance: 10 },
933				// out of 40, all was taken.
934				PoolsEvent::PoolSlashed { pool_id: 1, balance: 0 }
935			]
936		);
937	});
938}
939
940#[test]
941fn pool_migration_e2e() {
942	new_test_ext().execute_with(|| {
943		LegacyAdapter::set(true);
944		assert_eq!(CurrentEra::<T>::get(), None);
945
946		// hack: mint ED to pool so that the deprecated `TransferStake` works correctly with
947		// staking.
948		assert_eq!(Balances::minimum_balance(), 5);
949		assert_ok!(Balances::mint_into(&POOL1_BONDED, 5));
950
951		// create the pool with TransferStake strategy.
952		assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10));
953		assert_eq!(LastPoolId::<Runtime>::get(), 1);
954
955		// have the pool nominate.
956		assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]));
957
958		assert_eq!(
959			staking_events_since_last_call(),
960			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }]
961		);
962		assert_eq!(
963			pool_events_since_last_call(),
964			vec![
965				PoolsEvent::Created { depositor: 10, pool_id: 1 },
966				PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true },
967				PoolsEvent::PoolNominationMade { pool_id: 1, caller: 10 }
968			]
969		);
970
971		// have three members join
972		let pre_20 = Balances::free_balance(20);
973		assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1));
974		let pre_21 = Balances::free_balance(21);
975		assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1));
976		let pre_22 = Balances::free_balance(22);
977		assert_ok!(Pools::join(RuntimeOrigin::signed(22), 10, 1));
978
979		// verify members balance is moved to pool.
980		assert_eq!(Balances::free_balance(20), pre_20 - 10);
981		assert_eq!(Balances::free_balance(21), pre_21 - 10);
982		assert_eq!(Balances::free_balance(22), pre_22 - 10);
983
984		assert_eq!(
985			staking_events_since_last_call(),
986			vec![
987				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 },
988				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 },
989				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 },
990			]
991		);
992		assert_eq!(
993			pool_events_since_last_call(),
994			vec![
995				PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true },
996				PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true },
997				PoolsEvent::Bonded { member: 22, pool_id: 1, bonded: 10, joined: true },
998			]
999		);
1000
1001		CurrentEra::<Runtime>::set(Some(2));
1002		// 20 is partially unbonding
1003		assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5));
1004
1005		CurrentEra::<Runtime>::set(Some(3));
1006		// 21 is fully unbonding
1007		assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10));
1008
1009		assert_eq!(
1010			staking_events_since_last_call(),
1011			vec![
1012				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5 },
1013				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
1014			]
1015		);
1016		assert_eq!(
1017			pool_events_since_last_call(),
1018			vec![
1019				PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 5, points: 5, era: 5 },
1020				PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 10, points: 10, era: 6 },
1021			]
1022		);
1023
1024		// with `TransferStake`, we can't migrate.
1025		assert!(!Pools::api_pool_needs_delegate_migration(1));
1026		assert_noop!(
1027			Pools::migrate_pool_to_delegate_stake(RuntimeOrigin::signed(10), 1),
1028			PoolsError::<Runtime>::NotSupported
1029		);
1030
1031		// we reset the adapter to `DelegateStake`.
1032		LegacyAdapter::set(false);
1033
1034		// cannot migrate the member delegation unless pool is migrated first.
1035		assert_noop!(
1036			Pools::migrate_delegation(RuntimeOrigin::signed(10), 20),
1037			PoolsError::<Runtime>::NotMigrated
1038		);
1039
1040		// migrate the pool.
1041		assert!(Pools::api_pool_needs_delegate_migration(1));
1042		assert_ok!(Pools::migrate_pool_to_delegate_stake(RuntimeOrigin::signed(10), 1));
1043
1044		// migrate again does not work.
1045		assert!(!Pools::api_pool_needs_delegate_migration(1));
1046		assert_noop!(
1047			Pools::migrate_pool_to_delegate_stake(RuntimeOrigin::signed(10), 1),
1048			PoolsError::<Runtime>::AlreadyMigrated
1049		);
1050
1051		// unclaimed delegations to the pool are stored in this account.
1052		let proxy_delegator_1 =
1053			DelegatedStaking::generate_proxy_delegator(Agent::from(POOL1_BONDED)).get();
1054
1055		assert_eq!(
1056			delegated_staking_events_since_last_call(),
1057			// delegated also contains the extra ED that we minted when pool was `TransferStake` .
1058			vec![DelegatedStakingEvent::Delegated {
1059				agent: POOL1_BONDED,
1060				delegator: proxy_delegator_1,
1061				amount: 50 + 10 * 3 + 5
1062			}]
1063		);
1064
1065		// move to era 5 when 20 can withdraw unbonded funds.
1066		CurrentEra::<Runtime>::set(Some(5));
1067
1068		// Cannot unbond without claiming delegation. Lets unbond 22.
1069		assert_noop!(
1070			Pools::unbond(RuntimeOrigin::signed(22), 22, 5),
1071			PoolsError::<Runtime>::NotMigrated
1072		);
1073
1074		// withdraw fails for 20 before claiming delegation
1075		assert_noop!(
1076			Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 10),
1077			PoolsError::<Runtime>::NotMigrated
1078		);
1079
1080		let pre_claim_balance_20 = Balances::total_balance(&20);
1081		assert_eq!(Balances::total_balance_on_hold(&20), 0);
1082
1083		// migrate delegation for 20. This is permissionless and can be called by anyone.
1084		assert!(Pools::api_member_needs_delegate_migration(20));
1085		assert_ok!(Pools::migrate_delegation(RuntimeOrigin::signed(10), 20));
1086
1087		// tokens moved to 20's account and held there.
1088		assert_eq!(Balances::total_balance(&20), pre_claim_balance_20 + 10);
1089		assert_eq!(Balances::total_balance_on_hold(&20), 10);
1090
1091		// withdraw works now
1092		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 5));
1093
1094		// balance unlocked in 20's account
1095		assert_eq!(Balances::total_balance_on_hold(&20), 5);
1096		assert_eq!(Balances::total_balance(&20), pre_claim_balance_20 + 10);
1097
1098		assert_eq!(
1099			staking_events_since_last_call(),
1100			vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 5 }]
1101		);
1102		assert_eq!(
1103			pool_events_since_last_call(),
1104			vec![PoolsEvent::Withdrawn { member: 20, pool_id: 1, balance: 5, points: 5 },]
1105		);
1106		assert_eq!(
1107			delegated_staking_events_since_last_call(),
1108			vec![
1109				DelegatedStakingEvent::MigratedDelegation {
1110					agent: POOL1_BONDED,
1111					delegator: 20,
1112					amount: 10
1113				},
1114				DelegatedStakingEvent::Released { agent: POOL1_BONDED, delegator: 20, amount: 5 }
1115			]
1116		);
1117
1118		// MIGRATE 21
1119		let pre_migrate_balance_21 = Balances::total_balance(&21);
1120		assert_eq!(Balances::total_balance_on_hold(&21), 0);
1121
1122		// migrate delegation for 21.
1123		assert!(Pools::api_member_needs_delegate_migration(21));
1124		assert_ok!(Pools::migrate_delegation(RuntimeOrigin::signed(10), 21));
1125
1126		// tokens moved to 21's account and held there.
1127		assert_eq!(Balances::total_balance(&21), pre_migrate_balance_21 + 10);
1128		assert_eq!(Balances::total_balance_on_hold(&21), 10);
1129
1130		// withdraw fails since 21 only unbonds at era 6.
1131		assert_noop!(
1132			Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 10),
1133			PoolsError::<Runtime>::CannotWithdrawAny
1134		);
1135
1136		// go to era when 21 can unbond
1137		CurrentEra::<Runtime>::set(Some(6));
1138
1139		// withdraw works now
1140		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 10));
1141
1142		// all balance unlocked in 21's account
1143		assert_eq!(Balances::total_balance_on_hold(&21), 0);
1144		assert_eq!(Balances::total_balance(&21), pre_migrate_balance_21 + 10);
1145
1146		// MIGRATE 22
1147		assert_eq!(Balances::total_balance_on_hold(&22), 0);
1148		// make balance of 22 as 0.
1149		let _ = Balances::make_free_balance_be(&22, 0);
1150
1151		// migrate delegation for 22.
1152		assert!(Pools::api_member_needs_delegate_migration(22));
1153		assert_ok!(Pools::migrate_delegation(RuntimeOrigin::signed(10), 22));
1154
1155		// cannot migrate a pool member again.
1156		assert!(!Pools::api_member_needs_delegate_migration(22));
1157		assert_noop!(
1158			Pools::migrate_delegation(RuntimeOrigin::signed(10), 22),
1159			PoolsError::<Runtime>::AlreadyMigrated
1160		);
1161
1162		// tokens moved to 22's account and held there.
1163		assert_eq!(Balances::total_balance(&22), 10);
1164		assert_eq!(Balances::total_balance_on_hold(&22), 10);
1165
1166		// unbond 22 should work now
1167		assert_ok!(Pools::unbond(RuntimeOrigin::signed(22), 22, 5));
1168
1169		// withdraw fails since 22 only unbonds after era 9.
1170		assert_noop!(
1171			Pools::withdraw_unbonded(RuntimeOrigin::signed(22), 22, 5),
1172			PoolsError::<Runtime>::CannotWithdrawAny
1173		);
1174
1175		// go to era when 22 can unbond
1176		CurrentEra::<Runtime>::set(Some(9));
1177
1178		// withdraw works now
1179		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(22), 22, 10));
1180
1181		// balance of 5 unlocked in 22's account
1182		assert_eq!(Balances::total_balance_on_hold(&22), 10 - 5);
1183
1184		// assert events for 21 and 22.
1185		assert_eq!(
1186			staking_events_since_last_call(),
1187			vec![
1188				StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 10 },
1189				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5 },
1190				StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 5 }
1191			]
1192		);
1193
1194		assert_eq!(
1195			pool_events_since_last_call(),
1196			vec![
1197				PoolsEvent::Withdrawn { member: 21, pool_id: 1, balance: 10, points: 10 },
1198				// 21 was fully unbonding and removed from pool.
1199				PoolsEvent::MemberRemoved { member: 21, pool_id: 1, released_balance: 0 },
1200				PoolsEvent::Unbonded { member: 22, pool_id: 1, balance: 5, points: 5, era: 9 },
1201				PoolsEvent::Withdrawn { member: 22, pool_id: 1, balance: 5, points: 5 },
1202			]
1203		);
1204		assert_eq!(
1205			delegated_staking_events_since_last_call(),
1206			vec![
1207				DelegatedStakingEvent::MigratedDelegation {
1208					agent: POOL1_BONDED,
1209					delegator: 21,
1210					amount: 10
1211				},
1212				DelegatedStakingEvent::Released { agent: POOL1_BONDED, delegator: 21, amount: 10 },
1213				DelegatedStakingEvent::MigratedDelegation {
1214					agent: POOL1_BONDED,
1215					delegator: 22,
1216					amount: 10
1217				},
1218				DelegatedStakingEvent::Released { agent: POOL1_BONDED, delegator: 22, amount: 5 }
1219			]
1220		);
1221	})
1222}
1223
1224#[test]
1225fn disable_pool_operations_on_non_migrated() {
1226	new_test_ext().execute_with(|| {
1227		LegacyAdapter::set(true);
1228		assert_eq!(Balances::minimum_balance(), 5);
1229		assert_eq!(CurrentEra::<T>::get(), None);
1230
1231		// hack: mint ED to pool so that the deprecated `TransferStake` works correctly with
1232		// staking.
1233		assert_eq!(Balances::minimum_balance(), 5);
1234		assert_ok!(Balances::mint_into(&POOL1_BONDED, 5));
1235
1236		// create the pool with TransferStake strategy.
1237		assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10));
1238		assert_eq!(LastPoolId::<Runtime>::get(), 1);
1239
1240		// have the pool nominate.
1241		assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]));
1242
1243		assert_eq!(
1244			staking_events_since_last_call(),
1245			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }]
1246		);
1247		assert_eq!(
1248			pool_events_since_last_call(),
1249			vec![
1250				PoolsEvent::Created { depositor: 10, pool_id: 1 },
1251				PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true },
1252				PoolsEvent::PoolNominationMade { pool_id: 1, caller: 10 }
1253			]
1254		);
1255
1256		let pre_20 = Balances::free_balance(20);
1257		assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1));
1258
1259		// verify members balance is moved to pool.
1260		assert_eq!(Balances::free_balance(20), pre_20 - 10);
1261
1262		assert_eq!(
1263			staking_events_since_last_call(),
1264			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 },]
1265		);
1266		assert_eq!(
1267			pool_events_since_last_call(),
1268			vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true },]
1269		);
1270
1271		// we reset the adapter to `DelegateStake`.
1272		LegacyAdapter::set(false);
1273
1274		// pool is pending migration.
1275		assert!(Pools::api_pool_needs_delegate_migration(1));
1276
1277		// ensure pool mutation is not allowed until pool is migrated.
1278		assert_noop!(
1279			Pools::join(RuntimeOrigin::signed(21), 10, 1),
1280			PoolsError::<Runtime>::NotMigrated
1281		);
1282		assert_noop!(
1283			Pools::pool_withdraw_unbonded(RuntimeOrigin::signed(10), 1, 0),
1284			PoolsError::<Runtime>::NotMigrated
1285		);
1286		assert_noop!(
1287			Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]),
1288			PoolsError::<Runtime>::NotMigrated
1289		);
1290		assert_noop!(
1291			Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Blocked),
1292			PoolsError::<Runtime>::NotMigrated
1293		);
1294		assert_noop!(
1295			Pools::set_metadata(RuntimeOrigin::signed(10), 1, vec![1, 1]),
1296			PoolsError::<Runtime>::NotMigrated
1297		);
1298		assert_noop!(
1299			Pools::update_roles(
1300				RuntimeOrigin::signed(10),
1301				1,
1302				ConfigOp::Set(5),
1303				ConfigOp::Set(6),
1304				ConfigOp::Set(7)
1305			),
1306			PoolsError::<Runtime>::NotMigrated
1307		);
1308		assert_noop!(
1309			Pools::chill(RuntimeOrigin::signed(10), 1),
1310			PoolsError::<Runtime>::NotMigrated
1311		);
1312		assert_noop!(
1313			Pools::set_commission(RuntimeOrigin::signed(10), 1, None),
1314			PoolsError::<Runtime>::NotMigrated
1315		);
1316		assert_noop!(
1317			Pools::set_commission_max(RuntimeOrigin::signed(10), 1, Zero::zero()),
1318			PoolsError::<Runtime>::NotMigrated
1319		);
1320		assert_noop!(
1321			Pools::set_commission_change_rate(
1322				RuntimeOrigin::signed(10),
1323				1,
1324				CommissionChangeRate { max_increase: Perbill::from_percent(1), min_delay: 2_u64 }
1325			),
1326			PoolsError::<Runtime>::NotMigrated
1327		);
1328		assert_noop!(
1329			Pools::claim_commission(RuntimeOrigin::signed(10), 1),
1330			PoolsError::<Runtime>::NotMigrated
1331		);
1332		assert_noop!(
1333			Pools::adjust_pool_deposit(RuntimeOrigin::signed(10), 1),
1334			PoolsError::<Runtime>::NotMigrated
1335		);
1336		assert_noop!(
1337			Pools::set_commission_claim_permission(RuntimeOrigin::signed(10), 1, None),
1338			PoolsError::<Runtime>::NotMigrated
1339		);
1340
1341		// migrate the pool.
1342		assert_ok!(Pools::migrate_pool_to_delegate_stake(RuntimeOrigin::signed(10), 1));
1343		assert_eq!(
1344			delegated_staking_events_since_last_call(),
1345			// delegated also contains the extra ED that we minted when pool was `TransferStake` .
1346			vec![DelegatedStakingEvent::Delegated {
1347				agent: POOL1_BONDED,
1348				delegator: DelegatedStaking::generate_proxy_delegator(Agent::from(POOL1_BONDED))
1349					.get(),
1350				amount: 50 + 10 + 5
1351			},]
1352		);
1353
1354		// member is pending migration.
1355		assert!(Pools::api_member_needs_delegate_migration(20));
1356
1357		// ensure member mutation is not allowed until member's delegation is migrated.
1358		assert_noop!(
1359			Pools::bond_extra(RuntimeOrigin::signed(20), BondExtra::FreeBalance(5)),
1360			PoolsError::<Runtime>::NotMigrated
1361		);
1362		assert_noop!(
1363			Pools::bond_extra_other(RuntimeOrigin::signed(10), 20, BondExtra::Rewards),
1364			PoolsError::<Runtime>::NotMigrated
1365		);
1366		assert_noop!(
1367			Pools::claim_payout(RuntimeOrigin::signed(20)),
1368			PoolsError::<Runtime>::NotMigrated
1369		);
1370		assert_noop!(
1371			Pools::unbond(RuntimeOrigin::signed(20), 20, 5),
1372			PoolsError::<Runtime>::NotMigrated
1373		);
1374		assert_noop!(
1375			Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0),
1376			PoolsError::<Runtime>::NotMigrated
1377		);
1378
1379		// migrate 20
1380		assert_ok!(Pools::migrate_delegation(RuntimeOrigin::signed(10), 20));
1381		// now `bond_extra` for 20 works.
1382		assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(20), BondExtra::FreeBalance(5)));
1383
1384		assert_eq!(
1385			staking_events_since_last_call(),
1386			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 5 },]
1387		);
1388
1389		assert_eq!(
1390			pool_events_since_last_call(),
1391			vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 5, joined: false },]
1392		);
1393
1394		assert_eq!(
1395			delegated_staking_events_since_last_call(),
1396			vec![
1397				DelegatedStakingEvent::MigratedDelegation {
1398					agent: POOL1_BONDED,
1399					delegator: 20,
1400					amount: 10
1401				},
1402				DelegatedStakingEvent::Delegated { agent: POOL1_BONDED, delegator: 20, amount: 5 },
1403			]
1404		);
1405	})
1406}
1407
1408#[test]
1409fn pool_no_dangling_delegation() {
1410	new_test_ext().execute_with(|| {
1411		ExistentialDeposit::set(1);
1412		assert_eq!(Balances::minimum_balance(), 1);
1413		assert_eq!(CurrentEra::<T>::get(), None);
1414		// pool creator
1415		let alice = 10;
1416		let bob = 20;
1417		let charlie = 21;
1418
1419		// create the pool, we know this has id 1.
1420		assert_ok!(Pools::create(RuntimeOrigin::signed(alice), 40, alice, alice, alice));
1421		assert_eq!(LastPoolId::<Runtime>::get(), 1);
1422
1423		assert_eq!(
1424			staking_events_since_last_call(),
1425			vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }]
1426		);
1427		assert_eq!(
1428			pool_events_since_last_call(),
1429			vec![
1430				PoolsEvent::Created { depositor: alice, pool_id: 1 },
1431				PoolsEvent::Bonded { member: alice, pool_id: 1, bonded: 40, joined: true },
1432			]
1433		);
1434		assert_eq!(
1435			delegated_staking_events_since_last_call(),
1436			vec![DelegatedStakingEvent::Delegated {
1437				agent: POOL1_BONDED,
1438
1439				delegator: alice,
1440				amount: 40
1441			},]
1442		);
1443
1444		assert_eq!(
1445			Payee::<Runtime>::get(POOL1_BONDED),
1446			Some(RewardDestination::Account(POOL1_REWARD))
1447		);
1448
1449		// have two members join
1450		assert_ok!(Pools::join(RuntimeOrigin::signed(bob), 20, 1));
1451		assert_ok!(Pools::join(RuntimeOrigin::signed(charlie), 20, 1));
1452
1453		assert_eq!(
1454			staking_events_since_last_call(),
1455			vec![
1456				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 20 },
1457				StakingEvent::Bonded { stash: POOL1_BONDED, amount: 20 }
1458			]
1459		);
1460		assert_eq!(
1461			pool_events_since_last_call(),
1462			vec![
1463				PoolsEvent::Bonded { member: bob, pool_id: 1, bonded: 20, joined: true },
1464				PoolsEvent::Bonded { member: charlie, pool_id: 1, bonded: 20, joined: true },
1465			]
1466		);
1467		assert_eq!(
1468			delegated_staking_events_since_last_call(),
1469			vec![
1470				DelegatedStakingEvent::Delegated {
1471					agent: POOL1_BONDED,
1472					delegator: bob,
1473					amount: 20
1474				},
1475				DelegatedStakingEvent::Delegated {
1476					agent: POOL1_BONDED,
1477					delegator: charlie,
1478					amount: 20
1479				},
1480			]
1481		);
1482
1483		// now let's progress a bit.
1484		CurrentEra::<Runtime>::set(Some(1));
1485
1486		// bob is completely unbonding
1487		assert_ok!(Pools::unbond(RuntimeOrigin::signed(bob), 20, 20));
1488
1489		assert_eq!(
1490			staking_events_since_last_call(),
1491			vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 20 },]
1492		);
1493		assert_eq!(
1494			pool_events_since_last_call(),
1495			vec![PoolsEvent::Unbonded { member: bob, pool_id: 1, balance: 20, points: 20, era: 4 }]
1496		);
1497
1498		// this era will get slashed
1499		CurrentEra::<Runtime>::set(Some(2));
1500
1501		assert_ok!(Pools::unbond(RuntimeOrigin::signed(alice), 10, 10));
1502		assert_ok!(Pools::unbond(RuntimeOrigin::signed(charlie), 21, 10));
1503
1504		assert_eq!(
1505			staking_events_since_last_call(),
1506			vec![
1507				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
1508				StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
1509			]
1510		);
1511
1512		assert_eq!(
1513			pool_events_since_last_call(),
1514			vec![
1515				PoolsEvent::Unbonded { member: alice, pool_id: 1, balance: 10, points: 10, era: 5 },
1516				PoolsEvent::Unbonded {
1517					member: charlie,
1518					pool_id: 1,
1519					balance: 10,
1520					points: 10,
1521					era: 5
1522				},
1523			]
1524		);
1525
1526		// At this point, bob's 20 that is unlocking is safe from slash, 10 (alice) + 10 (charlie)
1527		// are also unlocking but vulnerable to slash, and another 40 are active and vulnerable to
1528		// slash. Let's slash half of them.
1529		pallet_staking::slashing::do_slash::<Runtime>(
1530			&POOL1_BONDED,
1531			30,
1532			&mut Default::default(),
1533			&mut Default::default(),
1534			2, // slash era 2, affects chunks at era 5 onwards.
1535		);
1536
1537		assert_eq!(
1538			staking_events_since_last_call(),
1539			vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 30 }]
1540		);
1541
1542		assert_eq!(
1543			pool_events_since_last_call(),
1544			vec![
1545				// unbonding pool of 20 for era 5 has been slashed to 10
1546				PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 5, balance: 10 },
1547				// active stake of 40 has been slashed to half
1548				PoolsEvent::PoolSlashed { pool_id: 1, balance: 20 } /* no slash to era 4
1549				                                                     * unbonding pool */
1550			]
1551		);
1552
1553		// alice's initial stake of 40 is reduced to half
1554		assert_eq!(PoolMembers::<Runtime>::get(alice).unwrap().total_balance(), 20);
1555		// bob unbonded in era 1 and is safe from slash
1556		assert_eq!(PoolMembers::<Runtime>::get(bob).unwrap().total_balance(), 20);
1557		// charlie's initial stake of 20 is slashed to half
1558		assert_eq!(PoolMembers::<Runtime>::get(charlie).unwrap().total_balance(), 10);
1559
1560		// apply pending slash to alice.
1561		assert_eq!(Pools::api_member_pending_slash(alice), 20);
1562		assert_ok!(Pools::apply_slash(RuntimeOrigin::signed(10), alice));
1563		// apply pending slash to charlie.
1564		assert_eq!(Pools::api_member_pending_slash(charlie), 10);
1565		assert_ok!(Pools::apply_slash(RuntimeOrigin::signed(10), charlie));
1566		// no pending slash for bob
1567		assert_eq!(Pools::api_member_pending_slash(bob), 0);
1568
1569		assert_eq!(
1570			delegated_staking_events_since_last_call(),
1571			vec![
1572				DelegatedStakingEvent::Slashed {
1573					agent: POOL1_BONDED,
1574					delegator: alice,
1575					amount: 20
1576				},
1577				DelegatedStakingEvent::Slashed {
1578					agent: POOL1_BONDED,
1579					delegator: charlie,
1580					amount: 10
1581				},
1582			]
1583		);
1584
1585		// go forward to an era after PostUnbondingPoolsWindow = 10 ends for era 5.
1586		CurrentEra::<Runtime>::set(Some(15));
1587		// At this point subpools will all be merged in no-era causing Bob to lose some value while
1588		// Alice and Charlie will gain some value.
1589		assert_ok!(Pools::unbond(RuntimeOrigin::signed(charlie), charlie, 10));
1590
1591		// Now alice and charlie has less balance locked than their contribution.
1592		assert_eq!(Balances::total_balance_on_hold(&alice), 20);
1593		assert_eq!(PoolMembers::<Runtime>::get(alice).unwrap().total_balance(), 22);
1594		assert_eq!(Balances::total_balance_on_hold(&charlie), 10);
1595		assert_eq!(PoolMembers::<Runtime>::get(charlie).unwrap().total_balance(), 12);
1596
1597		// and bob has more balance locked than his contribution.
1598		assert_eq!(Balances::total_balance_on_hold(&bob), 20);
1599		assert_eq!(PoolMembers::<Runtime>::get(bob).unwrap().total_balance(), 15);
1600
1601		assert_eq!(
1602			staking_events_since_last_call(),
1603			vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5 }]
1604		);
1605		assert_eq!(
1606			pool_events_since_last_call(),
1607			vec![PoolsEvent::Unbonded {
1608				member: charlie,
1609				pool_id: 1,
1610				balance: 5,
1611				points: 5,
1612				era: 18
1613			}]
1614		);
1615
1616		// When bob withdraws all, he gets all his locked funds back.
1617		let bob_pre_withdraw_balance = Balances::free_balance(&bob);
1618		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(bob), bob, 0));
1619		assert_eq!(Balances::free_balance(&bob), bob_pre_withdraw_balance + 20);
1620		assert_eq!(Balances::total_balance_on_hold(&bob), 0);
1621		assert!(!PoolMembers::<Runtime>::contains_key(bob));
1622
1623		assert_eq!(
1624			staking_events_since_last_call(),
1625			vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 30 },]
1626		);
1627
1628		assert_eq!(
1629			pool_events_since_last_call(),
1630			vec![
1631				PoolsEvent::Withdrawn { pool_id: 1, member: bob, balance: 15, points: 20 },
1632				// dangling delegation of 5 is released
1633				PoolsEvent::MemberRemoved { pool_id: 1, member: bob, released_balance: 5 },
1634			]
1635		);
1636		assert_eq!(
1637			delegated_staking_events_since_last_call(),
1638			vec![
1639				DelegatedStakingEvent::Released { agent: POOL1_BONDED, delegator: bob, amount: 15 },
1640				// the second release is the dangling delegation when member is removed.
1641				DelegatedStakingEvent::Released { agent: POOL1_BONDED, delegator: bob, amount: 5 },
1642			]
1643		);
1644
1645		// Charlie can withdraw as much as he has locked.
1646		CurrentEra::<Runtime>::set(Some(18));
1647		let charlie_pre_withdraw_balance = Balances::free_balance(&charlie);
1648		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(charlie), charlie, 0));
1649		// Charlie's total balance was 12, but we don't have enough funds to unlock. We try the best
1650		// effort and unlock 10.
1651		assert_eq!(Balances::free_balance(&charlie), charlie_pre_withdraw_balance + 10);
1652
1653		assert_eq!(
1654			staking_events_since_last_call(),
1655			vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 5 },]
1656		);
1657
1658		assert_eq!(
1659			pool_events_since_last_call(),
1660			vec![
1661				PoolsEvent::Withdrawn { pool_id: 1, member: charlie, balance: 10, points: 15 },
1662				PoolsEvent::MemberRemoved { member: charlie, pool_id: 1, released_balance: 0 }
1663			]
1664		);
1665		assert_eq!(
1666			delegated_staking_events_since_last_call(),
1667			vec![DelegatedStakingEvent::Released {
1668				agent: POOL1_BONDED,
1669				delegator: charlie,
1670				amount: 10
1671			},]
1672		);
1673
1674		// Set pools to destroying so alice can withdraw
1675		assert_ok!(Pools::set_state(RuntimeOrigin::signed(alice), 1, PoolState::Destroying));
1676		assert_ok!(Pools::unbond(RuntimeOrigin::signed(alice), alice, 30));
1677
1678		assert_eq!(
1679			staking_events_since_last_call(),
1680			vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 15 }]
1681		);
1682		assert_eq!(
1683			pool_events_since_last_call(),
1684			vec![
1685				PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying },
1686				PoolsEvent::Unbonded {
1687					member: alice,
1688					pool_id: 1,
1689					points: 15,
1690					balance: 15,
1691					era: 21
1692				}
1693			]
1694		);
1695
1696		CurrentEra::<Runtime>::set(Some(21));
1697		assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(alice), alice, 0));
1698
1699		assert_eq!(
1700			staking_events_since_last_call(),
1701			vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 15 }]
1702		);
1703		assert_eq!(
1704			pool_events_since_last_call(),
1705			vec![
1706				PoolsEvent::Withdrawn { member: alice, pool_id: 1, balance: 20, points: 25 },
1707				PoolsEvent::MemberRemoved { pool_id: 1, member: alice, released_balance: 0 },
1708				PoolsEvent::Destroyed { pool_id: 1 }
1709			]
1710		);
1711
1712		// holds for all members are released.
1713		assert_eq!(Balances::total_balance_on_hold(&alice), 0);
1714		assert_eq!(Balances::total_balance_on_hold(&bob), 0);
1715		assert_eq!(Balances::total_balance_on_hold(&charlie), 0);
1716	});
1717}