diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index db5b4fe2cc..7c7c0ea7ce 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 1a1cd0156e..a37e9e49ad 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; fn get_alpha_amount_for_tao(netuid: NetUid, tao_amount: TaoBalance) -> AlphaBalance; diff --git a/pallets/swap/src/benchmarking.rs b/pallets/swap/src/benchmarking.rs index a17ac59141..f61730a0d2 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,43 @@ mod benchmarks { ); } + #[benchmark] + fn disable_lp() { + // 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 id = PositionId::from(1u128); + + for index in 1..=128 { + let netuid = NetUid::from(index); + + 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); + } + // #[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 0eda907567..2b15601b0b 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 f096c80210..c364df3024 100644 --- a/pallets/swap/src/pallet/mod.rs +++ b/pallets/swap/src/pallet/mod.rs @@ -606,14 +606,17 @@ mod pallet { /// /// Emits `Event::UserLiquidityToggled` on success #[pallet::call_index(5)] - #[pallet::weight(::WeightInfo::modify_position())] - pub fn disable_lp(origin: OriginFor) -> DispatchResult { + #[pallet::weight(::WeightInfo::disable_lp())] + 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, @@ -623,10 +626,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()) } } } diff --git a/pallets/swap/src/weights.rs b/pallets/swap/src/weights.rs index 2bbbb8dbdf..ccffdd7504 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: 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)) + } } // 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(5_174_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(1920)) + .saturating_add(RocksDbWeight::get().writes(896)) + } }