@@ -457,155 +457,148 @@ impl<T: Config> Pallet<T> {
457
457
}
458
458
}
459
459
460
- /// Swaps TAO for the alpha token on the subnet.
460
+ /// Calculates Some(Alpha) returned from pool by staking operation
461
+ /// if liquidity allows that. If not, returns None.
461
462
///
462
- /// Updates TaoIn, AlphaIn, and AlphaOut
463
- pub fn sim_swap_tao_for_alpha ( netuid : u16 , tao : u64 ) -> u64 {
463
+ /// If new alpha_reserve is about to drop below DefaultMinimumPoolLiquidity,
464
+ /// then don't do it.
465
+ ///
466
+ pub fn sim_swap_tao_for_alpha ( netuid : u16 , tao : u64 ) -> Option < u64 > {
464
467
// Step 1: Get the mechanism type for the subnet (0 for Stable, 1 for Dynamic)
465
468
let mechanism_id: u16 = SubnetMechanism :: < T > :: get ( netuid) ;
466
469
// Step 2: Initialized vars.
467
- let alpha : I96F32 = if mechanism_id == 1 {
470
+ if mechanism_id == 1 {
468
471
// Step 3.a.1: Dynamic mechanism calculations
469
472
let tao_reserves: I96F32 = I96F32 :: saturating_from_num ( SubnetTAO :: < T > :: get ( netuid) ) ;
470
473
let alpha_reserves: I96F32 =
471
474
I96F32 :: saturating_from_num ( SubnetAlphaIn :: < T > :: get ( netuid) ) ;
472
475
// Step 3.a.2: Compute constant product k = alpha * tao
473
476
let k: I96F32 = alpha_reserves. saturating_mul ( tao_reserves) ;
477
+
478
+ // Calculate new alpha reserve
479
+ let new_alpha_reserves: I96F32 = k
480
+ . checked_div ( tao_reserves. saturating_add ( I96F32 :: saturating_from_num ( tao) ) )
481
+ . unwrap_or ( I96F32 :: saturating_from_num ( 0 ) ) ;
482
+
474
483
// Step 3.a.3: Calculate alpha staked using the constant product formula
475
484
// alpha_stake_recieved = current_alpha - (k / (current_tao + new_tao))
476
- alpha_reserves. saturating_sub (
477
- k. checked_div ( tao_reserves. saturating_add ( I96F32 :: saturating_from_num ( tao) ) )
478
- . unwrap_or ( I96F32 :: saturating_from_num ( 0 ) ) ,
479
- )
485
+ if new_alpha_reserves >= DefaultMinimumPoolLiquidity :: < T > :: get ( ) {
486
+ Some (
487
+ alpha_reserves
488
+ . saturating_sub ( new_alpha_reserves)
489
+ . saturating_to_num :: < u64 > ( ) ,
490
+ )
491
+ } else {
492
+ None
493
+ }
480
494
} else {
481
495
// Step 3.b.1: Stable mechanism, just return the value 1:1
482
- I96F32 :: saturating_from_num ( tao)
483
- } ;
484
- // Return simulated amount.
485
- alpha. saturating_to_num :: < u64 > ( )
496
+ Some ( tao)
497
+ }
486
498
}
487
499
488
- /// Swaps a subnet's Alpba token for TAO.
500
+ /// Calculates Some(Tao) returned from pool by unstaking operation
501
+ /// if liquidity allows that. If not, returns None.
489
502
///
490
- /// Updates TaoIn, AlphaIn, and AlphaOut
491
- pub fn sim_swap_alpha_for_tao ( netuid : u16 , alpha : u64 ) -> u64 {
503
+ /// If new tao_reserve is about to drop below DefaultMinimumPoolLiquidity,
504
+ /// then don't do it.
505
+ ///
506
+ pub fn sim_swap_alpha_for_tao ( netuid : u16 , alpha : u64 ) -> Option < u64 > {
492
507
// Step 1: Get the mechanism type for the subnet (0 for Stable, 1 for Dynamic)
493
508
let mechanism_id: u16 = SubnetMechanism :: < T > :: get ( netuid) ;
494
509
// Step 2: Swap alpha and attain tao
495
- let tao : I96F32 = if mechanism_id == 1 {
510
+ if mechanism_id == 1 {
496
511
// Step 3.a.1: Dynamic mechanism calculations
497
512
let tao_reserves: I96F32 = I96F32 :: saturating_from_num ( SubnetTAO :: < T > :: get ( netuid) ) ;
498
513
let alpha_reserves: I96F32 =
499
514
I96F32 :: saturating_from_num ( SubnetAlphaIn :: < T > :: get ( netuid) ) ;
500
515
// Step 3.a.2: Compute constant product k = alpha * tao
501
516
let k: I96F32 = alpha_reserves. saturating_mul ( tao_reserves) ;
517
+
518
+ // Calculate new tao reserve
519
+ let new_tao_reserves: I96F32 = k
520
+ . checked_div ( alpha_reserves. saturating_add ( I96F32 :: saturating_from_num ( alpha) ) )
521
+ . unwrap_or ( I96F32 :: saturating_from_num ( 0 ) ) ;
522
+
502
523
// Step 3.a.3: Calculate alpha staked using the constant product formula
503
524
// tao_recieved = tao_reserves - (k / (alpha_reserves + new_tao))
504
- tao_reserves. saturating_sub (
505
- k. checked_div ( alpha_reserves. saturating_add ( I96F32 :: saturating_from_num ( alpha) ) )
506
- . unwrap_or ( I96F32 :: saturating_from_num ( 0 ) ) ,
507
- )
525
+ if new_tao_reserves >= DefaultMinimumPoolLiquidity :: < T > :: get ( ) {
526
+ Some (
527
+ tao_reserves
528
+ . saturating_sub ( new_tao_reserves)
529
+ . saturating_to_num :: < u64 > ( ) ,
530
+ )
531
+ } else {
532
+ None
533
+ }
508
534
} else {
509
535
// Step 3.b.1: Stable mechanism, just return the value 1:1
510
- I96F32 :: saturating_from_num ( alpha)
511
- } ;
512
- tao. saturating_to_num :: < u64 > ( )
536
+ Some ( alpha)
537
+ }
513
538
}
514
539
515
540
/// Swaps TAO for the alpha token on the subnet.
516
541
///
517
542
/// Updates TaoIn, AlphaIn, and AlphaOut
518
543
pub fn swap_tao_for_alpha ( netuid : u16 , tao : u64 ) -> u64 {
519
- // Step 1: Get the mechanism type for the subnet (0 for Stable, 1 for Dynamic)
520
- let mechanism_id: u16 = SubnetMechanism :: < T > :: get ( netuid) ;
521
- // Step 2: Initialized vars.
522
- let alpha: I96F32 = if mechanism_id == 1 {
523
- // Step 3.a.1: Dynamic mechanism calculations
524
- let tao_reserves: I96F32 = I96F32 :: saturating_from_num ( SubnetTAO :: < T > :: get ( netuid) ) ;
525
- let alpha_reserves: I96F32 =
526
- I96F32 :: saturating_from_num ( SubnetAlphaIn :: < T > :: get ( netuid) ) ;
527
- // Step 3.a.2: Compute constant product k = alpha * tao
528
- let k: I96F32 = alpha_reserves. saturating_mul ( tao_reserves) ;
529
- // Step 3.a.3: Calculate alpha staked using the constant product formula
530
- // alpha_stake_recieved = current_alpha - (k / (current_tao + new_tao))
531
- alpha_reserves. saturating_sub (
532
- k. checked_div ( tao_reserves. saturating_add ( I96F32 :: saturating_from_num ( tao) ) )
533
- . unwrap_or ( I96F32 :: saturating_from_num ( 0 ) ) ,
534
- )
544
+ if let Some ( alpha) = Self :: sim_swap_tao_for_alpha ( netuid, tao) {
545
+ // Step 4. Decrease Alpha reserves.
546
+ SubnetAlphaIn :: < T > :: mutate ( netuid, |total| {
547
+ * total = total. saturating_sub ( alpha) ;
548
+ } ) ;
549
+ // Step 5: Increase Alpha outstanding.
550
+ SubnetAlphaOut :: < T > :: mutate ( netuid, |total| {
551
+ * total = total. saturating_add ( alpha) ;
552
+ } ) ;
553
+ // Step 6: Increase Tao reserves.
554
+ SubnetTAO :: < T > :: mutate ( netuid, |total| {
555
+ * total = total. saturating_add ( tao) ;
556
+ } ) ;
557
+ // Step 7: Increase Total Tao reserves.
558
+ TotalStake :: < T > :: mutate ( |total| {
559
+ * total = total. saturating_add ( tao) ;
560
+ } ) ;
561
+ // Step 8. Decrease Alpha reserves.
562
+ SubnetVolume :: < T > :: mutate ( netuid, |total| {
563
+ * total = total. saturating_add ( tao) ;
564
+ } ) ;
565
+ // Step 9. Return the alpha received.
566
+ alpha
535
567
} else {
536
- // Step 3.b.1: Stable mechanism, just return the value 1:1
537
- I96F32 :: saturating_from_num ( tao)
538
- } ;
539
- // Step 4. Decrease Alpha reserves.
540
- SubnetAlphaIn :: < T > :: mutate ( netuid, |total| {
541
- * total = total. saturating_sub ( alpha. saturating_to_num :: < u64 > ( ) ) ;
542
- } ) ;
543
- // Step 5: Increase Alpha outstanding.
544
- SubnetAlphaOut :: < T > :: mutate ( netuid, |total| {
545
- * total = total. saturating_add ( alpha. saturating_to_num :: < u64 > ( ) ) ;
546
- } ) ;
547
- // Step 6: Increase Tao reserves.
548
- SubnetTAO :: < T > :: mutate ( netuid, |total| {
549
- * total = total. saturating_add ( tao) ;
550
- } ) ;
551
- // Step 7: Increase Total Tao reserves.
552
- TotalStake :: < T > :: mutate ( |total| {
553
- * total = total. saturating_add ( tao) ;
554
- } ) ;
555
- // Step 8. Decrease Alpha reserves.
556
- SubnetVolume :: < T > :: mutate ( netuid, |total| {
557
- * total = total. saturating_sub ( tao) ;
558
- } ) ;
559
- // Step 9. Return the alpha received.
560
- alpha. saturating_to_num :: < u64 > ( )
568
+ 0
569
+ }
561
570
}
562
571
563
572
/// Swaps a subnet's Alpba token for TAO.
564
573
///
565
574
/// Updates TaoIn, AlphaIn, and AlphaOut
566
575
pub fn swap_alpha_for_tao ( netuid : u16 , alpha : u64 ) -> u64 {
567
- // Step 1: Get the mechanism type for the subnet (0 for Stable, 1 for Dynamic)
568
- let mechanism_id: u16 = SubnetMechanism :: < T > :: get ( netuid) ;
569
- // Step 2: Swap alpha and attain tao
570
- let tao: I96F32 = if mechanism_id == 1 {
571
- // Step 3.a.1: Dynamic mechanism calculations
572
- let tao_reserves: I96F32 = I96F32 :: saturating_from_num ( SubnetTAO :: < T > :: get ( netuid) ) ;
573
- let alpha_reserves: I96F32 =
574
- I96F32 :: saturating_from_num ( SubnetAlphaIn :: < T > :: get ( netuid) ) ;
575
- // Step 3.a.2: Compute constant product k = alpha * tao
576
- let k: I96F32 = alpha_reserves. saturating_mul ( tao_reserves) ;
577
- // Step 3.a.3: Calculate alpha staked using the constant product formula
578
- // tao_recieved = tao_reserves - (k / (alpha_reserves + new_tao))
579
- tao_reserves. saturating_sub (
580
- k. checked_div ( alpha_reserves. saturating_add ( I96F32 :: saturating_from_num ( alpha) ) )
581
- . unwrap_or ( I96F32 :: saturating_from_num ( 0 ) ) ,
582
- )
576
+ if let Some ( tao) = Self :: sim_swap_alpha_for_tao ( netuid, alpha) {
577
+ // Step 4: Increase Alpha reserves.
578
+ SubnetAlphaIn :: < T > :: mutate ( netuid, |total| {
579
+ * total = total. saturating_add ( alpha) ;
580
+ } ) ;
581
+ // Step 5: Decrease Alpha outstanding.
582
+ SubnetAlphaOut :: < T > :: mutate ( netuid, |total| {
583
+ * total = total. saturating_sub ( alpha) ;
584
+ } ) ;
585
+ // Step 6: Decrease tao reserves.
586
+ SubnetTAO :: < T > :: mutate ( netuid, |total| {
587
+ * total = total. saturating_sub ( tao) ;
588
+ } ) ;
589
+ // Step 7: Reduce total TAO reserves.
590
+ TotalStake :: < T > :: mutate ( |total| {
591
+ * total = total. saturating_sub ( tao) ;
592
+ } ) ;
593
+ // Step 8. Decrease Alpha reserves.
594
+ SubnetVolume :: < T > :: mutate ( netuid, |total| {
595
+ * total = total. saturating_add ( tao) ;
596
+ } ) ;
597
+ // Step 9. Return the tao received.
598
+ tao
583
599
} else {
584
- // Step 3.b.1: Stable mechanism, just return the value 1:1
585
- I96F32 :: saturating_from_num ( alpha)
586
- } ;
587
- // Step 4: Increase Alpha reserves.
588
- SubnetAlphaIn :: < T > :: mutate ( netuid, |total| {
589
- * total = total. saturating_add ( alpha) ;
590
- } ) ;
591
- // Step 5: Decrease Alpha outstanding.
592
- SubnetAlphaOut :: < T > :: mutate ( netuid, |total| {
593
- * total = total. saturating_sub ( alpha) ;
594
- } ) ;
595
- // Step 6: Decrease tao reserves.
596
- SubnetTAO :: < T > :: mutate ( netuid, |total| {
597
- * total = total. saturating_sub ( tao. saturating_to_num :: < u64 > ( ) ) ;
598
- } ) ;
599
- // Step 7: Reduce total TAO reserves.
600
- TotalStake :: < T > :: mutate ( |total| {
601
- * total = total. saturating_sub ( tao. saturating_to_num :: < u64 > ( ) ) ;
602
- } ) ;
603
- // Step 8. Decrease Alpha reserves.
604
- SubnetVolume :: < T > :: mutate ( netuid, |total| {
605
- * total = total. saturating_sub ( tao. saturating_to_num :: < u64 > ( ) ) ;
606
- } ) ;
607
- // Step 9. Return the tao received.
608
- tao. saturating_to_num :: < u64 > ( )
600
+ 0
601
+ }
609
602
}
610
603
611
604
/// Unstakes alpha from a subnet for a given hotkey and coldkey pair.
@@ -759,6 +752,12 @@ impl<T: Config> Pallet<T> {
759
752
Error :: <T >:: HotKeyAccountNotExists
760
753
) ;
761
754
755
+ // Ensure that we have adequate liquidity
756
+ ensure ! (
757
+ Self :: sim_swap_tao_for_alpha( netuid, stake_to_be_added) . is_some( ) ,
758
+ Error :: <T >:: InsufficientLiquidity
759
+ ) ;
760
+
762
761
Ok ( ( ) )
763
762
}
764
763
@@ -774,11 +773,14 @@ impl<T: Config> Pallet<T> {
774
773
ensure ! ( Self :: if_subnet_exist( netuid) , Error :: <T >:: SubnetNotExists ) ;
775
774
776
775
// Ensure that the stake amount to be removed is above the minimum in tao equivalent.
777
- let tao_equivalent = Self :: sim_swap_alpha_for_tao ( netuid, alpha_unstaked) ;
778
- ensure ! (
779
- tao_equivalent > DefaultMinStake :: <T >:: get( ) ,
780
- Error :: <T >:: AmountTooLow
781
- ) ;
776
+ if let Some ( tao_equivalent) = Self :: sim_swap_alpha_for_tao ( netuid, alpha_unstaked) {
777
+ ensure ! (
778
+ tao_equivalent > DefaultMinStake :: <T >:: get( ) ,
779
+ Error :: <T >:: AmountTooLow
780
+ ) ;
781
+ } else {
782
+ return Err ( Error :: < T > :: InsufficientLiquidity ) ;
783
+ } ;
782
784
783
785
// Ensure that the hotkey account exists this is only possible through registration.
784
786
ensure ! (
@@ -843,11 +845,14 @@ impl<T: Config> Pallet<T> {
843
845
) ;
844
846
845
847
// Ensure that the stake amount to be removed is above the minimum in tao equivalent.
846
- let tao_equivalent = Self :: sim_swap_alpha_for_tao ( origin_netuid, alpha_amount) ;
847
- ensure ! (
848
- tao_equivalent > DefaultMinStake :: <T >:: get( ) ,
849
- Error :: <T >:: AmountTooLow
850
- ) ;
848
+ if let Some ( tao_equivalent) = Self :: sim_swap_alpha_for_tao ( origin_netuid, alpha_amount) {
849
+ ensure ! (
850
+ tao_equivalent > DefaultMinStake :: <T >:: get( ) ,
851
+ Error :: <T >:: AmountTooLow
852
+ ) ;
853
+ } else {
854
+ return Err ( Error :: < T > :: InsufficientLiquidity ) ;
855
+ }
851
856
852
857
Ok ( ( ) )
853
858
}
0 commit comments