Skip to content
Merged
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
39 changes: 34 additions & 5 deletions pallets/subtensor/src/staking/stake_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,15 @@ impl<T: Config> Pallet<T> {
alpha_share_pool.update_value_for_one(coldkey, amount as i64);
}

pub fn try_increase_stake_for_hotkey_and_coldkey_on_subnet(
hotkey: &T::AccountId,
netuid: u16,
amount: u64,
) -> bool {
let mut alpha_share_pool = Self::get_alpha_share_pool(hotkey.clone(), netuid);
alpha_share_pool.sim_update_value_for_one(amount as i64)
}

/// Sell shares in the hotkey on a given subnet
///
/// The function updates share totals given current prices.
Expand Down Expand Up @@ -877,11 +886,18 @@ impl<T: Config> Pallet<T> {
Error::<T>::HotKeyAccountNotExists
);

let expected_alpha = Self::sim_swap_tao_for_alpha(netuid, stake_to_be_added);

// Ensure that we have adequate liquidity
ensure!(
Self::sim_swap_tao_for_alpha(netuid, stake_to_be_added).is_some(),
Error::<T>::InsufficientLiquidity
ensure!(expected_alpha.is_some(), Error::<T>::InsufficientLiquidity);

// Ensure hotkey pool is precise enough
let try_stake_result = Self::try_increase_stake_for_hotkey_and_coldkey_on_subnet(
hotkey,
netuid,
expected_alpha.unwrap_or(0),
);
ensure!(try_stake_result, Error::<T>::InsufficientLiquidity);

Ok(())
}
Expand Down Expand Up @@ -937,7 +953,7 @@ impl<T: Config> Pallet<T> {
origin_coldkey: &T::AccountId,
_destination_coldkey: &T::AccountId,
origin_hotkey: &T::AccountId,
_destination_hotkey: &T::AccountId,
destination_hotkey: &T::AccountId,
origin_netuid: u16,
destination_netuid: u16,
alpha_amount: u64,
Expand Down Expand Up @@ -975,7 +991,8 @@ impl<T: Config> Pallet<T> {
);

// Ensure that the stake amount to be removed is above the minimum in tao equivalent.
if let Some(tao_equivalent) = Self::sim_swap_alpha_for_tao(origin_netuid, alpha_amount) {
let tao_equivalent_result = Self::sim_swap_alpha_for_tao(origin_netuid, alpha_amount);
if let Some(tao_equivalent) = tao_equivalent_result {
ensure!(
tao_equivalent > DefaultMinStake::<T>::get(),
Error::<T>::AmountTooLow
Expand All @@ -992,6 +1009,18 @@ impl<T: Config> Pallet<T> {
}
}

let expected_alpha =
Self::sim_swap_tao_for_alpha(destination_netuid, tao_equivalent_result.unwrap_or(0))
.unwrap_or(0);

// Ensure that the amount being staked to the new hotkey is precise enough
let try_stake_result = Self::try_increase_stake_for_hotkey_and_coldkey_on_subnet(
destination_hotkey,
destination_netuid,
expected_alpha,
);
ensure!(try_stake_result, Error::<T>::InsufficientLiquidity);

if check_transfer_toggle {
// Ensure transfer is toggled.
ensure!(
Expand Down
275 changes: 274 additions & 1 deletion pallets/subtensor/src/tests/staking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use approx::assert_abs_diff_eq;
use frame_support::dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays};
use frame_support::sp_runtime::DispatchError;
use sp_core::{Get, H256, U256};
use substrate_fixed::types::{I96F32, U96F32};
use substrate_fixed::types::{I96F32, U64F64, U96F32};

/***********************************************************
staking::add_stake() tests
Expand Down Expand Up @@ -3495,3 +3495,276 @@ fn test_remove_stake_limit_fill_or_kill() {
),);
});
}

// #[test]
// fn test_add_stake_specific() {
// new_test_ext(1).execute_with(|| {
// let sn_owner_coldkey = U256::from(55453);

// let hotkey_account_id = U256::from(533453);
// let coldkey_account_id = U256::from(55454);
// let hotkey_owner_account_id = U256::from(533454);

// let existing_shares: U64F64 =
// U64F64::from_num(161_986_254).saturating_div(U64F64::from_num(u64::MAX));
// let existing_stake = 36_711_495_953;
// let amount_added = 1_274_280_132;

// //add network
// let netuid: u16 = add_dynamic_network(&sn_owner_coldkey, &sn_owner_coldkey);

// // Register hotkey on netuid
// register_ok_neuron(netuid, hotkey_account_id, hotkey_owner_account_id, 0);
// // Check we have zero staked
// assert_eq!(
// SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id),
// 0
// );

// // Set a hotkey pool for the hotkey
// let mut hotkey_pool = SubtensorModule::get_alpha_share_pool(hotkey_account_id, netuid);
// hotkey_pool.update_value_for_one(&hotkey_owner_account_id, 1234); // Doesn't matter, will be overridden

// // Adjust the total hotkey stake and shares to match the existing values
// TotalHotkeyShares::<Test>::insert(hotkey_account_id, netuid, existing_shares);
// TotalHotkeyAlpha::<Test>::insert(hotkey_account_id, netuid, existing_stake);

// // Make the hotkey a delegate
// Delegates::<Test>::insert(hotkey_account_id, 0);

// // Add stake as new hotkey
// SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
// &hotkey_account_id,
// &coldkey_account_id,
// netuid,
// amount_added,
// );

// // Check the stake and shares are correct
// assert!(Alpha::<Test>::get((&hotkey_account_id, &coldkey_account_id, netuid)) > 0);
// assert_eq!(
// TotalHotkeyAlpha::<Test>::get(hotkey_account_id, netuid),
// amount_added + existing_stake
// );
// });
// }

// #[test]
// // RUST_LOG=info cargo test --package pallet-subtensor --lib -- tests::staking::test_add_stake_specific_stake_into_subnet --exact --show-output
// fn test_add_stake_specific_stake_into_subnet() {
// new_test_ext(1).execute_with(|| {
// let sn_owner_coldkey = U256::from(55453);

// let hotkey_account_id = U256::from(533453);
// let coldkey_account_id = U256::from(55454);
// let hotkey_owner_account_id = U256::from(533454);

// let existing_shares: U64F64 =
// U64F64::from_num(161_986_254).saturating_div(U64F64::from_num(u64::MAX));
// let existing_stake = 36_711_495_953;

// let tao_in = 2_409_892_148_947;
// let alpha_in = 15_358_708_513_716;

// let tao_staked = 200_000_000;
// let fee = DefaultStakingFee::<Test>::get();

// //add network
// let netuid: u16 = add_dynamic_network(&sn_owner_coldkey, &sn_owner_coldkey);

// // Register hotkey on netuid
// register_ok_neuron(netuid, hotkey_account_id, hotkey_owner_account_id, 0);
// // Check we have zero staked
// assert_eq!(
// SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id),
// 0
// );

// // Set a hotkey pool for the hotkey
// let mut hotkey_pool = SubtensorModule::get_alpha_share_pool(hotkey_account_id, netuid);
// hotkey_pool.update_value_for_one(&hotkey_owner_account_id, 1234); // Doesn't matter, will be overridden

// // Adjust the total hotkey stake and shares to match the existing values
// TotalHotkeyShares::<Test>::insert(hotkey_account_id, netuid, existing_shares);
// TotalHotkeyAlpha::<Test>::insert(hotkey_account_id, netuid, existing_stake);

// // Make the hotkey a delegate
// Delegates::<Test>::insert(hotkey_account_id, 0);

// // Setup Subnet pool
// SubnetAlphaIn::<Test>::insert(netuid, alpha_in);
// SubnetTAO::<Test>::insert(netuid, tao_in);

// // Add stake as new hotkey
// SubtensorModule::stake_into_subnet(
// &hotkey_account_id,
// &coldkey_account_id,
// netuid,
// tao_staked,
// fee,
// );

// // Check the stake and shares are correct
// assert!(Alpha::<Test>::get((&hotkey_account_id, &coldkey_account_id, netuid)) > 0);
// log::info!(
// "Alpha: {}",
// Alpha::<Test>::get((&hotkey_account_id, &coldkey_account_id, netuid))
// );
// log::info!(
// "TotalHotkeyAlpha: {}",
// TotalHotkeyAlpha::<Test>::get(hotkey_account_id, netuid)
// );
// });
// }

#[test]
// RUST_LOG=info cargo test --package pallet-subtensor --lib -- tests::staking::test_add_stake_specific_stake_into_subnet_fail --exact --show-output
fn test_add_stake_specific_stake_into_subnet_fail() {
new_test_ext(1).execute_with(|| {
let sn_owner_coldkey = U256::from(55453);

let hotkey_account_id = U256::from(533453);
let coldkey_account_id = U256::from(55454);
let hotkey_owner_account_id = U256::from(533454);

let existing_shares: U64F64 =
U64F64::from_num(161_986_254).saturating_div(U64F64::from_num(u64::MAX));
let existing_stake = 36_711_495_953;

let tao_in = 2_409_892_148_947;
let alpha_in = 15_358_708_513_716;

let tao_staked = 200_000_000;

//add network
let netuid: u16 = add_dynamic_network(&sn_owner_coldkey, &sn_owner_coldkey);

// Register hotkey on netuid
register_ok_neuron(netuid, hotkey_account_id, hotkey_owner_account_id, 0);
// Check we have zero staked
assert_eq!(
SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id),
0
);

// Set a hotkey pool for the hotkey
let mut hotkey_pool = SubtensorModule::get_alpha_share_pool(hotkey_account_id, netuid);
hotkey_pool.update_value_for_one(&hotkey_owner_account_id, 1234); // Doesn't matter, will be overridden

// Adjust the total hotkey stake and shares to match the existing values
TotalHotkeyShares::<Test>::insert(hotkey_account_id, netuid, existing_shares);
TotalHotkeyAlpha::<Test>::insert(hotkey_account_id, netuid, existing_stake);

// Make the hotkey a delegate
Delegates::<Test>::insert(hotkey_account_id, 0);

// Setup Subnet pool
SubnetAlphaIn::<Test>::insert(netuid, alpha_in);
SubnetTAO::<Test>::insert(netuid, tao_in);

// Give TAO balance to coldkey
SubtensorModule::add_balance_to_coldkey_account(
&coldkey_account_id,
tao_staked + 1_000_000_000,
);

// Add stake as new hotkey
assert_noop!(
SubtensorModule::add_stake(
RuntimeOrigin::signed(coldkey_account_id),
hotkey_account_id,
netuid,
tao_staked,
),
Error::<Test>::InsufficientLiquidity
);
});
}

#[test]
// RUST_LOG=info cargo test --package pallet-subtensor --lib -- tests::staking::test_move_stake_specific_stake_into_subnet_fail --exact --show-output
fn test_move_stake_specific_stake_into_subnet_fail() {
new_test_ext(1).execute_with(|| {
let sn_owner_coldkey = U256::from(55453);

let hotkey_account_id = U256::from(533453);
let coldkey_account_id = U256::from(55454);
let hotkey_owner_account_id = U256::from(533454);

let existing_shares: U64F64 =
U64F64::from_num(161_986_254).saturating_div(U64F64::from_num(u64::MAX));
let existing_stake = 36_711_495_953;

let tao_in = 2_409_892_148_947;
let alpha_in = 15_358_708_513_716;

let tao_staked = 200_000_000;

//add network
let netuid: u16 = add_dynamic_network(&sn_owner_coldkey, &sn_owner_coldkey);

let origin_netuid: u16 = add_dynamic_network(&sn_owner_coldkey, &sn_owner_coldkey);

// Register hotkey on netuid
register_ok_neuron(netuid, hotkey_account_id, hotkey_owner_account_id, 0);
// Register hotkey on origin netuid
register_ok_neuron(origin_netuid, hotkey_account_id, hotkey_owner_account_id, 0);

// Check we have zero staked
assert_eq!(
SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id),
0
);

// Set a hotkey pool for the hotkey on destination subnet
let mut hotkey_pool = SubtensorModule::get_alpha_share_pool(hotkey_account_id, netuid);
hotkey_pool.update_value_for_one(&hotkey_owner_account_id, 1234); // Doesn't matter, will be overridden

// Adjust the total hotkey stake and shares to match the existing values
TotalHotkeyShares::<Test>::insert(hotkey_account_id, netuid, existing_shares);
TotalHotkeyAlpha::<Test>::insert(hotkey_account_id, netuid, existing_stake);

// Make the hotkey a delegate
Delegates::<Test>::insert(hotkey_account_id, 0);

// Setup Subnet pool
SubnetAlphaIn::<Test>::insert(netuid, alpha_in);
SubnetTAO::<Test>::insert(netuid, tao_in);

// Give TAO balance to coldkey
SubtensorModule::add_balance_to_coldkey_account(
&coldkey_account_id,
tao_staked + 1_000_000_000,
);

// Setup Subnet pool for origin netuid
SubnetAlphaIn::<Test>::insert(origin_netuid, alpha_in + 10_000_000);
SubnetTAO::<Test>::insert(origin_netuid, tao_in + 10_000_000);

// Add stake as new hotkey
assert_ok!(SubtensorModule::add_stake(
RuntimeOrigin::signed(coldkey_account_id),
hotkey_account_id,
origin_netuid,
tao_staked,
),);
let alpha_to_move = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
&hotkey_account_id,
&coldkey_account_id,
origin_netuid,
);

// Move stake to destination subnet
assert_noop!(
SubtensorModule::move_stake(
RuntimeOrigin::signed(coldkey_account_id),
hotkey_account_id,
hotkey_account_id,
origin_netuid,
netuid,
alpha_to_move,
),
Error::<Test>::InsufficientLiquidity
);
});
}
23 changes: 23 additions & 0 deletions primitives/share-pool/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,29 @@ where
});
}

pub fn sim_update_value_for_one(&mut self, update: i64) -> bool {
let shared_value: U64F64 = self.state_ops.get_shared_value();
let denominator: U64F64 = self.state_ops.get_denominator();

// Then, update this key's share
if denominator == 0 {
true
} else {
// There are already keys in the pool, set or update this key
let value_per_share: I64F64 = I64F64::saturating_from_num(
shared_value
.checked_div(denominator) // denominator is never 0 here
.unwrap_or(U64F64::saturating_from_num(0)),
);

let shares_per_update: I64F64 = I64F64::saturating_from_num(update)
.checked_div(value_per_share)
.unwrap_or(I64F64::saturating_from_num(0));

shares_per_update != 0
}
}

/// Update the value associated with an item identified by the Key
pub fn update_value_for_one(&mut self, key: &K, update: i64) {
let shared_value: U64F64 = self.state_ops.get_shared_value();
Expand Down
Loading
Loading