From cd020ce51819762e719276c4c3b563ad14dc1a7a Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 16 Mar 2026 20:02:41 +0800 Subject: [PATCH 1/6] init solution --- pallets/subtensor/src/coinbase/root.rs | 3 +- pallets/swap-interface/src/lib.rs | 2 +- pallets/swap/src/benchmarking.rs | 43 ++++++++++++++++++++++++-- pallets/swap/src/pallet/impls.rs | 34 +++++++++++++------- pallets/swap/src/pallet/mod.rs | 12 +++++-- 5 files changed, 76 insertions(+), 18 deletions(-) diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index e2714fba1b..7a1a210d8a 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -213,7 +213,8 @@ impl Pallet { Self::finalize_all_subnet_root_dividends(netuid); // --- Perform the cleanup before removing the network. - T::SwapInterface::dissolve_all_liquidity_providers(netuid)?; + // Will handle it in dissolve network PR. + let _ = T::SwapInterface::dissolve_all_liquidity_providers(netuid); Self::destroy_alpha_in_out_stakes(netuid)?; T::SwapInterface::clear_protocol_liquidity(netuid)?; T::CommitmentsInterface::purge_netuid(netuid); diff --git a/pallets/swap-interface/src/lib.rs b/pallets/swap-interface/src/lib.rs index 9fbeefd3b6..d925b0f78f 100644 --- a/pallets/swap-interface/src/lib.rs +++ b/pallets/swap-interface/src/lib.rs @@ -44,7 +44,7 @@ pub trait SwapHandler { fn min_price() -> C; fn adjust_protocol_liquidity(netuid: NetUid, tao_delta: TaoBalance, alpha_delta: AlphaBalance); fn is_user_liquidity_enabled(netuid: NetUid) -> bool; - fn dissolve_all_liquidity_providers(netuid: NetUid) -> DispatchResult; + fn dissolve_all_liquidity_providers(netuid: NetUid) -> DispatchResultWithPostInfo; fn toggle_user_liquidity(netuid: NetUid, enabled: bool); fn clear_protocol_liquidity(netuid: NetUid) -> DispatchResult; } diff --git a/pallets/swap/src/benchmarking.rs b/pallets/swap/src/benchmarking.rs index a17ac59141..a218094b78 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, EnabledUserLiquidity, Pallet, + Positions, SwapV3Initialized, }, position::{Position, PositionId}, tick::TickIndex, @@ -132,6 +132,45 @@ mod benchmarks { ); } + #[benchmark] + fn disable_lp() { + let netuid = NetUid::from(1); + + // Initialize V3 state for this subnet if needed + if !SwapV3Initialized::::get(netuid) { + SwapV3Initialized::::insert(netuid, true); + AlphaSqrtPrice::::insert(netuid, U64F64::from_num(1)); + CurrentTick::::insert(netuid, TickIndex::new(0).unwrap()); + CurrentLiquidity::::insert(netuid, T::MinimumLiquidity::get()); + } + + // Create a single user LP position so that do_dissolve_all_liquidity_providers + // executes its main path at least once. + let caller: T::AccountId = whitelisted_caller(); + let hotkey: T::AccountId = account("hotkey", 0, 0); + let id = PositionId::from(1u128); + + Positions::::insert( + (netuid, caller.clone(), id), + Position { + id, + netuid, + tick_low: TickIndex::new(-10000).unwrap(), + tick_high: TickIndex::new(10000).unwrap(), + liquidity: 1_000, + fees_tao: I64F64::from_num(0), + fees_alpha: I64F64::from_num(0), + _phantom: PhantomData, + }, + ); + + // Enable user liquidity on this subnet so the toggle path is exercised. + EnabledUserLiquidity::::insert(netuid, true); + + #[extrinsic_call] + disable_lp(RawOrigin::Root); + } + // #[benchmark] // fn toggle_user_liquidity() { // let netuid = NetUid::from(101); diff --git a/pallets/swap/src/pallet/impls.rs b/pallets/swap/src/pallet/impls.rs index cc309216bb..da88601df7 100644 --- a/pallets/swap/src/pallet/impls.rs +++ b/pallets/swap/src/pallet/impls.rs @@ -1,7 +1,8 @@ use core::ops::Neg; +use frame_support::dispatch::DispatchResultWithPostInfo; use frame_support::storage::{TransactionOutcome, transactional}; -use frame_support::{ensure, pallet_prelude::DispatchError, traits::Get}; +use frame_support::{ensure, pallet_prelude::DispatchError, traits::Get, weights::Weight}; use safe_math::*; use sp_arithmetic::{helpers_128bit, traits::Zero}; use sp_runtime::{DispatchResult, Vec, traits::AccountIdConversion}; @@ -10,10 +11,6 @@ use subtensor_runtime_common::{ AlphaBalance, BalanceOps, NetUid, SubnetInfo, TaoBalance, Token, TokenReserve, }; -use subtensor_swap_interface::{ - DefaultPriceLimit, Order as OrderT, SwapEngine, SwapHandler, SwapResult, -}; - use super::pallet::*; use super::swap_step::{BasicSwapStep, SwapStep, SwapStepAction}; use crate::{ @@ -21,6 +18,9 @@ use crate::{ position::{Position, PositionId}, tick::{ActiveTickIndexManager, Tick, TickIndex}, }; +use subtensor_swap_interface::{ + DefaultPriceLimit, Order as OrderT, SwapEngine, SwapHandler, SwapResult, +}; const MAX_SWAP_ITERATIONS: u16 = 1000; @@ -829,17 +829,21 @@ impl Pallet { } /// Dissolve all LPs and clean state. - pub fn do_dissolve_all_liquidity_providers(netuid: NetUid) -> DispatchResult { + pub fn do_dissolve_all_liquidity_providers(netuid: NetUid) -> DispatchResultWithPostInfo { + let mut weight = Weight::default(); if SwapV3Initialized::::get(netuid) { + weight = weight.saturating_add(T::DbWeight::get().reads(1)); // 1) Snapshot only *non‑protocol* positions: (owner, position_id). struct CloseItem { owner: A, pos_id: PositionId, } let protocol_account = Self::protocol_account_id(); + weight = weight.saturating_add(T::DbWeight::get().reads(1)); let mut to_close: sp_std::vec::Vec> = sp_std::vec::Vec::new(); for ((owner, pos_id), _pos) in Positions::::iter_prefix((netuid,)) { + weight = weight.saturating_add(T::DbWeight::get().reads(1)); if owner != protocol_account { to_close.push(CloseItem { owner, pos_id }); } @@ -849,14 +853,16 @@ impl Pallet { log::debug!( "dissolve_all_lp: no user positions; netuid={netuid:?}, protocol liquidity untouched" ); - return Ok(()); + return Ok(Some(weight).into()); } let mut user_refunded_tao = TaoBalance::ZERO; let mut user_staked_alpha = AlphaBalance::ZERO; let trust: Vec = T::SubnetInfo::get_validator_trust(netuid.into()); + weight = weight.saturating_add(T::DbWeight::get().reads(1)); let permit: Vec = T::SubnetInfo::get_validator_permit(netuid.into()); + weight = weight.saturating_add(T::DbWeight::get().reads(1)); // Helper: pick target validator uid, only among permitted validators, by highest trust. let pick_target_uid = |trust: &Vec, permit: &Vec| -> Option { @@ -874,6 +880,7 @@ impl Pallet { for CloseItem { owner, pos_id } in to_close.into_iter() { match Self::do_remove_liquidity(netuid, &owner, pos_id) { Ok(rm) => { + weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 6)); // α withdrawn from the pool = principal + accrued fees let alpha_total_from_pool: AlphaBalance = rm.alpha.saturating_add(rm.fee_alpha); @@ -884,9 +891,11 @@ impl Pallet { let tao_total_from_pool: TaoBalance = rm.tao.saturating_add(rm.fee_tao); if tao_total_from_pool > TaoBalance::ZERO { T::BalanceOps::increase_balance(&owner, tao_total_from_pool); + weight = weight.saturating_add(T::DbWeight::get().writes(1)); user_refunded_tao = user_refunded_tao.saturating_add(tao_total_from_pool); T::TaoReserve::decrease_provided(netuid, tao_total_from_pool); + weight = weight.saturating_add(T::DbWeight::get().writes(1)); } // 2) Stake ALL withdrawn α (principal + fees) to the best permitted validator. @@ -898,6 +907,7 @@ impl Pallet { "validator_hotkey_missing", ), )?; + weight = weight.saturating_add(T::DbWeight::get().reads(1)); // Stake α from LP owner (coldkey) to chosen validator (hotkey). T::BalanceOps::increase_stake( @@ -906,7 +916,7 @@ impl Pallet { netuid, alpha_total_from_pool, )?; - + weight = weight.saturating_add(T::DbWeight::get().writes(1)); user_staked_alpha = user_staked_alpha.saturating_add(alpha_total_from_pool); @@ -921,12 +931,14 @@ impl Pallet { } T::AlphaReserve::decrease_provided(netuid, alpha_total_from_pool); + weight = weight.saturating_add(T::DbWeight::get().writes(1)); } } Err(e) => { log::debug!( "dissolve_all_lp: force-close failed: netuid={netuid:?}, owner={owner:?}, pos_id={pos_id:?}, err={e:?}" ); + weight = weight.saturating_add(T::DbWeight::get().reads(1)); continue; } } @@ -936,14 +948,14 @@ impl Pallet { "dissolve_all_liquidity_providers (users-only): netuid={netuid:?}, users_refunded_total_τ={user_refunded_tao:?}, users_staked_total_α={user_staked_alpha:?}; protocol liquidity untouched" ); - return Ok(()); + return Ok(Some(weight).into()); } log::debug!( "dissolve_all_liquidity_providers: netuid={netuid:?}, mode=V2-or-nonV3, leaving all liquidity/state intact" ); - Ok(()) + Ok(Some(weight).into()) } /// Clear **protocol-owned** liquidity and wipe all swap state for `netuid`. @@ -1148,7 +1160,7 @@ impl SwapHandler for Pallet { fn is_user_liquidity_enabled(netuid: NetUid) -> bool { EnabledUserLiquidity::::get(netuid) } - fn dissolve_all_liquidity_providers(netuid: NetUid) -> DispatchResult { + fn dissolve_all_liquidity_providers(netuid: NetUid) -> DispatchResultWithPostInfo { Self::do_dissolve_all_liquidity_providers(netuid) } fn toggle_user_liquidity(netuid: NetUid, enabled: bool) { diff --git a/pallets/swap/src/pallet/mod.rs b/pallets/swap/src/pallet/mod.rs index 281467277e..9f758d72ef 100644 --- a/pallets/swap/src/pallet/mod.rs +++ b/pallets/swap/src/pallet/mod.rs @@ -612,13 +612,16 @@ mod pallet { /// Emits `Event::UserLiquidityToggled` on success #[pallet::call_index(5)] #[pallet::weight(::WeightInfo::modify_position())] - pub fn disable_lp(origin: OriginFor) -> DispatchResult { + pub fn disable_lp(origin: OriginFor) -> DispatchResultWithPostInfo { ensure_root(origin)?; + let mut weight = Weight::default(); for netuid in 1..=128 { let netuid = NetUid::from(netuid as u16); if EnabledUserLiquidity::::get(netuid) { + weight = weight.saturating_add(T::DbWeight::get().reads(1)); EnabledUserLiquidity::::insert(netuid, false); + weight = weight.saturating_add(T::DbWeight::get().writes(1)); Self::deposit_event(Event::UserLiquidityToggled { netuid, enable: false, @@ -628,10 +631,13 @@ mod pallet { // Remove provided liquidity unconditionally because the network may have // user liquidity previously disabled // Ignore result to avoid early stopping - let _ = Self::do_dissolve_all_liquidity_providers(netuid); + if let Ok(result) = Self::do_dissolve_all_liquidity_providers(netuid) { + weight = + weight.saturating_add(result.actual_weight.unwrap_or(Weight::default())); + } } - Ok(()) + Ok(Some(weight).into()) } } } From 88873cfc5b692cebedc84f499b9ecc2048be674c Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 16 Mar 2026 20:48:16 +0800 Subject: [PATCH 2/6] fix clippy issue --- pallets/swap/src/benchmarking.rs | 50 +++++++++++++++----------------- pallets/swap/src/pallet/mod.rs | 2 +- pallets/swap/src/weights.rs | 12 ++++++++ 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/pallets/swap/src/benchmarking.rs b/pallets/swap/src/benchmarking.rs index a218094b78..baf0b425f0 100644 --- a/pallets/swap/src/benchmarking.rs +++ b/pallets/swap/src/benchmarking.rs @@ -134,38 +134,36 @@ mod benchmarks { #[benchmark] fn disable_lp() { - let netuid = NetUid::from(1); - - // Initialize V3 state for this subnet if needed - if !SwapV3Initialized::::get(netuid) { - SwapV3Initialized::::insert(netuid, true); - AlphaSqrtPrice::::insert(netuid, U64F64::from_num(1)); - CurrentTick::::insert(netuid, TickIndex::new(0).unwrap()); - CurrentLiquidity::::insert(netuid, T::MinimumLiquidity::get()); - } - // Create a single user LP position so that do_dissolve_all_liquidity_providers // executes its main path at least once. let caller: T::AccountId = whitelisted_caller(); - let hotkey: T::AccountId = account("hotkey", 0, 0); let id = PositionId::from(1u128); - Positions::::insert( - (netuid, caller.clone(), id), - Position { - id, - netuid, - tick_low: TickIndex::new(-10000).unwrap(), - tick_high: TickIndex::new(10000).unwrap(), - liquidity: 1_000, - fees_tao: I64F64::from_num(0), - fees_alpha: I64F64::from_num(0), - _phantom: PhantomData, - }, - ); + for netuid in 1..=128 { + let netuid = NetUid::from(1); - // Enable user liquidity on this subnet so the toggle path is exercised. - EnabledUserLiquidity::::insert(netuid, true); + SwapV3Initialized::::insert(netuid, true); + AlphaSqrtPrice::::insert(netuid, U64F64::from_num(1)); + CurrentTick::::insert(netuid, TickIndex::new(0).unwrap()); + CurrentLiquidity::::insert(netuid, T::MinimumLiquidity::get()); + + Positions::::insert( + (netuid, caller.clone(), id), + Position { + id, + netuid, + tick_low: TickIndex::new(-10000).unwrap(), + tick_high: TickIndex::new(10000).unwrap(), + liquidity: 1_000, + fees_tao: I64F64::from_num(0), + fees_alpha: I64F64::from_num(0), + _phantom: PhantomData, + }, + ); + + // Enable user liquidity on this subnet so the toggle path is exercised. + EnabledUserLiquidity::::insert(netuid, true); + } #[extrinsic_call] disable_lp(RawOrigin::Root); diff --git a/pallets/swap/src/pallet/mod.rs b/pallets/swap/src/pallet/mod.rs index 9f758d72ef..b4a41629ce 100644 --- a/pallets/swap/src/pallet/mod.rs +++ b/pallets/swap/src/pallet/mod.rs @@ -611,7 +611,7 @@ mod pallet { /// /// Emits `Event::UserLiquidityToggled` on success #[pallet::call_index(5)] - #[pallet::weight(::WeightInfo::modify_position())] + #[pallet::weight(::WeightInfo::disable_lp())] pub fn disable_lp(origin: OriginFor) -> DispatchResultWithPostInfo { ensure_root(origin)?; let mut weight = Weight::default(); diff --git a/pallets/swap/src/weights.rs b/pallets/swap/src/weights.rs index 2bbbb8dbdf..8fec86bf92 100644 --- a/pallets/swap/src/weights.rs +++ b/pallets/swap/src/weights.rs @@ -19,6 +19,7 @@ pub trait WeightInfo { fn remove_liquidity() -> Weight; fn modify_position() -> Weight; fn toggle_user_liquidity() -> Weight; + fn disable_lp() -> Weight; } /// Default weights for pallet_subtensor_swap. @@ -58,6 +59,12 @@ impl WeightInfo for DefaultWeight { .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + fn disable_lp() -> Weight { + // Conservative weight estimate: one read and one write + Weight::from_parts(10_000_000, 0) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } // For backwards compatibility and tests @@ -91,4 +98,9 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().writes(1)) } + fn disable_lp() -> Weight { + Weight::from_parts(10_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) + } } From 6b262ea3eb2a8dd0f21dc3b8d29555ef52352ca1 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 16 Mar 2026 20:48:47 +0800 Subject: [PATCH 3/6] cargo clippy --- 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 baf0b425f0..30c649ab82 100644 --- a/pallets/swap/src/benchmarking.rs +++ b/pallets/swap/src/benchmarking.rs @@ -140,7 +140,7 @@ mod benchmarks { let id = PositionId::from(1u128); for netuid in 1..=128 { - let netuid = NetUid::from(1); + let netuid = NetUid::from(netuid as u16); SwapV3Initialized::::insert(netuid, true); AlphaSqrtPrice::::insert(netuid, U64F64::from_num(1)); From bf511dda57dd8e03cffbfbe8dd356e2e4996acd3 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 16 Mar 2026 20:49:00 +0800 Subject: [PATCH 4/6] cargo fix --- 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 30c649ab82..4b9b999694 100644 --- a/pallets/swap/src/benchmarking.rs +++ b/pallets/swap/src/benchmarking.rs @@ -140,7 +140,7 @@ mod benchmarks { let id = PositionId::from(1u128); for netuid in 1..=128 { - let netuid = NetUid::from(netuid as u16); + let netuid = NetUid::from(netuid); SwapV3Initialized::::insert(netuid, true); AlphaSqrtPrice::::insert(netuid, U64F64::from_num(1)); From da413aa5465f753fc2f63e35676b1d83e11e3017 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 16 Mar 2026 20:49:14 +0800 Subject: [PATCH 5/6] commit Cargo.lock --- 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 4b9b999694..f61730a0d2 100644 --- a/pallets/swap/src/benchmarking.rs +++ b/pallets/swap/src/benchmarking.rs @@ -139,8 +139,8 @@ mod benchmarks { let caller: T::AccountId = whitelisted_caller(); let id = PositionId::from(1u128); - for netuid in 1..=128 { - let netuid = NetUid::from(netuid); + for index in 1..=128 { + let netuid = NetUid::from(index); SwapV3Initialized::::insert(netuid, true); AlphaSqrtPrice::::insert(netuid, U64F64::from_num(1)); From cbe5d53696bf111178df5d0fd4a8d6ad860355b4 Mon Sep 17 00:00:00 2001 From: open-junius Date: Tue, 17 Mar 2026 09:46:21 +0800 Subject: [PATCH 6/6] update benchmark --- pallets/swap/src/weights.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pallets/swap/src/weights.rs b/pallets/swap/src/weights.rs index 8fec86bf92..ccffdd7504 100644 --- a/pallets/swap/src/weights.rs +++ b/pallets/swap/src/weights.rs @@ -60,10 +60,10 @@ impl WeightInfo for DefaultWeight { .saturating_add(T::DbWeight::get().writes(1)) } fn disable_lp() -> Weight { - // Conservative weight estimate: one read and one write - Weight::from_parts(10_000_000, 0) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) + // Conservative weight estimate: 1920 read and 896 write + Weight::from_parts(5_174_000_000, 0) + .saturating_add(T::DbWeight::get().reads(1920)) + .saturating_add(T::DbWeight::get().writes(896)) } } @@ -99,8 +99,8 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(1)) } fn disable_lp() -> Weight { - Weight::from_parts(10_000_000, 0) - .saturating_add(RocksDbWeight::get().reads(1)) - .saturating_add(RocksDbWeight::get().writes(1)) + Weight::from_parts(5_174_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(1920)) + .saturating_add(RocksDbWeight::get().writes(896)) } }