diff --git a/pallets/subtensor/src/staking/remove_stake.rs b/pallets/subtensor/src/staking/remove_stake.rs index 0b460612b9..cc30c6e3f1 100644 --- a/pallets/subtensor/src/staking/remove_stake.rs +++ b/pallets/subtensor/src/staking/remove_stake.rs @@ -48,8 +48,6 @@ impl Pallet { "do_remove_stake( origin:{coldkey:?} hotkey:{hotkey:?}, netuid: {netuid:?}, alpha_unstaked:{alpha_unstaked:?} )" ); - Self::ensure_subtoken_enabled(netuid)?; - // 1.1. Cap the alpha_unstaked at available Alpha because user might be paying transaxtion fees // in Alpha and their total is already reduced by now. let alpha_available = diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs index 2826590c50..436feb4751 100644 --- a/pallets/subtensor/src/staking/stake_utils.rs +++ b/pallets/subtensor/src/staking/stake_utils.rs @@ -1144,7 +1144,7 @@ impl Pallet { ensure!(Self::if_subnet_exist(netuid), Error::::SubnetNotExists); // Ensure that the subnet is enabled. - // Self::ensure_subtoken_enabled(netuid)?; + Self::ensure_subtoken_enabled(netuid)?; // Do not allow zero unstake amount ensure!(!alpha_unstaked.is_zero(), Error::::AmountTooLow); diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs index 3d759e200c..2db6e57813 100644 --- a/pallets/subtensor/src/tests/staking.rs +++ b/pallets/subtensor/src/tests/staking.rs @@ -4005,6 +4005,85 @@ fn test_remove_stake_limit_ok() { }); } +#[test] +fn test_remove_stake_limit_blocked_when_subtoken_disabled() { + new_test_ext(1).execute_with(|| { + let hotkey_account_id = U256::from(533453); + let coldkey_account_id = U256::from(55453); + let stake_amount = TaoBalance::from(300_000_000_000_u64); + + let netuid = add_dynamic_network(&hotkey_account_id, &coldkey_account_id); + add_balance_to_coldkey_account( + &coldkey_account_id, + stake_amount + ExistentialDeposit::get(), + ); + + // Force-set sufficient reserves so a swap would otherwise fill. + SubnetTAO::::insert(netuid, TaoBalance::from(100_000_000_000_u64)); + SubnetAlphaIn::::insert(netuid, AlphaBalance::from(100_000_000_000_u64)); + + // Stake while subtoken trading is still enabled. + assert_ok!(SubtensorModule::add_stake( + RuntimeOrigin::signed(coldkey_account_id), + hotkey_account_id, + netuid, + stake_amount + )); + let alpha_before = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey_account_id, + &coldkey_account_id, + netuid, + ); + let subnet_tao_before = SubnetTAO::::get(netuid); + + // Admin freezes subtoken trading on the live subnet. + SubtokenEnabled::::insert(netuid, false); + + // A permissive limit price that the current pool would otherwise satisfy. + let limit_price = TaoBalance::from(1_u64); + + // Every remove path must be rejected uniformly while the freeze is active. + assert_noop!( + SubtensorModule::remove_stake( + RuntimeOrigin::signed(coldkey_account_id), + hotkey_account_id, + netuid, + alpha_before / 2.into(), + ), + Error::::SubtokenDisabled + ); + assert_noop!( + SubtensorModule::remove_stake_limit( + RuntimeOrigin::signed(coldkey_account_id), + hotkey_account_id, + netuid, + alpha_before / 2.into(), + limit_price, + true + ), + Error::::SubtokenDisabled + ); + assert_noop!( + SubtensorModule::remove_stake_full_limit( + RuntimeOrigin::signed(coldkey_account_id), + hotkey_account_id, + netuid, + Some(limit_price), + ), + Error::::SubtokenDisabled + ); + + // Nothing was drawn down: the staker's alpha and the subnet reserve are untouched. + let alpha_after = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey_account_id, + &coldkey_account_id, + netuid, + ); + assert_eq!(alpha_after, alpha_before); + assert_eq!(SubnetTAO::::get(netuid), subnet_tao_before); + }); +} + #[test] fn test_remove_stake_limit_fill_or_kill() { new_test_ext(1).execute_with(|| { diff --git a/pallets/subtensor/src/tests/subnet.rs b/pallets/subtensor/src/tests/subnet.rs index be1487b4ec..24acd1d375 100644 --- a/pallets/subtensor/src/tests/subnet.rs +++ b/pallets/subtensor/src/tests/subnet.rs @@ -496,15 +496,17 @@ fn test_subtoken_enable_reject_trading_before_enable() { stake_bal ); - SubtensorModule::remove_stake_limit( - RuntimeOrigin::signed(coldkey_account_id), - hotkey_account_id, - netuid, - amount.into(), - limit_price, - false, - ) - .unwrap(); + assert_noop!( + SubtensorModule::remove_stake_limit( + RuntimeOrigin::signed(coldkey_account_id), + hotkey_account_id, + netuid, + amount.into(), + limit_price, + false, + ), + Error::::SubtokenDisabled + ); assert_noop!( SubtensorModule::remove_stake(