From 0fc7e4f4c8f200a475cb43d22e0b41fb948b8abe Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Thu, 4 Dec 2025 17:48:44 -0500 Subject: [PATCH 1/7] Extrinsic to disable LP on all subnets --- pallets/swap/src/pallet/mod.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/pallets/swap/src/pallet/mod.rs b/pallets/swap/src/pallet/mod.rs index 1501f9cb37..83d9847881 100644 --- a/pallets/swap/src/pallet/mod.rs +++ b/pallets/swap/src/pallet/mod.rs @@ -350,9 +350,9 @@ mod pallet { Error::::MechanismDoesNotExist ); - EnabledUserLiquidity::::insert(netuid, enable); + // EnabledUserLiquidity::::insert(netuid, enable); - Self::deposit_event(Event::UserLiquidityToggled { netuid, enable }); + // Self::deposit_event(Event::UserLiquidityToggled { netuid, enable }); Ok(()) } @@ -600,5 +600,27 @@ mod pallet { Ok(()) } + + /// Disable user liquidity in all subnets. + /// + /// Emits `Event::UserLiquidityToggled` on success + #[pallet::call_index(5)] + #[pallet::weight(::WeightInfo::modify_position())] + pub fn disable_lp(origin: OriginFor) -> DispatchResult { + ensure_root(origin)?; + + for netuid in 1..128 { + let netuid = NetUid::from(netuid as u16); + if EnabledUserLiquidity::::get(netuid) { + EnabledUserLiquidity::::insert(netuid, false); + Self::deposit_event(Event::UserLiquidityToggled { + netuid, + enable: false, + }); + } + } + + Ok(()) + } } } From 6a1a36db7c38d74a05524d4a94ae06ad8223aa0e Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Thu, 4 Dec 2025 17:51:34 -0500 Subject: [PATCH 2/7] Remove test_user_liquidity_access_control --- pallets/subtensor/src/tests/subnet.rs | 112 +++++++++++++------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/pallets/subtensor/src/tests/subnet.rs b/pallets/subtensor/src/tests/subnet.rs index a11eae759e..d2a73a919d 100644 --- a/pallets/subtensor/src/tests/subnet.rs +++ b/pallets/subtensor/src/tests/subnet.rs @@ -717,62 +717,62 @@ fn test_subtoken_enable_ok_for_burn_register_before_enable() { }); } -#[test] -fn test_user_liquidity_access_control() { - new_test_ext(1).execute_with(|| { - let owner_hotkey = U256::from(1); - let owner_coldkey = U256::from(2); - let not_owner = U256::from(999); // arbitrary non-owner - - // add network - let netuid = add_dynamic_network(&owner_hotkey, &owner_coldkey); - - // Not owner, not root: should fail - assert_noop!( - Swap::toggle_user_liquidity(RuntimeOrigin::signed(not_owner), netuid, true), - DispatchError::BadOrigin - ); - - // Subnet owner can enable - assert_ok!(Swap::toggle_user_liquidity( - RuntimeOrigin::signed(owner_coldkey), - netuid, - true - )); - assert!(pallet_subtensor_swap::EnabledUserLiquidity::::get( - NetUid::from(netuid) - )); - - // Root can disable - assert_ok!(Swap::toggle_user_liquidity( - RuntimeOrigin::root(), - netuid, - false - )); - assert!(!pallet_subtensor_swap::EnabledUserLiquidity::::get( - NetUid::from(netuid) - )); - - // Root can enable again - assert_ok!(Swap::toggle_user_liquidity( - RuntimeOrigin::root(), - netuid, - true - )); - assert!(pallet_subtensor_swap::EnabledUserLiquidity::::get( - NetUid::from(netuid) - )); - - // Subnet owner cannot disable (only root can disable) - assert_noop!( - Swap::toggle_user_liquidity(RuntimeOrigin::signed(owner_coldkey), netuid, false), - DispatchError::BadOrigin - ); - assert!(pallet_subtensor_swap::EnabledUserLiquidity::::get( - NetUid::from(netuid) - )); - }); -} +// #[test] +// fn test_user_liquidity_access_control() { +// new_test_ext(1).execute_with(|| { +// let owner_hotkey = U256::from(1); +// let owner_coldkey = U256::from(2); +// let not_owner = U256::from(999); // arbitrary non-owner + +// // add network +// let netuid = add_dynamic_network(&owner_hotkey, &owner_coldkey); + +// // Not owner, not root: should fail +// assert_noop!( +// Swap::toggle_user_liquidity(RuntimeOrigin::signed(not_owner), netuid, true), +// DispatchError::BadOrigin +// ); + +// // Subnet owner can enable +// assert_ok!(Swap::toggle_user_liquidity( +// RuntimeOrigin::signed(owner_coldkey), +// netuid, +// true +// )); +// assert!(pallet_subtensor_swap::EnabledUserLiquidity::::get( +// NetUid::from(netuid) +// )); + +// // Root can disable +// assert_ok!(Swap::toggle_user_liquidity( +// RuntimeOrigin::root(), +// netuid, +// false +// )); +// assert!(!pallet_subtensor_swap::EnabledUserLiquidity::::get( +// NetUid::from(netuid) +// )); + +// // Root can enable again +// assert_ok!(Swap::toggle_user_liquidity( +// RuntimeOrigin::root(), +// netuid, +// true +// )); +// assert!(pallet_subtensor_swap::EnabledUserLiquidity::::get( +// NetUid::from(netuid) +// )); + +// // Subnet owner cannot disable (only root can disable) +// assert_noop!( +// Swap::toggle_user_liquidity(RuntimeOrigin::signed(owner_coldkey), netuid, false), +// DispatchError::BadOrigin +// ); +// assert!(pallet_subtensor_swap::EnabledUserLiquidity::::get( +// NetUid::from(netuid) +// )); +// }); +// } // cargo test --package pallet-subtensor --lib -- tests::subnet::test_no_duplicates_in_symbol_static --exact --show-output #[test] From 7175c6301f028d4513d082a70d987b17c0d487e1 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Thu, 4 Dec 2025 18:04:13 -0500 Subject: [PATCH 3/7] Remove toggle_user_liquidity tests --- pallets/swap/src/pallet/mod.rs | 3 + pallets/swap/src/pallet/tests.rs | 356 +++++++++++++++---------------- runtime/src/lib.rs | 2 +- 3 files changed, 182 insertions(+), 179 deletions(-) diff --git a/pallets/swap/src/pallet/mod.rs b/pallets/swap/src/pallet/mod.rs index 83d9847881..06a122ab4f 100644 --- a/pallets/swap/src/pallet/mod.rs +++ b/pallets/swap/src/pallet/mod.rs @@ -617,6 +617,9 @@ mod pallet { netuid, enable: false, }); + + // Remove provided liquidity + // Self::do_dissolve_all_liquidity_providers(netuid)?; } } diff --git a/pallets/swap/src/pallet/tests.rs b/pallets/swap/src/pallet/tests.rs index 5b8cca643f..ff226a481c 100644 --- a/pallets/swap/src/pallet/tests.rs +++ b/pallets/swap/src/pallet/tests.rs @@ -114,42 +114,42 @@ mod dispatchables { }); } - #[test] - fn test_toggle_user_liquidity() { - new_test_ext().execute_with(|| { - let netuid = NetUid::from(101); - - assert!(!EnabledUserLiquidity::::get(netuid)); - - assert_ok!(Swap::toggle_user_liquidity( - RuntimeOrigin::root(), - netuid.into(), - true - )); - - assert!(EnabledUserLiquidity::::get(netuid)); - - assert_noop!( - Swap::toggle_user_liquidity(RuntimeOrigin::signed(666), netuid.into(), true), - DispatchError::BadOrigin - ); - - assert_ok!(Swap::toggle_user_liquidity( - RuntimeOrigin::signed(1), - netuid.into(), - true - )); - - assert_noop!( - Swap::toggle_user_liquidity( - RuntimeOrigin::root(), - NON_EXISTENT_NETUID.into(), - true - ), - Error::::MechanismDoesNotExist - ); - }); - } + // #[test] + // fn test_toggle_user_liquidity() { + // new_test_ext().execute_with(|| { + // let netuid = NetUid::from(101); + + // assert!(!EnabledUserLiquidity::::get(netuid)); + + // assert_ok!(Swap::toggle_user_liquidity( + // RuntimeOrigin::root(), + // netuid.into(), + // true + // )); + + // assert!(EnabledUserLiquidity::::get(netuid)); + + // assert_noop!( + // Swap::toggle_user_liquidity(RuntimeOrigin::signed(666), netuid.into(), true), + // DispatchError::BadOrigin + // ); + + // assert_ok!(Swap::toggle_user_liquidity( + // RuntimeOrigin::signed(1), + // netuid.into(), + // true + // )); + + // assert_noop!( + // Swap::toggle_user_liquidity( + // RuntimeOrigin::root(), + // NON_EXISTENT_NETUID.into(), + // true + // ), + // Error::::MechanismDoesNotExist + // ); + // }); + // } } #[test] @@ -1398,79 +1398,79 @@ fn test_convert_deltas() { }); } -#[test] -fn test_user_liquidity_disabled() { - new_test_ext().execute_with(|| { - // Use a netuid above 100 since our mock enables liquidity for 0-100 - let netuid = NetUid::from(101); - let tick_low = TickIndex::new_unchecked(-1000); - let tick_high = TickIndex::new_unchecked(1000); - let position_id = PositionId::from(1); - let liquidity = 1_000_000_000; - let liquidity_delta = 500_000_000; - - assert!(!EnabledUserLiquidity::::get(netuid)); - - assert_noop!( - Swap::do_add_liquidity( - netuid, - &OK_COLDKEY_ACCOUNT_ID, - &OK_HOTKEY_ACCOUNT_ID, - tick_low, - tick_high, - liquidity - ), - Error::::UserLiquidityDisabled - ); - - assert_noop!( - Swap::do_remove_liquidity(netuid, &OK_COLDKEY_ACCOUNT_ID, position_id), - Error::::LiquidityNotFound - ); - - assert_noop!( - Swap::modify_position( - RuntimeOrigin::signed(OK_COLDKEY_ACCOUNT_ID), - OK_HOTKEY_ACCOUNT_ID, - netuid, - position_id, - liquidity_delta - ), - Error::::UserLiquidityDisabled - ); - - assert_ok!(Swap::toggle_user_liquidity( - RuntimeOrigin::root(), - netuid, - true - )); - - let position_id = Swap::do_add_liquidity( - netuid, - &OK_COLDKEY_ACCOUNT_ID, - &OK_HOTKEY_ACCOUNT_ID, - tick_low, - tick_high, - liquidity, - ) - .unwrap() - .0; - - assert_ok!(Swap::do_modify_position( - netuid.into(), - &OK_COLDKEY_ACCOUNT_ID, - &OK_HOTKEY_ACCOUNT_ID, - position_id, - liquidity_delta, - )); - - assert_ok!(Swap::do_remove_liquidity( - netuid, - &OK_COLDKEY_ACCOUNT_ID, - position_id, - )); - }); -} +// #[test] +// fn test_user_liquidity_disabled() { +// new_test_ext().execute_with(|| { +// // Use a netuid above 100 since our mock enables liquidity for 0-100 +// let netuid = NetUid::from(101); +// let tick_low = TickIndex::new_unchecked(-1000); +// let tick_high = TickIndex::new_unchecked(1000); +// let position_id = PositionId::from(1); +// let liquidity = 1_000_000_000; +// let liquidity_delta = 500_000_000; + +// assert!(!EnabledUserLiquidity::::get(netuid)); + +// assert_noop!( +// Swap::do_add_liquidity( +// netuid, +// &OK_COLDKEY_ACCOUNT_ID, +// &OK_HOTKEY_ACCOUNT_ID, +// tick_low, +// tick_high, +// liquidity +// ), +// Error::::UserLiquidityDisabled +// ); + +// assert_noop!( +// Swap::do_remove_liquidity(netuid, &OK_COLDKEY_ACCOUNT_ID, position_id), +// Error::::LiquidityNotFound +// ); + +// assert_noop!( +// Swap::modify_position( +// RuntimeOrigin::signed(OK_COLDKEY_ACCOUNT_ID), +// OK_HOTKEY_ACCOUNT_ID, +// netuid, +// position_id, +// liquidity_delta +// ), +// Error::::UserLiquidityDisabled +// ); + +// assert_ok!(Swap::toggle_user_liquidity( +// RuntimeOrigin::root(), +// netuid, +// true +// )); + +// let position_id = Swap::do_add_liquidity( +// netuid, +// &OK_COLDKEY_ACCOUNT_ID, +// &OK_HOTKEY_ACCOUNT_ID, +// tick_low, +// tick_high, +// liquidity, +// ) +// .unwrap() +// .0; + +// assert_ok!(Swap::do_modify_position( +// netuid.into(), +// &OK_COLDKEY_ACCOUNT_ID, +// &OK_HOTKEY_ACCOUNT_ID, +// position_id, +// liquidity_delta, +// )); + +// assert_ok!(Swap::do_remove_liquidity( +// netuid, +// &OK_COLDKEY_ACCOUNT_ID, +// position_id, +// )); +// }); +// } /// Test correctness of swap fees: /// - Fees are distribued to (concentrated) liquidity providers @@ -2047,75 +2047,75 @@ fn test_liquidate_v3_removes_positions_ticks_and_state() { /// V3 path with user liquidity disabled at teardown: /// must still remove positions and clear state (after protocol clear). -#[test] -fn test_liquidate_v3_with_user_liquidity_disabled() { - new_test_ext().execute_with(|| { - let netuid = NetUid::from(101); - - assert_ok!(Pallet::::maybe_initialize_v3(netuid)); - assert!(SwapV3Initialized::::get(netuid)); - - // Enable temporarily to add a user position - assert_ok!(Swap::toggle_user_liquidity( - RuntimeOrigin::root(), - netuid.into(), - true - )); - - let min_price = tick_to_price(TickIndex::MIN); - let max_price = tick_to_price(TickIndex::MAX); - let tick_low = price_to_tick(min_price); - let tick_high = price_to_tick(max_price); - let liquidity = 1_000_000_000_u64; - - let (_pos_id, _tao, _alpha) = Pallet::::do_add_liquidity( - netuid, - &OK_COLDKEY_ACCOUNT_ID, - &OK_HOTKEY_ACCOUNT_ID, - tick_low, - tick_high, - liquidity, - ) - .expect("add liquidity"); - - // Disable user LP *before* liquidation; removal must ignore this flag. - assert_ok!(Swap::toggle_user_liquidity( - RuntimeOrigin::root(), - netuid.into(), - false - )); - - // Users-only dissolve, then clear protocol liquidity/state. - assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); - assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); - - // ASSERT: positions & ticks gone, state reset - assert_eq!( - Pallet::::count_positions(netuid, &OK_COLDKEY_ACCOUNT_ID), - 0 - ); - assert!( - Positions::::iter_prefix_values((netuid, OK_COLDKEY_ACCOUNT_ID)) - .next() - .is_none() - ); - assert!(Ticks::::iter_prefix(netuid).next().is_none()); - assert!( - TickIndexBitmapWords::::iter_prefix((netuid,)) - .next() - .is_none() - ); - assert!(!SwapV3Initialized::::contains_key(netuid)); - assert!(!AlphaSqrtPrice::::contains_key(netuid)); - assert!(!CurrentTick::::contains_key(netuid)); - assert!(!CurrentLiquidity::::contains_key(netuid)); - assert!(!FeeGlobalTao::::contains_key(netuid)); - assert!(!FeeGlobalAlpha::::contains_key(netuid)); - - // `EnabledUserLiquidity` is removed by protocol clear stage. - assert!(!EnabledUserLiquidity::::contains_key(netuid)); - }); -} +// #[test] +// fn test_liquidate_v3_with_user_liquidity_disabled() { +// new_test_ext().execute_with(|| { +// let netuid = NetUid::from(101); + +// assert_ok!(Pallet::::maybe_initialize_v3(netuid)); +// assert!(SwapV3Initialized::::get(netuid)); + +// // Enable temporarily to add a user position +// assert_ok!(Swap::toggle_user_liquidity( +// RuntimeOrigin::root(), +// netuid.into(), +// true +// )); + +// let min_price = tick_to_price(TickIndex::MIN); +// let max_price = tick_to_price(TickIndex::MAX); +// let tick_low = price_to_tick(min_price); +// let tick_high = price_to_tick(max_price); +// let liquidity = 1_000_000_000_u64; + +// let (_pos_id, _tao, _alpha) = Pallet::::do_add_liquidity( +// netuid, +// &OK_COLDKEY_ACCOUNT_ID, +// &OK_HOTKEY_ACCOUNT_ID, +// tick_low, +// tick_high, +// liquidity, +// ) +// .expect("add liquidity"); + +// // Disable user LP *before* liquidation; removal must ignore this flag. +// assert_ok!(Swap::toggle_user_liquidity( +// RuntimeOrigin::root(), +// netuid.into(), +// false +// )); + +// // Users-only dissolve, then clear protocol liquidity/state. +// assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); +// assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); + +// // ASSERT: positions & ticks gone, state reset +// assert_eq!( +// Pallet::::count_positions(netuid, &OK_COLDKEY_ACCOUNT_ID), +// 0 +// ); +// assert!( +// Positions::::iter_prefix_values((netuid, OK_COLDKEY_ACCOUNT_ID)) +// .next() +// .is_none() +// ); +// assert!(Ticks::::iter_prefix(netuid).next().is_none()); +// assert!( +// TickIndexBitmapWords::::iter_prefix((netuid,)) +// .next() +// .is_none() +// ); +// assert!(!SwapV3Initialized::::contains_key(netuid)); +// assert!(!AlphaSqrtPrice::::contains_key(netuid)); +// assert!(!CurrentTick::::contains_key(netuid)); +// assert!(!CurrentLiquidity::::contains_key(netuid)); +// assert!(!FeeGlobalTao::::contains_key(netuid)); +// assert!(!FeeGlobalAlpha::::contains_key(netuid)); + +// // `EnabledUserLiquidity` is removed by protocol clear stage. +// assert!(!EnabledUserLiquidity::::contains_key(netuid)); +// }); +// } /// Non‑V3 path: V3 not initialized (no positions); function must still clear any residual storages and succeed. #[test] diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index d568099c2f..9c63332a75 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -237,7 +237,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: 356, + spec_version: 357, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 71fc1c21ddf65ade7a0cfcd0c71e085ddccc81e5 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Thu, 4 Dec 2025 19:00:05 -0500 Subject: [PATCH 4/7] clippy --- pallets/swap/src/pallet/tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/swap/src/pallet/tests.rs b/pallets/swap/src/pallet/tests.rs index ff226a481c..4013248abb 100644 --- a/pallets/swap/src/pallet/tests.rs +++ b/pallets/swap/src/pallet/tests.rs @@ -2045,8 +2045,8 @@ fn test_liquidate_v3_removes_positions_ticks_and_state() { }); } -/// V3 path with user liquidity disabled at teardown: -/// must still remove positions and clear state (after protocol clear). +// V3 path with user liquidity disabled at teardown: +// must still remove positions and clear state (after protocol clear). // #[test] // fn test_liquidate_v3_with_user_liquidity_disabled() { // new_test_ext().execute_with(|| { From 5e94d283c0569bddfd4b457bb195b1e9a7b0f7e7 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Thu, 4 Dec 2025 19:26:44 -0500 Subject: [PATCH 5/7] Comment failing benchmark --- pallets/swap/src/benchmarking.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pallets/swap/src/benchmarking.rs b/pallets/swap/src/benchmarking.rs index 0d926a640f..cced187ce5 100644 --- a/pallets/swap/src/benchmarking.rs +++ b/pallets/swap/src/benchmarking.rs @@ -131,17 +131,17 @@ mod benchmarks { ); } - #[benchmark] - fn toggle_user_liquidity() { - let netuid = NetUid::from(101); + // #[benchmark] + // fn toggle_user_liquidity() { + // let netuid = NetUid::from(101); - assert!(!EnabledUserLiquidity::::get(netuid)); + // assert!(!EnabledUserLiquidity::::get(netuid)); - #[extrinsic_call] - toggle_user_liquidity(RawOrigin::Root, netuid.into(), true); + // #[extrinsic_call] + // toggle_user_liquidity(RawOrigin::Root, netuid.into(), true); - assert!(EnabledUserLiquidity::::get(netuid)); - } + // assert!(EnabledUserLiquidity::::get(netuid)); + // } impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); } From 056c1279532b05e155c703345f227e82bf8e4917 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Thu, 4 Dec 2025 19:43:27 -0500 Subject: [PATCH 6/7] Remove unused import --- pallets/swap/src/benchmarking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/swap/src/benchmarking.rs b/pallets/swap/src/benchmarking.rs index cced187ce5..a52e44d7b7 100644 --- a/pallets/swap/src/benchmarking.rs +++ b/pallets/swap/src/benchmarking.rs @@ -12,7 +12,7 @@ use subtensor_runtime_common::NetUid; use crate::{ pallet::{ - AlphaSqrtPrice, Call, Config, CurrentLiquidity, CurrentTick, EnabledUserLiquidity, Pallet, + AlphaSqrtPrice, Call, Config, CurrentLiquidity, CurrentTick, Pallet, Positions, SwapV3Initialized, }, position::{Position, PositionId}, From 5d545adeb1fe2753e6820bc94bde184afd2283ee Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Thu, 4 Dec 2025 19:58:42 -0500 Subject: [PATCH 7/7] fmt --- pallets/swap/src/benchmarking.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/swap/src/benchmarking.rs b/pallets/swap/src/benchmarking.rs index a52e44d7b7..66ff88fd31 100644 --- a/pallets/swap/src/benchmarking.rs +++ b/pallets/swap/src/benchmarking.rs @@ -12,8 +12,8 @@ use subtensor_runtime_common::NetUid; use crate::{ pallet::{ - AlphaSqrtPrice, Call, Config, CurrentLiquidity, CurrentTick, Pallet, - Positions, SwapV3Initialized, + AlphaSqrtPrice, Call, Config, CurrentLiquidity, CurrentTick, Pallet, Positions, + SwapV3Initialized, }, position::{Position, PositionId}, tick::TickIndex,