1
// Copyright (C) Moondance Labs Ltd.
2
// This file is part of Tanssi.
3

            
4
// Tanssi is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Tanssi is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Tanssi.  If not, see <http://www.gnu.org/licenses/>
16

            
17
use {
18
    super::*,
19
    crate::{
20
        assert_eq_last_events,
21
        pools::{ActivePoolKind, AutoCompounding, ManualRewards},
22
        Pallet,
23
    },
24
    frame_support::assert_err,
25
    sp_runtime::DispatchError,
26
    tp_traits::DistributeRewards,
27
};
28

            
29
struct Delegation {
30
    candidate: AccountId,
31
    delegator: AccountId,
32
    pool: ActivePoolKind,
33
    stake: Balance,
34
}
35

            
36
struct RewardRequest {
37
    collator: AccountId,
38
    rewards: Balance,
39
}
40

            
41
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42
struct DelegatorState {
43
    candidate: AccountId,
44
    delegator: AccountId,
45
    auto_stake: Balance,
46
    auto_shares: Balance,
47
    manual_stake: Balance,
48
    manual_shares: Balance,
49
    pending_rewards: Balance,
50
}
51

            
52
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53
struct Distribution {
54
    collator_auto: Balance,
55
    collator_manual: Balance,
56
    delegators_auto: Balance,
57
    delegators_manual: Balance,
58
}
59

            
60
9
fn test_distribution(
61
9
    delegations: &[Delegation],
62
9
    reward: RewardRequest,
63
9
    stakes: &[DelegatorState],
64
9
    distribution: Distribution,
65
9
) {
66
    use crate::traits::Timer;
67
9
    let block_number = <Runtime as crate::Config>::JoiningRequestTimer::now();
68
9

            
69
9
    // Create new supply for rewards
70
9
    let new_supply = currency_issue(reward.rewards);
71
    use frame_support::traits::Imbalance;
72
9
    let new_supply_amount = new_supply.peek();
73

            
74
    // Request all delegations
75
23
    for d in delegations {
76
14
        assert_ok!(Staking::request_delegate(
77
14
            RuntimeOrigin::signed(d.delegator),
78
14
            d.candidate,
79
14
            d.pool,
80
14
            d.stake,
81
14
        ));
82
    }
83

            
84
    // Wait for delegation to be executable
85
27
    for _ in 0..BLOCKS_TO_WAIT {
86
18
        roll_one_block();
87
18
    }
88

            
89
    // Execute delegations
90
23
    for d in delegations {
91
14
        assert_ok!(Staking::execute_pending_operations(
92
14
            RuntimeOrigin::signed(d.delegator),
93
14
            vec![PendingOperationQuery {
94
14
                delegator: d.delegator,
95
14
                operation: match d.pool {
96
                    ActivePoolKind::AutoCompounding =>
97
7
                        PendingOperationKey::JoiningAutoCompounding {
98
7
                            candidate: d.candidate,
99
7
                            at: block_number
100
7
                        },
101
7
                    ActivePoolKind::ManualRewards => PendingOperationKey::JoiningManualRewards {
102
7
                        candidate: d.candidate,
103
7
                        at: block_number
104
7
                    },
105
                }
106
            }]
107
        ));
108
    }
109

            
110
    // Distribute rewards
111
9
    let candidate_balance_before = total_balance(&ACCOUNT_CANDIDATE_1);
112
9
    assert_ok!(Pallet::<Runtime>::distribute_rewards(
113
9
        reward.collator,
114
9
        new_supply
115
9
    ));
116
9
    let candidate_balance_after = total_balance(&ACCOUNT_CANDIDATE_1);
117
9

            
118
9
    // Check events matches the expected distribution.
119
9
    assert_eq_last_events!(vec![
120
9
        Event::<Runtime>::RewardedCollator {
121
9
            collator: reward.collator,
122
9
            auto_compounding_rewards: distribution.collator_auto,
123
9
            manual_claim_rewards: distribution.collator_manual,
124
9
        },
125
9
        Event::RewardedDelegators {
126
9
            collator: reward.collator,
127
9
            auto_compounding_rewards: distribution.delegators_auto,
128
9
            manual_claim_rewards: distribution.delegators_manual,
129
9
        },
130
    ]);
131

            
132
    // Check the state of each delegate match the expected values.
133
19
    for expected in stakes {
134
10
        let actual = DelegatorState {
135
10
            candidate: expected.candidate,
136
10
            delegator: expected.delegator,
137
10
            auto_stake: AutoCompounding::<Runtime>::computed_stake(
138
10
                &expected.candidate,
139
10
                &expected.delegator,
140
10
            )
141
10
            .expect("to have stake")
142
10
            .0,
143
10
            auto_shares: AutoCompounding::<Runtime>::shares(
144
10
                &expected.candidate,
145
10
                &expected.delegator,
146
10
            )
147
10
            .0,
148
10
            manual_stake: ManualRewards::<Runtime>::computed_stake(
149
10
                &expected.candidate,
150
10
                &expected.delegator,
151
10
            )
152
10
            .expect("to have stake")
153
10
            .0,
154
10
            manual_shares: ManualRewards::<Runtime>::shares(
155
10
                &expected.candidate,
156
10
                &expected.delegator,
157
10
            )
158
10
            .0,
159
10
            pending_rewards: ManualRewards::<Runtime>::pending_rewards(
160
10
                &expected.candidate,
161
10
                &expected.delegator,
162
10
            )
163
10
            .expect("no overflow")
164
10
            .0,
165
10
        };
166
10

            
167
10
        similar_asserts::assert_eq!(&actual, expected);
168
    }
169

            
170
    // Additional checks.
171
9
    assert_eq!(
172
9
        distribution.collator_auto
173
9
            + distribution.collator_manual
174
9
            + distribution.delegators_auto
175
9
            + distribution.delegators_manual,
176
        new_supply_amount,
177
        "Distribution total doesn't match requested reward"
178
    );
179

            
180
9
    assert_eq!(
181
9
        candidate_balance_before + distribution.collator_manual,
182
        candidate_balance_after,
183
        "candidate balance should be increased by collator_manual"
184
    );
185

            
186
10
    let sum_manual: Balance = stakes.iter().map(|s| s.pending_rewards).sum();
187
9
    assert_eq!(
188
        sum_manual, distribution.delegators_manual,
189
        "sum of pending rewards should match distributed delegators manual rewards"
190
    );
191

            
192
9
    let sum_auto_stake_before: Balance = delegations
193
9
        .iter()
194
14
        .filter_map(|d| match d.pool {
195
7
            ActivePoolKind::AutoCompounding => Some(d.stake),
196
7
            _ => None,
197
14
        })
198
9
        .sum();
199
9

            
200
9
    let sum_auto_stake_after = AutoCompounding::<Runtime>::total_staked(&reward.collator).0;
201
9
    assert_eq!(
202
9
        sum_auto_stake_after - sum_auto_stake_before,
203
9
        distribution.collator_auto + distribution.delegators_auto,
204
        "diff between sum of auto stake before and after distribution should match distributed auto rewards"
205
    );
206
9
}
207

            
208
#[test]
209
1
fn candidate_only_manual_only() {
210
1
    ExtBuilder::default().build().execute_with(|| {
211
1
        test_distribution(
212
1
            &[Delegation {
213
1
                candidate: ACCOUNT_CANDIDATE_1,
214
1
                delegator: ACCOUNT_CANDIDATE_1,
215
1
                pool: ActivePoolKind::ManualRewards,
216
1
                stake: 1_000_000_000,
217
1
            }],
218
1
            RewardRequest {
219
1
                collator: ACCOUNT_CANDIDATE_1,
220
1
                rewards: 1_000_000,
221
1
            },
222
1
            &[DelegatorState {
223
1
                candidate: ACCOUNT_CANDIDATE_1,
224
1
                delegator: ACCOUNT_CANDIDATE_1,
225
1
                auto_shares: 0,
226
1
                auto_stake: 0,
227
1
                manual_shares: 1_000,
228
1
                manual_stake: 1_000_000_000,
229
1
                pending_rewards: 800_000,
230
1
            }],
231
1
            Distribution {
232
1
                collator_auto: 0,
233
1
                collator_manual: 200_000, // 20% of rewards
234
1
                delegators_auto: 0,
235
1
                delegators_manual: 800_000, // 80% of rewards
236
1
            },
237
1
        )
238
1
    });
239
1
}
240

            
241
#[test]
242
1
fn candidate_only_auto_only() {
243
1
    ExtBuilder::default().build().execute_with(|| {
244
1
        test_distribution(
245
1
            &[Delegation {
246
1
                candidate: ACCOUNT_CANDIDATE_1,
247
1
                delegator: ACCOUNT_CANDIDATE_1,
248
1
                pool: ActivePoolKind::AutoCompounding,
249
1
                stake: 1_000_000_000,
250
1
            }],
251
1
            RewardRequest {
252
1
                collator: ACCOUNT_CANDIDATE_1,
253
1
                rewards: 10_000_000,
254
1
            },
255
1
            &[DelegatorState {
256
1
                candidate: ACCOUNT_CANDIDATE_1,
257
1
                delegator: ACCOUNT_CANDIDATE_1,
258
1
                auto_shares: 1_001,
259
1
                // initial auto stake is 1_000_000_000 for
260
1
                // 8_000_000 is shared between all delegators, so 1 share
261
1
                // is now worth 1_008_000_000 / 1000 = 1_008_000 now
262
1
                // collator is should be rewarded 2_000_000 in auto shares,
263
1
                // which allows to get 1 more share, so the collator now
264
1
                // have 1_001 shares worth
265
1
                // 1_008_000_000 + 1_008_000 = 1_009_008_000
266
1
                auto_stake: 1_009_008_000,
267
1
                manual_shares: 0,
268
1
                manual_stake: 0,
269
1
                pending_rewards: 0,
270
1
            }],
271
1
            Distribution {
272
1
                // 20% of rewards, rounded down to closest amount of Auto shares
273
1
                // AFTER delegators rewards has been rewarded
274
1
                collator_auto: 1_008_000,
275
1
                // dust from collator_auto
276
1
                collator_manual: 992_000,
277
1
                delegators_auto: 8_000_000, // 80% of rewards
278
1
                delegators_manual: 0,
279
1
            },
280
1
        )
281
1
    });
282
1
}
283

            
284
#[test]
285
1
fn candidate_only_mixed() {
286
1
    ExtBuilder::default().build().execute_with(|| {
287
1
        test_distribution(
288
1
            &[
289
1
                Delegation {
290
1
                    candidate: ACCOUNT_CANDIDATE_1,
291
1
                    delegator: ACCOUNT_CANDIDATE_1,
292
1
                    pool: ActivePoolKind::AutoCompounding,
293
1
                    stake: 1_000_000_000,
294
1
                },
295
1
                Delegation {
296
1
                    candidate: ACCOUNT_CANDIDATE_1,
297
1
                    delegator: ACCOUNT_CANDIDATE_1,
298
1
                    pool: ActivePoolKind::ManualRewards,
299
1
                    stake: 250_000_000,
300
1
                },
301
1
            ],
302
1
            RewardRequest {
303
1
                collator: ACCOUNT_CANDIDATE_1,
304
1
                rewards: 10_000_000,
305
1
            },
306
1
            &[DelegatorState {
307
1
                candidate: ACCOUNT_CANDIDATE_1,
308
1
                delegator: ACCOUNT_CANDIDATE_1,
309
1
                auto_shares: 1_001,
310
1
                auto_stake: 1_007_406_400,
311
1
                manual_shares: 250,
312
1
                manual_stake: 250_000_000,
313
1
                pending_rewards: 1_600_000,
314
1
            }],
315
1
            Distribution {
316
1
                collator_auto: 1_006_400,
317
1
                collator_manual: 993_600,
318
1
                delegators_auto: 6_400_000,
319
1
                delegators_manual: 1_600_000,
320
1
            },
321
1
        )
322
1
    });
323
1
}
324

            
325
#[test]
326
1
fn delegators_manual_only() {
327
1
    ExtBuilder::default().build().execute_with(|| {
328
1
        test_distribution(
329
1
            &[
330
1
                Delegation {
331
1
                    candidate: ACCOUNT_CANDIDATE_1,
332
1
                    delegator: ACCOUNT_CANDIDATE_1,
333
1
                    pool: ActivePoolKind::ManualRewards,
334
1
                    stake: 1_000_000_000,
335
1
                },
336
1
                Delegation {
337
1
                    candidate: ACCOUNT_CANDIDATE_1,
338
1
                    delegator: ACCOUNT_DELEGATOR_1,
339
1
                    pool: ActivePoolKind::ManualRewards,
340
1
                    stake: 250_000_000,
341
1
                },
342
1
            ],
343
1
            RewardRequest {
344
1
                collator: ACCOUNT_CANDIDATE_1,
345
1
                rewards: 10_000_000,
346
1
            },
347
1
            &[
348
1
                DelegatorState {
349
1
                    candidate: ACCOUNT_CANDIDATE_1,
350
1
                    delegator: ACCOUNT_CANDIDATE_1,
351
1
                    auto_shares: 0,
352
1
                    auto_stake: 0,
353
1
                    manual_shares: 1_000,
354
1
                    manual_stake: 1_000_000_000,
355
1
                    pending_rewards: 6_400_000,
356
1
                },
357
1
                DelegatorState {
358
1
                    candidate: ACCOUNT_CANDIDATE_1,
359
1
                    delegator: ACCOUNT_DELEGATOR_1,
360
1
                    auto_shares: 0,
361
1
                    auto_stake: 0,
362
1
                    manual_shares: 250,
363
1
                    manual_stake: 250_000_000,
364
1
                    pending_rewards: 1_600_000,
365
1
                },
366
1
            ],
367
1
            Distribution {
368
1
                collator_auto: 0,
369
1
                collator_manual: 2_000_000,
370
1
                delegators_auto: 0,
371
1
                delegators_manual: 8_000_000,
372
1
            },
373
1
        )
374
1
    });
375
1
}
376

            
377
#[test]
378
1
fn delegators_auto_only() {
379
1
    ExtBuilder::default().build().execute_with(|| {
380
1
        test_distribution(
381
1
            &[
382
1
                Delegation {
383
1
                    candidate: ACCOUNT_CANDIDATE_1,
384
1
                    delegator: ACCOUNT_CANDIDATE_1,
385
1
                    pool: ActivePoolKind::AutoCompounding,
386
1
                    stake: 1_000_000_000,
387
1
                },
388
1
                Delegation {
389
1
                    candidate: ACCOUNT_CANDIDATE_1,
390
1
                    delegator: ACCOUNT_DELEGATOR_1,
391
1
                    pool: ActivePoolKind::AutoCompounding,
392
1
                    stake: 250_000_000,
393
1
                },
394
1
            ],
395
1
            RewardRequest {
396
1
                collator: ACCOUNT_CANDIDATE_1,
397
1
                rewards: 10_000_000,
398
1
            },
399
1
            &[
400
1
                DelegatorState {
401
1
                    candidate: ACCOUNT_CANDIDATE_1,
402
1
                    delegator: ACCOUNT_CANDIDATE_1,
403
1
                    auto_shares: 1_001,
404
1
                    auto_stake: 1_007_406_400,
405
1
                    manual_shares: 0,
406
1
                    manual_stake: 0,
407
1
                    pending_rewards: 0,
408
1
                },
409
1
                DelegatorState {
410
1
                    candidate: ACCOUNT_CANDIDATE_1,
411
1
                    delegator: ACCOUNT_DELEGATOR_1,
412
1
                    auto_shares: 250,
413
1
                    auto_stake: 251_600_000,
414
1
                    manual_shares: 0,
415
1
                    manual_stake: 0,
416
1
                    pending_rewards: 0,
417
1
                },
418
1
            ],
419
1
            Distribution {
420
1
                collator_auto: 1_006_400,
421
1
                collator_manual: 993_600,
422
1
                delegators_auto: 8_000_000,
423
1
                delegators_manual: 0,
424
1
            },
425
1
        )
426
1
    });
427
1
}
428

            
429
#[test]
430
1
fn delegators_mixed() {
431
1
    ExtBuilder::default().build().execute_with(|| {
432
1
        test_distribution(
433
1
            &[
434
1
                Delegation {
435
1
                    candidate: ACCOUNT_CANDIDATE_1,
436
1
                    delegator: ACCOUNT_CANDIDATE_1,
437
1
                    pool: ActivePoolKind::AutoCompounding,
438
1
                    stake: 1_000_000_000,
439
1
                },
440
1
                Delegation {
441
1
                    candidate: ACCOUNT_CANDIDATE_1,
442
1
                    delegator: ACCOUNT_CANDIDATE_1,
443
1
                    pool: ActivePoolKind::ManualRewards,
444
1
                    stake: 500_000_000,
445
1
                },
446
1
                Delegation {
447
1
                    candidate: ACCOUNT_CANDIDATE_1,
448
1
                    delegator: ACCOUNT_DELEGATOR_1,
449
1
                    pool: ActivePoolKind::ManualRewards,
450
1
                    stake: 250_000_000,
451
1
                },
452
1
                Delegation {
453
1
                    candidate: ACCOUNT_CANDIDATE_1,
454
1
                    delegator: ACCOUNT_DELEGATOR_1,
455
1
                    pool: ActivePoolKind::AutoCompounding,
456
1
                    stake: 500_000_000,
457
1
                },
458
1
            ],
459
1
            RewardRequest {
460
1
                collator: ACCOUNT_CANDIDATE_1,
461
1
                rewards: 10_000_000,
462
1
            },
463
1
            &[
464
1
                DelegatorState {
465
1
                    candidate: ACCOUNT_CANDIDATE_1,
466
1
                    delegator: ACCOUNT_CANDIDATE_1,
467
1
                    auto_shares: 1_001,
468
1
                    auto_stake: 1_004_559_388,
469
1
                    manual_shares: 500,
470
1
                    manual_stake: 500_000_000,
471
1
                    pending_rewards: 1_777_500,
472
1
                },
473
1
                DelegatorState {
474
1
                    candidate: ACCOUNT_CANDIDATE_1,
475
1
                    delegator: ACCOUNT_DELEGATOR_1,
476
1
                    auto_shares: 500,
477
1
                    auto_stake: 501_777_916,
478
1
                    manual_shares: 250,
479
1
                    manual_stake: 250_000_000,
480
1
                    pending_rewards: 888_750,
481
1
                },
482
1
            ],
483
1
            Distribution {
484
1
                collator_auto: 1_003_555,
485
1
                collator_manual: 996_445,
486
1
                // Total stake: 2_250_000_000
487
1
                // Auto stake: 1_500_000_000
488
1
                // Manual stake: 750_000_000
489
1
                // Manual shares: 750
490
1
                // Rewards towards delegators: 80% of 10_000_000 = 8_000_000
491
1
                // Rewards towards manual deleg
492
1
                //   = 8_000_000 * 750_000_000 / 2_250_000_000
493
1
                //   = 2_666_666
494
1
                //   => 2_666_250 (rounding down to closest multiple of 750)
495
1
                //   gives dust of 2_666_666 - 2_666_250 = 416
496
1
                delegators_manual: 2_666_250,
497
1
                // Rewards towards auto deleg
498
1
                // = Rewards deleg - Rewards manual deleg
499
1
                // = 8_000_000 - 2_666_250
500
1
                // = 5_333_750
501
1
                delegators_auto: 5_333_750,
502
1
            },
503
1
        );
504
1
    });
505
1
}
506

            
507
#[test]
508
1
fn candidate_only_no_stake() {
509
1
    // Rewarding a candidate that does not have any stake works
510
1
    ExtBuilder::default().build().execute_with(|| {
511
1
        test_distribution(
512
1
            &[],
513
1
            RewardRequest {
514
1
                collator: ACCOUNT_CANDIDATE_1,
515
1
                rewards: 1_000_000,
516
1
            },
517
1
            &[],
518
1
            Distribution {
519
1
                collator_auto: 0,
520
1
                collator_manual: 1_000_000, // 100% of rewards
521
1
                delegators_auto: 0,
522
1
                delegators_manual: 0, // 0% of rewards
523
1
            },
524
1
        )
525
1
    });
526
1
}
527

            
528
#[test]
529
1
fn delegator_only_candidate_zero() {
530
1
    // Rewarding a candidate that does not have any stake works
531
1
    ExtBuilder::default().build().execute_with(|| {
532
1
        test_distribution(
533
1
            &[Delegation {
534
1
                candidate: ACCOUNT_CANDIDATE_1,
535
1
                delegator: ACCOUNT_DELEGATOR_1,
536
1
                pool: ActivePoolKind::ManualRewards,
537
1
                stake: 250_000_000,
538
1
            }],
539
1
            RewardRequest {
540
1
                collator: ACCOUNT_CANDIDATE_1,
541
1
                rewards: 1_000_000,
542
1
            },
543
1
            &[DelegatorState {
544
1
                candidate: ACCOUNT_CANDIDATE_1,
545
1
                delegator: ACCOUNT_DELEGATOR_1,
546
1
                auto_shares: 0,
547
1
                auto_stake: 0,
548
1
                manual_shares: 250,
549
1
                manual_stake: 250_000_000,
550
1
                pending_rewards: 800_000,
551
1
            }],
552
1
            Distribution {
553
1
                collator_auto: 0,
554
1
                collator_manual: 200_000, // 20% of rewards
555
1
                delegators_auto: 0,
556
1
                delegators_manual: 800_000, // 80% of rewards
557
1
            },
558
1
        )
559
1
    });
560
1
}
561

            
562
#[test]
563
1
fn delegator_only_candidate_no_stake_auto_compounding() {
564
1
    // Rewarding a candidate that does not have any stake, while some delegator
565
1
    // has stake for that candidate
566
1
    ExtBuilder::default().build().execute_with(|| {
567
1
        test_distribution(
568
1
            &[Delegation {
569
1
                candidate: ACCOUNT_CANDIDATE_1,
570
1
                delegator: ACCOUNT_DELEGATOR_1,
571
1
                pool: ActivePoolKind::AutoCompounding,
572
1
                stake: 250_000_000,
573
1
            }],
574
1
            RewardRequest {
575
1
                collator: ACCOUNT_CANDIDATE_1,
576
1
                rewards: 1_000_000,
577
1
            },
578
1
            &[],
579
1
            Distribution {
580
1
                collator_auto: 0,
581
1
                collator_manual: 200_000, // 20% of rewards
582
1
                delegators_auto: 800_000, // 80% of rewards
583
1
                delegators_manual: 0,
584
1
            },
585
1
        )
586
1
    });
587
1
}
588

            
589
#[test]
590
1
fn reward_distribution_is_transactional() {
591
1
    ExtBuilder::default().build().execute_with(|| {
592
        use crate::traits::Timer;
593
1
        let request_time = <Runtime as crate::Config>::JoiningRequestTimer::now();
594
1

            
595
1
        assert_ok!(Staking::request_delegate(
596
1
            RuntimeOrigin::signed(ACCOUNT_CANDIDATE_1),
597
1
            ACCOUNT_CANDIDATE_1,
598
1
            ActivePoolKind::AutoCompounding,
599
1
            1_000_000_000,
600
1
        ));
601

            
602
        // Wait for delegation to be executable
603
3
        for _ in 0..BLOCKS_TO_WAIT {
604
2
            roll_one_block();
605
2
        }
606

            
607
1
        assert_ok!(Staking::execute_pending_operations(
608
1
            RuntimeOrigin::signed(ACCOUNT_CANDIDATE_1),
609
1
            vec![PendingOperationQuery {
610
1
                delegator: ACCOUNT_CANDIDATE_1,
611
1
                operation: PendingOperationKey::JoiningAutoCompounding {
612
1
                    candidate: ACCOUNT_CANDIDATE_1,
613
1
                    at: request_time
614
1
                },
615
1
            }]
616
1
        ));
617

            
618
1
        let total_staked_before =
619
1
            pools::AutoCompounding::<Runtime>::total_staked(&ACCOUNT_CANDIDATE_1);
620
1

            
621
1
        // Increase ED to make reward destribution fail when resolving
622
1
        // credit to Staking account.
623
1
        MockExistentialDeposit::set(u128::MAX);
624
1

            
625
1
        let rewards = Balances::issue(1_000_000_000);
626
1
        assert_err!(
627
1
            Staking::distribute_rewards(ACCOUNT_CANDIDATE_1, rewards),
628
1
            DispatchError::NoProviders
629
1
        );
630

            
631
1
        let total_staked_after =
632
1
            pools::AutoCompounding::<Runtime>::total_staked(&ACCOUNT_CANDIDATE_1);
633
1
        assert_eq!(
634
            total_staked_before, total_staked_after,
635
            "distribution should be reverted"
636
        );
637
1
    })
638
1
}