From b6cb0884891a6848003eec2d86e42590481de46d Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 5 Nov 2025 15:13:49 -0500 Subject: [PATCH 01/29] impl tests benchmarks --- pallets/subtensor/src/benchmarks.rs | 1 + .../subtensor/src/coinbase/run_coinbase.rs | 14 ++++++++++++-- pallets/subtensor/src/tests/claim_root.rs | 14 ++++++++++++++ pallets/subtensor/src/tests/coinbase.rs | 19 +++++++++++++++++++ 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index 2a13a18aa0..0e53facabc 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -1619,6 +1619,7 @@ mod pallet_benchmarks { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 53ac3c6ac5..9ced81fc5b 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -229,6 +229,9 @@ impl Pallet { if Self::should_run_epoch(netuid, current_block) && Self::is_epoch_input_state_consistent(netuid) { + let alpha_out_i: AlphaCurrency = + tou64!(*alpha_out.get(&netuid).unwrap_or(&asfloat!(0.0))).into(); + // Restart counters. BlocksSinceLastStep::::insert(netuid, 0); LastMechansimStepBlock::::insert(netuid, current_block); @@ -246,7 +249,13 @@ impl Pallet { PendingOwnerCut::::insert(netuid, AlphaCurrency::ZERO); // Drain pending root alpha divs, alpha emission, and owner cut. - Self::drain_pending_emission(netuid, pending_alpha, pending_root_alpha, owner_cut); + Self::drain_pending_emission( + netuid, + pending_alpha, + pending_root_alpha, + alpha_out_i, + owner_cut, + ); } else { // Increment BlocksSinceLastStep::::mutate(netuid, |total| *total = total.saturating_add(1)); @@ -604,6 +613,7 @@ impl Pallet { netuid: NetUid, pending_alpha: AlphaCurrency, pending_root_alpha: AlphaCurrency, + alpha_out: AlphaCurrency, // total alpha out for the subnet owner_cut: AlphaCurrency, ) { log::debug!( @@ -614,7 +624,7 @@ impl Pallet { // Run the epoch. let hotkey_emission: Vec<(T::AccountId, AlphaCurrency, AlphaCurrency)> = - Self::epoch_with_mechanisms(netuid, pending_alpha.saturating_add(pending_root_alpha)); + Self::epoch_with_mechanisms(netuid, alpha_out); log::debug!("hotkey_emission: {hotkey_emission:?}"); // Compute the pending validator alpha. diff --git a/pallets/subtensor/src/tests/claim_root.rs b/pallets/subtensor/src/tests/claim_root.rs index e73417a326..c75b4f5784 100644 --- a/pallets/subtensor/src/tests/claim_root.rs +++ b/pallets/subtensor/src/tests/claim_root.rs @@ -76,6 +76,7 @@ fn test_claim_root_with_drain_emissions() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -144,6 +145,7 @@ fn test_claim_root_with_drain_emissions() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -245,6 +247,7 @@ fn test_claim_root_adding_stake_proportionally_for_two_stakers() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -346,6 +349,7 @@ fn test_claim_root_adding_stake_disproportionally_for_two_stakers() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -437,6 +441,7 @@ fn test_claim_root_with_changed_stake() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -489,6 +494,7 @@ fn test_claim_root_with_changed_stake() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -542,6 +548,7 @@ fn test_claim_root_with_changed_stake() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -634,6 +641,7 @@ fn test_claim_root_with_drain_emissions_and_swap_claim_type() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -678,6 +686,7 @@ fn test_claim_root_with_drain_emissions_and_swap_claim_type() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -714,6 +723,7 @@ fn test_claim_root_with_drain_emissions_and_swap_claim_type() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -1100,6 +1110,7 @@ fn test_claim_root_with_swap_coldkey() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -1190,6 +1201,7 @@ fn test_claim_root_with_swap_hotkey() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -1306,6 +1318,7 @@ fn test_claim_root_on_network_deregistration() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -1446,6 +1459,7 @@ fn test_claim_root_with_unrelated_subnets() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index 60644b2a28..bbb7061e27 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -689,6 +689,7 @@ fn test_drain_base() { 0.into(), AlphaCurrency::ZERO, AlphaCurrency::ZERO, + AlphaCurrency::ZERO, // alpha out AlphaCurrency::ZERO, ) }); @@ -704,6 +705,7 @@ fn test_drain_base_with_subnet() { netuid, AlphaCurrency::ZERO, AlphaCurrency::ZERO, + AlphaCurrency::ZERO, // alpha out AlphaCurrency::ZERO, ) }); @@ -729,6 +731,7 @@ fn test_drain_base_with_subnet_with_single_staker_not_registered() { netuid, pending_alpha.into(), AlphaCurrency::ZERO, + pending_alpha.into(), // alpha out AlphaCurrency::ZERO, ); let stake_after = @@ -758,6 +761,7 @@ fn test_drain_base_with_subnet_with_single_staker_registered() { netuid, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, // alpha out AlphaCurrency::ZERO, ); let stake_after = @@ -802,6 +806,7 @@ fn test_drain_base_with_subnet_with_single_staker_registered_root_weight() { netuid, pending_alpha, pending_root_alpha, + pending_alpha.saturating_add(pending_root_alpha), // alpha out AlphaCurrency::ZERO, ); let stake_after = @@ -849,6 +854,7 @@ fn test_drain_base_with_subnet_with_two_stakers_registered() { netuid, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); let stake_after1 = @@ -914,6 +920,7 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root() { netuid, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); let stake_after1 = @@ -989,6 +996,7 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_am netuid, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, 0.into(), ); let stake_after1 = @@ -1069,6 +1077,7 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_am netuid, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); let stake_after1 = @@ -1130,6 +1139,7 @@ fn test_drain_alpha_childkey_parentkey() { netuid, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); let parent_stake_after = SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); @@ -1355,6 +1365,7 @@ fn test_get_root_children_drain() { alpha, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); @@ -1379,6 +1390,7 @@ fn test_get_root_children_drain() { pending_alpha, // pending_root1, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); @@ -1402,6 +1414,7 @@ fn test_get_root_children_drain() { alpha, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); @@ -1490,6 +1503,7 @@ fn test_get_root_children_drain_half_proportion() { alpha, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); @@ -1576,6 +1590,7 @@ fn test_get_root_children_drain_with_take() { alpha, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); @@ -1663,6 +1678,7 @@ fn test_get_root_children_drain_with_half_take() { alpha, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); @@ -2378,6 +2394,7 @@ fn test_drain_pending_emission_no_miners_all_drained() { netuid, emission, AlphaCurrency::ZERO, + emission, AlphaCurrency::ZERO, ); @@ -2451,6 +2468,7 @@ fn test_drain_pending_emission_zero_emission() { 0.into(), AlphaCurrency::ZERO, AlphaCurrency::ZERO, + AlphaCurrency::ZERO, ); // Get the new stake of the hotkey. @@ -2743,6 +2761,7 @@ fn test_drain_alpha_childkey_parentkey_with_burn() { netuid, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); let parent_stake_after = SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); From 3118bb7c53b78b94cd0b49f8277403f348134ea0 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 5 Nov 2025 15:13:59 -0500 Subject: [PATCH 02/29] bump spec --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 266a755708..240c490736 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -220,7 +220,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 338, + spec_version: 340, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 843bc884453a9aac28912f72a2acaf5f838a7bc8 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 5 Nov 2025 15:22:39 -0500 Subject: [PATCH 03/29] remove duplicate remove --- pallets/subtensor/src/coinbase/root.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index 642a7f18ac..80965f0bbb 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -348,7 +348,6 @@ impl Pallet { RAORecycledForRegistration::::remove(netuid); MaxRegistrationsPerBlock::::remove(netuid); WeightsVersionKey::::remove(netuid); - PendingRootAlphaDivs::::remove(netuid); // --- 17. Subtoken / feature flags. LiquidAlphaOn::::remove(netuid); From fb053c863b84c062551a1feccf0d14a27f64d9f3 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 5 Nov 2025 15:41:11 -0500 Subject: [PATCH 04/29] use alpha out here --- pallets/subtensor/src/coinbase/run_coinbase.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 9ced81fc5b..8ab4361353 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -640,8 +640,7 @@ impl Pallet { log::debug!("incentive_sum: {incentive_sum:?}"); let pending_validator_alpha = if !incentive_sum.is_zero() { - pending_alpha - .saturating_add(pending_root_alpha) + alpha_out .saturating_div(2.into()) .saturating_sub(pending_root_alpha) } else { From cb2085e031253123e21908a341c6422e5f89cce6 Mon Sep 17 00:00:00 2001 From: 0xcacti <97139981+0xcacti@users.noreply.github.com> Date: Wed, 5 Nov 2025 15:53:34 -0500 Subject: [PATCH 05/29] Hotfix/vune/epoch sub fix (#2186) * fix: injection logic * fix: fmt' --- .../subtensor/src/coinbase/run_coinbase.rs | 81 +++++++++++-------- 1 file changed, 48 insertions(+), 33 deletions(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 8ab4361353..6e759b9243 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -34,13 +34,19 @@ impl Pallet { // 2. Get subnets to emit to and emissions let subnet_emissions = Self::get_subnet_block_emissions(&subnets, block_emission); let subnets_to_emit_to: Vec = subnet_emissions.keys().copied().collect(); + let total_ema_price: U96F32 = subnets_to_emit_to + .iter() + .map(|netuid| Self::get_moving_alpha_price(*netuid)) + .sum(); + let subsidy_mode = total_ema_price <= U96F32::saturating_from_num(1); // --- 3. Get subnet terms (tao_in, alpha_in, and alpha_out) // Computation is described in detail in the dtao whitepaper. let mut tao_in: BTreeMap = BTreeMap::new(); let mut alpha_in: BTreeMap = BTreeMap::new(); let mut alpha_out: BTreeMap = BTreeMap::new(); - let mut is_subsidized: BTreeMap = BTreeMap::new(); + let mut subsidy_amount: BTreeMap = BTreeMap::new(); + // Only calculate for subnets that we are emitting to. for netuid_i in subnets_to_emit_to.iter() { // Get subnet price. @@ -62,32 +68,16 @@ impl Pallet { // Get initial alpha_in let mut alpha_in_i: U96F32; let mut tao_in_i: U96F32; - let tao_in_ratio: U96F32 = default_tao_in_i.safe_div_or( - U96F32::saturating_from_num(block_emission), - U96F32::saturating_from_num(0.0), - ); - if price_i < tao_in_ratio { - tao_in_i = price_i.saturating_mul(U96F32::saturating_from_num(block_emission)); - alpha_in_i = block_emission; + + if default_alpha_in_i > alpha_emission_i { + alpha_in_i = alpha_emission_i; + tao_in_i = alpha_in_i.saturating_mul(price_i); let difference_tao: U96F32 = default_tao_in_i.saturating_sub(tao_in_i); - // Difference becomes buy. - let buy_swap_result = Self::swap_tao_for_alpha( - *netuid_i, - tou64!(difference_tao).into(), - T::SwapInterface::max_price(), - true, - ); - if let Ok(buy_swap_result_ok) = buy_swap_result { - let bought_alpha = AlphaCurrency::from(buy_swap_result_ok.amount_paid_out); - SubnetAlphaOut::::mutate(*netuid_i, |total| { - *total = total.saturating_sub(bought_alpha); - }); - } - is_subsidized.insert(*netuid_i, true); + subsidy_amount.insert(*netuid_i, difference_tao); } else { tao_in_i = default_tao_in_i; - alpha_in_i = tao_in_i.safe_div_or(price_i, alpha_emission_i); - is_subsidized.insert(*netuid_i, false); + alpha_in_i = alpha_in_default_i; + subsidy_amount.insert(*netuid_i, U96F32::from_num(0.0)); } log::debug!("alpha_in_i: {alpha_in_i:?}"); @@ -110,9 +100,33 @@ impl Pallet { log::debug!("alpha_in: {alpha_in:?}"); log::debug!("alpha_out: {alpha_out:?}"); - // --- 4. Injection. - // Actually perform the injection of alpha_in, alpha_out and tao_in into the subnet pool. - // This operation changes the pool liquidity each block. + // --- 4. Inject and subsidize + for netuid_i in subnets_to_emit_to.iter() { + let tao_in_i: TaoCurrency = + tou64!(*tao_in.get(netuid_i).unwrap_or(&asfloat!(0))).into(); + let alpha_in_i: AlphaCurrency = + AlphaCurrency::from(tou64!(*alpha_in.get(netuid_i).unwrap_or(&asfloat!(0)))); + let difference_tao: U96F32 = *subsidy_amount.get(netuid_i).unwrap_or(&asfloat!(0)); + + T::SwapInterface::adjust_protocol_liquidity(*netuid_i, tao_in_i, alpha_in_i); + + if difference_tao > asfloat!(0) { + let buy_swap_result = Self::swap_tao_for_alpha( + *netuid_i, + tou64!(difference_tao).into(), + T::SwapInterface::max_price(), + true, + ); + if let Ok(buy_swap_result_ok) = buy_swap_result { + let bought_alpha = AlphaCurrency::from(buy_swap_result_ok.amount_paid_out); + SubnetAlphaOut::::mutate(*netuid_i, |total| { + *total = total.saturating_sub(bought_alpha); + }); + } + } + } + + // --- 5. Update counters for netuid_i in subnets_to_emit_to.iter() { // Inject Alpha in. let alpha_in_i = @@ -138,14 +152,15 @@ impl Pallet { TotalStake::::mutate(|total| { *total = total.saturating_add(tao_in_i.into()); }); + + let difference_tao: U96F32 = *subsidy_amount.get(netuid_i).unwrap_or(&asfloat!(0)); TotalIssuance::::mutate(|total| { *total = total.saturating_add(tao_in_i.into()); + *total = total.saturating_add(tou64!(difference_tao).into()); }); - // Adjust protocol liquidity based on new reserves - T::SwapInterface::adjust_protocol_liquidity(*netuid_i, tao_in_i, alpha_in_i); } - // --- 5. Compute owner cuts and remove them from alpha_out remaining. + // --- 6. Compute owner cuts and remove them from alpha_out remaining. // Remove owner cuts here so that we can properly seperate root dividends in the next step. // Owner cuts are accumulated and then fed to the drain at the end of this func. let cut_percent: U96F32 = Self::get_float_subnet_owner_cut(); @@ -174,7 +189,7 @@ impl Pallet { let tao_weight: U96F32 = root_tao.saturating_mul(Self::get_tao_weight()); log::debug!("tao_weight: {tao_weight:?}"); - // --- 6. Seperate out root dividends in alpha and keep them. + // --- 7. Seperate out root dividends in alpha and keep them. // Then accumulate those dividends for later. for netuid_i in subnets_to_emit_to.iter() { // Get remaining alpha out. @@ -211,14 +226,14 @@ impl Pallet { }); } - // --- 7. Update moving prices after using them in the emission calculation. + // --- 8. Update moving prices after using them in the emission calculation. // Only update price EMA for subnets that we emit to. for netuid_i in subnets_to_emit_to.iter() { // Update moving prices after using them above. Self::update_moving_price(*netuid_i); } - // --- 8. Drain pending emission through the subnet based on tempo. + // --- 9. Drain pending emission through the subnet based on tempo. // Run the epoch for *all* subnets, even if we don't emit anything. for &netuid in subnets.iter() { // Reveal matured weights. From b068d0247311858dc22a198162ae9767df22c7a9 Mon Sep 17 00:00:00 2001 From: camfairchild Date: Wed, 5 Nov 2025 15:55:14 -0500 Subject: [PATCH 06/29] emit full alpha if subsidized --- .../subtensor/src/coinbase/run_coinbase.rs | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 6e759b9243..e1635afb4e 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -204,21 +204,23 @@ impl Pallet { .unwrap_or(asfloat!(0.0)); log::debug!("root_proportion: {root_proportion:?}"); // Get root proportion of alpha_out dividends. - let root_alpha: U96F32 = root_proportion - .saturating_mul(alpha_out_i) // Total alpha emission per block remaining. - .saturating_mul(asfloat!(0.5)); // 50% to validators. - // Remove root alpha from alpha_out. - log::debug!("root_alpha: {root_alpha:?}"); - // Get pending alpha as original alpha_out - root_alpha. - let pending_alpha: U96F32 = alpha_out_i.saturating_sub(root_alpha); - log::debug!("pending_alpha: {pending_alpha:?}"); - + let mut root_alpha: U96F32 = asfloat!(0.0); let subsidized: bool = *is_subsidized.get(netuid_i).unwrap_or(&false); if !subsidized { + // Only give root alpha if not being subsidized. + root_alpha = root_proportion + .saturating_mul(alpha_out_i) // Total alpha emission per block remaining. + .saturating_mul(asfloat!(0.5)); // 50% to validators. PendingRootAlphaDivs::::mutate(*netuid_i, |total| { *total = total.saturating_add(tou64!(root_alpha).into()); }); } + // Remove root alpha from alpha_out. + log::debug!("root_alpha: {root_alpha:?}"); + + // Get pending alpha as original alpha_out - root_alpha. + let pending_alpha: U96F32 = alpha_out_i.saturating_sub(root_alpha); + log::debug!("pending_alpha: {pending_alpha:?}"); // Accumulate alpha emission in pending. PendingEmission::::mutate(*netuid_i, |total| { From 7d77cf0bea7da09a12ae72761a5e7330310b1784 Mon Sep 17 00:00:00 2001 From: camfairchild Date: Wed, 5 Nov 2025 15:59:43 -0500 Subject: [PATCH 07/29] fix coinbase test --- pallets/subtensor/src/tests/coinbase.rs | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index bbb7061e27..29fbfacf48 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -245,7 +245,7 @@ fn test_coinbase_tao_issuance_different_prices() { ); // Prices are low => we limit tao issued (buy alpha with it) - let tao_issued = TaoCurrency::from(((0.1 + 0.2) * emission as f64) as u64); + let tao_issued = TaoCurrency::from(((1.0) * emission as f64) as u64); assert_abs_diff_eq!( TotalIssuance::::get(), tao_issued, @@ -689,7 +689,6 @@ fn test_drain_base() { 0.into(), AlphaCurrency::ZERO, AlphaCurrency::ZERO, - AlphaCurrency::ZERO, // alpha out AlphaCurrency::ZERO, ) }); @@ -705,7 +704,6 @@ fn test_drain_base_with_subnet() { netuid, AlphaCurrency::ZERO, AlphaCurrency::ZERO, - AlphaCurrency::ZERO, // alpha out AlphaCurrency::ZERO, ) }); @@ -731,7 +729,6 @@ fn test_drain_base_with_subnet_with_single_staker_not_registered() { netuid, pending_alpha.into(), AlphaCurrency::ZERO, - pending_alpha.into(), // alpha out AlphaCurrency::ZERO, ); let stake_after = @@ -761,7 +758,6 @@ fn test_drain_base_with_subnet_with_single_staker_registered() { netuid, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, // alpha out AlphaCurrency::ZERO, ); let stake_after = @@ -806,7 +802,6 @@ fn test_drain_base_with_subnet_with_single_staker_registered_root_weight() { netuid, pending_alpha, pending_root_alpha, - pending_alpha.saturating_add(pending_root_alpha), // alpha out AlphaCurrency::ZERO, ); let stake_after = @@ -854,7 +849,6 @@ fn test_drain_base_with_subnet_with_two_stakers_registered() { netuid, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); let stake_after1 = @@ -920,7 +914,6 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root() { netuid, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); let stake_after1 = @@ -996,7 +989,6 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_am netuid, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, 0.into(), ); let stake_after1 = @@ -1077,7 +1069,6 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_am netuid, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); let stake_after1 = @@ -1139,7 +1130,6 @@ fn test_drain_alpha_childkey_parentkey() { netuid, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); let parent_stake_after = SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); @@ -1365,7 +1355,6 @@ fn test_get_root_children_drain() { alpha, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); @@ -1390,7 +1379,6 @@ fn test_get_root_children_drain() { pending_alpha, // pending_root1, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); @@ -1414,7 +1402,6 @@ fn test_get_root_children_drain() { alpha, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); @@ -1503,7 +1490,6 @@ fn test_get_root_children_drain_half_proportion() { alpha, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); @@ -1590,7 +1576,6 @@ fn test_get_root_children_drain_with_take() { alpha, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); @@ -1678,7 +1663,6 @@ fn test_get_root_children_drain_with_half_take() { alpha, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); @@ -2394,7 +2378,6 @@ fn test_drain_pending_emission_no_miners_all_drained() { netuid, emission, AlphaCurrency::ZERO, - emission, AlphaCurrency::ZERO, ); @@ -2468,7 +2451,6 @@ fn test_drain_pending_emission_zero_emission() { 0.into(), AlphaCurrency::ZERO, AlphaCurrency::ZERO, - AlphaCurrency::ZERO, ); // Get the new stake of the hotkey. @@ -2761,7 +2743,6 @@ fn test_drain_alpha_childkey_parentkey_with_burn() { netuid, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); let parent_stake_after = SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); From e792dd19d9d355d03a4bc0bc4de50326b494db82 Mon Sep 17 00:00:00 2001 From: camfairchild Date: Wed, 5 Nov 2025 16:08:07 -0500 Subject: [PATCH 08/29] fix tests --- pallets/subtensor/src/tests/coinbase.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index 29fbfacf48..0fc1ea8c98 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -690,6 +690,7 @@ fn test_drain_base() { AlphaCurrency::ZERO, AlphaCurrency::ZERO, AlphaCurrency::ZERO, + AlphaCurrency::ZERO, ) }); } @@ -705,6 +706,7 @@ fn test_drain_base_with_subnet() { AlphaCurrency::ZERO, AlphaCurrency::ZERO, AlphaCurrency::ZERO, + AlphaCurrency::ZERO, ) }); } @@ -730,6 +732,7 @@ fn test_drain_base_with_subnet_with_single_staker_not_registered() { pending_alpha.into(), AlphaCurrency::ZERO, AlphaCurrency::ZERO, + AlphaCurrency::ZERO, ); let stake_after = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid); @@ -758,6 +761,7 @@ fn test_drain_base_with_subnet_with_single_staker_registered() { netuid, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); let stake_after = @@ -802,6 +806,7 @@ fn test_drain_base_with_subnet_with_single_staker_registered_root_weight() { netuid, pending_alpha, pending_root_alpha, + pending_alpha.saturating_add(pending_root_alpha), AlphaCurrency::ZERO, ); let stake_after = @@ -849,6 +854,7 @@ fn test_drain_base_with_subnet_with_two_stakers_registered() { netuid, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); let stake_after1 = @@ -914,6 +920,7 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root() { netuid, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); let stake_after1 = @@ -989,6 +996,7 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_am netuid, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, 0.into(), ); let stake_after1 = @@ -1069,6 +1077,7 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_am netuid, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); let stake_after1 = @@ -1130,6 +1139,7 @@ fn test_drain_alpha_childkey_parentkey() { netuid, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); let parent_stake_after = SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); @@ -1355,6 +1365,7 @@ fn test_get_root_children_drain() { alpha, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); @@ -1379,6 +1390,7 @@ fn test_get_root_children_drain() { pending_alpha, // pending_root1, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); @@ -1402,6 +1414,7 @@ fn test_get_root_children_drain() { alpha, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); @@ -1490,6 +1503,7 @@ fn test_get_root_children_drain_half_proportion() { alpha, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); @@ -1576,6 +1590,7 @@ fn test_get_root_children_drain_with_take() { alpha, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); @@ -1663,6 +1678,7 @@ fn test_get_root_children_drain_with_half_take() { alpha, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); @@ -2378,6 +2394,7 @@ fn test_drain_pending_emission_no_miners_all_drained() { netuid, emission, AlphaCurrency::ZERO, + emission, AlphaCurrency::ZERO, ); @@ -2451,6 +2468,7 @@ fn test_drain_pending_emission_zero_emission() { 0.into(), AlphaCurrency::ZERO, AlphaCurrency::ZERO, + AlphaCurrency::ZERO, ); // Get the new stake of the hotkey. @@ -2743,6 +2761,7 @@ fn test_drain_alpha_childkey_parentkey_with_burn() { netuid, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); let parent_stake_after = SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); From d7a28ba22961771d4f44222799354abd9c29b70d Mon Sep 17 00:00:00 2001 From: camfairchild Date: Wed, 5 Nov 2025 17:54:01 -0500 Subject: [PATCH 09/29] Revert "Hotfix/vune/epoch sub fix (#2186)" This reverts commit ccc6bba7bdfa7501a461d0adfef80dd6488f9dfb. --- .../subtensor/src/coinbase/run_coinbase.rs | 81 ++++++++----------- 1 file changed, 33 insertions(+), 48 deletions(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index e1635afb4e..2bc985a7b1 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -34,19 +34,13 @@ impl Pallet { // 2. Get subnets to emit to and emissions let subnet_emissions = Self::get_subnet_block_emissions(&subnets, block_emission); let subnets_to_emit_to: Vec = subnet_emissions.keys().copied().collect(); - let total_ema_price: U96F32 = subnets_to_emit_to - .iter() - .map(|netuid| Self::get_moving_alpha_price(*netuid)) - .sum(); - let subsidy_mode = total_ema_price <= U96F32::saturating_from_num(1); // --- 3. Get subnet terms (tao_in, alpha_in, and alpha_out) // Computation is described in detail in the dtao whitepaper. let mut tao_in: BTreeMap = BTreeMap::new(); let mut alpha_in: BTreeMap = BTreeMap::new(); let mut alpha_out: BTreeMap = BTreeMap::new(); - let mut subsidy_amount: BTreeMap = BTreeMap::new(); - + let mut is_subsidized: BTreeMap = BTreeMap::new(); // Only calculate for subnets that we are emitting to. for netuid_i in subnets_to_emit_to.iter() { // Get subnet price. @@ -68,16 +62,32 @@ impl Pallet { // Get initial alpha_in let mut alpha_in_i: U96F32; let mut tao_in_i: U96F32; - - if default_alpha_in_i > alpha_emission_i { - alpha_in_i = alpha_emission_i; - tao_in_i = alpha_in_i.saturating_mul(price_i); + let tao_in_ratio: U96F32 = default_tao_in_i.safe_div_or( + U96F32::saturating_from_num(block_emission), + U96F32::saturating_from_num(0.0), + ); + if price_i < tao_in_ratio { + tao_in_i = price_i.saturating_mul(U96F32::saturating_from_num(block_emission)); + alpha_in_i = block_emission; let difference_tao: U96F32 = default_tao_in_i.saturating_sub(tao_in_i); - subsidy_amount.insert(*netuid_i, difference_tao); + // Difference becomes buy. + let buy_swap_result = Self::swap_tao_for_alpha( + *netuid_i, + tou64!(difference_tao).into(), + T::SwapInterface::max_price(), + true, + ); + if let Ok(buy_swap_result_ok) = buy_swap_result { + let bought_alpha = AlphaCurrency::from(buy_swap_result_ok.amount_paid_out); + SubnetAlphaOut::::mutate(*netuid_i, |total| { + *total = total.saturating_sub(bought_alpha); + }); + } + is_subsidized.insert(*netuid_i, true); } else { tao_in_i = default_tao_in_i; - alpha_in_i = alpha_in_default_i; - subsidy_amount.insert(*netuid_i, U96F32::from_num(0.0)); + alpha_in_i = tao_in_i.safe_div_or(price_i, alpha_emission_i); + is_subsidized.insert(*netuid_i, false); } log::debug!("alpha_in_i: {alpha_in_i:?}"); @@ -100,33 +110,9 @@ impl Pallet { log::debug!("alpha_in: {alpha_in:?}"); log::debug!("alpha_out: {alpha_out:?}"); - // --- 4. Inject and subsidize - for netuid_i in subnets_to_emit_to.iter() { - let tao_in_i: TaoCurrency = - tou64!(*tao_in.get(netuid_i).unwrap_or(&asfloat!(0))).into(); - let alpha_in_i: AlphaCurrency = - AlphaCurrency::from(tou64!(*alpha_in.get(netuid_i).unwrap_or(&asfloat!(0)))); - let difference_tao: U96F32 = *subsidy_amount.get(netuid_i).unwrap_or(&asfloat!(0)); - - T::SwapInterface::adjust_protocol_liquidity(*netuid_i, tao_in_i, alpha_in_i); - - if difference_tao > asfloat!(0) { - let buy_swap_result = Self::swap_tao_for_alpha( - *netuid_i, - tou64!(difference_tao).into(), - T::SwapInterface::max_price(), - true, - ); - if let Ok(buy_swap_result_ok) = buy_swap_result { - let bought_alpha = AlphaCurrency::from(buy_swap_result_ok.amount_paid_out); - SubnetAlphaOut::::mutate(*netuid_i, |total| { - *total = total.saturating_sub(bought_alpha); - }); - } - } - } - - // --- 5. Update counters + // --- 4. Injection. + // Actually perform the injection of alpha_in, alpha_out and tao_in into the subnet pool. + // This operation changes the pool liquidity each block. for netuid_i in subnets_to_emit_to.iter() { // Inject Alpha in. let alpha_in_i = @@ -152,15 +138,14 @@ impl Pallet { TotalStake::::mutate(|total| { *total = total.saturating_add(tao_in_i.into()); }); - - let difference_tao: U96F32 = *subsidy_amount.get(netuid_i).unwrap_or(&asfloat!(0)); TotalIssuance::::mutate(|total| { *total = total.saturating_add(tao_in_i.into()); - *total = total.saturating_add(tou64!(difference_tao).into()); }); + // Adjust protocol liquidity based on new reserves + T::SwapInterface::adjust_protocol_liquidity(*netuid_i, tao_in_i, alpha_in_i); } - // --- 6. Compute owner cuts and remove them from alpha_out remaining. + // --- 5. Compute owner cuts and remove them from alpha_out remaining. // Remove owner cuts here so that we can properly seperate root dividends in the next step. // Owner cuts are accumulated and then fed to the drain at the end of this func. let cut_percent: U96F32 = Self::get_float_subnet_owner_cut(); @@ -189,7 +174,7 @@ impl Pallet { let tao_weight: U96F32 = root_tao.saturating_mul(Self::get_tao_weight()); log::debug!("tao_weight: {tao_weight:?}"); - // --- 7. Seperate out root dividends in alpha and keep them. + // --- 6. Seperate out root dividends in alpha and keep them. // Then accumulate those dividends for later. for netuid_i in subnets_to_emit_to.iter() { // Get remaining alpha out. @@ -228,14 +213,14 @@ impl Pallet { }); } - // --- 8. Update moving prices after using them in the emission calculation. + // --- 7. Update moving prices after using them in the emission calculation. // Only update price EMA for subnets that we emit to. for netuid_i in subnets_to_emit_to.iter() { // Update moving prices after using them above. Self::update_moving_price(*netuid_i); } - // --- 9. Drain pending emission through the subnet based on tempo. + // --- 8. Drain pending emission through the subnet based on tempo. // Run the epoch for *all* subnets, even if we don't emit anything. for &netuid in subnets.iter() { // Reveal matured weights. From a837632fdefc9e0528adcce86fe0c3a6e941e4c7 Mon Sep 17 00:00:00 2001 From: camfairchild Date: Wed, 5 Nov 2025 17:59:28 -0500 Subject: [PATCH 10/29] add total issuance bump --- pallets/subtensor/src/coinbase/run_coinbase.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 2bc985a7b1..c1f7052d84 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -69,11 +69,15 @@ impl Pallet { if price_i < tao_in_ratio { tao_in_i = price_i.saturating_mul(U96F32::saturating_from_num(block_emission)); alpha_in_i = block_emission; - let difference_tao: U96F32 = default_tao_in_i.saturating_sub(tao_in_i); + let difference_tao: TaoCurrency = + tou64!(default_tao_in_i.saturating_sub(tao_in_i)).into(); + TotalIssuance::::mutate(|total| { + *total = total.saturating_add(difference_tao); + }); // Difference becomes buy. let buy_swap_result = Self::swap_tao_for_alpha( *netuid_i, - tou64!(difference_tao).into(), + difference_tao, T::SwapInterface::max_price(), true, ); From 6bddb56301974770eeb58f92844e2f4f359821de Mon Sep 17 00:00:00 2001 From: camfairchild Date: Wed, 5 Nov 2025 21:34:14 -0500 Subject: [PATCH 11/29] no alpha out thing --- .../subtensor/src/coinbase/run_coinbase.rs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index c1f7052d84..9b1ad984af 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -83,9 +83,7 @@ impl Pallet { ); if let Ok(buy_swap_result_ok) = buy_swap_result { let bought_alpha = AlphaCurrency::from(buy_swap_result_ok.amount_paid_out); - SubnetAlphaOut::::mutate(*netuid_i, |total| { - *total = total.saturating_sub(bought_alpha); - }); + Self::recycle_subnet_alpha(*netuid_i, bought_alpha); } is_subsidized.insert(*netuid_i, true); } else { @@ -110,6 +108,7 @@ impl Pallet { alpha_in.insert(*netuid_i, alpha_in_i); alpha_out.insert(*netuid_i, alpha_out_i); } + log::debug!("is_subsidized: {is_subsidized:?}"); log::debug!("tao_in: {tao_in:?}"); log::debug!("alpha_in: {alpha_in:?}"); log::debug!("alpha_out: {alpha_out:?}"); @@ -235,9 +234,6 @@ impl Pallet { if Self::should_run_epoch(netuid, current_block) && Self::is_epoch_input_state_consistent(netuid) { - let alpha_out_i: AlphaCurrency = - tou64!(*alpha_out.get(&netuid).unwrap_or(&asfloat!(0.0))).into(); - // Restart counters. BlocksSinceLastStep::::insert(netuid, 0); LastMechansimStepBlock::::insert(netuid, current_block); @@ -259,7 +255,7 @@ impl Pallet { netuid, pending_alpha, pending_root_alpha, - alpha_out_i, + pending_alpha.saturating_add(pending_root_alpha), owner_cut, ); } else { @@ -497,6 +493,7 @@ impl Pallet { let destination = maybe_dest.clone().unwrap_or(hotkey.clone()); if let Some(dest) = maybe_dest { + log::debug!("incentives: auto staking {incentive:?} to {dest:?}"); Self::deposit_event(Event::::AutoStakeAdded { netuid, destination: dest, @@ -505,6 +502,9 @@ impl Pallet { incentive, }); } + log::debug!( + "incentives: increasing stake for {hotkey:?} to {incentive:?} with owner {owner:?}" + ); Self::increase_stake_for_hotkey_and_coldkey_on_subnet( &destination, &owner, @@ -619,7 +619,7 @@ impl Pallet { netuid: NetUid, pending_alpha: AlphaCurrency, pending_root_alpha: AlphaCurrency, - alpha_out: AlphaCurrency, // total alpha out for the subnet + total_alpha: AlphaCurrency, owner_cut: AlphaCurrency, ) { log::debug!( @@ -630,7 +630,7 @@ impl Pallet { // Run the epoch. let hotkey_emission: Vec<(T::AccountId, AlphaCurrency, AlphaCurrency)> = - Self::epoch_with_mechanisms(netuid, alpha_out); + Self::epoch_with_mechanisms(netuid, total_alpha); log::debug!("hotkey_emission: {hotkey_emission:?}"); // Compute the pending validator alpha. @@ -646,7 +646,7 @@ impl Pallet { log::debug!("incentive_sum: {incentive_sum:?}"); let pending_validator_alpha = if !incentive_sum.is_zero() { - alpha_out + total_alpha .saturating_div(2.into()) .saturating_sub(pending_root_alpha) } else { From b857d4d4bc8cc2fb0702af4c6d6aba64ef304a4c Mon Sep 17 00:00:00 2001 From: camfairchild Date: Wed, 5 Nov 2025 21:34:29 -0500 Subject: [PATCH 12/29] add tests for emissions w/ subs --- pallets/subtensor/src/tests/coinbase.rs | 350 ++++++++++++++++++++++++ 1 file changed, 350 insertions(+) diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index 0fc1ea8c98..56f7d2171f 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -2928,3 +2928,353 @@ fn test_zero_shares_zero_emission() { assert_eq!(SubnetAlphaIn::::get(netuid2), initial.into()); }); } + +#[test] +fn test_mining_emission_distribution_with_subsidy() { + new_test_ext(1).execute_with(|| { + let validator_coldkey = U256::from(1); + let validator_hotkey = U256::from(2); + let validator_miner_coldkey = U256::from(3); + let validator_miner_hotkey = U256::from(4); + let miner_coldkey = U256::from(5); + let miner_hotkey = U256::from(6); + let netuid = NetUid::from(1); + let subnet_tempo = 10; + let stake: u64 = 100_000_000_000; + let root_stake: u64 = 200_000_000_000; // 200 TAO + + // Create root network + SubtensorModule::set_tao_weight(0); // Start tao weight at 0 + SubtokenEnabled::::insert(NetUid::ROOT, true); + NetworksAdded::::insert(NetUid::ROOT, true); + + // Add network, register hotkeys, and setup network parameters + add_network(netuid, subnet_tempo, 0); + SubnetMechanism::::insert(netuid, 1); // Set mechanism to 1 + + // Setup large LPs to prevent slippage + SubnetTAO::::insert(netuid, TaoCurrency::from(1_000_000_000_000_000)); + SubnetAlphaIn::::insert(netuid, AlphaCurrency::from(1_000_000_000_000_000)); + + register_ok_neuron(netuid, validator_hotkey, validator_coldkey, 0); + register_ok_neuron(netuid, validator_miner_hotkey, validator_miner_coldkey, 1); + register_ok_neuron(netuid, miner_hotkey, miner_coldkey, 2); + SubtensorModule::add_balance_to_coldkey_account( + &validator_coldkey, + stake + ExistentialDeposit::get(), + ); + SubtensorModule::add_balance_to_coldkey_account( + &validator_miner_coldkey, + stake + ExistentialDeposit::get(), + ); + SubtensorModule::add_balance_to_coldkey_account( + &miner_coldkey, + stake + ExistentialDeposit::get(), + ); + SubtensorModule::set_weights_set_rate_limit(netuid, 0); + step_block(subnet_tempo); + SubnetOwnerCut::::set(u16::MAX / 10); + // There are two validators and three neurons + MaxAllowedUids::::set(netuid, 3); + SubtensorModule::set_max_allowed_validators(netuid, 2); + + // Setup stakes: + // Stake from validator + // Stake from valiminer + assert_ok!(SubtensorModule::add_stake( + RuntimeOrigin::signed(validator_coldkey), + validator_hotkey, + netuid, + stake.into() + )); + assert_ok!(SubtensorModule::add_stake( + RuntimeOrigin::signed(validator_miner_coldkey), + validator_miner_hotkey, + netuid, + stake.into() + )); + + // Setup YUMA so that it creates emissions + Weights::::insert(NetUidStorageIndex::from(netuid), 0, vec![(1, 0xFFFF)]); + Weights::::insert(NetUidStorageIndex::from(netuid), 1, vec![(2, 0xFFFF)]); + BlockAtRegistration::::set(netuid, 0, 1); + BlockAtRegistration::::set(netuid, 1, 1); + BlockAtRegistration::::set(netuid, 2, 1); + LastUpdate::::set(NetUidStorageIndex::from(netuid), vec![2, 2, 2]); + Kappa::::set(netuid, u16::MAX / 5); + ActivityCutoff::::set(netuid, u16::MAX); // makes all stake active + ValidatorPermit::::insert(netuid, vec![true, true, false]); + + // Run run_coinbase until emissions are drained + step_block(subnet_tempo); + + // Add stake to validator so it has root stake + SubtensorModule::add_balance_to_coldkey_account(&validator_coldkey, root_stake.into()); + // init root + assert_ok!(SubtensorModule::add_stake( + RuntimeOrigin::signed(validator_coldkey), + validator_hotkey, + NetUid::ROOT, + root_stake.into() + )); + // Set tao weight non zero + SubtensorModule::set_tao_weight(u64::MAX / 10); + + // Make subsidy happen + // set price very low, e.g. a lot of alpha in + //SubnetAlphaIn::::insert(netuid, AlphaCurrency::from(1_000_000_000_000_000)); + pallet_subtensor_swap::AlphaSqrtPrice::::insert( + netuid, + U64F64::saturating_from_num(0.01), + ); + + // Run run_coinbase until emissions are drained + step_block(subnet_tempo); + + log::info!("is_sub: Running epoch with subsidy"); + + let old_root_alpha_divs = PendingRootAlphaDivs::::get(netuid); + let per_block_emission = SubtensorModule::get_block_emission_for_issuance( + SubtensorModule::get_alpha_issuance(netuid).into(), + ) + .unwrap_or(0); + + // step by one block + step_block(1); + // Verify that root alpha divs + let new_root_alpha_divs = PendingRootAlphaDivs::::get(netuid); + // Check that we are indeed being subsidized, i.e. that root alpha divs are NOT increasing + assert_eq!( + new_root_alpha_divs, old_root_alpha_divs, + "Root alpha divs should not increase" + ); + // Check root divs are zero + assert_eq!( + new_root_alpha_divs, + AlphaCurrency::ZERO, + "Root alpha divs should be zero" + ); + let miner_stake_before_epoch = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &miner_hotkey, + &miner_coldkey, + netuid, + ); + // Run again but with some root stake + step_block(subnet_tempo - 2); + assert_abs_diff_eq!( + PendingEmission::::get(netuid).to_u64(), + U96F32::saturating_from_num(per_block_emission) + .saturating_mul(U96F32::saturating_from_num(subnet_tempo as u64)) + .saturating_mul(U96F32::saturating_from_num(0.90)) + .saturating_to_num::(), + epsilon = 100_000_u64.into() + ); + step_block(1); + assert!( + BlocksSinceLastStep::::get(netuid) == 0, + "Blocks since last step should be 0" + ); + + let miner_uid = Uids::::get(netuid, miner_hotkey).unwrap_or(0); + log::info!("Miner uid: {miner_uid:?}"); + let miner_incentive: AlphaCurrency = + (*Incentive::::get(NetUidStorageIndex::from(netuid)) + .get(miner_uid as usize) + .expect("Miner uid should be present") as u64) + .into(); + log::info!("Miner incentive: {miner_incentive:?}"); + + // Miner emissions + let miner_emission_1: u64 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &miner_hotkey, + &miner_coldkey, + netuid, + ) + .to_u64() + - miner_stake_before_epoch.to_u64(); + + assert_abs_diff_eq!( + Incentive::::get(NetUidStorageIndex::from(netuid)) + .iter() + .sum::(), + u16::MAX, + epsilon = 10 + ); + + assert_abs_diff_eq!( + miner_emission_1, + U96F32::saturating_from_num(miner_incentive) + .saturating_div(u16::MAX.into()) + .saturating_mul(U96F32::saturating_from_num(per_block_emission)) + .saturating_mul(U96F32::saturating_from_num(subnet_tempo + 1)) + .saturating_mul(U96F32::saturating_from_num(0.45)) // miner cut + .saturating_to_num::(), + epsilon = 1_000_000_u64 + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_mining_emission_distribution_with_no_subsidy --exact --show-output --nocapture +#[test] +fn test_mining_emission_distribution_with_no_subsidy() { + new_test_ext(1).execute_with(|| { + let validator_coldkey = U256::from(1); + let validator_hotkey = U256::from(2); + let validator_miner_coldkey = U256::from(3); + let validator_miner_hotkey = U256::from(4); + let miner_coldkey = U256::from(5); + let miner_hotkey = U256::from(6); + let netuid = NetUid::from(1); + let subnet_tempo = 10; + let stake: u64 = 100_000_000_000; + let root_stake: u64 = 200_000_000_000; // 200 TAO + + // Create root network + SubtensorModule::set_tao_weight(0); // Start tao weight at 0 + SubtokenEnabled::::insert(NetUid::ROOT, true); + NetworksAdded::::insert(NetUid::ROOT, true); + + // Add network, register hotkeys, and setup network parameters + add_network(netuid, subnet_tempo, 0); + SubnetMechanism::::insert(netuid, 1); // Set mechanism to 1 + + // Setup large LPs to prevent slippage + SubnetTAO::::insert(netuid, TaoCurrency::from(1_000_000_000_000_000)); + SubnetAlphaIn::::insert(netuid, AlphaCurrency::from(1_000_000_000_000_000)); + + register_ok_neuron(netuid, validator_hotkey, validator_coldkey, 0); + register_ok_neuron(netuid, validator_miner_hotkey, validator_miner_coldkey, 1); + register_ok_neuron(netuid, miner_hotkey, miner_coldkey, 2); + SubtensorModule::add_balance_to_coldkey_account( + &validator_coldkey, + stake + ExistentialDeposit::get(), + ); + SubtensorModule::add_balance_to_coldkey_account( + &validator_miner_coldkey, + stake + ExistentialDeposit::get(), + ); + SubtensorModule::add_balance_to_coldkey_account( + &miner_coldkey, + stake + ExistentialDeposit::get(), + ); + SubtensorModule::set_weights_set_rate_limit(netuid, 0); + step_block(subnet_tempo); + SubnetOwnerCut::::set(u16::MAX / 10); + // There are two validators and three neurons + MaxAllowedUids::::set(netuid, 3); + SubtensorModule::set_max_allowed_validators(netuid, 2); + + // Setup stakes: + // Stake from validator + // Stake from valiminer + assert_ok!(SubtensorModule::add_stake( + RuntimeOrigin::signed(validator_coldkey), + validator_hotkey, + netuid, + stake.into() + )); + assert_ok!(SubtensorModule::add_stake( + RuntimeOrigin::signed(validator_miner_coldkey), + validator_miner_hotkey, + netuid, + stake.into() + )); + + // Setup YUMA so that it creates emissions + Weights::::insert(NetUidStorageIndex::from(netuid), 0, vec![(1, 0xFFFF)]); + Weights::::insert(NetUidStorageIndex::from(netuid), 1, vec![(2, 0xFFFF)]); + BlockAtRegistration::::set(netuid, 0, 1); + BlockAtRegistration::::set(netuid, 1, 1); + BlockAtRegistration::::set(netuid, 2, 1); + LastUpdate::::set(NetUidStorageIndex::from(netuid), vec![2, 2, 2]); + Kappa::::set(netuid, u16::MAX / 5); + ActivityCutoff::::set(netuid, u16::MAX); // makes all stake active + ValidatorPermit::::insert(netuid, vec![true, true, false]); + + // Run run_coinbase until emissions are drained + step_block(subnet_tempo); + + // Add stake to validator so it has root stake + SubtensorModule::add_balance_to_coldkey_account(&validator_coldkey, root_stake.into()); + // init root + assert_ok!(SubtensorModule::add_stake( + RuntimeOrigin::signed(validator_coldkey), + validator_hotkey, + NetUid::ROOT, + root_stake.into() + )); + // Set tao weight non zero + SubtensorModule::set_tao_weight(u64::MAX / 10); + + // Make subsidy not happen + // set price very high + // e.g. very little alpha in pool + //SubnetAlphaIn::::insert(netuid, AlphaCurrency::from(5)); + pallet_subtensor_swap::AlphaSqrtPrice::::insert( + netuid, + U64F64::saturating_from_num(10.0), + ); + + // Run run_coinbase until emissions are drained + step_block(subnet_tempo); + + log::info!("is_sub: Running epoch with no subsidy"); + + let old_root_alpha_divs = PendingRootAlphaDivs::::get(netuid); + let miner_stake_before_epoch = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &miner_hotkey, + &miner_coldkey, + netuid, + ); + + // step by one block + step_block(1); + // Verify that root alpha divs + let new_root_alpha_divs = PendingRootAlphaDivs::::get(netuid); + // Check that we are NOT being subsidized, i.e. that root alpha divs are are changing + assert_ne!( + new_root_alpha_divs, old_root_alpha_divs, + "Root alpha divs should be changing" + ); + assert!( + new_root_alpha_divs > AlphaCurrency::ZERO, + "Root alpha divs should be greater than 0" + ); + + // Run again but with some root stake + step_block(subnet_tempo - 1); + + let miner_uid = Uids::::get(netuid, miner_hotkey).unwrap_or(0); + let miner_incentive: AlphaCurrency = + (*Incentive::::get(NetUidStorageIndex::from(netuid)) + .get(miner_uid as usize) + .expect("Miner uid should be present") as u64) + .into(); + log::info!("Miner incentive: {miner_incentive:?}"); + + let per_block_emission = SubtensorModule::get_block_emission_for_issuance( + SubtensorModule::get_alpha_issuance(netuid).into(), + ) + .unwrap_or(0); + + // Miner emissions + let miner_emission_1: u64 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &miner_hotkey, + &miner_coldkey, + netuid, + ) + .to_u64() + - miner_stake_before_epoch.to_u64(); + + assert_abs_diff_eq!( + miner_emission_1, + U96F32::saturating_from_num(miner_incentive) + .saturating_div(u16::MAX.into()) + .saturating_mul(U96F32::saturating_from_num(per_block_emission)) + .saturating_mul(U96F32::saturating_from_num(subnet_tempo + 1)) + .saturating_mul(U96F32::saturating_from_num(0.45)) // miner cut + .saturating_to_num::(), + epsilon = 1_000_000_u64 + ); + }); +} From e1feb05c3936b010a15a1c64844245b144c8e659 Mon Sep 17 00:00:00 2001 From: camfairchild Date: Wed, 5 Nov 2025 21:41:14 -0500 Subject: [PATCH 13/29] bump spec --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 240c490736..42f35cbc80 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -220,7 +220,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 340, + spec_version: 341, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From ad602c101f076ff7a2ed7794e249244f1e4d1e9c Mon Sep 17 00:00:00 2001 From: Shamil Gadelshin Date: Thu, 6 Nov 2025 18:48:38 +0700 Subject: [PATCH 14/29] Fix clippy warnings --- pallets/subtensor/src/tests/coinbase.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index 56f7d2171f..525de22d1d 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -3077,11 +3077,15 @@ fn test_mining_emission_distribution_with_subsidy() { let miner_uid = Uids::::get(netuid, miner_hotkey).unwrap_or(0); log::info!("Miner uid: {miner_uid:?}"); - let miner_incentive: AlphaCurrency = - (*Incentive::::get(NetUidStorageIndex::from(netuid)) + let miner_incentive: AlphaCurrency = { + let miner_incentive = Incentive::::get(NetUidStorageIndex::from(netuid)) .get(miner_uid as usize) - .expect("Miner uid should be present") as u64) - .into(); + .copied(); + + assert!(miner_incentive.is_some()); + + (miner_incentive.unwrap_or_default() as u64).into() + }; log::info!("Miner incentive: {miner_incentive:?}"); // Miner emissions @@ -3245,11 +3249,15 @@ fn test_mining_emission_distribution_with_no_subsidy() { step_block(subnet_tempo - 1); let miner_uid = Uids::::get(netuid, miner_hotkey).unwrap_or(0); - let miner_incentive: AlphaCurrency = - (*Incentive::::get(NetUidStorageIndex::from(netuid)) + let miner_incentive: AlphaCurrency = { + let miner_incentive = Incentive::::get(NetUidStorageIndex::from(netuid)) .get(miner_uid as usize) - .expect("Miner uid should be present") as u64) - .into(); + .copied(); + + assert!(miner_incentive.is_some()); + + (miner_incentive.unwrap_or_default() as u64).into() + }; log::info!("Miner incentive: {miner_incentive:?}"); let per_block_emission = SubtensorModule::get_block_emission_for_issuance( From cac43c52eb076dd7086d93b18838250de603e70e Mon Sep 17 00:00:00 2001 From: 0xcacti <97139981+0xcacti@users.noreply.github.com> Date: Wed, 5 Nov 2025 15:53:34 -0500 Subject: [PATCH 15/29] Hotfix/vune/epoch sub fix (#2186) * fix: injection logic * fix: fmt' --- .../subtensor/src/coinbase/run_coinbase.rs | 85 +++++++++++-------- 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 9b1ad984af..1a39bea498 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -34,13 +34,19 @@ impl Pallet { // 2. Get subnets to emit to and emissions let subnet_emissions = Self::get_subnet_block_emissions(&subnets, block_emission); let subnets_to_emit_to: Vec = subnet_emissions.keys().copied().collect(); + let total_ema_price: U96F32 = subnets_to_emit_to + .iter() + .map(|netuid| Self::get_moving_alpha_price(*netuid)) + .sum(); + let subsidy_mode = total_ema_price <= U96F32::saturating_from_num(1); // --- 3. Get subnet terms (tao_in, alpha_in, and alpha_out) // Computation is described in detail in the dtao whitepaper. let mut tao_in: BTreeMap = BTreeMap::new(); let mut alpha_in: BTreeMap = BTreeMap::new(); let mut alpha_out: BTreeMap = BTreeMap::new(); - let mut is_subsidized: BTreeMap = BTreeMap::new(); + let mut subsidy_amount: BTreeMap = BTreeMap::new(); + // Only calculate for subnets that we are emitting to. for netuid_i in subnets_to_emit_to.iter() { // Get subnet price. @@ -62,34 +68,16 @@ impl Pallet { // Get initial alpha_in let mut alpha_in_i: U96F32; let mut tao_in_i: U96F32; - let tao_in_ratio: U96F32 = default_tao_in_i.safe_div_or( - U96F32::saturating_from_num(block_emission), - U96F32::saturating_from_num(0.0), - ); - if price_i < tao_in_ratio { - tao_in_i = price_i.saturating_mul(U96F32::saturating_from_num(block_emission)); - alpha_in_i = block_emission; - let difference_tao: TaoCurrency = - tou64!(default_tao_in_i.saturating_sub(tao_in_i)).into(); - TotalIssuance::::mutate(|total| { - *total = total.saturating_add(difference_tao); - }); - // Difference becomes buy. - let buy_swap_result = Self::swap_tao_for_alpha( - *netuid_i, - difference_tao, - T::SwapInterface::max_price(), - true, - ); - if let Ok(buy_swap_result_ok) = buy_swap_result { - let bought_alpha = AlphaCurrency::from(buy_swap_result_ok.amount_paid_out); - Self::recycle_subnet_alpha(*netuid_i, bought_alpha); - } - is_subsidized.insert(*netuid_i, true); + + if default_alpha_in_i > alpha_emission_i { + alpha_in_i = alpha_emission_i; + tao_in_i = alpha_in_i.saturating_mul(price_i); + let difference_tao: U96F32 = default_tao_in_i.saturating_sub(tao_in_i); + subsidy_amount.insert(*netuid_i, difference_tao); } else { tao_in_i = default_tao_in_i; - alpha_in_i = tao_in_i.safe_div_or(price_i, alpha_emission_i); - is_subsidized.insert(*netuid_i, false); + alpha_in_i = alpha_in_default_i; + subsidy_amount.insert(*netuid_i, U96F32::from_num(0.0)); } log::debug!("alpha_in_i: {alpha_in_i:?}"); @@ -113,9 +101,33 @@ impl Pallet { log::debug!("alpha_in: {alpha_in:?}"); log::debug!("alpha_out: {alpha_out:?}"); - // --- 4. Injection. - // Actually perform the injection of alpha_in, alpha_out and tao_in into the subnet pool. - // This operation changes the pool liquidity each block. + // --- 4. Inject and subsidize + for netuid_i in subnets_to_emit_to.iter() { + let tao_in_i: TaoCurrency = + tou64!(*tao_in.get(netuid_i).unwrap_or(&asfloat!(0))).into(); + let alpha_in_i: AlphaCurrency = + AlphaCurrency::from(tou64!(*alpha_in.get(netuid_i).unwrap_or(&asfloat!(0)))); + let difference_tao: U96F32 = *subsidy_amount.get(netuid_i).unwrap_or(&asfloat!(0)); + + T::SwapInterface::adjust_protocol_liquidity(*netuid_i, tao_in_i, alpha_in_i); + + if difference_tao > asfloat!(0) { + let buy_swap_result = Self::swap_tao_for_alpha( + *netuid_i, + tou64!(difference_tao).into(), + T::SwapInterface::max_price(), + true, + ); + if let Ok(buy_swap_result_ok) = buy_swap_result { + let bought_alpha = AlphaCurrency::from(buy_swap_result_ok.amount_paid_out); + SubnetAlphaOut::::mutate(*netuid_i, |total| { + *total = total.saturating_sub(bought_alpha); + }); + } + } + } + + // --- 5. Update counters for netuid_i in subnets_to_emit_to.iter() { // Inject Alpha in. let alpha_in_i = @@ -141,14 +153,15 @@ impl Pallet { TotalStake::::mutate(|total| { *total = total.saturating_add(tao_in_i.into()); }); + + let difference_tao: U96F32 = *subsidy_amount.get(netuid_i).unwrap_or(&asfloat!(0)); TotalIssuance::::mutate(|total| { *total = total.saturating_add(tao_in_i.into()); + *total = total.saturating_add(tou64!(difference_tao).into()); }); - // Adjust protocol liquidity based on new reserves - T::SwapInterface::adjust_protocol_liquidity(*netuid_i, tao_in_i, alpha_in_i); } - // --- 5. Compute owner cuts and remove them from alpha_out remaining. + // --- 6. Compute owner cuts and remove them from alpha_out remaining. // Remove owner cuts here so that we can properly seperate root dividends in the next step. // Owner cuts are accumulated and then fed to the drain at the end of this func. let cut_percent: U96F32 = Self::get_float_subnet_owner_cut(); @@ -177,7 +190,7 @@ impl Pallet { let tao_weight: U96F32 = root_tao.saturating_mul(Self::get_tao_weight()); log::debug!("tao_weight: {tao_weight:?}"); - // --- 6. Seperate out root dividends in alpha and keep them. + // --- 7. Seperate out root dividends in alpha and keep them. // Then accumulate those dividends for later. for netuid_i in subnets_to_emit_to.iter() { // Get remaining alpha out. @@ -216,14 +229,14 @@ impl Pallet { }); } - // --- 7. Update moving prices after using them in the emission calculation. + // --- 8. Update moving prices after using them in the emission calculation. // Only update price EMA for subnets that we emit to. for netuid_i in subnets_to_emit_to.iter() { // Update moving prices after using them above. Self::update_moving_price(*netuid_i); } - // --- 8. Drain pending emission through the subnet based on tempo. + // --- 9. Drain pending emission through the subnet based on tempo. // Run the epoch for *all* subnets, even if we don't emit anything. for &netuid in subnets.iter() { // Reveal matured weights. From 85fe2d4bf95339fd3d1204230f4b420475ed559f Mon Sep 17 00:00:00 2001 From: camfairchild Date: Thu, 6 Nov 2025 00:24:10 -0500 Subject: [PATCH 16/29] rename drain_pending to distr em --- pallets/subtensor/src/benchmarks.rs | 2 +- .../subtensor/src/coinbase/run_coinbase.rs | 4 +- .../src/coinbase/subnet_emissions.rs | 19 ++++---- pallets/subtensor/src/tests/children.rs | 2 +- pallets/subtensor/src/tests/claim_root.rs | 28 +++++------ pallets/subtensor/src/tests/coinbase.rs | 46 +++++++++---------- 6 files changed, 51 insertions(+), 50 deletions(-) diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index 0e53facabc..5d9567fec1 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -1615,7 +1615,7 @@ mod pallet_benchmarks { ); let pending_root_alpha = 10_000_000u64; - Subtensor::::drain_pending_emission( + Subtensor::::distribute_emission( netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 1a39bea498..62e5492cb8 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -264,7 +264,7 @@ impl Pallet { PendingOwnerCut::::insert(netuid, AlphaCurrency::ZERO); // Drain pending root alpha divs, alpha emission, and owner cut. - Self::drain_pending_emission( + Self::distribute_emission( netuid, pending_alpha, pending_root_alpha, @@ -628,7 +628,7 @@ impl Pallet { (incentives, (alpha_dividends, root_alpha_dividends)) } - pub fn drain_pending_emission( + pub fn distribute_emission( netuid: NetUid, pending_alpha: AlphaCurrency, pending_root_alpha: AlphaCurrency, diff --git a/pallets/subtensor/src/coinbase/subnet_emissions.rs b/pallets/subtensor/src/coinbase/subnet_emissions.rs index 184f27a4ba..12396b6ea0 100644 --- a/pallets/subtensor/src/coinbase/subnet_emissions.rs +++ b/pallets/subtensor/src/coinbase/subnet_emissions.rs @@ -7,21 +7,22 @@ use substrate_fixed::types::{I32F32, I64F64, U64F64, U96F32}; use subtensor_swap_interface::SwapHandler; impl Pallet { - pub fn get_subnet_block_emissions( - subnets: &[NetUid], - block_emission: U96F32, - ) -> BTreeMap { + + pub fn get_subnets_to_emit_to(subnets: &[NetUid]) -> Vec { // Filter out subnets with no first emission block number. - let subnets_to_emit_to: Vec = subnets + subnets .to_owned() - .clone() .into_iter() .filter(|netuid| FirstEmissionBlockNumber::::get(*netuid).is_some()) - .collect(); - log::debug!("Subnets to emit to: {subnets_to_emit_to:?}"); + .collect() + } + pub fn get_subnet_block_emissions( + subnets_to_emit_to: &[NetUid], + block_emission: U96F32, + ) -> BTreeMap { // Get subnet TAO emissions. - let shares = Self::get_shares(&subnets_to_emit_to); + let shares = Self::get_shares(subnets_to_emit_to); log::debug!("Subnet emission shares = {shares:?}"); shares diff --git a/pallets/subtensor/src/tests/children.rs b/pallets/subtensor/src/tests/children.rs index e9b8c2aa6b..14b7a0b29d 100644 --- a/pallets/subtensor/src/tests/children.rs +++ b/pallets/subtensor/src/tests/children.rs @@ -2827,7 +2827,7 @@ fn test_set_weights_no_parent() { }); } -/// Test that drain_pending_emission sends childkey take fully to the nominators if childkey +/// Test that distribute_emission sends childkey take fully to the nominators if childkey /// doesn't have its own stake, independently of parent hotkey take. /// cargo test --package pallet-subtensor --lib -- tests::children::test_childkey_take_drain --exact --show-output #[allow(clippy::assertions_on_constants)] diff --git a/pallets/subtensor/src/tests/claim_root.rs b/pallets/subtensor/src/tests/claim_root.rs index c75b4f5784..77e7b2a317 100644 --- a/pallets/subtensor/src/tests/claim_root.rs +++ b/pallets/subtensor/src/tests/claim_root.rs @@ -72,7 +72,7 @@ fn test_claim_root_with_drain_emissions() { // Distribute pending root alpha let pending_root_alpha = 1_000_000u64; - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), @@ -141,7 +141,7 @@ fn test_claim_root_with_drain_emissions() { // Distribute pending root alpha (round 2) - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), @@ -243,7 +243,7 @@ fn test_claim_root_adding_stake_proportionally_for_two_stakers() { // Distribute pending root alpha let pending_root_alpha = 10_000_000u64; - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), @@ -345,7 +345,7 @@ fn test_claim_root_adding_stake_disproportionally_for_two_stakers() { // Distribute pending root alpha let pending_root_alpha = 10_000_000u64; - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), @@ -437,7 +437,7 @@ fn test_claim_root_with_changed_stake() { // Distribute pending root alpha let pending_root_alpha = 10_000_000u64; - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), @@ -490,7 +490,7 @@ fn test_claim_root_with_changed_stake() { // Distribute pending root alpha let pending_root_alpha = 10_000_000u64; - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), @@ -544,7 +544,7 @@ fn test_claim_root_with_changed_stake() { // Distribute pending root alpha let pending_root_alpha = 10_000_000u64; - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), @@ -637,7 +637,7 @@ fn test_claim_root_with_drain_emissions_and_swap_claim_type() { // Distribute pending root alpha let pending_root_alpha = 10_000_000u64; - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), @@ -682,7 +682,7 @@ fn test_claim_root_with_drain_emissions_and_swap_claim_type() { // Distribute and claim pending root alpha (round 2) - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), @@ -719,7 +719,7 @@ fn test_claim_root_with_drain_emissions_and_swap_claim_type() { ); // Distribute and claim pending root alpha (round 3) - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), @@ -1106,7 +1106,7 @@ fn test_claim_root_with_swap_coldkey() { // Distribute pending root alpha let pending_root_alpha = 1_000_000u64; - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), @@ -1197,7 +1197,7 @@ fn test_claim_root_with_swap_hotkey() { // Distribute pending root alpha let pending_root_alpha = 1_000_000u64; - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), @@ -1314,7 +1314,7 @@ fn test_claim_root_on_network_deregistration() { // Distribute pending root alpha let pending_root_alpha = 10_000_000u64; - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), @@ -1455,7 +1455,7 @@ fn test_claim_root_with_unrelated_subnets() { // Distribute pending root alpha let pending_root_alpha = 1_000_000u64; - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index 525de22d1d..919cff7b7d 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -685,7 +685,7 @@ fn test_pending_emission() { #[test] fn test_drain_base() { new_test_ext(1).execute_with(|| { - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( 0.into(), AlphaCurrency::ZERO, AlphaCurrency::ZERO, @@ -701,7 +701,7 @@ fn test_drain_base_with_subnet() { new_test_ext(1).execute_with(|| { let netuid = NetUid::from(1); add_network(netuid, 1, 0); - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, AlphaCurrency::ZERO, @@ -727,7 +727,7 @@ fn test_drain_base_with_subnet_with_single_staker_not_registered() { stake_before, ); let pending_alpha = AlphaCurrency::from(1_000_000_000); - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, pending_alpha.into(), AlphaCurrency::ZERO, @@ -757,7 +757,7 @@ fn test_drain_base_with_subnet_with_single_staker_registered() { stake_before, ); let pending_alpha = AlphaCurrency::from(1_000_000_000); - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, pending_alpha, AlphaCurrency::ZERO, @@ -802,7 +802,7 @@ fn test_drain_base_with_subnet_with_single_staker_registered_root_weight() { let pending_alpha = AlphaCurrency::from(1_000_000_000); let pending_root_alpha = AlphaCurrency::from(1_000_000_000); assert_eq!(SubnetTAO::::get(NetUid::ROOT), TaoCurrency::ZERO); - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, pending_alpha, pending_root_alpha, @@ -850,7 +850,7 @@ fn test_drain_base_with_subnet_with_two_stakers_registered() { stake_before, ); let pending_alpha = AlphaCurrency::from(1_000_000_000); - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, pending_alpha, AlphaCurrency::ZERO, @@ -916,7 +916,7 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root() { let pending_tao = TaoCurrency::from(1_000_000_000); let pending_alpha = AlphaCurrency::from(1_000_000_000); assert_eq!(SubnetTAO::::get(NetUid::ROOT), TaoCurrency::ZERO); - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, pending_alpha, AlphaCurrency::ZERO, @@ -992,7 +992,7 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_am let pending_tao = TaoCurrency::from(1_000_000_000); let pending_alpha = AlphaCurrency::from(1_000_000_000); assert_eq!(SubnetTAO::::get(NetUid::ROOT), TaoCurrency::ZERO); - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, pending_alpha, AlphaCurrency::ZERO, @@ -1073,7 +1073,7 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_am let pending_tao = TaoCurrency::from(1_000_000_000); let pending_alpha = AlphaCurrency::from(1_000_000_000); assert_eq!(SubnetTAO::::get(NetUid::ROOT), TaoCurrency::ZERO); - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, pending_alpha, AlphaCurrency::ZERO, @@ -1135,7 +1135,7 @@ fn test_drain_alpha_childkey_parentkey() { ChildkeyTake::::insert(child, netuid, u16::MAX / 10); let pending_alpha = AlphaCurrency::from(1_000_000_000); - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, pending_alpha, AlphaCurrency::ZERO, @@ -1361,7 +1361,7 @@ fn test_get_root_children_drain() { // Lets drain let pending_alpha = AlphaCurrency::from(1_000_000_000); - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( alpha, pending_alpha, AlphaCurrency::ZERO, @@ -1385,7 +1385,7 @@ fn test_get_root_children_drain() { // Lets drain let pending_alpha = AlphaCurrency::from(1_000_000_000); let pending_root1 = TaoCurrency::from(1_000_000_000); - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( alpha, pending_alpha, // pending_root1, @@ -1410,7 +1410,7 @@ fn test_get_root_children_drain() { // Lets drain let pending_alpha = AlphaCurrency::from(1_000_000_000); let pending_root2 = TaoCurrency::from(1_000_000_000); - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( alpha, pending_alpha, AlphaCurrency::ZERO, @@ -1499,7 +1499,7 @@ fn test_get_root_children_drain_half_proportion() { // Lets drain! let pending_alpha = AlphaCurrency::from(1_000_000_000); - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( alpha, pending_alpha, AlphaCurrency::ZERO, @@ -1586,7 +1586,7 @@ fn test_get_root_children_drain_with_take() { // Lets drain! let pending_alpha = AlphaCurrency::from(1_000_000_000); - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( alpha, pending_alpha, AlphaCurrency::ZERO, @@ -1674,7 +1674,7 @@ fn test_get_root_children_drain_with_half_take() { // Lets drain! let pending_alpha = AlphaCurrency::from(1_000_000_000); - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( alpha, pending_alpha, AlphaCurrency::ZERO, @@ -1777,7 +1777,7 @@ fn test_get_root_children_drain_with_half_take() { // // Lets drain! // let pending_alpha = AlphaCurrency::from(1_000_000_000); -// SubtensorModule::drain_pending_emission(alpha, pending_alpha, 0, 0.into(), 0.into()); +// SubtensorModule::distribute_emission(alpha, pending_alpha, 0, 0.into(), 0.into()); // // Alice and Bob make the same amount. // close( @@ -2365,7 +2365,7 @@ fn test_calculate_dividends_and_incentives_only_miners() { } #[test] -fn test_drain_pending_emission_no_miners_all_drained() { +fn test_distribute_emission_no_miners_all_drained() { new_test_ext(1).execute_with(|| { let netuid = add_dynamic_network(&U256::from(1), &U256::from(2)); let hotkey = U256::from(3); @@ -2390,7 +2390,7 @@ fn test_drain_pending_emission_no_miners_all_drained() { // Set the emission to be 1 million. let emission = AlphaCurrency::from(1_000_000); // Run drain pending without any miners. - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, emission, AlphaCurrency::ZERO, @@ -2410,9 +2410,9 @@ fn test_drain_pending_emission_no_miners_all_drained() { }); } -// cargo test --package pallet-subtensor --lib -- tests::coinbase::test_drain_pending_emission_zero_emission --exact --show-output +// cargo test --package pallet-subtensor --lib -- tests::coinbase::test_distribute_emission_zero_emission --exact --show-output #[test] -fn test_drain_pending_emission_zero_emission() { +fn test_distribute_emission_zero_emission() { new_test_ext(1).execute_with(|| { let netuid = add_dynamic_network_disable_commit_reveal(&U256::from(1), &U256::from(2)); let hotkey = U256::from(3); @@ -2463,7 +2463,7 @@ fn test_drain_pending_emission_zero_emission() { Dividends::::remove(netuid); // Set the emission to be ZERO. - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, 0.into(), AlphaCurrency::ZERO, @@ -2757,7 +2757,7 @@ fn test_drain_alpha_childkey_parentkey_with_burn() { let child_stake_before = SubtensorModule::get_stake_for_hotkey_on_subnet(&child, netuid); let pending_alpha = AlphaCurrency::from(1_000_000_000); - SubtensorModule::drain_pending_emission( + SubtensorModule::distribute_emission( netuid, pending_alpha, AlphaCurrency::ZERO, From 90d4be48a02d24fe0cc9ddaad4e939358156ef1e Mon Sep 17 00:00:00 2001 From: camfairchild Date: Thu, 6 Nov 2025 00:35:58 -0500 Subject: [PATCH 17/29] remove arg and total internally --- pallets/subtensor/src/benchmarks.rs | 1 - .../subtensor/src/coinbase/run_coinbase.rs | 5 ++--- pallets/subtensor/src/tests/claim_root.rs | 14 -------------- pallets/subtensor/src/tests/coinbase.rs | 19 ------------------- 4 files changed, 2 insertions(+), 37 deletions(-) diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index 5d9567fec1..1e7d6991c1 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -1619,7 +1619,6 @@ mod pallet_benchmarks { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), - pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 62e5492cb8..f58814460c 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -263,12 +263,11 @@ impl Pallet { let owner_cut = PendingOwnerCut::::get(netuid); PendingOwnerCut::::insert(netuid, AlphaCurrency::ZERO); - // Drain pending root alpha divs, alpha emission, and owner cut. + // Distribute the emission. Self::distribute_emission( netuid, pending_alpha, pending_root_alpha, - pending_alpha.saturating_add(pending_root_alpha), owner_cut, ); } else { @@ -632,7 +631,6 @@ impl Pallet { netuid: NetUid, pending_alpha: AlphaCurrency, pending_root_alpha: AlphaCurrency, - total_alpha: AlphaCurrency, owner_cut: AlphaCurrency, ) { log::debug!( @@ -640,6 +638,7 @@ impl Pallet { ); let tao_weight = Self::get_tao_weight(); + let total_alpha = pending_alpha.saturating_add(pending_root_alpha); // Run the epoch. let hotkey_emission: Vec<(T::AccountId, AlphaCurrency, AlphaCurrency)> = diff --git a/pallets/subtensor/src/tests/claim_root.rs b/pallets/subtensor/src/tests/claim_root.rs index 77e7b2a317..8d46841d5b 100644 --- a/pallets/subtensor/src/tests/claim_root.rs +++ b/pallets/subtensor/src/tests/claim_root.rs @@ -76,7 +76,6 @@ fn test_claim_root_with_drain_emissions() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), - pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -145,7 +144,6 @@ fn test_claim_root_with_drain_emissions() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), - pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -247,7 +245,6 @@ fn test_claim_root_adding_stake_proportionally_for_two_stakers() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), - pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -349,7 +346,6 @@ fn test_claim_root_adding_stake_disproportionally_for_two_stakers() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), - pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -441,7 +437,6 @@ fn test_claim_root_with_changed_stake() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), - pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -494,7 +489,6 @@ fn test_claim_root_with_changed_stake() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), - pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -548,7 +542,6 @@ fn test_claim_root_with_changed_stake() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), - pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -641,7 +634,6 @@ fn test_claim_root_with_drain_emissions_and_swap_claim_type() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), - pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -686,7 +678,6 @@ fn test_claim_root_with_drain_emissions_and_swap_claim_type() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), - pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -723,7 +714,6 @@ fn test_claim_root_with_drain_emissions_and_swap_claim_type() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), - pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -1110,7 +1100,6 @@ fn test_claim_root_with_swap_coldkey() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), - pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -1201,7 +1190,6 @@ fn test_claim_root_with_swap_hotkey() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), - pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -1318,7 +1306,6 @@ fn test_claim_root_on_network_deregistration() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), - pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); @@ -1459,7 +1446,6 @@ fn test_claim_root_with_unrelated_subnets() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), - pending_root_alpha.into(), // alpha out AlphaCurrency::ZERO, ); diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index 919cff7b7d..1ff974ac57 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -690,7 +690,6 @@ fn test_drain_base() { AlphaCurrency::ZERO, AlphaCurrency::ZERO, AlphaCurrency::ZERO, - AlphaCurrency::ZERO, ) }); } @@ -706,7 +705,6 @@ fn test_drain_base_with_subnet() { AlphaCurrency::ZERO, AlphaCurrency::ZERO, AlphaCurrency::ZERO, - AlphaCurrency::ZERO, ) }); } @@ -732,7 +730,6 @@ fn test_drain_base_with_subnet_with_single_staker_not_registered() { pending_alpha.into(), AlphaCurrency::ZERO, AlphaCurrency::ZERO, - AlphaCurrency::ZERO, ); let stake_after = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid); @@ -761,7 +758,6 @@ fn test_drain_base_with_subnet_with_single_staker_registered() { netuid, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); let stake_after = @@ -806,7 +802,6 @@ fn test_drain_base_with_subnet_with_single_staker_registered_root_weight() { netuid, pending_alpha, pending_root_alpha, - pending_alpha.saturating_add(pending_root_alpha), AlphaCurrency::ZERO, ); let stake_after = @@ -854,7 +849,6 @@ fn test_drain_base_with_subnet_with_two_stakers_registered() { netuid, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); let stake_after1 = @@ -920,7 +914,6 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root() { netuid, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); let stake_after1 = @@ -996,7 +989,6 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_am netuid, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, 0.into(), ); let stake_after1 = @@ -1077,7 +1069,6 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_am netuid, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); let stake_after1 = @@ -1139,7 +1130,6 @@ fn test_drain_alpha_childkey_parentkey() { netuid, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); let parent_stake_after = SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); @@ -1365,7 +1355,6 @@ fn test_get_root_children_drain() { alpha, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); @@ -1390,7 +1379,6 @@ fn test_get_root_children_drain() { pending_alpha, // pending_root1, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); @@ -1414,7 +1402,6 @@ fn test_get_root_children_drain() { alpha, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); @@ -1503,7 +1490,6 @@ fn test_get_root_children_drain_half_proportion() { alpha, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); @@ -1590,7 +1576,6 @@ fn test_get_root_children_drain_with_take() { alpha, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); @@ -1678,7 +1663,6 @@ fn test_get_root_children_drain_with_half_take() { alpha, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); @@ -2394,7 +2378,6 @@ fn test_distribute_emission_no_miners_all_drained() { netuid, emission, AlphaCurrency::ZERO, - emission, AlphaCurrency::ZERO, ); @@ -2468,7 +2451,6 @@ fn test_distribute_emission_zero_emission() { 0.into(), AlphaCurrency::ZERO, AlphaCurrency::ZERO, - AlphaCurrency::ZERO, ); // Get the new stake of the hotkey. @@ -2761,7 +2743,6 @@ fn test_drain_alpha_childkey_parentkey_with_burn() { netuid, pending_alpha, AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); let parent_stake_after = SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); From f81986b73b30838c77747310a1ef4ddaa9765b7c Mon Sep 17 00:00:00 2001 From: camfairchild Date: Thu, 6 Nov 2025 01:23:26 -0500 Subject: [PATCH 18/29] test pending em --- pallets/subtensor/src/tests/coinbase.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index 1ff974ac57..c81148e520 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -661,15 +661,27 @@ fn test_owner_cut_base() { #[test] fn test_pending_emission() { new_test_ext(1).execute_with(|| { - let netuid = NetUid::from(1); let emission: u64 = 1_000_000; - add_network(netuid, 1, 0); + let hotkey = U256::from(1); + let coldkey = U256::from(2); + let netuid = add_dynamic_network(&hotkey, &coldkey); + Tempo::::insert(netuid, 1); + FirstEmissionBlockNumber::::insert(netuid, 0); + mock::setup_reserves(netuid, 1_000_000.into(), 1.into()); SubtensorModule::run_coinbase(U96F32::from_num(0)); SubnetTAO::::insert(NetUid::ROOT, TaoCurrency::from(1_000_000_000)); // Add root weight. SubtensorModule::run_coinbase(U96F32::from_num(0)); SubtensorModule::set_tempo(netuid, 10000); // Large number (dont drain) SubtensorModule::set_tao_weight(u64::MAX); // Set TAO weight to 1.0 + + // Set moving price > 1.0 + SubnetMovingPrice::::insert(netuid, I96F32::from_num(2)); + + // Make sure we are not subsidizing, so we have root alpha divs. + let subsidy_mode = SubtensorModule::get_network_subsidy_mode(&[netuid]); + assert!(!subsidy_mode, "Subsidy mode should be false"); + SubtensorModule::run_coinbase(U96F32::from_num(0)); // 1 TAO / ( 1 + 3 ) = 0.25 * 1 / 2 = 125000000 @@ -678,6 +690,12 @@ fn test_pending_emission() { 1_000_000_000 - 125000000, epsilon = 1 ); // 1 - swapped. + + assert_abs_diff_eq!( + u64::from(PendingRootAlphaDivs::::get(netuid)), + 125000000, + epsilon = 1 + ); // 1 / 2 = 125000000 }); } From be16df688594211a2664c5db24dda6a9873fbfea Mon Sep 17 00:00:00 2001 From: camfairchild Date: Thu, 6 Nov 2025 01:31:20 -0500 Subject: [PATCH 19/29] make sure we check subsidize during those tests --- pallets/subtensor/src/tests/coinbase.rs | 29 +++++++++++++++---------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index c81148e520..7477a70676 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -3027,11 +3027,13 @@ fn test_mining_emission_distribution_with_subsidy() { U64F64::saturating_from_num(0.01), ); + // Make sure we ARE subsidizing, so we have root alpha divs. + let subsidy_mode = SubtensorModule::get_network_subsidy_mode(&[netuid]); + assert!(subsidy_mode, "Subsidy mode should be true"); + // Run run_coinbase until emissions are drained step_block(subnet_tempo); - log::info!("is_sub: Running epoch with subsidy"); - let old_root_alpha_divs = PendingRootAlphaDivs::::get(netuid); let per_block_emission = SubtensorModule::get_block_emission_for_issuance( SubtensorModule::get_alpha_issuance(netuid).into(), @@ -3127,7 +3129,6 @@ fn test_mining_emission_distribution_with_no_subsidy() { let validator_miner_hotkey = U256::from(4); let miner_coldkey = U256::from(5); let miner_hotkey = U256::from(6); - let netuid = NetUid::from(1); let subnet_tempo = 10; let stake: u64 = 100_000_000_000; let root_stake: u64 = 200_000_000_000; // 200 TAO @@ -3138,8 +3139,11 @@ fn test_mining_emission_distribution_with_no_subsidy() { NetworksAdded::::insert(NetUid::ROOT, true); // Add network, register hotkeys, and setup network parameters - add_network(netuid, subnet_tempo, 0); - SubnetMechanism::::insert(netuid, 1); // Set mechanism to 1 + let owner_hotkey = U256::from(10); + let owner_coldkey = U256::from(11); + let netuid = add_dynamic_network(&owner_hotkey, &owner_coldkey); + Tempo::::insert(netuid, 1); + FirstEmissionBlockNumber::::insert(netuid, 0); // Setup large LPs to prevent slippage SubnetTAO::::insert(netuid, TaoCurrency::from(1_000_000_000_000_000)); @@ -3210,19 +3214,22 @@ fn test_mining_emission_distribution_with_no_subsidy() { SubtensorModule::set_tao_weight(u64::MAX / 10); // Make subsidy not happen - // set price very high - // e.g. very little alpha in pool - //SubnetAlphaIn::::insert(netuid, AlphaCurrency::from(5)); + // Set moving price > 1.0 + // Set price > 1.0 pallet_subtensor_swap::AlphaSqrtPrice::::insert( netuid, U64F64::saturating_from_num(10.0), ); + SubnetMovingPrice::::insert(netuid, I96F32::from_num(2)); + + // Make sure we are not subsidizing, so we have root alpha divs. + let subsidy_mode = SubtensorModule::get_network_subsidy_mode(&[netuid]); + assert!(!subsidy_mode, "Subsidy mode should be false"); + // Run run_coinbase until emissions are drained step_block(subnet_tempo); - log::info!("is_sub: Running epoch with no subsidy"); - let old_root_alpha_divs = PendingRootAlphaDivs::::get(netuid); let miner_stake_before_epoch = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( &miner_hotkey, @@ -3232,7 +3239,7 @@ fn test_mining_emission_distribution_with_no_subsidy() { // step by one block step_block(1); - // Verify that root alpha divs + // Verify root alpha divs let new_root_alpha_divs = PendingRootAlphaDivs::::get(netuid); // Check that we are NOT being subsidized, i.e. that root alpha divs are are changing assert_ne!( From 69249f43e6e9aaa7ec05ade04b6d81cb8ce89322 Mon Sep 17 00:00:00 2001 From: camfairchild Date: Thu, 6 Nov 2025 01:51:05 -0500 Subject: [PATCH 20/29] fix root claim tests --- pallets/subtensor/src/tests/claim_root.rs | 49 ++++++++++++++++++++--- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/pallets/subtensor/src/tests/claim_root.rs b/pallets/subtensor/src/tests/claim_root.rs index 8d46841d5b..71b8947c43 100644 --- a/pallets/subtensor/src/tests/claim_root.rs +++ b/pallets/subtensor/src/tests/claim_root.rs @@ -6,8 +6,8 @@ use crate::tests::mock::{ use crate::{ DefaultMinRootClaimAmount, Error, MAX_NUM_ROOT_CLAIMS, MAX_ROOT_CLAIM_THRESHOLD, NetworksAdded, NumRootClaim, NumStakingColdkeys, PendingRootAlphaDivs, RootClaimable, RootClaimableThreshold, - StakingColdkeys, StakingColdkeysByIndex, SubnetAlphaIn, SubnetMechanism, SubnetTAO, - SubtokenEnabled, Tempo, pallet, + StakingColdkeys, StakingColdkeysByIndex, SubnetAlphaIn, SubnetMechanism, SubnetMovingPrice, + SubnetTAO, SubtokenEnabled, Tempo, pallet, }; use crate::{RootClaimType, RootClaimTypeEnum, RootClaimed}; use approx::assert_abs_diff_eq; @@ -18,7 +18,7 @@ use frame_support::{assert_err, assert_noop, assert_ok}; use sp_core::{H256, U256}; use sp_runtime::DispatchError; use std::collections::BTreeSet; -use substrate_fixed::types::{I96F32, U96F32}; +use substrate_fixed::types::{I96F32, U64F64, U96F32}; use subtensor_runtime_common::{AlphaCurrency, Currency, NetUid, TaoCurrency}; use subtensor_swap_interface::SwapHandler; @@ -779,6 +779,18 @@ fn test_claim_root_with_run_coinbase() { initial_total_hotkey_alpha.into(), ); + // Set moving price > 1.0 and price > 1.0 + // So we turn off subsidy + SubnetMovingPrice::::insert(netuid, I96F32::from_num(2)); + pallet_subtensor_swap::AlphaSqrtPrice::::insert( + netuid, + U64F64::saturating_from_num(10.0), + ); + + // Make sure we are not subsidizing, so we have root alpha divs. + let subsidy_mode = SubtensorModule::get_network_subsidy_mode(&[netuid]); + assert!(!subsidy_mode, "Subsidy mode should be false"); + // Distribute pending root alpha let initial_stake: u64 = @@ -878,6 +890,18 @@ fn test_claim_root_with_block_emissions() { ); SubtensorModule::maybe_add_coldkey_index(&coldkey); + // Set moving price > 1.0 and price > 1.0 + // So we turn off subsidy + SubnetMovingPrice::::insert(netuid, I96F32::from_num(2)); + pallet_subtensor_swap::AlphaSqrtPrice::::insert( + netuid, + U64F64::saturating_from_num(10.0), + ); + + // Make sure we are not subsidizing, so we have root alpha divs. + let subsidy_mode = SubtensorModule::get_network_subsidy_mode(&[netuid]); + assert!(!subsidy_mode, "Subsidy mode should be false"); + let initial_total_hotkey_alpha = 10_000_000u64; SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( &hotkey, @@ -991,12 +1015,27 @@ fn test_claim_root_coinbase_distribution() { let initial_alpha_issuance = SubtensorModule::get_alpha_issuance(netuid); let alpha_emissions: AlphaCurrency = 1_000_000_000u64.into(); - // Check total issuance (saved to pending alpha divs) + // Set moving price > 1.0 and price > 1.0 + // So we turn off subsidy + SubnetMovingPrice::::insert(netuid, I96F32::from_num(2)); + pallet_subtensor_swap::AlphaSqrtPrice::::insert( + netuid, + U64F64::saturating_from_num(10.0), + ); + + // Make sure we are not subsidizing, so we have root alpha divs. + let subsidy_mode = SubtensorModule::get_network_subsidy_mode(&[netuid]); + assert!(!subsidy_mode, "Subsidy mode should be false"); + // Check total issuance (saved to pending alpha divs) run_to_block(2); let alpha_issuance = SubtensorModule::get_alpha_issuance(netuid); - assert_eq!(initial_alpha_issuance + alpha_emissions, alpha_issuance); + // We went two blocks so we should have 2x the alpha emissions + assert_eq!( + initial_alpha_issuance + alpha_emissions.saturating_mul(2.into()), + alpha_issuance + ); let root_prop = initial_tao as f64 / (u64::from(alpha_issuance) + initial_tao) as f64; let root_validators_share = 0.5f64; From 9762f6ad423d48d9d3fb0ea8c074623c395862f0 Mon Sep 17 00:00:00 2001 From: camfairchild Date: Thu, 6 Nov 2025 11:01:33 -0500 Subject: [PATCH 21/29] helper and clippy --- .../subtensor/src/coinbase/run_coinbase.rs | 33 ++++++++++--------- .../src/coinbase/subnet_emissions.rs | 6 ++-- pallets/subtensor/src/tests/coinbase.rs | 7 +--- 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index f58814460c..7071f6ff6b 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -34,11 +34,7 @@ impl Pallet { // 2. Get subnets to emit to and emissions let subnet_emissions = Self::get_subnet_block_emissions(&subnets, block_emission); let subnets_to_emit_to: Vec = subnet_emissions.keys().copied().collect(); - let total_ema_price: U96F32 = subnets_to_emit_to - .iter() - .map(|netuid| Self::get_moving_alpha_price(*netuid)) - .sum(); - let subsidy_mode = total_ema_price <= U96F32::saturating_from_num(1); + let subsidy_mode = Self::get_network_subsidy_mode(&subnets_to_emit_to); // --- 3. Get subnet terms (tao_in, alpha_in, and alpha_out) // Computation is described in detail in the dtao whitepaper. @@ -58,6 +54,9 @@ impl Pallet { .copied() .unwrap_or(asfloat!(0)); log::debug!("default_tao_in_i: {default_tao_in_i:?}"); + let default_alpha_in_i: U96F32 = + default_tao_in_i.safe_div_or(price_i, U96F32::saturating_from_num(0.0)); + log::debug!("default_alpha_in_i: {default_alpha_in_i:?}"); // Get alpha_emission total let alpha_emission_i: U96F32 = asfloat!( Self::get_block_emission_for_issuance(Self::get_alpha_issuance(*netuid_i).into()) @@ -76,7 +75,7 @@ impl Pallet { subsidy_amount.insert(*netuid_i, difference_tao); } else { tao_in_i = default_tao_in_i; - alpha_in_i = alpha_in_default_i; + alpha_in_i = default_alpha_in_i; subsidy_amount.insert(*netuid_i, U96F32::from_num(0.0)); } log::debug!("alpha_in_i: {alpha_in_i:?}"); @@ -96,10 +95,10 @@ impl Pallet { alpha_in.insert(*netuid_i, alpha_in_i); alpha_out.insert(*netuid_i, alpha_out_i); } - log::debug!("is_subsidized: {is_subsidized:?}"); log::debug!("tao_in: {tao_in:?}"); log::debug!("alpha_in: {alpha_in:?}"); log::debug!("alpha_out: {alpha_out:?}"); + log::debug!("subsidy_mode: {subsidy_mode:?}"); // --- 4. Inject and subsidize for netuid_i in subnets_to_emit_to.iter() { @@ -206,8 +205,7 @@ impl Pallet { log::debug!("root_proportion: {root_proportion:?}"); // Get root proportion of alpha_out dividends. let mut root_alpha: U96F32 = asfloat!(0.0); - let subsidized: bool = *is_subsidized.get(netuid_i).unwrap_or(&false); - if !subsidized { + if !subsidy_mode { // Only give root alpha if not being subsidized. root_alpha = root_proportion .saturating_mul(alpha_out_i) // Total alpha emission per block remaining. @@ -264,12 +262,7 @@ impl Pallet { PendingOwnerCut::::insert(netuid, AlphaCurrency::ZERO); // Distribute the emission. - Self::distribute_emission( - netuid, - pending_alpha, - pending_root_alpha, - owner_cut, - ); + Self::distribute_emission(netuid, pending_alpha, pending_root_alpha, owner_cut); } else { // Increment BlocksSinceLastStep::::mutate(netuid, |total| *total = total.saturating_add(1)); @@ -277,6 +270,16 @@ impl Pallet { } } + pub fn get_network_subsidy_mode(subnets_to_emit_to: &[NetUid]) -> bool { + let total_ema_price: U96F32 = subnets_to_emit_to + .iter() + .map(|netuid| Self::get_moving_alpha_price(*netuid)) + .sum(); + + // If the total EMA price is less than or equal to 1, then we subsidize the network. + total_ema_price <= U96F32::saturating_from_num(1) + } + pub fn calculate_dividends_and_incentives( netuid: NetUid, hotkey_emission: Vec<(T::AccountId, AlphaCurrency, AlphaCurrency)>, diff --git a/pallets/subtensor/src/coinbase/subnet_emissions.rs b/pallets/subtensor/src/coinbase/subnet_emissions.rs index 12396b6ea0..895a908ba8 100644 --- a/pallets/subtensor/src/coinbase/subnet_emissions.rs +++ b/pallets/subtensor/src/coinbase/subnet_emissions.rs @@ -1,5 +1,4 @@ use super::*; -use crate::alloc::borrow::ToOwned; use alloc::collections::BTreeMap; use safe_math::FixedExt; use substrate_fixed::transcendental::{exp, ln}; @@ -7,13 +6,12 @@ use substrate_fixed::types::{I32F32, I64F64, U64F64, U96F32}; use subtensor_swap_interface::SwapHandler; impl Pallet { - pub fn get_subnets_to_emit_to(subnets: &[NetUid]) -> Vec { // Filter out subnets with no first emission block number. subnets - .to_owned() - .into_iter() + .iter() .filter(|netuid| FirstEmissionBlockNumber::::get(*netuid).is_some()) + .copied() .collect() } diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index 7477a70676..87a8f560e3 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -1003,12 +1003,7 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_am let pending_tao = TaoCurrency::from(1_000_000_000); let pending_alpha = AlphaCurrency::from(1_000_000_000); assert_eq!(SubnetTAO::::get(NetUid::ROOT), TaoCurrency::ZERO); - SubtensorModule::distribute_emission( - netuid, - pending_alpha, - AlphaCurrency::ZERO, - 0.into(), - ); + SubtensorModule::distribute_emission(netuid, pending_alpha, AlphaCurrency::ZERO, 0.into()); let stake_after1 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey1, &coldkey, netuid); let root_after1 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( From 94d31d74ecbaf132e649ccf8c9127ed5ef71878a Mon Sep 17 00:00:00 2001 From: camfairchild Date: Thu, 6 Nov 2025 11:03:02 -0500 Subject: [PATCH 22/29] bump spec --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 42f35cbc80..fe9bda8b6c 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -220,7 +220,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 341, + spec_version: 342, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 186c7178c176d0ab287d2f0d4c65c513dd597128 Mon Sep 17 00:00:00 2001 From: camfairchild Date: Thu, 6 Nov 2025 11:11:53 -0500 Subject: [PATCH 23/29] rename subsidy to root flag --- .../subtensor/src/coinbase/run_coinbase.rs | 25 ++++++------------- pallets/subtensor/src/tests/claim_root.rs | 18 ++++++------- pallets/subtensor/src/tests/coinbase.rs | 20 +++++++-------- 3 files changed, 27 insertions(+), 36 deletions(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 7071f6ff6b..bd539af0da 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -34,7 +34,7 @@ impl Pallet { // 2. Get subnets to emit to and emissions let subnet_emissions = Self::get_subnet_block_emissions(&subnets, block_emission); let subnets_to_emit_to: Vec = subnet_emissions.keys().copied().collect(); - let subsidy_mode = Self::get_network_subsidy_mode(&subnets_to_emit_to); + let root_sell_flag = Self::get_network_root_sell_flag(&subnets_to_emit_to); // --- 3. Get subnet terms (tao_in, alpha_in, and alpha_out) // Computation is described in detail in the dtao whitepaper. @@ -98,7 +98,8 @@ impl Pallet { log::debug!("tao_in: {tao_in:?}"); log::debug!("alpha_in: {alpha_in:?}"); log::debug!("alpha_out: {alpha_out:?}"); - log::debug!("subsidy_mode: {subsidy_mode:?}"); + log::debug!("subsidy_amount: {subsidy_amount:?}"); + log::debug!("root_sell_flag: {root_sell_flag:?}"); // --- 4. Inject and subsidize for netuid_i in subnets_to_emit_to.iter() { @@ -195,18 +196,7 @@ impl Pallet { // Get remaining alpha out. let alpha_out_i: U96F32 = *alpha_out.get(netuid_i).unwrap_or(&asfloat!(0.0)); log::debug!("alpha_out_i: {alpha_out_i:?}"); - // Get total ALPHA on subnet. - let alpha_issuance: U96F32 = asfloat!(Self::get_alpha_issuance(*netuid_i)); - log::debug!("alpha_issuance: {alpha_issuance:?}"); - // Get root proportional dividends. - let root_proportion: U96F32 = tao_weight - .checked_div(tao_weight.saturating_add(alpha_issuance)) - .unwrap_or(asfloat!(0.0)); - log::debug!("root_proportion: {root_proportion:?}"); - // Get root proportion of alpha_out dividends. - let mut root_alpha: U96F32 = asfloat!(0.0); - if !subsidy_mode { - // Only give root alpha if not being subsidized. + if root_sell_flag { root_alpha = root_proportion .saturating_mul(alpha_out_i) // Total alpha emission per block remaining. .saturating_mul(asfloat!(0.5)); // 50% to validators. @@ -270,14 +260,15 @@ impl Pallet { } } - pub fn get_network_subsidy_mode(subnets_to_emit_to: &[NetUid]) -> bool { + pub fn get_network_root_sell_flag(subnets_to_emit_to: &[NetUid]) -> bool { let total_ema_price: U96F32 = subnets_to_emit_to .iter() .map(|netuid| Self::get_moving_alpha_price(*netuid)) .sum(); - // If the total EMA price is less than or equal to 1, then we subsidize the network. - total_ema_price <= U96F32::saturating_from_num(1) + // If the total EMA price is less than or equal to 1 + // then we WILL NOT root sell. + total_ema_price > U96F32::saturating_from_num(1) } pub fn calculate_dividends_and_incentives( diff --git a/pallets/subtensor/src/tests/claim_root.rs b/pallets/subtensor/src/tests/claim_root.rs index 71b8947c43..e143f19ef4 100644 --- a/pallets/subtensor/src/tests/claim_root.rs +++ b/pallets/subtensor/src/tests/claim_root.rs @@ -787,9 +787,9 @@ fn test_claim_root_with_run_coinbase() { U64F64::saturating_from_num(10.0), ); - // Make sure we are not subsidizing, so we have root alpha divs. - let subsidy_mode = SubtensorModule::get_network_subsidy_mode(&[netuid]); - assert!(!subsidy_mode, "Subsidy mode should be false"); + // Make sure we are root selling, so we have root alpha divs. + let root_sell_flag = SubtensorModule::get_network_root_sell_flag(&[netuid]); + assert!(root_sell_flag, "Root sell flag should be true"); // Distribute pending root alpha @@ -898,9 +898,9 @@ fn test_claim_root_with_block_emissions() { U64F64::saturating_from_num(10.0), ); - // Make sure we are not subsidizing, so we have root alpha divs. - let subsidy_mode = SubtensorModule::get_network_subsidy_mode(&[netuid]); - assert!(!subsidy_mode, "Subsidy mode should be false"); + // Make sure we are root selling, so we have root alpha divs. + let root_sell_flag = SubtensorModule::get_network_root_sell_flag(&[netuid]); + assert!(root_sell_flag, "Root sell flag should be true"); let initial_total_hotkey_alpha = 10_000_000u64; SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( @@ -1023,9 +1023,9 @@ fn test_claim_root_coinbase_distribution() { U64F64::saturating_from_num(10.0), ); - // Make sure we are not subsidizing, so we have root alpha divs. - let subsidy_mode = SubtensorModule::get_network_subsidy_mode(&[netuid]); - assert!(!subsidy_mode, "Subsidy mode should be false"); + // Make sure we are root selling, so we have root alpha divs. + let root_sell_flag = SubtensorModule::get_network_root_sell_flag(&[netuid]); + assert!(root_sell_flag, "Root sell flag should be true"); // Check total issuance (saved to pending alpha divs) run_to_block(2); diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index 87a8f560e3..dae954e6df 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -678,9 +678,9 @@ fn test_pending_emission() { // Set moving price > 1.0 SubnetMovingPrice::::insert(netuid, I96F32::from_num(2)); - // Make sure we are not subsidizing, so we have root alpha divs. - let subsidy_mode = SubtensorModule::get_network_subsidy_mode(&[netuid]); - assert!(!subsidy_mode, "Subsidy mode should be false"); + // Make sure we are root selling, so we have root alpha divs. + let root_sell_flag = SubtensorModule::get_network_root_sell_flag(&[netuid]); + assert!(root_sell_flag, "Root sell flag should be true"); SubtensorModule::run_coinbase(U96F32::from_num(0)); // 1 TAO / ( 1 + 3 ) = 0.25 * 1 / 2 = 125000000 @@ -3022,9 +3022,9 @@ fn test_mining_emission_distribution_with_subsidy() { U64F64::saturating_from_num(0.01), ); - // Make sure we ARE subsidizing, so we have root alpha divs. - let subsidy_mode = SubtensorModule::get_network_subsidy_mode(&[netuid]); - assert!(subsidy_mode, "Subsidy mode should be true"); + // Make sure we ARE NOT root selling, so we do not have root alpha divs. + let root_sell_flag = SubtensorModule::get_network_root_sell_flag(&[netuid]); + assert!(!root_sell_flag, "Root sell flag should be false"); // Run run_coinbase until emissions are drained step_block(subnet_tempo); @@ -3039,7 +3039,7 @@ fn test_mining_emission_distribution_with_subsidy() { step_block(1); // Verify that root alpha divs let new_root_alpha_divs = PendingRootAlphaDivs::::get(netuid); - // Check that we are indeed being subsidized, i.e. that root alpha divs are NOT increasing + // Check that we are indeed NOT root selling, i.e. that root alpha divs are NOT increasing assert_eq!( new_root_alpha_divs, old_root_alpha_divs, "Root alpha divs should not increase" @@ -3218,9 +3218,9 @@ fn test_mining_emission_distribution_with_no_subsidy() { SubnetMovingPrice::::insert(netuid, I96F32::from_num(2)); - // Make sure we are not subsidizing, so we have root alpha divs. - let subsidy_mode = SubtensorModule::get_network_subsidy_mode(&[netuid]); - assert!(!subsidy_mode, "Subsidy mode should be false"); + // Make sure we are root selling, so we have root alpha divs. + let root_sell_flag = SubtensorModule::get_network_root_sell_flag(&[netuid]); + assert!(root_sell_flag, "Root sell flag should be true"); // Run run_coinbase until emissions are drained step_block(subnet_tempo); From 25290f19dd9c677691de3fadbbd4856f3b543c50 Mon Sep 17 00:00:00 2001 From: camfairchild Date: Thu, 6 Nov 2025 11:12:53 -0500 Subject: [PATCH 24/29] only pull these values if root selling --- pallets/subtensor/src/coinbase/run_coinbase.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index bd539af0da..de31101ece 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -196,7 +196,21 @@ impl Pallet { // Get remaining alpha out. let alpha_out_i: U96F32 = *alpha_out.get(netuid_i).unwrap_or(&asfloat!(0.0)); log::debug!("alpha_out_i: {alpha_out_i:?}"); + + // Get root proportion of alpha_out dividends. + let mut root_alpha: U96F32 = asfloat!(0.0); if root_sell_flag { + // Get ALPHA issuance. + let alpha_issuance: U96F32 = asfloat!(Self::get_alpha_issuance(*netuid_i)); + log::debug!("alpha_issuance: {alpha_issuance:?}"); + + // Get root proportional dividends. + let root_proportion: U96F32 = tao_weight + .checked_div(tao_weight.saturating_add(alpha_issuance)) + .unwrap_or(asfloat!(0.0)); + log::debug!("root_proportion: {root_proportion:?}"); + + // Get root alpha from root prop. root_alpha = root_proportion .saturating_mul(alpha_out_i) // Total alpha emission per block remaining. .saturating_mul(asfloat!(0.5)); // 50% to validators. From d3698bf2fc4f0b1a804467b6b053e98d92e628bc Mon Sep 17 00:00:00 2001 From: camfairchild Date: Thu, 6 Nov 2025 11:17:25 -0500 Subject: [PATCH 25/29] rename subsidy checks to the root_sell flag --- pallets/subtensor/src/tests/claim_root.rs | 6 +++--- pallets/subtensor/src/tests/coinbase.rs | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pallets/subtensor/src/tests/claim_root.rs b/pallets/subtensor/src/tests/claim_root.rs index e143f19ef4..951dfa0ae1 100644 --- a/pallets/subtensor/src/tests/claim_root.rs +++ b/pallets/subtensor/src/tests/claim_root.rs @@ -780,7 +780,7 @@ fn test_claim_root_with_run_coinbase() { ); // Set moving price > 1.0 and price > 1.0 - // So we turn off subsidy + // So we turn ON root sell SubnetMovingPrice::::insert(netuid, I96F32::from_num(2)); pallet_subtensor_swap::AlphaSqrtPrice::::insert( netuid, @@ -891,7 +891,7 @@ fn test_claim_root_with_block_emissions() { SubtensorModule::maybe_add_coldkey_index(&coldkey); // Set moving price > 1.0 and price > 1.0 - // So we turn off subsidy + // So we turn ON root sell SubnetMovingPrice::::insert(netuid, I96F32::from_num(2)); pallet_subtensor_swap::AlphaSqrtPrice::::insert( netuid, @@ -1016,7 +1016,7 @@ fn test_claim_root_coinbase_distribution() { let alpha_emissions: AlphaCurrency = 1_000_000_000u64.into(); // Set moving price > 1.0 and price > 1.0 - // So we turn off subsidy + // So we turn ON root sell SubnetMovingPrice::::insert(netuid, I96F32::from_num(2)); pallet_subtensor_swap::AlphaSqrtPrice::::insert( netuid, diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index dae954e6df..5d03afa973 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -2924,7 +2924,7 @@ fn test_zero_shares_zero_emission() { } #[test] -fn test_mining_emission_distribution_with_subsidy() { +fn test_mining_emission_distribution_with_no_root_sell() { new_test_ext(1).execute_with(|| { let validator_coldkey = U256::from(1); let validator_hotkey = U256::from(2); @@ -3014,7 +3014,7 @@ fn test_mining_emission_distribution_with_subsidy() { // Set tao weight non zero SubtensorModule::set_tao_weight(u64::MAX / 10); - // Make subsidy happen + // Make root sell NOT happen // set price very low, e.g. a lot of alpha in //SubnetAlphaIn::::insert(netuid, AlphaCurrency::from(1_000_000_000_000_000)); pallet_subtensor_swap::AlphaSqrtPrice::::insert( @@ -3114,9 +3114,9 @@ fn test_mining_emission_distribution_with_subsidy() { }); } -// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_mining_emission_distribution_with_no_subsidy --exact --show-output --nocapture +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_mining_emission_distribution_with_root_sell --exact --show-output --nocapture #[test] -fn test_mining_emission_distribution_with_no_subsidy() { +fn test_mining_emission_distribution_with_root_sell() { new_test_ext(1).execute_with(|| { let validator_coldkey = U256::from(1); let validator_hotkey = U256::from(2); @@ -3208,7 +3208,7 @@ fn test_mining_emission_distribution_with_no_subsidy() { // Set tao weight non zero SubtensorModule::set_tao_weight(u64::MAX / 10); - // Make subsidy not happen + // Make root sell happen // Set moving price > 1.0 // Set price > 1.0 pallet_subtensor_swap::AlphaSqrtPrice::::insert( @@ -3236,7 +3236,7 @@ fn test_mining_emission_distribution_with_no_subsidy() { step_block(1); // Verify root alpha divs let new_root_alpha_divs = PendingRootAlphaDivs::::get(netuid); - // Check that we are NOT being subsidized, i.e. that root alpha divs are are changing + // Check that we ARE root selling, i.e. that root alpha divs are changing assert_ne!( new_root_alpha_divs, old_root_alpha_divs, "Root alpha divs should be changing" From 62ecfe14bc264d60bf875781f254d3dfaa609578 Mon Sep 17 00:00:00 2001 From: camfairchild Date: Thu, 6 Nov 2025 11:18:37 -0500 Subject: [PATCH 26/29] rename subsidy to excess_tao --- pallets/subtensor/src/coinbase/run_coinbase.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index de31101ece..1fa8641ff0 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -41,7 +41,7 @@ impl Pallet { let mut tao_in: BTreeMap = BTreeMap::new(); let mut alpha_in: BTreeMap = BTreeMap::new(); let mut alpha_out: BTreeMap = BTreeMap::new(); - let mut subsidy_amount: BTreeMap = BTreeMap::new(); + let mut excess_tao: BTreeMap = BTreeMap::new(); // Only calculate for subnets that we are emitting to. for netuid_i in subnets_to_emit_to.iter() { @@ -72,11 +72,11 @@ impl Pallet { alpha_in_i = alpha_emission_i; tao_in_i = alpha_in_i.saturating_mul(price_i); let difference_tao: U96F32 = default_tao_in_i.saturating_sub(tao_in_i); - subsidy_amount.insert(*netuid_i, difference_tao); + excess_tao.insert(*netuid_i, difference_tao); } else { tao_in_i = default_tao_in_i; alpha_in_i = default_alpha_in_i; - subsidy_amount.insert(*netuid_i, U96F32::from_num(0.0)); + excess_tao.insert(*netuid_i, U96F32::from_num(0.0)); } log::debug!("alpha_in_i: {alpha_in_i:?}"); @@ -98,16 +98,16 @@ impl Pallet { log::debug!("tao_in: {tao_in:?}"); log::debug!("alpha_in: {alpha_in:?}"); log::debug!("alpha_out: {alpha_out:?}"); - log::debug!("subsidy_amount: {subsidy_amount:?}"); + log::debug!("excess_tao: {excess_tao:?}"); log::debug!("root_sell_flag: {root_sell_flag:?}"); - // --- 4. Inject and subsidize + // --- 4. Inject and buy Alpha with any excess TAO. for netuid_i in subnets_to_emit_to.iter() { let tao_in_i: TaoCurrency = tou64!(*tao_in.get(netuid_i).unwrap_or(&asfloat!(0))).into(); let alpha_in_i: AlphaCurrency = AlphaCurrency::from(tou64!(*alpha_in.get(netuid_i).unwrap_or(&asfloat!(0)))); - let difference_tao: U96F32 = *subsidy_amount.get(netuid_i).unwrap_or(&asfloat!(0)); + let difference_tao: U96F32 = *excess_tao.get(netuid_i).unwrap_or(&asfloat!(0)); T::SwapInterface::adjust_protocol_liquidity(*netuid_i, tao_in_i, alpha_in_i); @@ -154,7 +154,7 @@ impl Pallet { *total = total.saturating_add(tao_in_i.into()); }); - let difference_tao: U96F32 = *subsidy_amount.get(netuid_i).unwrap_or(&asfloat!(0)); + let difference_tao: U96F32 = *excess_tao.get(netuid_i).unwrap_or(&asfloat!(0)); TotalIssuance::::mutate(|total| { *total = total.saturating_add(tao_in_i.into()); *total = total.saturating_add(tou64!(difference_tao).into()); From c5a7f514aa5b63ccb606eab4892d67bd9412f37c Mon Sep 17 00:00:00 2001 From: camfairchild Date: Thu, 6 Nov 2025 11:20:02 -0500 Subject: [PATCH 27/29] use recycle alpha helper --- pallets/subtensor/src/coinbase/run_coinbase.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 1fa8641ff0..5b1c4b5704 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -120,9 +120,7 @@ impl Pallet { ); if let Ok(buy_swap_result_ok) = buy_swap_result { let bought_alpha = AlphaCurrency::from(buy_swap_result_ok.amount_paid_out); - SubnetAlphaOut::::mutate(*netuid_i, |total| { - *total = total.saturating_sub(bought_alpha); - }); + Self::recycle_subnet_alpha(*netuid_i, bought_alpha); } } } From 75440be62905687a4575161ccd6f67fdacfe2587 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Thu, 6 Nov 2025 14:39:39 -0500 Subject: [PATCH 28/29] Hotfix/vune/subnet-dereg-burn-use-issuance (#2190) * use alpha issuance for owner estimate * fix tests * use price for estimate only * fix tests for using just price * docs: comment fix --- pallets/subtensor/src/staking/remove_stake.rs | 34 ++--- pallets/subtensor/src/tests/networks.rs | 132 ++++++++++-------- 2 files changed, 81 insertions(+), 85 deletions(-) diff --git a/pallets/subtensor/src/staking/remove_stake.rs b/pallets/subtensor/src/staking/remove_stake.rs index 5771029f74..7fdd335556 100644 --- a/pallets/subtensor/src/staking/remove_stake.rs +++ b/pallets/subtensor/src/staking/remove_stake.rs @@ -447,19 +447,13 @@ impl Pallet { let should_refund_owner: bool = reg_at < start_block; // 3) Compute owner's received emission in TAO at current price (ONLY if we may refund). - // Emission:: is Vec. We: - // - sum emitted α, + // We: + // - get the current alpha issuance, // - apply owner fraction to get owner α, // - price that α using a *simulated* AMM swap. let mut owner_emission_tao = TaoCurrency::ZERO; if should_refund_owner && !lock_cost.is_zero() { - let total_emitted_alpha_u128: u128 = - Emission::::get(netuid) - .into_iter() - .fold(0u128, |acc, e_alpha| { - let e_u64: u64 = Into::::into(e_alpha); - acc.saturating_add(e_u64 as u128) - }); + let total_emitted_alpha_u128: u128 = Self::get_alpha_issuance(netuid).to_u64() as u128; if total_emitted_alpha_u128 > 0 { let owner_fraction: U96F32 = Self::get_float_subnet_owner_cut(); @@ -469,22 +463,12 @@ impl Pallet { .saturating_to_num::(); owner_emission_tao = if owner_alpha_u64 > 0 { - let order = GetTaoForAlpha::with_amount(owner_alpha_u64); - match T::SwapInterface::sim_swap(netuid.into(), order) { - Ok(sim) => TaoCurrency::from(sim.amount_paid_out), - Err(e) => { - log::debug!( - "destroy_alpha_in_out_stakes: sim_swap owner α→τ failed (netuid={netuid:?}, alpha={owner_alpha_u64}, err={e:?}); falling back to price multiply.", - ); - let cur_price: U96F32 = - T::SwapInterface::current_alpha_price(netuid.into()); - let val_u64 = U96F32::from_num(owner_alpha_u64) - .saturating_mul(cur_price) - .floor() - .saturating_to_num::(); - TaoCurrency::from(val_u64) - } - } + let cur_price: U96F32 = T::SwapInterface::current_alpha_price(netuid.into()); + let val_u64 = U96F32::from_num(owner_alpha_u64) + .saturating_mul(cur_price) + .floor() + .saturating_to_num::(); + TaoCurrency::from(val_u64) } else { TaoCurrency::ZERO }; diff --git a/pallets/subtensor/src/tests/networks.rs b/pallets/subtensor/src/tests/networks.rs index 0449c67f86..3706878bb6 100644 --- a/pallets/subtensor/src/tests/networks.rs +++ b/pallets/subtensor/src/tests/networks.rs @@ -216,43 +216,49 @@ fn dissolve_owner_cut_refund_logic() { // One staker and a TAO pot (not relevant to refund amount). let sh = U256::from(77); let sc = U256::from(88); - Alpha::::insert((sh, sc, net), U64F64::from_num(100u128)); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &sh, + &sc, + net, + AlphaCurrency::from(800u64), + ); SubnetTAO::::insert(net, TaoCurrency::from(1_000)); // Lock & emissions: total emitted α = 800. let lock: TaoCurrency = TaoCurrency::from(2_000); SubtensorModule::set_subnet_locked_balance(net, lock); - Emission::::insert( - net, - vec![AlphaCurrency::from(200), AlphaCurrency::from(600)], - ); + // ensure there was some Alpha issued + assert!(SubtensorModule::get_alpha_issuance(net).to_u64() > 0); // Owner cut = 11796 / 65535 (about 18%). SubnetOwnerCut::::put(11_796u16); // Compute expected refund with the SAME math as the pallet. let frac: U96F32 = SubtensorModule::get_float_subnet_owner_cut(); - let total_emitted_alpha: u64 = 800; + let total_emitted_alpha: u64 = SubtensorModule::get_alpha_issuance(net).to_u64(); let owner_alpha_u64: u64 = U96F32::from_num(total_emitted_alpha) .saturating_mul(frac) .floor() .saturating_to_num::(); - // Current α→τ price for this subnet. - let price: U96F32 = - ::SwapInterface::current_alpha_price(net.into()); - let owner_emission_tao_u64: u64 = U96F32::from_num(owner_alpha_u64) - .saturating_mul(price) - .floor() - .saturating_to_num::(); + // Use the current alpha price to estimate the TAO equivalent. + let owner_emission_tao = { + let price: U96F32 = + ::SwapInterface::current_alpha_price(net.into()); + U96F32::from_num(owner_alpha_u64) + .saturating_mul(price) + .floor() + .saturating_to_num::() + .into() + }; - let expected_refund: TaoCurrency = - lock.saturating_sub(TaoCurrency::from(owner_emission_tao_u64)); + let expected_refund: TaoCurrency = lock.saturating_sub(owner_emission_tao); let before = SubtensorModule::get_coldkey_balance(&oc); assert_ok!(SubtensorModule::do_dissolve_network(net)); let after = SubtensorModule::get_coldkey_balance(&oc); + assert!(after > before); // some refund is expected assert_eq!( TaoCurrency::from(after), TaoCurrency::from(before) + expected_refund @@ -841,15 +847,10 @@ fn destroy_alpha_out_many_stakers_complex_distribution() { SubnetTAO::::insert(netuid, TaoCurrency::from(tao_pot)); SubtensorModule::set_subnet_locked_balance(netuid, TaoCurrency::from(lock)); + // ensure there was some Alpha issued + assert!(SubtensorModule::get_alpha_issuance(netuid).to_u64() > 0); + // Owner already earned some emission; owner-cut = 50 % - Emission::::insert( - netuid, - vec![ - AlphaCurrency::from(1_000), - AlphaCurrency::from(2_000), - AlphaCurrency::from(1_500), - ], - ); SubnetOwnerCut::::put(32_768u16); // ~ 0.5 in fixed-point // ── 4) balances before ────────────────────────────────────────────── @@ -879,28 +880,23 @@ fn destroy_alpha_out_many_stakers_complex_distribution() { // ── 5b) expected owner refund with price-aware emission deduction ─── let frac: U96F32 = SubtensorModule::get_float_subnet_owner_cut(); - let total_emitted_alpha: u64 = 1_000 + 2_000 + 1_500; // 4500 α + let total_emitted_alpha: u64 = SubtensorModule::get_alpha_issuance(netuid).to_u64(); let owner_alpha_u64: u64 = U96F32::from_num(total_emitted_alpha) .saturating_mul(frac) .floor() .saturating_to_num::(); - let order = GetTaoForAlpha::::with_amount(owner_alpha_u64); - let owner_emission_tao = - ::SwapInterface::sim_swap(netuid.into(), order) - .map(|res| res.amount_paid_out) - .unwrap_or_else(|_| { - // Fallback matches the pallet's fallback - let price: U96F32 = - ::SwapInterface::current_alpha_price(netuid.into()); - U96F32::from_num(owner_alpha_u64) - .saturating_mul(price) - .floor() - .saturating_to_num::() - .into() - }); - - let expected_refund = lock.saturating_sub(owner_emission_tao.to_u64()); + let owner_emission_tao: u64 = { + // Fallback matches the pallet's fallback + let price: U96F32 = + ::SwapInterface::current_alpha_price(netuid.into()); + U96F32::from_num(owner_alpha_u64) + .saturating_mul(price) + .floor() + .saturating_to_num::() + }; + + let expected_refund = lock.saturating_sub(owner_emission_tao); // ── 6) run distribution (credits τ to coldkeys, wipes α state) ───── assert_ok!(SubtensorModule::destroy_alpha_in_out_stakes(netuid)); @@ -947,34 +943,38 @@ fn destroy_alpha_out_refund_gating_by_registration_block() { // Lock and (nonzero) emissions let lock_u64: u64 = 50_000; SubtensorModule::set_subnet_locked_balance(netuid, TaoCurrency::from(lock_u64)); - Emission::::insert( - netuid, - vec![AlphaCurrency::from(1_500u64), AlphaCurrency::from(3_000u64)], // total 4_500 α - ); // Owner cut ≈ 50% SubnetOwnerCut::::put(32_768u16); + // give some stake to other key + let other_cold = U256::from(1_234); + let other_hot = U256::from(2_345); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &other_hot, + &other_cold, + netuid, + AlphaCurrency::from(30u64), // not nearly enough to cover the lock + ); + + // ensure there was some Alpha issued + assert!(SubtensorModule::get_alpha_issuance(netuid).to_u64() > 0); + // Compute expected refund using the same math as the pallet let frac: U96F32 = SubtensorModule::get_float_subnet_owner_cut(); - let total_emitted_alpha: u64 = 1_500 + 3_000; // 4_500 α + let total_emitted_alpha: u64 = SubtensorModule::get_alpha_issuance(netuid).to_u64(); let owner_alpha_u64: u64 = U96F32::from_num(total_emitted_alpha) .saturating_mul(frac) .floor() .saturating_to_num::(); - // Prefer sim_swap; fall back to current price if unavailable. - let order = GetTaoForAlpha::::with_amount(owner_alpha_u64); - let owner_emission_tao_u64 = - ::SwapInterface::sim_swap(netuid.into(), order) - .map(|res| res.amount_paid_out.to_u64()) - .unwrap_or_else(|_| { - let price: U96F32 = - ::SwapInterface::current_alpha_price(netuid.into()); - U96F32::from_num(owner_alpha_u64) - .saturating_mul(price) - .floor() - .saturating_to_num::() - }); + let owner_emission_tao_u64 = { + let price: U96F32 = + ::SwapInterface::current_alpha_price(netuid.into()); + U96F32::from_num(owner_alpha_u64) + .saturating_mul(price) + .floor() + .saturating_to_num::() + }; let expected_refund: u64 = lock_u64.saturating_sub(owner_emission_tao_u64); @@ -1011,7 +1011,17 @@ fn destroy_alpha_out_refund_gating_by_registration_block() { // Lock and emissions present (should be ignored for refund) let lock_u64: u64 = 42_000; SubtensorModule::set_subnet_locked_balance(netuid, TaoCurrency::from(lock_u64)); - Emission::::insert(netuid, vec![AlphaCurrency::from(5_000u64)]); + // give some stake to other key + let other_cold = U256::from(1_234); + let other_hot = U256::from(2_345); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &other_hot, + &other_cold, + netuid, + AlphaCurrency::from(300u64), // not nearly enough to cover the lock + ); + // ensure there was some Alpha issued + assert!(SubtensorModule::get_alpha_issuance(netuid).to_u64() > 0); SubnetOwnerCut::::put(32_768u16); // ~50% // Balances before @@ -1046,7 +1056,9 @@ fn destroy_alpha_out_refund_gating_by_registration_block() { // lock = 0; emissions present (must not matter) SubtensorModule::set_subnet_locked_balance(netuid, TaoCurrency::from(0u64)); - Emission::::insert(netuid, vec![AlphaCurrency::from(10_000u64)]); + SubnetAlphaOut::::insert(netuid, AlphaCurrency::from(10_000)); + // ensure there was some Alpha issued + assert!(SubtensorModule::get_alpha_issuance(netuid).to_u64() > 0); SubnetOwnerCut::::put(32_768u16); // ~50% let owner_before = SubtensorModule::get_coldkey_balance(&owner_cold); From 40b4ffca057db9056a2211b6051353c56c040099 Mon Sep 17 00:00:00 2001 From: camfairchild Date: Thu, 6 Nov 2025 15:00:59 -0500 Subject: [PATCH 29/29] remove log out --- pallets/subtensor/src/coinbase/run_coinbase.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 5b1c4b5704..d998ad1f7d 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -520,9 +520,7 @@ impl Pallet { incentive, }); } - log::debug!( - "incentives: increasing stake for {hotkey:?} to {incentive:?} with owner {owner:?}" - ); + Self::increase_stake_for_hotkey_and_coldkey_on_subnet( &destination, &owner,