1#![cfg(test)]
19
20#[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 assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10));
53 assert_eq!(LastPoolId::<Runtime>::get(), 1);
54
55 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 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 assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying));
92
93 assert_noop!(
95 Pools::unbond(RuntimeOrigin::signed(10), 10, 50),
96 PoolsError::<Runtime>::MinimumBondNotMet,
97 );
98
99 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 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 CurrentEra::<Runtime>::set(Some(BondingDuration::get()));
140
141 assert_noop!(
143 Pools::unbond(RuntimeOrigin::signed(10), 10, 50),
144 PoolsError::<Runtime>::MinimumBondNotMet,
145 );
146
147 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 CurrentEra::<Runtime>::set(Some(BondingDuration::get() * 2));
183 assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 1));
184
185 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 assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10));
209 assert_eq!(LastPoolId::<Runtime>::get(), 1);
210
211 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 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 assert_ok!(Staking::set_staking_configs(
251 RuntimeOrigin::root(),
252 pallet_staking::ConfigOp::Set(55), 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 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 assert_noop!(
268 Pools::unbond(RuntimeOrigin::signed(21), 21, 10),
269 StakingError::<Runtime>::InsufficientBond,
270 );
271
272 assert_ok!(Pools::chill(RuntimeOrigin::signed(20), 1));
274
275 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 assert_noop!(
282 Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]),
283 PoolsError::<Runtime>::MinimumBondNotMet,
284 );
285
286 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 assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10)));
296
297 assert_noop!(
299 Pools::chill(RuntimeOrigin::signed(20), 1),
300 PoolsError::<Runtime>::NotNominator,
301 );
302
303 assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]));
305
306 CurrentEra::<Runtime>::set(Some(BondingDuration::get()));
308
309 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 }, StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, 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 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 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 CurrentEra::<Runtime>::set(Some(1));
376
377 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 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 pallet_staking::slashing::do_slash::<Runtime>(
425 &POOL1_BONDED,
426 30,
427 &mut Default::default(),
428 &mut Default::default(),
429 2, );
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 PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 5, balance: 15 },
441 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 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 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 PoolsEvent::Withdrawn { member: 20, pool_id: 1, balance: 10 + 5, points: 20 },
478 PoolsEvent::MemberRemoved { pool_id: 1, member: 20, released_balance: 0 },
479 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 vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 15 + 10 + 15 }]
488 );
489
490 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 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 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 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 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 CurrentEra::<T>::set(Some(99));
613
614 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 assert_eq!(BondedPools::<T>::get(1).unwrap().points, 40);
669
670 assert_eq!(Pools::api_pool_pending_slash(1), 0);
672 assert_noop!(
674 Pools::apply_slash(RuntimeOrigin::signed(10), 21),
675 PoolsError::<Runtime>::NothingToSlash
676 );
677
678 hypothetically!({
679 pallet_staking::slashing::do_slash::<Runtime>(
681 &POOL1_BONDED,
682 3,
683 &mut Default::default(),
684 &mut Default::default(),
685 100,
686 );
687
688 assert_eq!(Pools::api_pool_pending_slash(1), 3);
690
691 assert_eq!(Pools::api_member_pending_slash(21), 1);
693
694 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 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 PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 128, balance: 7 },
721 PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 129, balance: 8 },
724 PoolsEvent::PoolSlashed { pool_id: 1, balance: 15 }
726 ]
727 );
728
729 assert_eq!(PoolMembers::<Runtime>::get(21).unwrap().total_balance(), 7);
731 assert_eq!(Balances::total_balance_on_hold(&21), bond);
733 assert_eq!(Pools::api_member_pending_slash(21), bond - 7);
735 assert_ok!(Pools::apply_slash(RuntimeOrigin::signed(10), 21));
737 assert_eq!(Balances::total_balance_on_hold(&21), 7);
739 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 assert_eq!(PoolMembers::<Runtime>::get(22).unwrap().total_balance(), 8);
753 assert_eq!(Balances::total_balance_on_hold(&22), bond);
754
755 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 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 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 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 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 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 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 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 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 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 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 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 PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 127, balance: 10 },
933 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 assert_eq!(Balances::minimum_balance(), 5);
949 assert_ok!(Balances::mint_into(&POOL1_BONDED, 5));
950
951 assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10));
953 assert_eq!(LastPoolId::<Runtime>::get(), 1);
954
955 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 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 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 assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5));
1004
1005 CurrentEra::<Runtime>::set(Some(3));
1006 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 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 LegacyAdapter::set(false);
1033
1034 assert_noop!(
1036 Pools::migrate_delegation(RuntimeOrigin::signed(10), 20),
1037 PoolsError::<Runtime>::NotMigrated
1038 );
1039
1040 assert!(Pools::api_pool_needs_delegate_migration(1));
1042 assert_ok!(Pools::migrate_pool_to_delegate_stake(RuntimeOrigin::signed(10), 1));
1043
1044 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 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 vec![DelegatedStakingEvent::Delegated {
1059 agent: POOL1_BONDED,
1060 delegator: proxy_delegator_1,
1061 amount: 50 + 10 * 3 + 5
1062 }]
1063 );
1064
1065 CurrentEra::<Runtime>::set(Some(5));
1067
1068 assert_noop!(
1070 Pools::unbond(RuntimeOrigin::signed(22), 22, 5),
1071 PoolsError::<Runtime>::NotMigrated
1072 );
1073
1074 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 assert!(Pools::api_member_needs_delegate_migration(20));
1085 assert_ok!(Pools::migrate_delegation(RuntimeOrigin::signed(10), 20));
1086
1087 assert_eq!(Balances::total_balance(&20), pre_claim_balance_20 + 10);
1089 assert_eq!(Balances::total_balance_on_hold(&20), 10);
1090
1091 assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 5));
1093
1094 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 let pre_migrate_balance_21 = Balances::total_balance(&21);
1120 assert_eq!(Balances::total_balance_on_hold(&21), 0);
1121
1122 assert!(Pools::api_member_needs_delegate_migration(21));
1124 assert_ok!(Pools::migrate_delegation(RuntimeOrigin::signed(10), 21));
1125
1126 assert_eq!(Balances::total_balance(&21), pre_migrate_balance_21 + 10);
1128 assert_eq!(Balances::total_balance_on_hold(&21), 10);
1129
1130 assert_noop!(
1132 Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 10),
1133 PoolsError::<Runtime>::CannotWithdrawAny
1134 );
1135
1136 CurrentEra::<Runtime>::set(Some(6));
1138
1139 assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 10));
1141
1142 assert_eq!(Balances::total_balance_on_hold(&21), 0);
1144 assert_eq!(Balances::total_balance(&21), pre_migrate_balance_21 + 10);
1145
1146 assert_eq!(Balances::total_balance_on_hold(&22), 0);
1148 let _ = Balances::make_free_balance_be(&22, 0);
1150
1151 assert!(Pools::api_member_needs_delegate_migration(22));
1153 assert_ok!(Pools::migrate_delegation(RuntimeOrigin::signed(10), 22));
1154
1155 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 assert_eq!(Balances::total_balance(&22), 10);
1164 assert_eq!(Balances::total_balance_on_hold(&22), 10);
1165
1166 assert_ok!(Pools::unbond(RuntimeOrigin::signed(22), 22, 5));
1168
1169 assert_noop!(
1171 Pools::withdraw_unbonded(RuntimeOrigin::signed(22), 22, 5),
1172 PoolsError::<Runtime>::CannotWithdrawAny
1173 );
1174
1175 CurrentEra::<Runtime>::set(Some(9));
1177
1178 assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(22), 22, 10));
1180
1181 assert_eq!(Balances::total_balance_on_hold(&22), 10 - 5);
1183
1184 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 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 assert_eq!(Balances::minimum_balance(), 5);
1234 assert_ok!(Balances::mint_into(&POOL1_BONDED, 5));
1235
1236 assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10));
1238 assert_eq!(LastPoolId::<Runtime>::get(), 1);
1239
1240 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 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 LegacyAdapter::set(false);
1273
1274 assert!(Pools::api_pool_needs_delegate_migration(1));
1276
1277 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 assert_ok!(Pools::migrate_pool_to_delegate_stake(RuntimeOrigin::signed(10), 1));
1343 assert_eq!(
1344 delegated_staking_events_since_last_call(),
1345 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 assert!(Pools::api_member_needs_delegate_migration(20));
1356
1357 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 assert_ok!(Pools::migrate_delegation(RuntimeOrigin::signed(10), 20));
1381 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 let alice = 10;
1416 let bob = 20;
1417 let charlie = 21;
1418
1419 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 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 CurrentEra::<Runtime>::set(Some(1));
1485
1486 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 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 pallet_staking::slashing::do_slash::<Runtime>(
1530 &POOL1_BONDED,
1531 30,
1532 &mut Default::default(),
1533 &mut Default::default(),
1534 2, );
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 PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 5, balance: 10 },
1547 PoolsEvent::PoolSlashed { pool_id: 1, balance: 20 } ]
1551 );
1552
1553 assert_eq!(PoolMembers::<Runtime>::get(alice).unwrap().total_balance(), 20);
1555 assert_eq!(PoolMembers::<Runtime>::get(bob).unwrap().total_balance(), 20);
1557 assert_eq!(PoolMembers::<Runtime>::get(charlie).unwrap().total_balance(), 10);
1559
1560 assert_eq!(Pools::api_member_pending_slash(alice), 20);
1562 assert_ok!(Pools::apply_slash(RuntimeOrigin::signed(10), alice));
1563 assert_eq!(Pools::api_member_pending_slash(charlie), 10);
1565 assert_ok!(Pools::apply_slash(RuntimeOrigin::signed(10), charlie));
1566 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 CurrentEra::<Runtime>::set(Some(15));
1587 assert_ok!(Pools::unbond(RuntimeOrigin::signed(charlie), charlie, 10));
1590
1591 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 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 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 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 DelegatedStakingEvent::Released { agent: POOL1_BONDED, delegator: bob, amount: 5 },
1642 ]
1643 );
1644
1645 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 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 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 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}