Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion pallets/subtensor/src/coinbase/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,8 @@ impl<T: Config> Pallet<T> {
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);
Expand Down
2 changes: 1 addition & 1 deletion pallets/swap-interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub trait SwapHandler {
fn min_price<C: Token>() -> 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;
Expand Down
41 changes: 39 additions & 2 deletions pallets/swap/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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::<T>::insert(netuid, true);
AlphaSqrtPrice::<T>::insert(netuid, U64F64::from_num(1));
CurrentTick::<T>::insert(netuid, TickIndex::new(0).unwrap());
CurrentLiquidity::<T>::insert(netuid, T::MinimumLiquidity::get());

Positions::<T>::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::<T>::insert(netuid, true);
}

#[extrinsic_call]
disable_lp(RawOrigin::Root);
}

// #[benchmark]
// fn toggle_user_liquidity() {
// let netuid = NetUid::from(101);
Expand Down
34 changes: 23 additions & 11 deletions pallets/swap/src/pallet/impls.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -10,17 +11,16 @@ 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::{
SqrtPrice,
position::{Position, PositionId},
tick::{ActiveTickIndexManager, Tick, TickIndex},
};
use subtensor_swap_interface::{
DefaultPriceLimit, Order as OrderT, SwapEngine, SwapHandler, SwapResult,
};

const MAX_SWAP_ITERATIONS: u16 = 1000;

Expand Down Expand Up @@ -829,17 +829,21 @@ impl<T: Config> Pallet<T> {
}

/// 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::<T>::get(netuid) {
weight = weight.saturating_add(T::DbWeight::get().reads(1));
// 1) Snapshot only *non‑protocol* positions: (owner, position_id).
struct CloseItem<A> {
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<CloseItem<T::AccountId>> = sp_std::vec::Vec::new();
for ((owner, pos_id), _pos) in Positions::<T>::iter_prefix((netuid,)) {
weight = weight.saturating_add(T::DbWeight::get().reads(1));
if owner != protocol_account {
to_close.push(CloseItem { owner, pos_id });
}
Expand All @@ -849,14 +853,16 @@ impl<T: Config> Pallet<T> {
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<u16> = T::SubnetInfo::get_validator_trust(netuid.into());
weight = weight.saturating_add(T::DbWeight::get().reads(1));
let permit: Vec<bool> = 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<u16>, permit: &Vec<bool>| -> Option<u16> {
Expand All @@ -874,6 +880,7 @@ impl<T: Config> Pallet<T> {
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);
Expand All @@ -884,9 +891,11 @@ impl<T: Config> Pallet<T> {
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.
Expand All @@ -898,6 +907,7 @@ impl<T: Config> Pallet<T> {
"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(
Expand All @@ -906,7 +916,7 @@ impl<T: Config> Pallet<T> {
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);

Expand All @@ -921,12 +931,14 @@ impl<T: Config> Pallet<T> {
}

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;
}
}
Expand All @@ -936,14 +948,14 @@ impl<T: Config> Pallet<T> {
"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`.
Expand Down Expand Up @@ -1148,7 +1160,7 @@ impl<T: Config> SwapHandler for Pallet<T> {
fn is_user_liquidity_enabled(netuid: NetUid) -> bool {
EnabledUserLiquidity::<T>::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) {
Expand Down
14 changes: 10 additions & 4 deletions pallets/swap/src/pallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -606,14 +606,17 @@ mod pallet {
///
/// Emits `Event::UserLiquidityToggled` on success
#[pallet::call_index(5)]
#[pallet::weight(<T as pallet::Config>::WeightInfo::modify_position())]
pub fn disable_lp(origin: OriginFor<T>) -> DispatchResult {
#[pallet::weight(<T as pallet::Config>::WeightInfo::disable_lp())]
pub fn disable_lp(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
ensure_root(origin)?;
let mut weight = Weight::default();

for netuid in 1..=128 {
let netuid = NetUid::from(netuid as u16);
if EnabledUserLiquidity::<T>::get(netuid) {
weight = weight.saturating_add(T::DbWeight::get().reads(1));
EnabledUserLiquidity::<T>::insert(netuid, false);
weight = weight.saturating_add(T::DbWeight::get().writes(1));
Self::deposit_event(Event::UserLiquidityToggled {
netuid,
enable: false,
Expand All @@ -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())
}
}
}
12 changes: 12 additions & 0 deletions pallets/swap/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -58,6 +59,12 @@ impl<T: frame_system::Config> WeightInfo for DefaultWeight<T> {
.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
Expand Down Expand Up @@ -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))
}
}
Loading