diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 9d6d44de8..5217160e9 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -38,11 +38,10 @@ impl Pallet { .collect(); log::debug!("Subnets to emit to: {subnets_to_emit_to:?}"); - // --- 2. Get sum of tao reserves ( in a later version we will switch to prices. ) + // --- 2. Get sum of moving alpha prices let mut acc_total_moving_prices = U96F32::saturating_from_num(0.0); // Only get price EMA for subnets that we emit to. for netuid_i in subnets_to_emit_to.iter() { - // Get and update the moving price of each subnet adding the total together. acc_total_moving_prices = acc_total_moving_prices.saturating_add(Self::get_moving_alpha_price(*netuid_i)); } @@ -55,6 +54,8 @@ impl Pallet { 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. @@ -69,6 +70,11 @@ impl Pallet { .checked_div(total_moving_prices) .unwrap_or(asfloat!(0.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,36 +82,41 @@ impl Pallet { ); log::debug!("alpha_emission_i: {alpha_emission_i:?}"); - // 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: 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); - }); + if default_alpha_in_i > alpha_emission_i + || total_moving_prices < U96F32::saturating_from_num(1.0) + { + let min_alpha_emission = + default_alpha_in_i.min(alpha_emission_i).min(block_emission); + alpha_in_i = min_alpha_emission; + tao_in_i = alpha_in_i.saturating_mul(price_i); + + if total_moving_prices < U96F32::saturating_from_num(1.0) { + 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); } - is_subsidized.insert(*netuid_i, true); } else { + alpha_in_i = default_alpha_in_i; 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); + subsidy_amount.insert(*netuid_i, asfloat!(0.0)); } + log::debug!("tao_in_i: {tao_in_i:?}"); log::debug!("alpha_in_i: {alpha_in_i:?}"); // Get alpha_out. @@ -123,6 +134,7 @@ impl Pallet { alpha_in.insert(*netuid_i, alpha_in_i); alpha_out.insert(*netuid_i, alpha_out_i); } + log::debug!("tao_in: {tao_in:?}"); log::debug!("alpha_in: {alpha_in:?}"); log::debug!("alpha_out: {alpha_out:?}"); @@ -145,18 +157,25 @@ impl Pallet { SubnetAlphaOut::::mutate(*netuid_i, |total| { *total = total.saturating_add(alpha_out_i); }); + // Inject TAO in. let tao_in_i: TaoCurrency = tou64!(*tao_in.get(netuid_i).unwrap_or(&asfloat!(0))).into(); + let subsidy_tao: TaoCurrency = + tou64!(*subsidy_amount.get(netuid_i).unwrap_or(&asfloat!(0))).into(); SubnetTaoInEmission::::insert(*netuid_i, TaoCurrency::from(tao_in_i)); + + // No need to add subsidy_tao here as it is captured from the swap result above. SubnetTAO::::mutate(*netuid_i, |total| { *total = total.saturating_add(tao_in_i.into()); }); TotalStake::::mutate(|total| { *total = total.saturating_add(tao_in_i.into()); }); + // Here we add subsidy tao as it is technically as issuance TotalIssuance::::mutate(|total| { *total = total.saturating_add(tao_in_i.into()); + *total = total.saturating_add(subsidy_tao.into()); }); // Adjust protocol liquidity based on new reserves T::SwapInterface::adjust_protocol_liquidity(*netuid_i, tao_in_i, alpha_in_i); @@ -214,7 +233,6 @@ impl Pallet { // 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:?}"); - // Sell root emission through the pool (do not pay fees) let subsidized: bool = *is_subsidized.get(netuid_i).unwrap_or(&false); if !subsidized { let swap_result = Self::swap_alpha_for_tao( diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index 39a964a06..ab9381b0e 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -153,7 +153,7 @@ fn test_coinbase_tao_issuance_different_prices() { new_test_ext(1).execute_with(|| { let netuid1 = NetUid::from(1); let netuid2 = NetUid::from(2); - let emission = 100_000_000; + let emission = 1_000_000_000; add_network(netuid1, 1, 0); add_network(netuid2, 1, 0); @@ -194,16 +194,15 @@ fn test_coinbase_tao_issuance_different_prices() { // Run the coinbase with the emission amount. SubtensorModule::run_coinbase(U96F32::from_num(emission)); - // Assert tao emission is split evenly. assert_abs_diff_eq!( SubnetTAO::::get(netuid1), - TaoCurrency::from(initial_tao + emission / 3), + TaoCurrency::from(initial_tao + emission / 10), epsilon = 1.into(), ); assert_abs_diff_eq!( SubnetTAO::::get(netuid2), - TaoCurrency::from(initial_tao + 2 * emission / 3), + TaoCurrency::from(initial_tao + 2 * emission / 10), epsilon = 1.into(), ); @@ -214,11 +213,7 @@ fn test_coinbase_tao_issuance_different_prices() { tao_issued, epsilon = 10.into() ); - assert_abs_diff_eq!( - TotalStake::::get(), - emission.into(), - epsilon = 10.into() - ); + assert_abs_diff_eq!(TotalStake::::get(), tao_issued, epsilon = 10.into()); }); } @@ -468,8 +463,8 @@ fn test_coinbase_alpha_issuance_with_cap_trigger_and_block_emission() { // Enable emission FirstEmissionBlockNumber::::insert(netuid1, 0); FirstEmissionBlockNumber::::insert(netuid2, 0); - SubnetMovingPrice::::insert(netuid1, I96F32::from_num(1)); - SubnetMovingPrice::::insert(netuid2, I96F32::from_num(2)); + SubnetMovingPrice::::insert(netuid1, I96F32::from_num(0.1)); + SubnetMovingPrice::::insert(netuid2, I96F32::from_num(0.2)); // Force the swap to initialize SubtensorModule::swap_tao_for_alpha( @@ -503,7 +498,7 @@ fn test_coinbase_alpha_issuance_with_cap_trigger_and_block_emission() { let price_2_after = ::SwapInterface::current_alpha_price(netuid2); // AlphaIn gets decreased beacuse of a buy - assert!(u64::from(SubnetAlphaIn::::get(netuid1)) < initial_alpha); + assert!(u64::from(SubnetAlphaIn::::get(netuid1)) < initial_alpha); // HERE assert_eq!( u64::from(SubnetAlphaOut::::get(netuid2)), 21_000_000_000_000_000_u64