@@ -252,27 +252,10 @@ impl<T: Config> Pallet<T> {
252
252
}
253
253
}
254
254
255
- pub fn drain_pending_emission (
255
+ pub fn calculate_dividends_and_incentives (
256
256
netuid : u16 ,
257
- pending_alpha : u64 ,
258
- pending_tao : u64 ,
259
- pending_swapped : u64 ,
260
- owner_cut : u64 ,
261
- ) {
262
- log:: debug!(
263
- "Draining pending alpha emission for netuid {:?}, pending_alpha: {:?}, pending_tao: {:?}, pending_swapped: {:?}, owner_cut: {:?}" ,
264
- netuid,
265
- pending_alpha,
266
- pending_tao,
267
- pending_swapped,
268
- owner_cut
269
- ) ;
270
-
271
- // Run the epoch.
272
- let hotkey_emission: Vec < ( T :: AccountId , u64 , u64 ) > =
273
- Self :: epoch ( netuid, pending_alpha. saturating_add ( pending_swapped) ) ;
274
- log:: debug!( "hotkey_emission: {:?}" , hotkey_emission) ;
275
-
257
+ hotkey_emission : Vec < ( T :: AccountId , u64 , u64 ) > ,
258
+ ) -> ( BTreeMap < T :: AccountId , u64 > , BTreeMap < T :: AccountId , I96F32 > ) {
276
259
// Accumulate emission of dividends and incentive per hotkey.
277
260
let mut incentives: BTreeMap < T :: AccountId , u64 > = BTreeMap :: new ( ) ;
278
261
let mut dividends: BTreeMap < T :: AccountId , I96F32 > = BTreeMap :: new ( ) ;
@@ -284,7 +267,7 @@ impl<T: Config> Pallet<T> {
284
267
. or_insert ( incentive) ;
285
268
// Accumulate dividends to parents.
286
269
let div_tuples: Vec < ( T :: AccountId , u64 ) > =
287
- Self :: get_dividends_distribution ( & hotkey, netuid, dividend) ;
270
+ Self :: get_parent_child_dividends_distribution ( & hotkey, netuid, dividend) ;
288
271
// Accumulate dividends per hotkey.
289
272
for ( parent, parent_div) in div_tuples {
290
273
dividends
@@ -296,64 +279,71 @@ impl<T: Config> Pallet<T> {
296
279
log:: debug!( "incentives: {:?}" , incentives) ;
297
280
log:: debug!( "dividends: {:?}" , dividends) ;
298
281
299
- Self :: distribute_dividends_and_incentives (
300
- netuid,
301
- pending_tao,
302
- owner_cut,
303
- incentives,
304
- dividends,
305
- ) ;
282
+ ( incentives, dividends)
306
283
}
307
284
308
- pub fn distribute_dividends_and_incentives (
309
- netuid : u16 ,
285
+ pub fn calculate_dividend_distribution (
286
+ pending_alpha : u64 ,
310
287
pending_tao : u64 ,
311
- owner_cut : u64 ,
312
- incentives : BTreeMap < T :: AccountId , u64 > ,
288
+ tao_weight : I96F32 ,
289
+ stake_map : BTreeMap < T :: AccountId , ( u64 , u64 ) > ,
313
290
dividends : BTreeMap < T :: AccountId , I96F32 > ,
291
+ ) -> (
292
+ BTreeMap < T :: AccountId , I96F32 > ,
293
+ BTreeMap < T :: AccountId , I96F32 > ,
314
294
) {
295
+ log:: debug!( "dividends: {:?}" , dividends) ;
296
+ log:: debug!( "stake_map: {:?}" , stake_map) ;
297
+ log:: debug!( "pending_alpha: {:?}" , pending_alpha) ;
298
+ log:: debug!( "pending_tao: {:?}" , pending_tao) ;
299
+ log:: debug!( "tao_weight: {:?}" , tao_weight) ;
300
+
315
301
// Setup.
316
302
let zero: I96F32 = asfloat ! ( 0.0 ) ;
317
303
318
304
// Accumulate root divs and alpha_divs. For each hotkey we compute their
319
305
// local and root dividend proportion based on their alpha_stake/root_stake
320
306
let mut total_root_divs: I96F32 = asfloat ! ( 0 ) ;
307
+ let mut total_alpha_divs: I96F32 = asfloat ! ( 0 ) ;
321
308
let mut root_dividends: BTreeMap < T :: AccountId , I96F32 > = BTreeMap :: new ( ) ;
322
309
let mut alpha_dividends: BTreeMap < T :: AccountId , I96F32 > = BTreeMap :: new ( ) ;
323
310
for ( hotkey, dividend) in dividends {
324
- // Get hotkey ALPHA on subnet.
325
- let alpha_stake = asfloat ! ( Self :: get_stake_for_hotkey_on_subnet( & hotkey, netuid) ) ;
326
- // Get hotkey TAO on root.
327
- let root_stake: I96F32 = asfloat ! ( Self :: get_stake_for_hotkey_on_subnet(
328
- & hotkey,
329
- Self :: get_root_netuid( )
330
- ) ) ;
331
- // Convert TAO to alpha with weight.
332
- let root_alpha: I96F32 = root_stake. saturating_mul ( Self :: get_tao_weight ( ) ) ;
333
- // Get total from root and local
334
- let total_alpha: I96F32 = alpha_stake. saturating_add ( root_alpha) ;
335
- // Copmute root prop.
336
- let root_prop: I96F32 = root_alpha. checked_div ( total_alpha) . unwrap_or ( zero) ;
337
- // Compute root dividends
338
- let root_divs: I96F32 = dividend. saturating_mul ( root_prop) ;
339
- // Compute alpha dividends
340
- let alpha_divs: I96F32 = dividend. saturating_sub ( root_divs) ;
341
- // Record the alpha dividends.
342
- alpha_dividends
343
- . entry ( hotkey. clone ( ) )
344
- . and_modify ( |e| * e = e. saturating_add ( alpha_divs) )
345
- . or_insert ( alpha_divs) ;
346
- // Record the root dividends.
347
- root_dividends
348
- . entry ( hotkey. clone ( ) )
349
- . and_modify ( |e| * e = e. saturating_add ( root_divs) )
350
- . or_insert ( root_divs) ;
351
- // Accumulate total root divs.
352
- total_root_divs = total_root_divs. saturating_add ( root_divs) ;
311
+ if let Some ( ( alpha_stake_u64, root_stake_u64) ) = stake_map. get ( & hotkey) {
312
+ // Get hotkey ALPHA on subnet.
313
+ let alpha_stake: I96F32 = asfloat ! ( * alpha_stake_u64) ;
314
+ // Get hotkey TAO on root.
315
+ let root_stake: I96F32 = asfloat ! ( * root_stake_u64) ;
316
+
317
+ // Convert TAO to alpha with weight.
318
+ let root_alpha: I96F32 = root_stake. saturating_mul ( tao_weight) ;
319
+ // Get total from root and local
320
+ let total_alpha: I96F32 = alpha_stake. saturating_add ( root_alpha) ;
321
+ // Compute root prop.
322
+ let root_prop: I96F32 = root_alpha. checked_div ( total_alpha) . unwrap_or ( zero) ;
323
+ // Compute root dividends
324
+ let root_divs: I96F32 = dividend. saturating_mul ( root_prop) ;
325
+ // Compute alpha dividends
326
+ let alpha_divs: I96F32 = dividend. saturating_sub ( root_divs) ;
327
+ // Record the alpha dividends.
328
+ alpha_dividends
329
+ . entry ( hotkey. clone ( ) )
330
+ . and_modify ( |e| * e = e. saturating_add ( alpha_divs) )
331
+ . or_insert ( alpha_divs) ;
332
+ // Accumulate total alpha divs.
333
+ total_alpha_divs = total_alpha_divs. saturating_add ( alpha_divs) ;
334
+ // Record the root dividends.
335
+ root_dividends
336
+ . entry ( hotkey. clone ( ) )
337
+ . and_modify ( |e| * e = e. saturating_add ( root_divs) )
338
+ . or_insert ( root_divs) ;
339
+ // Accumulate total root divs.
340
+ total_root_divs = total_root_divs. saturating_add ( root_divs) ;
341
+ }
353
342
}
354
343
log:: debug!( "alpha_dividends: {:?}" , alpha_dividends) ;
355
344
log:: debug!( "root_dividends: {:?}" , root_dividends) ;
356
345
log:: debug!( "total_root_divs: {:?}" , total_root_divs) ;
346
+ log:: debug!( "total_alpha_divs: {:?}" , total_alpha_divs) ;
357
347
358
348
// Compute root divs as TAO. Here we take
359
349
let mut tao_dividends: BTreeMap < T :: AccountId , I96F32 > = BTreeMap :: new ( ) ;
@@ -372,6 +362,34 @@ impl<T: Config> Pallet<T> {
372
362
}
373
363
log:: debug!( "tao_dividends: {:?}" , tao_dividends) ;
374
364
365
+ // Compute proportional alpha divs using the pending alpha and total alpha divs from the epoch.
366
+ let mut prop_alpha_dividends: BTreeMap < T :: AccountId , I96F32 > = BTreeMap :: new ( ) ;
367
+ for ( hotkey, alpha_divs) in alpha_dividends {
368
+ // Alpha proportion.
369
+ let alpha_share: I96F32 = alpha_divs. checked_div ( total_alpha_divs) . unwrap_or ( zero) ;
370
+ log:: debug!( "hotkey: {:?}, alpha_share: {:?}" , hotkey, alpha_share) ;
371
+
372
+ // Compute the proportional pending_alpha to this hotkey.
373
+ let prop_alpha: I96F32 = asfloat ! ( pending_alpha) . saturating_mul ( alpha_share) ;
374
+ log:: debug!( "hotkey: {:?}, prop_alpha: {:?}" , hotkey, prop_alpha) ;
375
+ // Record the proportional alpha dividends.
376
+ prop_alpha_dividends
377
+ . entry ( hotkey. clone ( ) )
378
+ . and_modify ( |e| * e = prop_alpha)
379
+ . or_insert ( prop_alpha) ;
380
+ }
381
+ log:: debug!( "prop_alpha_dividends: {:?}" , prop_alpha_dividends) ;
382
+
383
+ ( prop_alpha_dividends, tao_dividends)
384
+ }
385
+
386
+ pub fn distribute_dividends_and_incentives (
387
+ netuid : u16 ,
388
+ owner_cut : u64 ,
389
+ incentives : BTreeMap < T :: AccountId , u64 > ,
390
+ alpha_dividends : BTreeMap < T :: AccountId , I96F32 > ,
391
+ tao_dividends : BTreeMap < T :: AccountId , I96F32 > ,
392
+ ) {
375
393
// Distribute the owner cut.
376
394
if let Ok ( owner_coldkey) = SubnetOwner :: < T > :: try_get ( netuid) {
377
395
if let Ok ( owner_hotkey) = SubnetOwnerHotkey :: < T > :: try_get ( netuid) {
@@ -468,6 +486,114 @@ impl<T: Config> Pallet<T> {
468
486
}
469
487
}
470
488
489
+ pub fn get_stake_map (
490
+ netuid : u16 ,
491
+ hotkeys : Vec < & T :: AccountId > ,
492
+ ) -> BTreeMap < T :: AccountId , ( u64 , u64 ) > {
493
+ let mut stake_map: BTreeMap < T :: AccountId , ( u64 , u64 ) > = BTreeMap :: new ( ) ;
494
+ for hotkey in hotkeys {
495
+ // Get hotkey ALPHA on subnet.
496
+ let alpha_stake: u64 = Self :: get_stake_for_hotkey_on_subnet ( hotkey, netuid) ;
497
+ // Get hotkey TAO on root.
498
+ let root_stake: u64 =
499
+ Self :: get_stake_for_hotkey_on_subnet ( hotkey, Self :: get_root_netuid ( ) ) ;
500
+ stake_map. insert ( hotkey. clone ( ) , ( alpha_stake, root_stake) ) ;
501
+ }
502
+ stake_map
503
+ }
504
+
505
+ pub fn calculate_dividend_and_incentive_distribution (
506
+ netuid : u16 ,
507
+ pending_tao : u64 ,
508
+ pending_validator_alpha : u64 ,
509
+ hotkey_emission : Vec < ( T :: AccountId , u64 , u64 ) > ,
510
+ tao_weight : I96F32 ,
511
+ ) -> (
512
+ BTreeMap < T :: AccountId , u64 > ,
513
+ (
514
+ BTreeMap < T :: AccountId , I96F32 > ,
515
+ BTreeMap < T :: AccountId , I96F32 > ,
516
+ ) ,
517
+ ) {
518
+ let ( incentives, dividends) =
519
+ Self :: calculate_dividends_and_incentives ( netuid, hotkey_emission) ;
520
+
521
+ let stake_map: BTreeMap < T :: AccountId , ( u64 , u64 ) > =
522
+ Self :: get_stake_map ( netuid, dividends. keys ( ) . collect :: < Vec < _ > > ( ) ) ;
523
+
524
+ let ( alpha_dividends, tao_dividends) = Self :: calculate_dividend_distribution (
525
+ pending_validator_alpha,
526
+ pending_tao,
527
+ tao_weight,
528
+ stake_map,
529
+ dividends,
530
+ ) ;
531
+
532
+ ( incentives, ( alpha_dividends, tao_dividends) )
533
+ }
534
+
535
+ pub fn drain_pending_emission (
536
+ netuid : u16 ,
537
+ pending_alpha : u64 ,
538
+ pending_tao : u64 ,
539
+ pending_swapped : u64 ,
540
+ owner_cut : u64 ,
541
+ ) {
542
+ log:: debug!(
543
+ "Draining pending alpha emission for netuid {:?}, pending_alpha: {:?}, pending_tao: {:?}, pending_swapped: {:?}, owner_cut: {:?}" ,
544
+ netuid,
545
+ pending_alpha,
546
+ pending_tao,
547
+ pending_swapped,
548
+ owner_cut
549
+ ) ;
550
+
551
+ let tao_weight = Self :: get_tao_weight ( ) ;
552
+
553
+ // Run the epoch.
554
+ let hotkey_emission: Vec < ( T :: AccountId , u64 , u64 ) > =
555
+ Self :: epoch ( netuid, pending_alpha. saturating_add ( pending_swapped) ) ;
556
+ log:: debug!( "hotkey_emission: {:?}" , hotkey_emission) ;
557
+
558
+ // Compute the pending validator alpha.
559
+ // This is the total alpha being injected,
560
+ // minus the the alpha for the miners, (50%)
561
+ // and minus the alpha swapped for TAO (pending_swapped).
562
+ // Important! If the incentives are 0, then Validators get 100% of the alpha.
563
+ let incentive_sum = hotkey_emission
564
+ . iter ( )
565
+ . map ( |( _, incentive, _) | incentive)
566
+ . sum :: < u64 > ( ) ;
567
+ log:: debug!( "incentive_sum: {:?}" , incentive_sum) ;
568
+
569
+ let pending_validator_alpha: u64 = if incentive_sum != 0 {
570
+ pending_alpha
571
+ . saturating_add ( pending_swapped)
572
+ . saturating_div ( 2 )
573
+ . saturating_sub ( pending_swapped)
574
+ } else {
575
+ // If the incentive is 0, then Validators get 100% of the alpha.
576
+ pending_alpha
577
+ } ;
578
+
579
+ let ( incentives, ( alpha_dividends, tao_dividends) ) =
580
+ Self :: calculate_dividend_and_incentive_distribution (
581
+ netuid,
582
+ pending_tao,
583
+ pending_validator_alpha,
584
+ hotkey_emission,
585
+ tao_weight,
586
+ ) ;
587
+
588
+ Self :: distribute_dividends_and_incentives (
589
+ netuid,
590
+ owner_cut,
591
+ incentives,
592
+ alpha_dividends,
593
+ tao_dividends,
594
+ ) ;
595
+ }
596
+
471
597
/// Returns the self contribution of a hotkey on a subnet.
472
598
/// This is the portion of the hotkey's stake that is provided by itself, and not delegated to other hotkeys.
473
599
pub fn get_self_contribution ( hotkey : & T :: AccountId , netuid : u16 ) -> u64 {
@@ -516,7 +642,7 @@ impl<T: Config> Pallet<T> {
516
642
/// # Returns
517
643
/// * dividend_tuples: `Vec<(T::AccountId, u64)>` - Vector of (hotkey, divs) for each parent including self.
518
644
///
519
- pub fn get_dividends_distribution (
645
+ pub fn get_parent_child_dividends_distribution (
520
646
hotkey : & T :: AccountId ,
521
647
netuid : u16 ,
522
648
dividends : u64 ,
0 commit comments