Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pallets/subtensor/src/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1611,8 +1611,8 @@ mod pallet_benchmarks {
Subtensor::<T>::set_network_pow_registration_allowed(netuid, true);
SubtokenEnabled::<T>::insert(netuid, true);

let reg_fee = Subtensor::<T>::get_burn_as_u64(netuid);
Subtensor::<T>::add_balance_to_coldkey_account(&hotkey, reg_fee.saturating_mul(2));
let reg_fee = Subtensor::<T>::get_burn(netuid);
Subtensor::<T>::add_balance_to_coldkey_account(&hotkey, reg_fee.saturating_mul(2.into()).into());

assert_ok!(Subtensor::<T>::burned_register(
RawOrigin::Signed(hotkey.clone()).into(),
Expand Down
72 changes: 41 additions & 31 deletions pallets/subtensor/src/coinbase/run_coinbase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,12 @@ impl<T: Config> Pallet<T> {
U96F32::saturating_from_num(block_emission),
U96F32::saturating_from_num(0.0),
);

let alpha_per_tao = T::SwapInterface::get_current_alpha_per_tao(*netuid_i);
log::debug!("alpha_per_tao: {:?}", alpha_per_tao);
if price_i < tao_in_ratio {
tao_in_i = price_i.saturating_mul(U96F32::saturating_from_num(block_emission));
alpha_in_i = alpha_emission_i;
tao_in_i = U96F32::saturating_from_num(block_emission).safe_div(alpha_per_tao);
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(
Expand All @@ -100,9 +103,11 @@ impl<T: Config> Pallet<T> {
});
}
is_subsidized.insert(*netuid_i, true);
log::debug!("netuid: {:?} is subsidized", *netuid_i);
log::debug!("difference_tao: {:?}", difference_tao);
} else {
tao_in_i = default_tao_in_i;
alpha_in_i = tao_in_i.safe_div_or(price_i, alpha_emission_i);
alpha_in_i = tao_in_i.saturating_mul(alpha_per_tao);
is_subsidized.insert(*netuid_i, false);
}
log::debug!("alpha_in_i: {alpha_in_i:?}");
Expand All @@ -114,9 +119,12 @@ impl<T: Config> Pallet<T> {
&& !Self::get_network_pow_registration_allowed(*netuid_i)
{
tao_in_i = asfloat!(0.0);
log::debug!("netuid: {:?} registrations are not allowed", *netuid_i);
alpha_in_i = asfloat!(0.0);
alpha_out_i = asfloat!(0.0);
}
log::debug!("tao_in_i: {:?}", tao_in_i);

// Insert values into maps
tao_in.insert(*netuid_i, tao_in_i);
alpha_in.insert(*netuid_i, alpha_in_i);
Expand Down Expand Up @@ -188,33 +196,34 @@ impl<T: Config> Pallet<T> {
for netuid_i in subnets_to_emit_to.iter() {
// 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 TAO on root.
let root_tao: U96F32 = asfloat!(SubnetTAO::<T>::get(NetUid::ROOT));
log::debug!("root_tao: {root_tao:?}");
// Get total ALPHA on subnet.
let alpha_issuance: U96F32 = asfloat!(Self::get_alpha_issuance(*netuid_i));
log::debug!("alpha_issuance: {alpha_issuance:?}");
// Get tao_weight
let tao_weight: U96F32 = root_tao.saturating_mul(Self::get_tao_weight());
log::debug!("tao_weight: {tao_weight:?}");
// 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 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:?}");
log::debug!("alpha_out_i: {:?}", alpha_out_i);
// Get pending alpha as original alpha_out
let mut pending_alpha: U96F32 = alpha_out_i;
// Sell root emission through the pool (do not pay fees)
let subsidized: bool = *is_subsidized.get(netuid_i).unwrap_or(&false);
if !subsidized {
// Get total TAO on root.
let root_tao: U96F32 = asfloat!(SubnetTAO::<T>::get(NetUid::ROOT));
log::debug!("root_tao: {:?}", root_tao);
// Get total ALPHA on subnet.
let alpha_issuance: U96F32 = asfloat!(Self::get_alpha_issuance(*netuid_i));
log::debug!("alpha_issuance: {:?}", alpha_issuance);
// Get tao_weight
let tao_weight: U96F32 = root_tao.saturating_mul(Self::get_tao_weight());
log::debug!("tao_weight: {:?}", tao_weight);
// 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 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.
pending_alpha = alpha_out_i.saturating_sub(root_alpha);
let swap_result = Self::swap_alpha_for_tao(
*netuid_i,
tou64!(root_alpha).into(),
Expand All @@ -228,11 +237,12 @@ impl<T: Config> Pallet<T> {
*total = total.saturating_add(root_tao.into());
});
}
// Accumulate alpha emission in pending.
PendingAlphaSwapped::<T>::mutate(*netuid_i, |total| {
*total = total.saturating_add(tou64!(root_alpha).into());
});
}
// Accumulate alpha emission in pending.
PendingAlphaSwapped::<T>::mutate(*netuid_i, |total| {
*total = total.saturating_add(tou64!(root_alpha).into());
});
log::debug!("pending_alpha: {:?}", pending_alpha);
// Accumulate alpha emission in pending.
PendingEmission::<T>::mutate(*netuid_i, |total| {
*total = total.saturating_add(tou64!(pending_alpha).into());
Expand Down
1 change: 0 additions & 1 deletion pallets/subtensor/src/staking/stake_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,6 @@ impl<T: Config> Pallet<T> {
});

// Decrease Alpha outstanding.
// TODO: Deprecate, not accurate in v3 anymore
SubnetAlphaOut::<T>::mutate(netuid, |total| {
*total = total.saturating_sub((swap_result.alpha_reserve_delta as u64).into());
});
Expand Down
146 changes: 129 additions & 17 deletions pallets/subtensor/src/tests/coinbase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,11 @@ fn test_coinbase_tao_issuance_multiple() {
#[test]
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;
add_network(netuid1, 1, 0);
add_network(netuid2, 1, 0);
let hotkey_account_id = U256::from(533453);
let coldkey_account_id = U256::from(55453);
let netuid1 = add_dynamic_network(&hotkey_account_id, &coldkey_account_id);
let netuid2 = add_dynamic_network(&hotkey_account_id, &coldkey_account_id);

// Setup prices 0.1 and 0.2
let initial_tao: u64 = 100_000_u64;
Expand All @@ -180,10 +180,6 @@ fn test_coinbase_tao_issuance_different_prices() {
)
.unwrap();

// Make subnets dynamic.
SubnetMechanism::<Test>::insert(netuid1, 1);
SubnetMechanism::<Test>::insert(netuid2, 1);

// Set subnet prices.
SubnetMovingPrice::<Test>::insert(netuid1, I96F32::from_num(1));
SubnetMovingPrice::<Test>::insert(netuid2, I96F32::from_num(2));
Expand Down Expand Up @@ -341,28 +337,50 @@ fn test_update_moving_price_after_time() {
#[test]
fn test_coinbase_alpha_issuance_base() {
new_test_ext(1).execute_with(|| {
let netuid1 = NetUid::from(1);
let netuid2 = NetUid::from(2);
let hotkey_account_id = U256::from(533453);
let coldkey_account_id = U256::from(55453);
let netuid1 = add_dynamic_network(&hotkey_account_id, &coldkey_account_id);
let netuid2 = add_dynamic_network(&hotkey_account_id, &coldkey_account_id);
let emission: u64 = 1_000_000;
add_network(netuid1, 1, 0);
add_network(netuid2, 1, 0);

// Set up prices 1 and 1
let initial: u64 = 1_000_000;
let initial: u64 = emission * 100;
SubnetTAO::<Test>::insert(netuid1, TaoCurrency::from(initial));
SubnetAlphaIn::<Test>::insert(netuid1, AlphaCurrency::from(initial));
SubnetMovingPrice::<Test>::insert(netuid1, I96F32::from_num(1));
SubnetTAO::<Test>::insert(netuid2, TaoCurrency::from(initial));
SubnetAlphaIn::<Test>::insert(netuid2, AlphaCurrency::from(initial));
SubnetMovingPrice::<Test>::insert(netuid2, I96F32::from_num(1));

// Force the swaps to initialize
SubtensorModule::swap_tao_for_alpha(
netuid1,
TaoCurrency::ZERO,
1_000_000_000_000.into(),
false,
)
.unwrap();
SubtensorModule::swap_tao_for_alpha(
netuid2,
TaoCurrency::ZERO,
1_000_000_000_000.into(),
false,
)
.unwrap();

// Check initial
SubtensorModule::run_coinbase(U96F32::from_num(emission));
// tao_in = 500_000
// alpha_in = 500_000/price = 500_000
assert_eq!(
assert_abs_diff_eq!(
SubnetAlphaIn::<Test>::get(netuid1),
(initial + emission / 2).into()
(initial + emission / 2).into(),
epsilon = 1.into(),
);
assert_eq!(
assert_abs_diff_eq!(
SubnetAlphaIn::<Test>::get(netuid2),
(initial + emission / 2).into()
(initial + emission / 2).into(),
epsilon = 1.into(),
);
});
}
Expand Down Expand Up @@ -393,6 +411,23 @@ fn test_coinbase_alpha_issuance_different() {
// Set subnet prices.
SubnetMovingPrice::<Test>::insert(netuid1, I96F32::from_num(1));
SubnetMovingPrice::<Test>::insert(netuid2, I96F32::from_num(2));

// Force the swaps to initialize
SubtensorModule::swap_tao_for_alpha(
netuid1,
TaoCurrency::ZERO,
1_000_000_000_000.into(),
false,
)
.unwrap();
SubtensorModule::swap_tao_for_alpha(
netuid2,
TaoCurrency::ZERO,
1_000_000_000_000.into(),
false,
)
.unwrap();

// Run coinbase
SubtensorModule::run_coinbase(U96F32::from_num(emission));
// tao_in = 333_333
Expand Down Expand Up @@ -519,6 +554,83 @@ fn test_coinbase_alpha_issuance_with_cap_trigger_and_block_emission() {
});
}

// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_coinbase_alpha_issuance_price_convergence --exact --show-output --nocapture
#[test]
fn test_coinbase_alpha_issuance_price_convergence() {
new_test_ext(1).execute_with(|| {
let netuid0 = NetUid::from(0);
let netuid1 = NetUid::from(1);
let netuid2 = NetUid::from(2);
let emission: u64 = 1_000_000;
add_network(netuid0, 1, 0);
add_network(netuid1, 1, 0);
add_network(netuid2, 1, 0);

// Make subnets dynamic.
SubnetMechanism::<Test>::insert(netuid1, 1);
SubnetMechanism::<Test>::insert(netuid2, 1);

// Setup prices
let initial_tao: u64 = 10_000_000_000;
let initial_alpha: u64 = initial_tao * 4;
let initial_alpha2: u64 = initial_tao * 2;
mock::setup_reserves(netuid1, initial_tao.into(), initial_alpha.into());
mock::setup_reserves(netuid2, initial_tao.into(), initial_alpha2.into());

// Enable emission
FirstEmissionBlockNumber::<Test>::insert(netuid1, 0);
FirstEmissionBlockNumber::<Test>::insert(netuid2, 0);
SubnetMovingPrice::<Test>::insert(netuid1, I96F32::from_num(1));
SubnetMovingPrice::<Test>::insert(netuid2, I96F32::from_num(2));

// Force the swap to initialize
SubtensorModule::swap_tao_for_alpha(netuid1, 0.into(), 1_000_000_000_000.into(), false).unwrap();
SubtensorModule::swap_tao_for_alpha(netuid2, 0.into(), 1_000_000_000_000.into(), false).unwrap();

// Get the prices before the run_coinbase
let price_1_before = <Test as pallet::Config>::SwapInterface::current_alpha_price(netuid1);
let price_2_before = <Test as pallet::Config>::SwapInterface::current_alpha_price(netuid2);

// Set issuance
SubnetAlphaOut::<Test>::insert(netuid1, AlphaCurrency::from(1_000_000_000_000));
SubnetAlphaOut::<Test>::insert(netuid2, AlphaCurrency::from(1_000_000_000_000));

// Setup root stake and (a tiny) weight
SubnetTAO::<Test>::insert(netuid0, TaoCurrency::from(1_000_000_000_000_u64));
TaoWeight::<Test>::set((0.001 * u64::MAX as f64) as u64);

// Run coinbase 1000 times to move closer to equillibrium
let mut last_price_1 = price_1_before;
let mut last_price_2 = price_2_before;
for _ in 0..1000 {
SubtensorModule::run_coinbase(U96F32::from_num(emission));

// Get the prices after the run_coinbase
let price_1_after =
<Test as pallet::Config>::SwapInterface::current_alpha_price(netuid1);
let price_2_after =
<Test as pallet::Config>::SwapInterface::current_alpha_price(netuid2);

// Make sure prices move towards emission
let threshold_1 = U96F32::from_num(1. / 3.);
let threshold_2 = U96F32::from_num(2. / 3.);
if threshold_1.saturating_sub(last_price_1) > 1_000 {
assert!(price_1_after > last_price_1);
} else if last_price_1.saturating_sub(threshold_1) > 1_000 {
assert!(price_1_after < last_price_1);
}
if threshold_2.saturating_sub(last_price_2) > 1_000 {
assert!(price_2_after > last_price_2);
} else if last_price_2.saturating_sub(threshold_2) > 1_000 {
assert!(price_2_after < last_price_2);
}

last_price_1 = price_1_after;
last_price_2 = price_2_after;
}
});
}

// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_owner_cut_base --exact --show-output --nocapture
#[test]
fn test_owner_cut_base() {
Expand Down
1 change: 1 addition & 0 deletions pallets/swap-interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub trait SwapHandler<AccountId> {
alpha_delta: AlphaCurrency,
);
fn is_user_liquidity_enabled(netuid: NetUid) -> bool;
fn get_current_alpha_per_tao(netuid: NetUid) -> U96F32;
}

#[derive(Debug, PartialEq)]
Expand Down
14 changes: 14 additions & 0 deletions pallets/swap/src/pallet/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1289,6 +1289,20 @@ impl<T: Config> SwapHandler<T::AccountId> for Pallet<T> {
fn is_user_liquidity_enabled(netuid: NetUid) -> bool {
EnabledUserLiquidity::<T>::get(netuid)
}

fn get_current_alpha_per_tao(netuid: NetUid) -> U96F32 {
let one = SqrtPrice::saturating_from_num(1);
let sqrt_price_current = Self::current_price_sqrt(netuid.into());
let sqrt_price_min = TickIndex::min_sqrt_price();
let sqrt_price_max = TickIndex::max_sqrt_price();
let price_diff = sqrt_price_current.saturating_sub(sqrt_price_min);
let inv_price_diff = one
.safe_div(sqrt_price_current)
.saturating_sub(one.safe_div(sqrt_price_max));
price_diff
.saturating_mul(inv_price_diff)
.saturating_to_num::<U96F32>()
}
}

#[derive(Debug, PartialEq)]
Expand Down