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] diff --git a/pallets/swap/src/benchmarking.rs b/pallets/swap/src/benchmarking.rs index 0d926a640f..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, EnabledUserLiquidity, Pallet, - Positions, SwapV3Initialized, + AlphaSqrtPrice, Call, Config, CurrentLiquidity, CurrentTick, Pallet, Positions, + SwapV3Initialized, }, position::{Position, PositionId}, tick::TickIndex, @@ -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); } diff --git a/pallets/swap/src/pallet/mod.rs b/pallets/swap/src/pallet/mod.rs index 1501f9cb37..97a25ec242 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,31 @@ 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, + }); + } + + // Remove provided liquidity unconditionally because the network may have + // user liquidity previously disabled + Self::do_dissolve_all_liquidity_providers(netuid)?; + } + + Ok(()) + } } } diff --git a/pallets/swap/src/pallet/tests.rs b/pallets/swap/src/pallet/tests.rs index 5b8cca643f..4013248abb 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 @@ -2045,77 +2045,77 @@ 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)); - }); -} +// 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)); +// }); +// } /// 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 8f46d2d8e2..e5c733d7ed 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -220,7 +220,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: 349, + spec_version: 350, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1,