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::{AutoCompounding, ManualRewards},
22
        Pallet, TargetPool,
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: TargetPool,
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
7
                    TargetPool::AutoCompounding => PendingOperationKey::JoiningAutoCompounding {
97
7
                        candidate: d.candidate,
98
7
                        at: block_number
99
7
                    },
100
7
                    TargetPool::ManualRewards => PendingOperationKey::JoiningManualRewards {
101
7
                        candidate: d.candidate,
102
7
                        at: block_number
103
7
                    },
104
                }
105
            }]
106
        ));
107
    }
108

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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